double.js
Version:
Emulated float128 or double-double arithmetic. A floating point expansion with 31 accurate decimal digits.
650 lines (622 loc) • 18 kB
JavaScript
var Double = (function (exports) {
'use strict';
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
var splitter = 134217729.;
function twoSum(a, b) {
var s = a + b;
var a1 = s - b;
return {
hi: s,
lo: a - a1 + (b - (s - a1))
};
}
function twoProd(a, b) {
var t = splitter * a;
var ah = t + (a - t),
al = a - ah;
t = splitter * b;
var bh = t + (b - t),
bl = b - bh;
t = a * b;
return {
hi: t,
lo: ah * bh - t + ah * bl + al * bh + al * bl
};
}
function oneSqr(a) {
var t = splitter * a;
var ah = t + (a - t),
al = a - ah;
t = a * a;
var hl = al * ah;
return {
hi: t,
lo: ah * ah - t + hl + hl + al * al
};
}
var Double =
/*#__PURE__*/
function () {
function Double(obj) {
_classCallCheck(this, Double);
if (obj instanceof Double) {
this.hi = obj.hi;
this.lo = obj.lo;
} else if (typeof obj === 'number') {
this.hi = obj;
this.lo = 0.;
} else if (typeof obj === 'string') {
var d = Double.fromString(obj);
this.hi = d.hi;
this.lo = d.lo;
} else if (Array.isArray(obj)) {
this.hi = obj[0];
this.lo = obj[1];
} else if (_typeof(obj) === 'object') {
this.hi = obj.hi;
this.lo = obj.lo;
}
}
_createClass(Double, [{
key: "toNumber",
value: function toNumber() {
return this.hi + this.lo;
}
}, {
key: "toExponential",
value: function toExponential(precision) {
if (precision === undefined) precision = 33;
var result = this.hi < 0. ? '-' : '';
if (isNaN(this.hi)) return 'NaN';
if (!isFinite(this.hi)) return result + 'Infinity';
if (this.toNumber() == 0.) return '0e+0';
var exp = this.hi.toExponential().split('e')[1];
var str, nextDigs, shift, isPositive;
for (var i = 0; i < precision; i += 15) {
str = this.hi.toExponential().split('e');
isPositive = str[0][0] != '-';
nextDigs = str[0].replace(/^0\.|\./, '').slice(0, 15);
if (!isPositive) nextDigs = nextDigs.slice(1);
shift = Double.pow2n(new Double(10), parseInt(str[1]) - 14);
Double.sub22(this, Double.mul21(shift, parseInt(nextDigs) * (isPositive ? 1 : -1)));
nextDigs = nextDigs.slice(0, precision - i);
result += i != 0 ? nextDigs : nextDigs.slice(0, 1) + '.' + nextDigs.slice(1);
}
return result + 'e' + exp;
}
}, {
key: "add",
value: function add(other) {
if (other instanceof Double) return Double.add22(Double.clone(this), other);else if (typeof other == 'number') return Double.add21(Double.clone(this), other);
}
}, {
key: "sub",
value: function sub(other) {
if (other instanceof Double) return Double.sub22(Double.clone(this), other);else if (typeof other == 'number') return Double.sub21(Double.clone(this), other);
}
}, {
key: "mul",
value: function mul(other) {
if (other instanceof Double) return Double.mul22(Double.clone(this), other);else if (typeof other == 'number') return Double.mul21(Double.clone(this), other);
}
}, {
key: "div",
value: function div(other) {
if (other instanceof Double) return Double.div22(Double.clone(this), other);else if (typeof other == 'number') return Double.div21(Double.clone(this), other);
}
}, {
key: "eq",
value: function eq(other) {
if (other instanceof Double) return Double.eq22(this, other);else if (typeof other == 'number') return Double.eq21(this, other);
}
}, {
key: "ne",
value: function ne(other) {
if (other instanceof Double) return Double.ne22(this, other);else if (typeof other == 'number') return Double.ne21(this, other);
}
}, {
key: "gt",
value: function gt(other) {
if (other instanceof Double) return Double.gt22(this, other);else if (typeof other == 'number') return Double.gt21(this, other);
}
}, {
key: "lt",
value: function lt(other) {
if (other instanceof Double) return Double.lt22(this, other);else if (typeof other == 'number') return Double.lt21(this, other);
}
}, {
key: "ge",
value: function ge(other) {
if (other instanceof Double) return Double.ge22(this, other);else if (typeof other == 'number') return Double.ge21(this, other);
}
}, {
key: "le",
value: function le(other) {
if (other instanceof Double) return Double.le22(this, other);else if (typeof other == 'number') return Double.le21(this, other);
}
}, {
key: "abs",
value: function abs() {
return Double.abs2(Double.clone(this));
}
}, {
key: "neg",
value: function neg() {
return Double.neg2(Double.clone(this));
}
}, {
key: "inv",
value: function inv() {
return Double.inv2(Double.clone(this));
}
}, {
key: "sqr",
value: function sqr() {
return Double.sqr2(Double.clone(this));
}
}, {
key: "sqrt",
value: function sqrt() {
return Double.sqrt2(Double.clone(this));
}
}, {
key: "exp",
value: function exp() {
return Double.exp2(Double.clone(this));
}
}, {
key: "ln",
value: function ln() {
return Double.ln2(Double.clone(this));
}
}, {
key: "sinh",
value: function sinh() {
return Double.sinh2(Double.clone(this));
}
}, {
key: "cosh",
value: function cosh() {
return Double.cosh2(Double.clone(this));
}
}, {
key: "pow",
value: function pow(exp) {
return Double.pow22(Double.clone(this), exp);
}
}, {
key: "pown",
value: function pown(exp) {
return Double.pow2n(Double.clone(this), exp);
}
}], [{
key: "clone",
value: function clone(X) {
var d = new Double();
d.hi = X.hi;
d.lo = X.lo;
return d;
}
}, {
key: "fromSum11",
value: function fromSum11(a, b) {
return new Double(twoSum(a, b));
}
}, {
key: "fromMul11",
value: function fromMul11(a, b) {
return new Double(twoProd(a, b));
}
}, {
key: "fromSqr1",
value: function fromSqr1(a) {
return new Double(oneSqr(a));
}
}, {
key: "fromString",
value: function fromString(s) {
var isPositive = /^\s*-/.exec(s) === null;
s = s.replace(/^\s*[+-]?/, '');
if (/Infinity.*/.exec(s) !== null) return isPositive ? Double.Infinity : Double.neg2(Double.Infinity);
var rex = /^([0-9]*\.?[0-9]+)(?:[eE]([-+]?[0-9]+))?/.exec(s);
if (!rex) return Double.NaN;
var digits = rex[1].replace('.', '');
var exp = rex[2] !== undefined ? parseInt(rex[2]) : 0;
var dotId = rex[0].indexOf('.');
if (dotId == -1) dotId = digits.length;
if (exp + dotId - 1. < -300.) return isPositive ? Double.Zero : Double.neg2(Double.Zero);
if (exp + dotId - 1. > 300.) return isPositive ? Double.Infinity : Double.neg2(Double.Infinity);
var nextDigs,
shift,
result = Double.Zero;
for (var i = 0; i < digits.length; i += 15) {
nextDigs = digits.slice(i, i + 15);
shift = Double.pow2n(new Double(10.), exp + dotId - i - nextDigs.length);
Double.add22(result, Double.mul21(shift, parseInt(nextDigs)));
}
return isPositive ? result : Double.neg2(result);
}
}, {
key: "add22",
value: function add22(X, Y) {
var S = twoSum(X.hi, Y.hi);
var E = twoSum(X.lo, Y.lo);
var c = S.lo + E.hi;
var vh = S.hi + c,
vl = c - (vh - S.hi);
c = vl + E.lo;
X.hi = vh + c;
X.lo = c - (X.hi - vh);
return X;
}
}, {
key: "sub22",
value: function sub22(X, Y) {
var S = twoSum(X.hi, -Y.hi);
var E = twoSum(X.lo, -Y.lo);
var c = S.lo + E.hi;
var vh = S.hi + c,
vl = c - (vh - S.hi);
c = vl + E.lo;
X.hi = vh + c;
X.lo = c - (X.hi - vh);
return X;
}
}, {
key: "mul22",
value: function mul22(X, Y) {
var S = twoProd(X.hi, Y.hi);
S.lo += X.hi * Y.lo + X.lo * Y.hi;
X.hi = S.hi + S.lo;
X.lo = S.lo - (X.hi - S.hi);
return X;
}
}, {
key: "div22",
value: function div22(X, Y) {
var s = X.hi / Y.hi;
var T = twoProd(s, Y.hi);
var e = (X.hi - T.hi - T.lo + X.lo - s * Y.lo) / Y.hi;
X.hi = s + e;
X.lo = e - (X.hi - s);
return X;
}
}, {
key: "add21",
value: function add21(X, f) {
var S = twoSum(X.hi, f);
S.lo += X.lo;
X.hi = S.hi + S.lo;
X.lo = S.lo - (X.hi - S.hi);
return X;
}
}, {
key: "sub21",
value: function sub21(X, f) {
var S = twoSum(X.hi, -f);
S.lo += X.lo;
X.hi = S.hi + S.lo;
X.lo = S.lo - (X.hi - S.hi);
return X;
}
}, {
key: "mul21",
value: function mul21(X, f) {
var C = twoProd(X.hi, f);
var cl = X.lo * f;
var th = C.hi + cl;
X.lo = cl - (th - C.hi);
cl = X.lo + C.lo;
X.hi = th + cl;
X.lo = cl - (X.hi - th);
return X;
}
}, {
key: "div21",
value: function div21(X, f) {
var th = X.hi / f;
var P = twoProd(th, f);
var D = twoSum(X.hi, -P.hi);
var tl = (D.hi + (D.lo + (X.lo - P.lo))) / f;
X.hi = th + tl;
X.lo = tl - (X.hi - th);
return X;
}
}, {
key: "abs2",
value: function abs2(X) {
if (X.hi < 0.) {
X.hi = -X.hi;
X.lo = -X.lo;
}
return X;
}
}, {
key: "neg2",
value: function neg2(X) {
X.hi = -X.hi;
X.lo = -X.lo;
return X;
}
}, {
key: "inv2",
value: function inv2(X) {
var xh = X.hi;
var s = 1. / xh;
Double.mul21(X, s);
var zl = (1. - X.hi - X.lo) / xh;
X.hi = s + zl;
X.lo = zl - (X.hi - s);
return X;
}
}, {
key: "sqr2",
value: function sqr2(X) {
var S = oneSqr(X.hi);
var c = X.hi * X.lo;
S.lo += c + c;
X.hi = S.hi + S.lo;
X.lo = S.lo - (X.hi - S.hi);
return X;
}
}, {
key: "sqrt2",
value: function sqrt2(X) {
var s = Math.sqrt(X.hi);
var T = oneSqr(s);
var e = (X.hi - T.hi - T.lo + X.lo) * 0.5 / s;
X.hi = s + e;
X.lo = e - (X.hi - s);
return X;
}
}, {
key: "eq22",
value: function eq22(X, Y) {
return X.hi === Y.hi && X.lo === Y.lo;
}
}, {
key: "ne22",
value: function ne22(X, Y) {
return X.hi !== Y.hi || X.lo !== Y.lo;
}
}, {
key: "gt22",
value: function gt22(X, Y) {
return X.hi > Y.hi || X.hi === Y.hi && X.lo > Y.lo;
}
}, {
key: "lt22",
value: function lt22(X, Y) {
return X.hi < Y.hi || X.hi === Y.hi && X.lo < Y.lo;
}
}, {
key: "ge22",
value: function ge22(X, Y) {
return X.hi > Y.hi || X.hi === Y.hi && X.lo >= Y.lo;
}
}, {
key: "le22",
value: function le22(X, Y) {
return X.hi < Y.hi || X.hi === Y.hi && X.lo <= Y.lo;
}
}, {
key: "eq21",
value: function eq21(X, f) {
return X.hi === f && X.lo === 0.;
}
}, {
key: "ne21",
value: function ne21(X, f) {
return X.hi !== f || X.lo !== 0.;
}
}, {
key: "gt21",
value: function gt21(X, f) {
return X.hi > f || X.hi === f && X.lo > 0.;
}
}, {
key: "lt21",
value: function lt21(X, f) {
return X.hi < f || X.hi === f && X.lo < 0.;
}
}, {
key: "ge21",
value: function ge21(X, f) {
return X.hi > f || X.hi === f && X.lo >= 0.;
}
}, {
key: "le21",
value: function le21(X, f) {
return X.hi < f || X.hi === f && X.lo <= 0.;
}
}, {
key: "exp2",
value: function exp2(X) {
if (Double.eq21(X, 0.)) return Double.One;
if (Double.eq21(X, 1.)) return Double.E;
var n = Math.floor(X.hi / Double.Log2.hi + 0.5);
Double.sub22(X, Double.mul21(Double.Log2, n));
var U = Double.One,
V = Double.One;
var padeCoef = [1, 272, 36720, 3255840, 211629600, 10666131840, 430200650880, 14135164243200, 381649434566400, 8481098545920000, 154355993535744030, 2273242813890047700, 26521166162050560000, 236650405753681870000, 1.5213240369879552e+21, 6.288139352883548e+21, 1.2576278705767096e+22];
for (var i = 0, cLen = padeCoef.length; i < cLen; i++) {
Double.add21(Double.mul22(U, X), padeCoef[i]);
}
for (var _i = 0, _cLen = padeCoef.length; _i < _cLen; _i++) {
Double.add21(Double.mul22(V, X), padeCoef[_i] * (_i % 2 ? -1 : 1));
}
X = Double.mul21pow2(Double.div22(U, V), n);
return X;
}
}, {
key: "ln2",
value: function ln2(X) {
if (Double.le21(X, 0)) return Double.MinusInfinity;
if (Double.eq21(X, 1)) return Double.Zero;
var Z = new Double(Math.log(X.hi));
Double.sub21(Double.add22(Double.mul22(X, Double.exp2(Double.neg2(Double.clone(Z)))), Z), 1.);
return X;
}
}, {
key: "sinh2",
value: function sinh2(X) {
var exp = Double.exp2(X);
X = Double.mul21pow2(Double.sub22(new Double(exp), Double.inv2(exp)), -1.);
return X;
}
}, {
key: "cosh2",
value: function cosh2(X) {
var exp = Double.exp2(X);
X = Double.mul21pow2(Double.add22(new Double(exp), Double.inv2(exp)), -1.);
return X;
}
}, {
key: "pow22",
value: function pow22(base, exp) {
return Double.exp2(Double.mul22(Double.ln2(base), exp));
}
}, {
key: "mul21pow2",
value: function mul21pow2(X, n) {
var c = 1. << Math.abs(n);
if (n < 0) c = 1 / c;
X.hi = X.hi * c;
X.lo = X.lo * c;
return X;
}
}, {
key: "pow2n",
value: function pow2n(X, n) {
if (n === 0) return Double.One;
if (n == 1) return X;
var isPositive = n > 0;
if (!isPositive) n = -n;
var i = 31 - Math.clz32(n | 1);
var j = Math.floor(n - (1 << i));
var X0 = Double.clone(X);
while (i--) {
Double.sqr2(X);
}
while (j--) {
Double.mul22(X, X0);
}
return isPositive ? X : Double.inv2(X);
}
}, {
key: "One",
get: function get() {
var d = new Double();
d.hi = 1.;
d.lo = 0.;
return d;
}
}, {
key: "Zero",
get: function get() {
var d = new Double();
d.hi = 0.;
d.lo = 0.;
return d;
}
}, {
key: "Infinity",
get: function get() {
var d = new Double();
d.hi = Infinity;
d.lo = Infinity;
return d;
}
}, {
key: "MinusInfinity",
get: function get() {
var d = new Double();
d.hi = -Infinity;
d.lo = -Infinity;
return d;
}
}, {
key: "NaN",
get: function get() {
var d = new Double();
d.hi = NaN;
d.lo = NaN;
return d;
}
}, {
key: "Pi",
get: function get() {
var d = new Double();
d.hi = 3.141592653589793;
d.lo = 1.2246467991473532e-16;
return d;
}
}, {
key: "X2Pi",
get: function get() {
var d = new Double();
d.hi = 6.283185307179586;
d.lo = 2.4492935982947064e-16;
return d;
}
}, {
key: "E",
get: function get() {
var d = new Double();
d.hi = 2.718281828459045;
d.lo = 1.4456468917292502e-16;
return d;
}
}, {
key: "Log2",
get: function get() {
var d = new Double();
d.hi = 0.6931471805599453;
d.lo = 2.319046813846299e-17;
return d;
}
}, {
key: "Phi",
get: function get() {
var d = new Double();
d.hi = 1.618033988749895;
d.lo = -5.432115203682505e-17;
return d;
}
}]);
return Double;
}();
exports.Double = Double;
exports.default = Double;
return exports;
}({}));