babel-plugin-transform-bigint
Advanced tools
Comparing version 1.0.6 to 1.0.7
19
index.js
@@ -34,2 +34,3 @@ // see https://github.com/babel/babel/pull/6015 | ||
case '===': return 'equal'; | ||
case '!==': return 'notEqual'; | ||
} | ||
@@ -73,2 +74,5 @@ return null; | ||
} | ||
if (path.node.type === 'UnaryExpression') { | ||
return canBeBigInt(path.get('argument')); | ||
} | ||
if (path.node.type === 'BinaryExpression') { | ||
@@ -100,2 +104,17 @@ return canBeBigInt(path.get('left')) && canBeBigInt(path.get('right')); | ||
} | ||
if (path.node.type === 'FunctionExpression') { | ||
return false; | ||
} | ||
if (path.node.type === 'NewExpression') { | ||
return false; | ||
} | ||
if (path.node.type === 'NullLiteral') { | ||
return false; | ||
} | ||
if (path.node.type === 'LogicalExpression') { | ||
return false;//? | ||
} | ||
if (path.node.type === 'ObjectProperty') { | ||
return false;//? | ||
} | ||
//TODO: | ||
@@ -102,0 +121,0 @@ return true; |
{ | ||
"name": "babel-plugin-transform-bigint", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "A plugin for babel to transform `x * y` into something like `JSBI.multiply(x, y)` to support bigints.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
671
tests.js
@@ -0,3 +1,670 @@ | ||
/*jslint bigint: true, vars: true, indent: 2*/ | ||
var x = true ? "" : "-"; | ||
var s = x + "test"; | ||
// Usage: | ||
// BigDecimal.BigDecimal(bigint) | ||
// BigDecimal.BigDecimal(string) | ||
// BigDecimal.toBigInt(a) (not in the spec) | ||
// BigDecimal.unaryMinus(a) | ||
// BigDecimal.add(a, b[, rounding]) | ||
// BigDecimal.subtract(a, b[, rounding]) | ||
// BigDecimal.multiply(a, b[, rounding]) | ||
// BigDecimal.divide(a, b, rounding) | ||
// BigDecimal.lessThan(a, b) | ||
// BigDecimal.greaterThan(a, b) | ||
// BigDecimal.equal(a, b) | ||
// BigDecimal.round(a, rounding) | ||
// a.toExponential([fractionDigits]) | ||
// a.toString() | ||
// a.toPrecision(fractionDigits) | ||
// a.toFixed(fractionDigits) | ||
// Math: (not in the spec) | ||
// BigDecimal.log(a, rounding) | ||
// BigDecimal.exp(a, rounding) | ||
// BigDecimal.sin(a, rounding) | ||
// BigDecimal.cos(a, rounding) | ||
// BigDecimal.atan(a, rounding) | ||
function BigDecimal(significand, exponent) { | ||
this.significand = significand; | ||
this.exponent = exponent; | ||
} | ||
BigDecimal.BigDecimal = function (value) { | ||
if (value instanceof BigDecimal) { | ||
return value; | ||
} | ||
if (typeof value === "string") { | ||
//throw new TypeError(); | ||
var match = /^\s*([+\-])?(\d+)?\.?(\d+)?(?:e([+\-]?\d+))?\s*$/.exec(value); | ||
if (match == null) { | ||
throw new RangeError(); | ||
} | ||
return create(BigInt((match[1] || "") + (match[2] || "") + (match[3] || "")), BigInt(match[4] || "0") - BigInt((match[3] || "").length)); | ||
} | ||
return create(BigInt(value), 0n); | ||
}; | ||
BigDecimal.toBigInt = function (a) { | ||
if (a.exponent < 0n && a.significand % 10n**(-a.exponent) !== 0n) { | ||
throw new RangeError("The bigdecimal " + a.toString() + " cannot be converted to a BigInt because it is not an integer"); | ||
} | ||
return a.exponent < 0n ? a.significand / 10n**(-a.exponent) : a.significand * 10n**a.exponent; | ||
}; | ||
function create(significand, exponent) { | ||
return new BigDecimal(significand, exponent); | ||
} | ||
function bigIntMax(a, b) { | ||
return a < b ? b : a; | ||
} | ||
function bigIntMin(a, b) { | ||
return a < b ? a : b; | ||
} | ||
function bigIntSign(a) { | ||
return a < 0n ? -1n : (a > 0n ? 1n : 0n); | ||
} | ||
function bigIntAbs(a) { | ||
return a < 0n ? -a : a; | ||
} | ||
function digits(a) { | ||
function binaryDigits(n) { | ||
// https://github.com/tc39/proposal-bigint/issues/205 | ||
var s = n.toString(16); | ||
var c = s.charCodeAt(0); | ||
var k = 0; | ||
if (c <= "1".charCodeAt(0)) { | ||
k = 1; | ||
} else if (c <= "3".charCodeAt(0)) { | ||
k = 2; | ||
} else if (c <= "7".charCodeAt(0)) { | ||
k = 3; | ||
} else { | ||
k = 4; | ||
} | ||
return 4 * (s.length - 1) + k; | ||
} | ||
var n = bigIntMax(bigIntAbs(a.significand), 1n); | ||
var number = Number(n); | ||
if (number < 2**49) { | ||
var result = Math.floor(Math.log10(number + 0.5)) + 1; | ||
//console.assert(Math.pow(10, result) <= number * 10 && number < Math.pow(10, result)); | ||
return result; | ||
} | ||
if (number < 1 / 0) { | ||
var e = Math.log10(number); | ||
if (Math.floor(e * (1 + 2 / (Number.MAX_SAFE_INTEGER + 1))) < e) { | ||
var result = Math.floor(e) + 1; | ||
//console.assert(10n**BigInt(result) <= n * 10n && n < 10n**BigInt(result)); | ||
return result; | ||
} | ||
} | ||
var k = binaryDigits(n); | ||
var log10nApproximation = Math.log10(2) * (k - 50) + Math.log10(Number(n / 2n**BigInt(k - 50))); | ||
var e = log10nApproximation; | ||
if (Math.floor(e * (1 - 2**-48)) === Math.floor(e) && | ||
Math.floor(e * (1 + 2**-48)) === Math.floor(e)) { | ||
var result = Math.floor(e) + 1; | ||
//console.assert(10n**BigInt(result) <= n * 10n && n < 10n**BigInt(result)); | ||
return result; | ||
} | ||
e = Math.floor(e + 0.5); | ||
var g = 10n**BigInt(e); | ||
if (n >= g) { | ||
e += 1; | ||
g *= 10n; | ||
} | ||
if (n * 10n < g) { | ||
g /= 10n; | ||
e -= 1; | ||
} | ||
console.assert(g <= n * 10n && n < g); | ||
return e; | ||
} | ||
function normalize(a) { | ||
if (a.significand <= -67108864n || a.significand >= 67108864n) { // Math.sqrt((Number.MAX_SAFE_INTEGER + 1) / 2) | ||
var dividend = a.significand; | ||
var divisor = 10n**15n; | ||
var e = 15; | ||
if (dividend % divisor === 0n) { | ||
while (dividend % (divisor**2n) === 0n) { | ||
divisor = divisor**2n; | ||
e *= 2; | ||
} | ||
var quotient = dividend / divisor; | ||
return create(quotient, a.exponent + BigInt(e)); | ||
} | ||
} | ||
if (a.significand === 0n && a.exponent !== 0n) { | ||
return create(0n, 0n); | ||
} | ||
return a; | ||
} | ||
function round(a, d, r, rounding) { | ||
if (rounding != null) { | ||
var k = 0n; | ||
if (rounding.maximumSignificantDigits != null) { | ||
console.assert(rounding.maximumSignificantDigits > 0); | ||
k = bigIntMax(BigInt(digits(a) - rounding.maximumSignificantDigits), 0n); | ||
} | ||
if (rounding.maximumFractionDigits != null) { | ||
console.assert(rounding.maximumFractionDigits >= 0); | ||
k = bigIntMax(0n - (a.exponent + BigInt(rounding.maximumFractionDigits)), 0n); | ||
} | ||
if (k > 0n || r !== 0n) { | ||
var divisor = 10n**k; | ||
var dividend = a.significand; | ||
var quotient = dividend / divisor; | ||
var remainder = dividend - quotient * divisor; | ||
divisor = divisor * d; | ||
remainder = remainder * d + r; | ||
if (remainder !== 0n) { | ||
if (rounding.roundingMode === "floor") { | ||
if (remainder < 0n) { | ||
quotient -= 1n; | ||
} | ||
} else if (rounding.roundingMode === "ceil") { | ||
if (remainder > 0n) { | ||
quotient += 1n; | ||
} | ||
} else if (rounding.roundingMode === "half-up") { | ||
if (remainder * 2n >= divisor) { | ||
quotient += 1n; | ||
} | ||
if (-remainder * 2n >= divisor) { | ||
quotient -= 1n; | ||
} | ||
} else if (rounding.roundingMode === "half-down") { | ||
if (remainder * 2n > divisor) { | ||
quotient += 1n; | ||
} | ||
if (-remainder * 2n > divisor) { | ||
quotient -= 1n; | ||
} | ||
} else if (rounding.roundingMode === "half-even") { | ||
if (remainder * 2n > divisor || (remainder * 2n === divisor && quotient % 2n !== 0n)) { | ||
quotient += 1n; | ||
} | ||
if (-remainder * 2n > divisor || (-remainder * 2n === divisor && quotient % 2n !== 0n)) { | ||
quotient -= 1n; | ||
} | ||
} else { | ||
throw new RangeError("supported roundingMode (floor/ceil/half-even/half-up/half-down) is not given"); | ||
} | ||
} | ||
return create(quotient, a.exponent + k); | ||
} | ||
} | ||
if (r !== 0n) { | ||
throw new RangeError("rounding is not given for inexact operation"); | ||
} | ||
return a; | ||
} | ||
BigDecimal.unaryMinus = function (a) { | ||
return create(-a.significand, a.exponent); | ||
}; | ||
BigDecimal.add = function (a, b, rounding = null) { | ||
if (b.significand === 0n) { | ||
return round(a, 1n, 0n, rounding); | ||
} | ||
if (a.significand === 0n) { | ||
return round(b, 1n, 0n, rounding); | ||
} | ||
if (rounding != null && rounding.maximumSignificantDigits != null && a.exponent - b.exponent > BigInt(digits(b) + (rounding.maximumSignificantDigits + 1))) { | ||
b = create(bigIntSign(b.significand), a.exponent - BigInt(rounding.maximumSignificantDigits + 1)); | ||
} | ||
if (rounding != null && rounding.maximumSignificantDigits != null && b.exponent - a.exponent > BigInt(digits(a) + (rounding.maximumSignificantDigits + 1))) { | ||
a = create(bigIntSign(a.significand), b.exponent - BigInt(rounding.maximumSignificantDigits + 1)); | ||
} | ||
var exponent = bigIntMax(a.exponent, b.exponent); | ||
return round(create(a.significand * 10n**(exponent - b.exponent) + b.significand * 10n**(exponent - a.exponent), bigIntMin(a.exponent, b.exponent)), 1n, 0n, rounding); | ||
}; | ||
BigDecimal.subtract = function (a, b, rounding = null) { | ||
return BigDecimal.add(a, BigDecimal.unaryMinus(b), rounding); | ||
}; | ||
BigDecimal.multiply = function (a, b, rounding = null) { | ||
return normalize(round(create(a.significand * b.significand, a.exponent + b.exponent), 1n, 0n, rounding)); | ||
}; | ||
BigDecimal.divide = function (a, b, rounding) { | ||
if (a.significand === 0n) { | ||
return a; | ||
} | ||
var exponent = a.exponent - b.exponent; | ||
var scaling = 0n; | ||
if (rounding != null && rounding.maximumSignificantDigits != null) { | ||
scaling = BigInt(rounding.maximumSignificantDigits + digits(b) - digits(a)); | ||
} else if (rounding != null && rounding.maximumFractionDigits != null) { | ||
//scaling = BigInt(rounding.maximumFractionDigits) + bigIntMax(a.exponent, 0n) + bigIntMax(0n - b.exponent, 0n) - bigIntMin(a.exponent - b.exponent + BigInt(digits(a) - digits(b)), 0n); | ||
scaling = BigInt(rounding.maximumFractionDigits) + exponent; | ||
} else { | ||
// Try to do exact division: | ||
scaling = BigInt(Math.ceil(digits(b) / Math.log10(2) + 1)); | ||
} | ||
var dividend = a.significand * (scaling > 0n ? 10n**scaling : 1n); | ||
var divisor = b.significand * (scaling < 0n ? 10n**(-scaling) : 1n); | ||
var quotient = dividend / divisor; | ||
var remainder = dividend - quotient * divisor; | ||
return round(create(quotient, exponent - scaling), divisor < 0n ? -divisor : divisor, divisor < 0n ? -remainder : remainder, rounding); | ||
}; | ||
function lessThan(a, b) { | ||
if (a.significand <= 0n && b.significand >= 0n) { | ||
return !(a.significand === 0n && b.significand === 0n); | ||
} | ||
if (a.significand >= 0n && b.significand <= 0n) { | ||
return (a.significand === 0n && b.significand === 0n); | ||
} | ||
var differenceOfLogarithms = a.exponent - b.exponent + BigInt(digits(a) - digits(b)); | ||
if (differenceOfLogarithms !== 0n) { | ||
return a.significand < 0n && b.significand < 0n ? differenceOfLogarithms > 0n : differenceOfLogarithms < 0n; | ||
} | ||
var exponent = bigIntMax(a.exponent, b.exponent); | ||
return a.significand * 10n**(exponent - b.exponent) < b.significand * 10n**(exponent - a.exponent); | ||
}; | ||
BigDecimal.lessThan = function (a, b) { | ||
return lessThan(a, b); | ||
}; | ||
BigDecimal.greaterThan = function (a, b) { | ||
return lessThan(b, a); | ||
}; | ||
BigDecimal.equal = function (a, b) { | ||
return !lessThan(a, b) && !lessThan(b, a); | ||
}; | ||
BigDecimal.round = function (a, rounding) { | ||
return round(a, 1n, 0n, rounding); | ||
}; | ||
function getSignificand(a, log10) { | ||
var s = BigDecimal.divide(a, exponentiate(BigDecimal.BigDecimal(10n), log10)); | ||
while (!BigDecimal.equal(BigDecimal.round(s, {maximumFractionDigits: 0, roundingMode: "half-even"}), s)) { | ||
s = BigDecimal.multiply(s, BigDecimal.BigDecimal(10n**15n)); | ||
} | ||
return BigDecimal.toBigInt(s).toString().replace(/0+$/g, "") || "0"; | ||
}; | ||
BigDecimal.prototype.toExponential = function (fractionDigits) { | ||
//! https://tc39.es/ecma262/#sec-number.prototype.toexponential | ||
fractionDigits = fractionDigits == undefined ? undefined : Number(fractionDigits); | ||
var x = BigDecimal.BigDecimal(this); | ||
if (fractionDigits != undefined) { | ||
x = BigDecimal.round(x, {maximumSignificantDigits: fractionDigits + 1, roundingMode: "half-up"}) | ||
} | ||
var sign = BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n)) ? "-" : ""; | ||
var e = BigDecimal.equal(x, BigDecimal.BigDecimal(0n)) ? 0n : getCountOfDigits(x) - 1n; | ||
var m = getSignificand(BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n)) ? BigDecimal.unaryMinus(x) : x, e + 1n); | ||
return sign + (fractionDigits == undefined && m.length === 1 || fractionDigits === 0 ? m : m.slice(0, 1) + "." + m.slice(1) + (fractionDigits != undefined ? "0".repeat(fractionDigits - (m.length - 1)) : "")) + "e" + (e >= 0n ? "+" : "") + e.toString(); | ||
}; | ||
BigDecimal.prototype.toString = function () { | ||
//! https://tc39.es/ecma262/#sec-number.prototype.tostring | ||
if (arguments.length !== 0) { | ||
throw new RangeError("not implemented"); | ||
} | ||
var x = BigDecimal.BigDecimal(this); | ||
//! https://tc39.es/ecma262/#sec-numeric-types-number-tostring | ||
if (BigDecimal.equal(x, BigDecimal.BigDecimal(0n))) { | ||
return "0"; | ||
} | ||
function ToStringPositive(x) { | ||
var n = getCountOfDigits(x); | ||
var s = getSignificand(x, n); | ||
var k = BigInt(s.length); | ||
if (k <= n && n <= 21n) { | ||
return s + "0".repeat(Number(n - k)); | ||
} | ||
if (0n < n && n <= 21n) { | ||
return s.slice(0, Number(n)) + "." + s.slice(Number(n)); | ||
} | ||
if (-6n < n && n <= 0n) { | ||
return "0" + "." + "0".repeat(Number(-n)) + s; | ||
} | ||
if (k === 1n) { | ||
return s + "e" + (n - 1n < 0n ? "-" : "+") + bigIntAbs(n - 1n).toString(); | ||
} | ||
return s.slice(0, 1) + "." + s.slice(1) + "e" + (n - 1n < 0n ? "-" : "+") + bigIntAbs(n - 1n).toString(); | ||
} | ||
return (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n)) ? "-" + ToStringPositive(BigDecimal.unaryMinus(x)) : ToStringPositive(x)); | ||
}; | ||
BigDecimal.prototype.toPrecision = function (precision) { | ||
//! https://tc39.es/ecma262/#sec-number.prototype.tostring | ||
if (precision == undefined) { | ||
return this.toString(); | ||
} | ||
var p = Number(precision); | ||
var x = BigDecimal.BigDecimal(this); | ||
var s = ""; | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n))) { | ||
x = BigDecimal.unaryMinus(x); | ||
s = "-"; | ||
} | ||
var m = ""; | ||
var e = 0n; | ||
if (BigDecimal.equal(x, BigDecimal.BigDecimal(0n))) { | ||
m = "0".repeat(p); | ||
e = 0n; | ||
} else { | ||
x = BigDecimal.round(x, {maximumSignificantDigits: p, roundingMode: "half-up"}); | ||
var e = getCountOfDigits(x) - 1n; | ||
var significand = getSignificand(x, e + 1n); | ||
m = significand + "0".repeat(p - 1 - (significand.length - 1)); | ||
} | ||
if (e < -6n || e >= BigInt(p)) { | ||
console.assert(e !== 0n); | ||
if (p !== 1) { | ||
m = m.slice(0, 1) + "." + m.slice(1); | ||
} | ||
return s + m + "e" + (e < 0n ? "-" : "+") + bigIntAbs(e).toString(); | ||
} | ||
if (e === BigInt(p - 1)) { | ||
return s + m; | ||
} | ||
if (e >= 0n) { | ||
m = m.slice(0, Number(e) + 1) + "." + m.slice(Number(e) + 1); | ||
} else { | ||
// e >= -6 && e <= -1 | ||
// e + 1 >= -5 && e + 1 <= 0 | ||
// -(e + 1) >= 0 && -(e + 1) <= 5 | ||
m = "0" + "." + "0".repeat(-(Number(e) + 1)) + m; | ||
} | ||
return s + m; | ||
}; | ||
BigDecimal.prototype.toFixed = function (fractionDigits) { | ||
//! https://tc39.es/ecma262/#sec-number.prototype.tofixed | ||
var f = Number(fractionDigits || 0); | ||
var x = BigDecimal.BigDecimal(this); | ||
var s = ""; | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n))) { | ||
x = BigDecimal.unaryMinus(x); | ||
s = "-"; | ||
} | ||
var m = ""; | ||
if (!BigDecimal.lessThan(x, BigDecimal.BigDecimal(10n**21n))) { | ||
m = x.toString(); | ||
} else { | ||
x = BigDecimal.round(x, {maximumFractionDigits: f, roundingMode: "half-up"}); | ||
var e = BigDecimal.equal(x, BigDecimal.BigDecimal(0n)) ? 1n : getCountOfDigits(x); | ||
var significand = getSignificand(x, e); | ||
var m = significand + "0".repeat(Number(e) - significand.length + f); | ||
if (f !== 0) { | ||
var k = m.length; | ||
if (k <= f) { | ||
m = "0".repeat(f + 1 - k) + m; | ||
k = f + 1; | ||
} | ||
m = m.slice(0, k - f) + "." + m.slice(k - f); | ||
} | ||
} | ||
return s + m; | ||
}; | ||
function exponentiate(a, n) { | ||
if (n < 0n) { | ||
return BigDecimal.divide(BigDecimal.BigDecimal(1n), exponentiate(a, -n)); | ||
} | ||
console.assert(n >= 0n); | ||
var accumulator = BigDecimal.BigDecimal(1n); | ||
var x = a; | ||
while (n > 0n) { | ||
if (n % 2n !== 0n) { | ||
accumulator = BigDecimal.multiply(accumulator, x); | ||
n -= 1n; | ||
} else { | ||
n /= 2n; | ||
x = BigDecimal.multiply(x, x); | ||
} | ||
} | ||
return accumulator; | ||
} | ||
function getCountOfDigits(a) { // floor(log10(abs(a))) + 1 | ||
if (a.significand === 0n) { | ||
throw new RangeError(); | ||
} | ||
return BigInt(digits(a)) + a.exponent; | ||
} | ||
function abs(a) { | ||
return BigDecimal.lessThan(a, BigDecimal.BigDecimal(0n)) ? BigDecimal.unaryMinus(a) : a; | ||
} | ||
function sign(x) { | ||
return BigDecimal.BigDecimal(BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n)) ? -1n : (BigDecimal.greaterThan(x, BigDecimal.BigDecimal(0n)) ? 1n : 0n)); | ||
} | ||
function significandDigits(a) { | ||
var maximumSignificantDigits = 1; | ||
while (!BigDecimal.equal(BigDecimal.round(a, {maximumSignificantDigits: maximumSignificantDigits, roundingMode: "half-even"}), a)) { | ||
maximumSignificantDigits *= 2; | ||
} | ||
return maximumSignificantDigits; | ||
} | ||
function tryToMakeCorrectlyRounded(specialValue, f, name) { | ||
function getExpectedResultIntegerDigits(x) { | ||
if (name === "exp") { | ||
// e**x <= 10**k | ||
// k >= x / log(10) | ||
return Math.ceil(Number(BigDecimal.toBigInt(BigDecimal.round(x, {maximumFractionDigits: 0, roundingMode: "half-even"}))) / Math.log(10)); | ||
} | ||
if (name === "log") { | ||
// log(x) <= 10**k | ||
// log10(log10(x)*log(10)) <= k | ||
return Math.log10(Math.ceil(Math.max(Number(getCountOfDigits(x)), 1) * Math.log(10))); | ||
} | ||
return 1; | ||
} | ||
// (?) https://en.wikipedia.org/wiki/Rounding#Table-maker's_dilemma | ||
return function (x, rounding) { | ||
if (BigDecimal.equal(x, BigDecimal.BigDecimal(specialValue))) { | ||
return f(x, rounding); | ||
} | ||
var result = BigDecimal.BigDecimal(0n); | ||
var i = 0; | ||
do { | ||
i += 1; | ||
var internalRounding = { | ||
maximumSignificantDigits: Math.ceil(Math.max(rounding.maximumSignificantDigits || (rounding.maximumFractionDigits + 1 + getExpectedResultIntegerDigits(x) - 1), significandDigits(x)) * Math.cbrt(2)**(i - 1)) + 2, | ||
roundingMode: "half-even" | ||
}; | ||
result = f(x, internalRounding); | ||
// round(result - error) === round(result + error) | ||
var error = BigDecimal.divide(abs(result), BigDecimal.BigDecimal(10n**BigInt(internalRounding.maximumSignificantDigits))); | ||
if (i > 0) { | ||
//console.log(i, f.name, x + "", result + "", error + "", BigDecimal.round(BigDecimal.subtract(result, error), rounding) + "", BigDecimal.round(BigDecimal.add(result, error), rounding) + ""); | ||
} | ||
if (i > 10 && rounding.maximumSignificantDigits != undefined) { | ||
throw new Error(); | ||
} | ||
} while (!BigDecimal.equal(BigDecimal.round(BigDecimal.subtract(result, error), rounding), BigDecimal.round(BigDecimal.add(result, error), rounding))); | ||
if (i > 1) { | ||
console.log(i); | ||
} | ||
return BigDecimal.round(result, rounding); | ||
}; | ||
} | ||
function sqrt(x, rounding) { | ||
// from https://en.wikipedia.org/wiki/Square_root#Computation | ||
var lastResult = x; | ||
var result = BigDecimal.divide(x, BigDecimal.BigDecimal(2n)); | ||
while (BigDecimal.lessThan(result, lastResult)) { | ||
lastResult = result; | ||
result = BigDecimal.divide(BigDecimal.add(BigDecimal.divide(BigDecimal.BigDecimal(x), result, rounding), result), BigDecimal.BigDecimal(2n), rounding); | ||
} | ||
return result; | ||
} | ||
BigDecimal.log = tryToMakeCorrectlyRounded(1n, function (x, rounding) { | ||
if (!BigDecimal.greaterThan(x, BigDecimal.BigDecimal(0n))) { | ||
throw new RangeError(); | ||
} | ||
// https://ru.wikipedia.org/wiki/Логарифм#Разложение_в_ряд_и_вычисление_натурального_логарифма | ||
var internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log10(rounding.maximumSignificantDigits)), | ||
roundingMode: "half-even" | ||
}; | ||
if (true) { | ||
//! ln(f * 10**k) = ln(f) + k * ln(10), where 0.1 <= f <= 10 | ||
var k = getCountOfDigits(x) - 1n; | ||
var f = BigDecimal.divide(x, exponentiate(BigDecimal.BigDecimal(10n), k)); | ||
var ff = BigDecimal.round(BigDecimal.multiply(f, f), {maximumSignificantDigits: 3, roundingMode: "half-even"}); | ||
if (BigDecimal.greaterThan(ff, BigDecimal.BigDecimal(10n))) { | ||
k += 1n; | ||
f = BigDecimal.divide(f, BigDecimal.BigDecimal(10n)); | ||
} | ||
if (BigDecimal.lessThan(ff, BigDecimal.divide(BigDecimal.BigDecimal(1n), BigDecimal.BigDecimal(10n)))) { | ||
k -= 1n; | ||
f = BigDecimal.multiply(f, BigDecimal.BigDecimal(10n)); | ||
} | ||
if (k !== 0n) { | ||
return BigDecimal.add(BigDecimal.log(f, internalRounding), BigDecimal.multiply(BigDecimal.BigDecimal(2n * k), BigDecimal.log(BigDecimal.BigDecimal(sqrt(BigDecimal.BigDecimal(10n), internalRounding)), internalRounding))); | ||
} | ||
} | ||
//! log(x) = log((1 + g) / (1 - g)) = 2*(g + g**3/3 + g**5/5 + ...) | ||
var g = BigDecimal.divide(BigDecimal.subtract(x, BigDecimal.BigDecimal(1n)), BigDecimal.add(x, BigDecimal.BigDecimal(1n)), internalRounding); | ||
var t = BigDecimal.BigDecimal(1n); | ||
var lastSum = BigDecimal.BigDecimal(42n); | ||
var s = BigDecimal.BigDecimal(0n); | ||
var n = 1n; | ||
while (!BigDecimal.equal(lastSum, s)) { | ||
lastSum = s; | ||
s = BigDecimal.add(s, t, internalRounding); | ||
n += 2n; | ||
t = BigDecimal.multiply(t, BigDecimal.BigDecimal(n - 2n)); | ||
t = BigDecimal.multiply(t, BigDecimal.multiply(g, g)); | ||
t = BigDecimal.divide(t, BigDecimal.BigDecimal(n), internalRounding); | ||
} | ||
return BigDecimal.multiply(BigDecimal.multiply(BigDecimal.BigDecimal(2n), g), s); | ||
}, "log"); | ||
BigDecimal.exp = tryToMakeCorrectlyRounded(0n, function (x, rounding) { | ||
//! exp(x) = exp((x / ln(10) - round(x / ln(10)) + round(x / ln(10))) * ln(10)) = exp(x - round(x / ln(10)) * ln(10)) * 10**round(x / ln(10)) | ||
var k = BigDecimal.divide(x, BigDecimal.BigDecimal(BigDecimal.divide(BigDecimal.BigDecimal(2302585092994046n), BigDecimal.BigDecimal(1000000000000000n))), {maximumFractionDigits: 0, roundingMode: "half-even"}); | ||
var internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log10(rounding.maximumSignificantDigits)), | ||
roundingMode: "half-even" | ||
}; | ||
if (!BigDecimal.equal(k, BigDecimal.BigDecimal(0n))) { | ||
var r = BigDecimal.subtract(x, BigDecimal.multiply(k, BigDecimal.log(BigDecimal.BigDecimal(10n), {maximumSignificantDigits: internalRounding.maximumSignificantDigits + Number(getCountOfDigits(k)), roundingMode: "half-even"}))); | ||
return BigDecimal.multiply(BigDecimal.exp(r, internalRounding), exponentiate(BigDecimal.BigDecimal(10n), BigDecimal.toBigInt(k))); | ||
} | ||
//! https://en.wikipedia.org/wiki/Exponential_function#Computation | ||
var t = x; | ||
var lastSum = BigDecimal.BigDecimal(42n); | ||
var s = BigDecimal.BigDecimal(1n); | ||
var n = 1n; | ||
while (!BigDecimal.equal(lastSum, s)) { | ||
lastSum = s; | ||
s = BigDecimal.add(s, t, internalRounding); | ||
n += 1n; | ||
t = BigDecimal.multiply(t, x); | ||
t = BigDecimal.divide(t, BigDecimal.BigDecimal(n), internalRounding); | ||
} | ||
return s; | ||
}, "exp"); | ||
function divideByHalfOfPI(x, rounding) { // x = k*pi/2 + r + 2*pi*n, where |r| < pi/4 | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n))) { | ||
throw new RangeError(); | ||
} | ||
if (BigDecimal.greaterThan(x, BigDecimal.BigDecimal(String(Math.PI / 4)))) { | ||
var halfOfPi = BigDecimal.multiply(BigDecimal.BigDecimal(2n), BigDecimal.atan(BigDecimal.BigDecimal(1n), {maximumSignificantDigits: rounding.maximumSignificantDigits + Number(getCountOfDigits(x)), roundingMode: "half-even"})); | ||
var i = BigDecimal.divide(x, halfOfPi, {maximumFractionDigits: 0, roundingMode: "half-even"}); | ||
var remainder = BigDecimal.subtract(x, BigDecimal.multiply(i, halfOfPi)); | ||
return {remainder: remainder, k: (Number(BigDecimal.toBigInt(i) % 4n) + 4) % 4}; | ||
} | ||
return {remainder: x, k: 0}; | ||
} | ||
BigDecimal.sin = tryToMakeCorrectlyRounded(0n, function (x, rounding) { | ||
// https://en.wikipedia.org/wiki/Lookup_table#Computing_sines | ||
var internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log10(rounding.maximumSignificantDigits)), | ||
roundingMode: rounding.roundingMode | ||
}; | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n))) { | ||
return BigDecimal.unaryMinus(BigDecimal.sin(BigDecimal.unaryMinus(x), rounding)); | ||
} | ||
var tmp = divideByHalfOfPI(x, rounding); | ||
var a = tmp.remainder; | ||
var k = tmp.k; | ||
if (k === 1) { | ||
return BigDecimal.cos(a, rounding); | ||
} | ||
if (k === 2) { | ||
return BigDecimal.unaryMinus(BigDecimal.sin(a, rounding)); | ||
} | ||
if (k === 3) { | ||
return BigDecimal.unaryMinus(BigDecimal.cos(a, rounding)); | ||
} | ||
var term = BigDecimal.BigDecimal(1n); | ||
var lastSum = BigDecimal.BigDecimal(42n); | ||
var sum = term; | ||
var i = 3n; | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
term = BigDecimal.divide(BigDecimal.multiply(term, BigDecimal.multiply(a, a)), BigDecimal.BigDecimal(-i * (i - 1n)), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
i += 2n; | ||
} | ||
return BigDecimal.multiply(a, sum); | ||
}); | ||
BigDecimal.cos = tryToMakeCorrectlyRounded(0n, function (x, rounding) { | ||
// https://en.wikipedia.org/wiki/Trigonometric_functions#Power_series_expansion | ||
var internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log10(rounding.maximumSignificantDigits)), | ||
roundingMode: rounding.roundingMode | ||
}; | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0n))) { | ||
return BigDecimal.cos(BigDecimal.unaryMinus(x), rounding); | ||
} | ||
var tmp = divideByHalfOfPI(x, rounding); | ||
var a = tmp.remainder; | ||
var k = tmp.k; | ||
if (k === 1) { | ||
return BigDecimal.unaryMinus(BigDecimal.sin(a, rounding)); | ||
} | ||
if (k === 2) { | ||
return BigDecimal.unaryMinus(BigDecimal.cos(a, rounding)); | ||
} | ||
if (k === 3) { | ||
return BigDecimal.sin(a, rounding); | ||
} | ||
var term = BigDecimal.BigDecimal(1n); | ||
var lastSum = BigDecimal.BigDecimal(42n); | ||
var sum = term; | ||
var i = 2n; | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
term = BigDecimal.divide(BigDecimal.multiply(term, BigDecimal.multiply(a, a)), BigDecimal.BigDecimal(-i * (i - 1n)), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
i += 2n; | ||
} | ||
return sum; | ||
}); | ||
BigDecimal.atan = tryToMakeCorrectlyRounded(0n, function (x, rounding) { | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(-1n)) || BigDecimal.greaterThan(x, BigDecimal.BigDecimal(1n))) { | ||
return BigDecimal.multiply(sign(x), BigDecimal.subtract(BigDecimal.multiply(BigDecimal.atan(BigDecimal.BigDecimal(1n), rounding), BigDecimal.BigDecimal(2n)), BigDecimal.atan(BigDecimal.divide(BigDecimal.BigDecimal(1n), abs(x), {maximumSignificantDigits: rounding.maximumSignificantDigits, roundingMode: "half-even"}), rounding))); | ||
} | ||
//! https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#Infinite_series | ||
var internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log10(rounding.maximumSignificantDigits)), | ||
roundingMode: "half-even" | ||
}; | ||
var n = 0n; | ||
var term = BigDecimal.divide(BigDecimal.BigDecimal(1n), BigDecimal.add(BigDecimal.BigDecimal(1n), BigDecimal.multiply(x, x)), internalRounding); | ||
var sum = term; | ||
var lastSum = BigDecimal.BigDecimal(42n); | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
n += 1n; | ||
term = BigDecimal.multiply(term, BigDecimal.BigDecimal(2n**2n)); | ||
term = BigDecimal.multiply(term, BigDecimal.BigDecimal(n**2n)); | ||
term = BigDecimal.divide(term, BigDecimal.BigDecimal(BigDecimal.BigDecimal((2n * n) * (2n * n + 1n))), internalRounding); | ||
term = BigDecimal.multiply(term, BigDecimal.multiply(x, x)); | ||
term = BigDecimal.divide(term, BigDecimal.add(BigDecimal.BigDecimal(1n), BigDecimal.multiply(x, x)), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(term, sum, internalRounding); | ||
} | ||
return BigDecimal.multiply(x, sum); | ||
}); | ||
export default BigDecimal; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
50993
1059