@yaffle/bigdecimal
Advanced tools
Comparing version 1.0.36 to 2.0.0
@@ -10,5 +10,3 @@ type RoundingMode = "floor" | "down" | "ceil" | "up" | "half-even" | "half-up" | "half-down"; | ||
declare class BigDecimal { | ||
static BigDecimal(value: bigint | string | number | BigDecimal): BigDecimal; | ||
static toBigInt(a: BigDecimal): bigint; | ||
static toNumber(a: BigDecimal): number; | ||
static BigDecimal(value: string | number | bigint | BigDecimal): BigDecimal; | ||
static unaryMinus(a: BigDecimal): BigDecimal; | ||
@@ -20,5 +18,3 @@ static add(a: BigDecimal, b: BigDecimal, rounding?: Rounding): BigDecimal; | ||
static lessThan(a: BigDecimal, b: BigDecimal): boolean; | ||
static greaterThan(a: BigDecimal, b: BigDecimal): boolean; | ||
static equal(a: BigDecimal, b: BigDecimal): boolean; | ||
static cmp(a: BigDecimal, b: BigDecimal): boolean; | ||
static round(a: BigDecimal, rounding: Rounding): BigDecimal; | ||
@@ -25,0 +21,0 @@ |
@@ -1,2 +0,2 @@ | ||
/*jslint bigint: true, vars: true, indent: 2*/ | ||
/*jslint bigint: true, vars: true, indent: 2, esversion:11*/ | ||
@@ -8,7 +8,6 @@ // https://github.com/tc39/proposal-decimal | ||
// Usage: | ||
// BigDecimal.BigDecimal(bigint) | ||
// BigDecimal.BigDecimal(string) | ||
// BigDecimal.BigDecimal(number) (only integers) | ||
// BigDecimal.toBigInt(a) (not in the spec) | ||
// BigDecimal.toNumber(a) (not in the spec, only integers) | ||
// BigDecimal(string) | ||
// BigDecimal(number) | ||
// BigDecimal(bigint) | ||
// BigDecimal.unaryMinus(a) | ||
@@ -19,6 +18,5 @@ // BigDecimal.add(a, b[, rounding]) | ||
// BigDecimal.divide(a, b, rounding) | ||
// BigDecimal.lessThan(a, b) | ||
// BigDecimal.greaterThan(a, b) | ||
// BigDecimal.equal(a, b) | ||
// BigDecimal.cmp(a, b) | ||
// BigDecimal.round(a, rounding) | ||
// a.toString() | ||
@@ -28,14 +26,3 @@ // a.toFixed(fractionDigits[, roundingMode = "half-up"]) | ||
// a.toExponential(fractionDigits[, roundingMode = "half-up"]) | ||
// 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) | ||
// BigDecimal.sqrt(a, rounding) | ||
// "simple" Math functions: | ||
// BigDecimal.abs(a) | ||
// BigDecimal.sign(a) | ||
// BigDecimal.max(a, b) | ||
// BigDecimal.min(a, b) | ||
// (!) Note: consider to use only "half-even" rounding mode and rounding to a maximum number of significant digits for floating-point arithmetic, | ||
@@ -45,5 +32,4 @@ // or only "floor" rounding to a maximum number of fraction digits for fixed-point arithmetic. | ||
const factory = function (BASE, format = null) { | ||
const factory = function (BASE) { | ||
const BIGINT_BASE = BigInt(BASE); | ||
@@ -54,8 +40,11 @@ const BASE_LOG2 = Math.log2(BASE); | ||
const parseRegex = /^\s*([+\-])?(\d+)?\.?(\d+)?(?:e([+\-]?\d+))?\s*$/; | ||
const defaultRounding = format === 'decimal128' ? {maximumFractionDigits: 6176, maximumSignificantDigits: 34, maximumExponent: 6144, roundingMode: 'half-even'} : null; | ||
function BigDecimal(significand, exponent) { | ||
this.significand = significand; | ||
this.exponent = exponent; | ||
function getExponent(number) { | ||
const e = Math.floor(Math.log(Math.abs(number)) / Math.log(2)) - 1; | ||
return Math.abs(number) / 2**e >= 2 ? e + 1 : e; | ||
} | ||
BigDecimal.BigFloat = BigDecimal.BigDecimal = function (value) { | ||
function convert(value) { | ||
if (value instanceof BigDecimal) { | ||
@@ -68,2 +57,16 @@ return value; | ||
} | ||
if (format != null) { | ||
if (value === 'Infinity') { | ||
return create(1n, SPECIAL_EXPONENT); | ||
} | ||
if (value === '-Infinity') { | ||
return create(-1n, SPECIAL_EXPONENT); | ||
} | ||
if (value === 'NaN') { | ||
return create(0n, SPECIAL_EXPONENT); | ||
} | ||
if (value === '-0') { | ||
return create(-1n, -SPECIAL_EXPONENT); | ||
} | ||
} | ||
const match = parseRegex.exec(value); | ||
@@ -73,4 +76,13 @@ if (match == null) { | ||
} | ||
const exponent = Number(match[4] || "0"); | ||
return create(BigInt((match[1] || "") + (match[2] || "") + (match[3] || "")), diff(Math.abs(exponent) < Number.MAX_SAFE_INTEGER ? exponent : BigInt(match[4] || "0"), (match[3] || "").length)); | ||
const sign = (match[1] || ""); | ||
const integer = (match[2] || ""); | ||
const fraction = (match[3] || ""); | ||
const exponent = (match[4] || "0"); | ||
let result = round(create(BigInt(sign + integer + fraction), diff(Math.abs(exponent) < Number.MAX_SAFE_INTEGER ? exponent : BigInt(match[4] || "0"), (match[3] || "").length)), null); | ||
if (format != null) { | ||
if (sign === "-" && result.significand === 0n) { | ||
result = BigDecimal.unaryMinus(result); | ||
} | ||
} | ||
return result; | ||
} | ||
@@ -85,3 +97,20 @@ if (typeof value === "number" && Math.floor(value) !== value) { | ||
} | ||
if (format != null) { | ||
const e = getExponent(value); | ||
const f = value / 2**e; | ||
const significand = f * (Number.MAX_SAFE_INTEGER + 1) / 2; | ||
const exponent = e - (NumberSafeBits - 1); | ||
if (exponent >= 0) { | ||
return BigDecimal.multiply(create(BigInt(significand), 0), create(BigInt(2)**BigInt(exponent), 0)); | ||
} else if (exponent < 0) { | ||
return BigDecimal.divide(create(BigInt(significand), 0), create(BigInt(2)**BigInt(-exponent), 0)); | ||
} | ||
} | ||
} | ||
if (value === 0 && 1 / value < 0) { | ||
if (format != null) { | ||
return create(-1n, -SPECIAL_EXPONENT); | ||
} | ||
throw new RangeError(); | ||
} | ||
let a = create(BigInt(value), 0); | ||
@@ -94,8 +123,20 @@ // `normalize` will change the exponent which is not good for fixed-point arithmetic (?) | ||
//} | ||
if (format != null) { | ||
a = round(a, defaultRounding); | ||
} | ||
return a; | ||
}; | ||
BigDecimal.toNumber = function (a) { | ||
return Number(BigInt(BigDecimal.toBigInt(a))); | ||
}; | ||
BigDecimal.toBigInt = function (a) { | ||
} | ||
function BigDecimal(significand, exponent) { | ||
if (!(this instanceof BigDecimal)) { | ||
return convert(significand); | ||
} | ||
this.significand = significand; | ||
this.exponent = exponent; | ||
} | ||
const SPECIAL_EXPONENT = 1/0; | ||
//TODO: remove | ||
const toBigInt = function (a) { | ||
const e = a.exponent; | ||
@@ -115,2 +156,17 @@ const exponent = typeof e === 'number' ? e : Number(BigInt(e)); | ||
}; | ||
const abs = function (a) { | ||
return a.significand < 0n ? BigDecimal.unaryMinus(a) : a; | ||
}; | ||
function getCountOfDigits(a) { // floor(log(abs(a))/log(BASE)) + 1 | ||
if (a.significand === 0n) { | ||
throw new RangeError(); | ||
} | ||
return BigInt(digits(a.significand)) + BigInt(a.exponent); | ||
} | ||
function exponentiateBase(n) { | ||
return create(BASE, n); | ||
} | ||
function create(significand, exponent) { | ||
@@ -133,3 +189,3 @@ return /*Object.freeze(*/new BigDecimal(significand, exponent)/*)*/; | ||
const s = a.toString(16); | ||
const c = +s.charCodeAt(0) - "0".charCodeAt(0); | ||
const c = +s.charCodeAt(0) - +"0".charCodeAt(0); | ||
if (c <= 0) { | ||
@@ -225,3 +281,21 @@ throw new RangeError(); | ||
function applyMaxExponent(x, rounding) { | ||
const maximumExponent = rounding.maximumExponent; | ||
if (maximumExponent != null) { | ||
if (digits(x.significand) - 1 + x.exponent > maximumExponent) { | ||
return x.significand === 0n ? create(0n, 0) : create(x.significand < 0n ? -1n : 1n, SPECIAL_EXPONENT); | ||
} | ||
} | ||
return x; | ||
} | ||
function round(a, rounding) { | ||
if (format === 'decimal128') { | ||
if (rounding == null) { | ||
return round(a, defaultRounding); | ||
} | ||
if (Math.abs(a.exponent) === SPECIAL_EXPONENT) { | ||
return a; | ||
} | ||
} | ||
if (rounding != null) { | ||
@@ -239,3 +313,3 @@ let k = 0; | ||
} | ||
k = digits(dividend) - maximumSignificantDigits; | ||
k = Math.max(k, digits(dividend) - maximumSignificantDigits); | ||
} | ||
@@ -247,3 +321,3 @@ const maximumFractionDigits = rounding.maximumFractionDigits; | ||
} | ||
k = 0 - sum(exponent, maximumFractionDigits); | ||
k = Math.max(k, 0 - sum(exponent, maximumFractionDigits)); | ||
//k = Math.min(k, digits(a.significand) + 1); | ||
@@ -336,11 +410,46 @@ //if (k < 0 && k >= -1024 && BASE === 2) { | ||
} | ||
return create(quotient, sum(exponent, k)); | ||
const e = sum(exponent, k); | ||
return applyMaxExponent(create(quotient, e), rounding); | ||
} | ||
return applyMaxExponent(a, rounding); | ||
} | ||
return a; | ||
} | ||
BigDecimal.unaryMinus = function (a) { | ||
if (format != null) { | ||
if (a.exponent === -SPECIAL_EXPONENT) { | ||
return create(0n, 0); | ||
} | ||
if (a.significand === 0n && a.exponent !== SPECIAL_EXPONENT) { | ||
return create(-1n, -SPECIAL_EXPONENT); | ||
} | ||
} | ||
return create(-BigInt(a.significand), a.exponent); | ||
}; | ||
BigDecimal.add = function (a, b, rounding = null) { | ||
function tonum(x) { | ||
// converts +0, +-Infinity, NaN to corresponding values, and other values to sign(value) | ||
return (x.significand < 0n ? -1 : (x.significand > 0n ? +1 : 0)) * (Math.abs(x.exponent) !== SPECIAL_EXPONENT ? 1 : Math.pow(BASE, x.exponent)); | ||
} | ||
function fromnum(x) { | ||
if (x !== x) { | ||
return create(0n, SPECIAL_EXPONENT); | ||
} | ||
if (x === +1/0) { | ||
return create(1n, SPECIAL_EXPONENT); | ||
} | ||
if (x === -1/0) { | ||
return create(-1n, SPECIAL_EXPONENT); | ||
} | ||
if (x === 0 && 1/x > 0) { | ||
return create(0n, 0); | ||
} | ||
if (x === 0 && 1/x < 0) { | ||
return create(-1n, -SPECIAL_EXPONENT); | ||
} | ||
throw new Error(x); | ||
} | ||
BigDecimal.add = function (a, b, rounding = defaultRounding) { | ||
const as = BigInt(a.significand); | ||
@@ -350,2 +459,16 @@ const bs = BigInt(b.significand); | ||
const be = b.exponent; | ||
if (format != null) { | ||
if (ae === -SPECIAL_EXPONENT || be === -SPECIAL_EXPONENT) { | ||
if (ae === -SPECIAL_EXPONENT && be !== -SPECIAL_EXPONENT) { | ||
return round(b, rounding); | ||
} | ||
if (be === -SPECIAL_EXPONENT && ae !== -SPECIAL_EXPONENT) { | ||
return round(a, rounding); | ||
} | ||
return create(-1n, -SPECIAL_EXPONENT); | ||
} | ||
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT) { | ||
return fromnum(tonum(a) + tonum(b)); | ||
} | ||
} | ||
const bd = diff(ae, be); | ||
@@ -376,7 +499,25 @@ const d = typeof bd === 'number' ? bd : Number(BigInt(bd)); | ||
}; | ||
BigDecimal.subtract = function (a, b, rounding = null) { | ||
BigDecimal.subtract = function (a, b, rounding = defaultRounding) { | ||
return BigDecimal.add(a, BigDecimal.unaryMinus(b), rounding); | ||
}; | ||
BigDecimal.multiply = function (a, b, rounding = null) { | ||
return normalize(round(create(BigInt(a.significand) * BigInt(b.significand), sum(a.exponent, b.exponent)), rounding), rounding); | ||
function toSignedZero(a, b, p) { | ||
if (format != null) { | ||
if (p.significand === 0n || p.exponent === -SPECIAL_EXPONENT) { | ||
if (a.significand < 0n) { | ||
return toSignedZero(BigDecimal.unaryMinus(a), b, BigDecimal.unaryMinus(p)); | ||
} | ||
if (b.significand < 0n) { | ||
return toSignedZero(a, BigDecimal.unaryMinus(b), BigDecimal.unaryMinus(p)); | ||
} | ||
} | ||
} | ||
return p; | ||
} | ||
BigDecimal.multiply = function (a, b, rounding = defaultRounding) { | ||
if (format != null) { | ||
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT) { | ||
return fromnum(tonum(a) * tonum(b)); | ||
} | ||
} | ||
return toSignedZero(a, b, normalize(round(create(BigInt(a.significand) * BigInt(b.significand), sum(a.exponent, b.exponent)), rounding), rounding)); | ||
}; | ||
@@ -395,5 +536,7 @@ function bigIntScale(a, scaling) { | ||
} | ||
BigDecimal.divide = function (a, b, rounding = null) { | ||
if (a.significand === 0n) { | ||
return a; | ||
BigDecimal.divide = function (a, b, rounding = defaultRounding) { | ||
if (format != null) { | ||
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT || b.significand === 0n) { | ||
return fromnum(tonum(a) / tonum(b)); | ||
} | ||
} | ||
@@ -403,3 +546,3 @@ const exponent = diff(a.exponent, b.exponent); | ||
if (rounding != null && rounding.maximumSignificantDigits != null) { | ||
scaling = rounding.maximumSignificantDigits + (digits(b.significand) - digits(a.significand)); | ||
scaling = rounding.maximumSignificantDigits + ((b.significand === 0n ? 0 : digits(b.significand)) - (a.significand === 0n ? 0 : digits(a.significand))); | ||
} else if (rounding != null && rounding.maximumFractionDigits != null) { | ||
@@ -452,7 +595,21 @@ //scaling = BigInt(rounding.maximumFractionDigits) + bigIntMax(a.exponent, 0n) + bigIntMax(0n - b.exponent, 0n) - bigIntMin(a.exponent - b.exponent + BigInt(digits(a.significand) - digits(b.significand)), 0n); | ||
} | ||
} else { | ||
//TODO: optimize | ||
while (scaling >= 1 && quotient % BIGINT_BASE === 0n) { | ||
quotient /= BIGINT_BASE; | ||
scaling -= 1; | ||
} | ||
} | ||
} | ||
return round(create(quotient, diff(exponent, scaling)), rounding); | ||
return toSignedZero(a, b, round(create(quotient, diff(exponent, scaling)), rounding)); | ||
}; | ||
function cmpnum(a, b) { | ||
return a < b ? -1 : (b < a ? +1 : (a === b ? 0 : undefined)); | ||
} | ||
function compare(a, b) { | ||
if (format != null) { | ||
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT || b.significand === 0n) { | ||
return cmpnum(tonum(a), tonum(b)); | ||
} | ||
} | ||
const as = BigInt(a.significand); | ||
@@ -495,2 +652,9 @@ const bs = BigInt(b.significand); | ||
} | ||
BigDecimal.cmp = function (a, b) { | ||
return compare(a, b); | ||
}; | ||
BigDecimal.equal = function (a, b) { | ||
return compare(a, b) === 0; | ||
}; | ||
BigDecimal.lessThan = function (a, b) { | ||
@@ -502,5 +666,3 @@ return compare(a, b) < 0; | ||
}; | ||
BigDecimal.equal = function (a, b) { | ||
return compare(a, b) === 0; | ||
}; | ||
BigDecimal.round = function (a, rounding) { | ||
@@ -519,4 +681,9 @@ //TODO: quick round algorithm (?) | ||
} | ||
const x = BigDecimal.BigDecimal(this); | ||
const x = convert(this); | ||
let significand = x.significand.toString(); | ||
if (format != null) { | ||
if (Math.abs(x.exponent) === SPECIAL_EXPONENT) { | ||
return tonum(x).toString(); | ||
} | ||
} | ||
//! https://tc39.es/ecma262/#sec-numeric-types-number-tostring | ||
@@ -527,3 +694,3 @@ if (significand === "0") { | ||
let sign = ""; | ||
if (significand.charCodeAt(0) === "-".charCodeAt(0)) { | ||
if (+significand.charCodeAt(0) === +"-".charCodeAt(0)) { | ||
significand = significand.slice(1); | ||
@@ -534,6 +701,8 @@ sign = "-"; | ||
const e = typeof E === 'number' ? E : Number(BigInt(E)); | ||
const normalize = format != null ? false : true; | ||
const minSignificant = normalize ? 0 : significand.length; | ||
if (e > -7 && e < 21) { | ||
return sign + bigDecimalToPlainString(significand, e + 1 - significand.length, 0, 0); | ||
return sign + bigDecimalToPlainString(significand, e + 1 - significand.length, 0, minSignificant); | ||
} | ||
return sign + bigDecimalToPlainString(significand, -(significand.length - 1), 0, 0) + "e" + (e >= 0 ? "+" : "") + E.toString(); | ||
return sign + bigDecimalToPlainString(significand, -(significand.length - 1), 0, minSignificant) + "e" + (e >= 0 ? "+" : "") + E.toString(); | ||
}; | ||
@@ -551,12 +720,12 @@ | ||
while (fraction > minFraction && | ||
i >= minSignificant && | ||
i >= 1 && 0 + significand.charCodeAt(i - 1) === "0".charCodeAt(0)) { | ||
+i >= +minSignificant && | ||
i >= 1 && +significand.charCodeAt(i - 1) === +"0".charCodeAt(0)) { | ||
i -= 1; | ||
fraction -= 1; | ||
} | ||
if (i < significand.length) { | ||
if (+i < +significand.length) { | ||
significand = significand.slice(0, i); | ||
} | ||
const zeros = Math.max(Math.max(0, minFraction - fraction), Math.max(0, minSignificant - significand.length)); | ||
if (zeros !== 0) { | ||
const zeros = Math.max(minFraction - fraction, +minSignificant - +significand.length); | ||
if (zeros > 0) { | ||
significand += String("0".repeat(zeros)); | ||
@@ -588,7 +757,12 @@ } | ||
} | ||
const value = BASE === 10 ? create(this.significand, sum(this.exponent, fractionDigits)) : BigDecimal.multiply(BigDecimal.BigDecimal(10n**BigInt(fractionDigits)), this); | ||
if (format != null) { | ||
if (Math.abs(this.exponent) === SPECIAL_EXPONENT) { | ||
return tonum(this).toFixed(fractionDigits); | ||
} | ||
} | ||
const value = BASE === 10 ? create(this.significand, sum(this.exponent, fractionDigits)) : BigDecimal.multiply(convert(10n**BigInt(fractionDigits)), this); | ||
const sign = value.significand < 0n ? "-" : ""; | ||
const rounded = BigDecimal.round(value, {maximumFractionDigits: 0, roundingMode: roundingMode}); | ||
const a = BigDecimal.abs(rounded); | ||
return sign + toFixed(BigDecimal.toBigInt(a).toString(), 0 - fractionDigits, fractionDigits); | ||
const a = abs(rounded); | ||
return sign + toFixed(toBigInt(a).toString(), 0 - fractionDigits, fractionDigits); | ||
}; | ||
@@ -598,3 +772,3 @@ | ||
if (BASE === 10) { | ||
const x = BigDecimal.round(BigDecimal.abs(value), {maximumSignificantDigits: precision, roundingMode: roundingMode}); | ||
const x = BigDecimal.round(abs(value), {maximumSignificantDigits: precision, roundingMode: roundingMode}); | ||
return {significand: x.significand.toString(), exponent: BigInt(x.exponent)}; | ||
@@ -605,3 +779,3 @@ } | ||
if (n < 0n) { | ||
return BigDecimal.divide(BigDecimal.BigDecimal(1), exponentiate(x, -BigInt(n), rounding), rounding); | ||
return BigDecimal.divide(convert(1), exponentiate(x, -BigInt(n), rounding), rounding); | ||
} | ||
@@ -618,10 +792,10 @@ let y = undefined; | ||
} | ||
return y == undefined ? BigDecimal.BigDecimal(1) : y; | ||
return y == undefined ? convert(1) : y; | ||
}; | ||
const logarithm = function (x, b, rounding) { | ||
if (!BigDecimal.greaterThan(x, BigDecimal.BigDecimal(0))) { | ||
if (BigDecimal.cmp(x, convert(0)) <= 0) { | ||
throw new RangeError(); | ||
} | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(1))) { | ||
return 0n - logarithm(BigDecimal.divide(BigDecimal.BigDecimal(1), x, rounding), b, rounding); | ||
if (BigDecimal.cmp(x, convert(1)) < 0) { | ||
return 0n - logarithm(BigDecimal.divide(convert(1), x, rounding), b, rounding); | ||
} | ||
@@ -634,3 +808,3 @@ const digits = getCountOfDigits(x); | ||
} | ||
return log + logarithm(BigDecimal.divide(x, exponentiate(BigDecimal.BigDecimal(b), log, rounding), rounding), b, rounding); | ||
return log + logarithm(BigDecimal.divide(x, exponentiate(convert(b), log, rounding), rounding), b, rounding); | ||
}; | ||
@@ -641,6 +815,6 @@ const sign = value.significand < 0n ? -1 : +1; | ||
}; | ||
if (BigDecimal.equal(value, BigDecimal.BigDecimal(0))) { | ||
if (BigDecimal.cmp(value, convert(0)) === 0) { | ||
return {significand: "0", exponent: 0n}; | ||
} | ||
const ten = BigDecimal.BigDecimal(10); | ||
const ten = convert(10); | ||
const minimumSignificantDigits = Math.pow(2, Math.ceil(Math.log2(bitLength(bigIntAbs(BigInt(value.exponent)) + 1n) * BASE_LOG2_INV))); | ||
@@ -651,26 +825,26 @@ let rounding = {maximumSignificantDigits: Math.max(minimumSignificantDigits, BASE === 2 ? 32 : 8), roundingMode: "half-even"}; | ||
do { | ||
let x = BigDecimal.abs(value); | ||
let x = abs(value); | ||
fd = 0n - logarithm(x, 10, rounding); | ||
x = BigDecimal.multiply(exponentiate(ten, fd, rounding), x, rounding); | ||
if (!BigDecimal.lessThan(x, ten)) { | ||
if (BigDecimal.cmp(x, ten) >= 0) { | ||
fd -= 1n; | ||
x = BigDecimal.divide(x, ten, rounding); | ||
} | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(1))) { | ||
if (BigDecimal.cmp(x, convert(1)) < 0) { | ||
fd += 1n; | ||
x = BigDecimal.multiply(x, ten, rounding); | ||
} | ||
if (!BigDecimal.lessThan(x, BigDecimal.BigDecimal(1)) && BigDecimal.lessThan(x, ten)) { | ||
if (BigDecimal.cmp(x, convert(1)) >= 0 && BigDecimal.cmp(x, ten) < 0) { | ||
fd += BigInt(precision - 1); | ||
//TODO: ? | ||
if (rounding.maximumSignificantDigits > (Math.abs(Number(fd)) + precision) * Math.log2(10) + digits(value.significand)) { | ||
x = BigDecimal.abs(value); | ||
x = abs(value); | ||
x = BigDecimal.multiply(x, exponentiate(ten, fd, rounding), rounding) | ||
result = BigDecimal.toBigInt(BigDecimal.abs(roundToInteger(x))).toString(); | ||
result = toBigInt(abs(roundToInteger(x))).toString(); | ||
} else { | ||
x = BigDecimal.multiply(x, exponentiate(ten, BigInt(precision - 1), rounding), rounding); | ||
x = BigDecimal.abs(x); | ||
const error = BigDecimal.multiply(BigDecimal.multiply(BigDecimal.BigDecimal(bigIntAbs(fd) + BigInt(precision)), exponentiateBase(BASE, 0 - rounding.maximumSignificantDigits)), x); | ||
if (BigDecimal.equal(roundToInteger(BigDecimal.add(x, error)), roundToInteger(BigDecimal.subtract(x, error)))) { | ||
result = BigDecimal.toBigInt(BigDecimal.abs(roundToInteger(x))).toString(); | ||
x = abs(x); | ||
const error = BigDecimal.multiply(BigDecimal.multiply(convert(bigIntAbs(fd) + BigInt(precision)), exponentiateBase(0 - rounding.maximumSignificantDigits)), x); | ||
if (BigDecimal.cmp(roundToInteger(BigDecimal.add(x, error)), roundToInteger(BigDecimal.subtract(x, error))) === 0) { | ||
result = toBigInt(abs(roundToInteger(x))).toString(); | ||
} | ||
@@ -685,341 +859,19 @@ } | ||
BigDecimal.prototype.toPrecision = function (precision, roundingMode = "half-up") { | ||
if (format != null) { | ||
if (Math.abs(this.exponent) === SPECIAL_EXPONENT) { | ||
return tonum(this).toPrecision(precision); | ||
} | ||
} | ||
const tmp = getDecimalSignificantAndExponent(this, precision, roundingMode); | ||
return (BigDecimal.lessThan(this, BigDecimal.BigDecimal(0)) ? "-" : "") + toPrecision(tmp.significand, tmp.exponent, precision); | ||
return (BigDecimal.cmp(this, convert(0)) < 0 ? "-" : "") + toPrecision(tmp.significand, tmp.exponent, precision); | ||
}; | ||
BigDecimal.prototype.toExponential = function (fractionDigits, roundingMode = "half-up") { | ||
const tmp = getDecimalSignificantAndExponent(this, fractionDigits + 1, roundingMode); | ||
return (BigDecimal.lessThan(this, BigDecimal.BigDecimal(0)) ? "-" : "") + toExponential(tmp.significand, tmp.exponent, fractionDigits); | ||
}; | ||
function exponentiate(a, n) { | ||
if (+a !== BASE) { | ||
throw new RangeError("a should be BASE");//? | ||
} | ||
return create(1n, n); | ||
} | ||
function exponentiateBase(a, n) { | ||
return exponentiate(a, n); | ||
} | ||
function getCountOfDigits(a) { // floor(log(abs(a))/log(BASE)) + 1 | ||
if (a.significand === 0n) { | ||
throw new RangeError(); | ||
} | ||
return BigInt(digits(a.significand)) + BigInt(a.exponent); | ||
} | ||
BigDecimal.abs = function (a) { | ||
return a.significand < 0n ? BigDecimal.unaryMinus(a) : a; | ||
}; | ||
BigDecimal.sign = function (a) { | ||
return a.significand < 0n ? -1 : (a.significand > 0n ? +1 : 0); | ||
}; | ||
BigDecimal.max = function (a, b) { | ||
if (arguments.length > 2) { | ||
throw new RangeError("not implemented"); | ||
} | ||
return BigDecimal.lessThan(a, b) ? b : a; | ||
}; | ||
BigDecimal.min = function (a, b) { | ||
if (arguments.length > 2) { | ||
throw new RangeError("not implemented"); | ||
} | ||
return BigDecimal.greaterThan(a, b) ? b : a; | ||
}; | ||
function significandDigits(a) { | ||
let maximumSignificantDigits = 1; | ||
while (!BigDecimal.equal(BigDecimal.round(a, {maximumSignificantDigits: maximumSignificantDigits, roundingMode: "half-even"}), a)) { | ||
maximumSignificantDigits *= 2; | ||
} | ||
let from = maximumSignificantDigits / 2; | ||
let to = maximumSignificantDigits; | ||
while (to - 1 > from) { | ||
const middle = from + Math.floor((to - from) / 2); | ||
if (!BigDecimal.equal(BigDecimal.round(a, {maximumSignificantDigits: middle, roundingMode: "half-even"}), a)) { | ||
from = middle; | ||
} else { | ||
to = middle; | ||
if (format != null) { | ||
if (Math.abs(this.exponent) === SPECIAL_EXPONENT) { | ||
return tonum(this).toExponential(fractionDigits); | ||
} | ||
} | ||
return to; | ||
} | ||
function getExponent(number) { | ||
const e = Math.floor(Math.log(Math.abs(number)) / Math.log(2)) - 1; | ||
return Math.abs(number) / 2**e >= 2 ? e + 1 : e; | ||
} | ||
function tryToMakeCorrectlyRounded(specialValue, f, name) { | ||
function getExpectedResultIntegerDigits(x) { | ||
if (name === "exp") { | ||
// e**x <= BASE**k | ||
// k >= x / log(BASE) | ||
return Math.ceil(Number(BigInt(BigDecimal.toBigInt(BigDecimal.round(x, {maximumFractionDigits: 0, roundingMode: "half-even"})))) / Math.log(BASE)); | ||
} | ||
if (name === "log") { | ||
// log(x) <= BASE**k | ||
// log(log(x))/log(BASE) <= k | ||
return Math.ceil(Math.log2(Math.ceil(Math.max(Number(getCountOfDigits(x)), 1) * Math.log(BASE))) * BASE_LOG2_INV); | ||
} | ||
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, {maximumSignificantDigits: 1, roundingMode: "half-even"}); | ||
} | ||
let result = BigDecimal.BigDecimal(0); | ||
let i = 0; | ||
let error = BigDecimal.BigDecimal(0); | ||
do { | ||
if (i > 4 * ((9 + 1) / BASE) && rounding.maximumSignificantDigits != null && rounding.roundingMode === "half-even" && name !== "sin" && name !== "cos") { | ||
console.error(x, rounding); | ||
throw new Error(); | ||
} | ||
i += 1; | ||
const internalRounding = { | ||
maximumSignificantDigits: Math.ceil(Math.max(rounding.maximumSignificantDigits || (rounding.maximumFractionDigits + 1 + getExpectedResultIntegerDigits(x) - 1), significandDigits(x)) * Math.pow(2, Math.ceil((i - 1) / 3))) + 2 + (BASE === 2 ? 1 : 0), | ||
roundingMode: "half-even" | ||
}; | ||
result = undefined; | ||
if (BASE === 2 && Math.max(internalRounding.maximumSignificantDigits + 2, significandDigits(x) + 1) <= Math.log2(Number.MAX_SAFE_INTEGER + 1)) { | ||
// Hm... https://www.gnu.org/software/libc/manual/html_node/Errors-in-Math-Functions.html | ||
const e = x.exponent; | ||
const exponent = typeof e === 'number' ? e : Number(BigInt(e)); | ||
const v = Number(BigInt(x.significand)) * BASE**exponent; | ||
// some browsers have inaccurate results for Math.sin, Math.cos, Math.tan outside of [-pi/4;pi/4] range | ||
if ((name !== "sin" && name !== "cos" && name !== "tan") || Math.abs(v) <= Math.PI / 4) { | ||
const numberValue = Math[name](v); | ||
const MIN_NORMALIZED_VALUE = (Number.MIN_VALUE * 1.25 > Number.MIN_VALUE ? Number.MIN_VALUE : Number.MIN_VALUE * (Number.MAX_SAFE_INTEGER + 1) / 2) || 2**-1022; | ||
const a = Math.abs(numberValue); | ||
if (a < 1/0 && a > MIN_NORMALIZED_VALUE) { | ||
result = BigDecimal.BigDecimal(numberValue); | ||
} | ||
} | ||
} | ||
if (result == undefined) { | ||
result = f(x, internalRounding); | ||
} | ||
// round(result - error) === round(result + error) | ||
error = BigDecimal.multiply(exponentiate(BASE, -BigInt(internalRounding.maximumSignificantDigits)), BigDecimal.abs(result)); | ||
//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) + ""); | ||
//} | ||
} while (!BigDecimal.equal(BigDecimal.round(BigDecimal.subtract(result, error), rounding), BigDecimal.round(BigDecimal.add(result, error), rounding))); | ||
if (i > 1) { | ||
//console.debug(i, name); | ||
} | ||
return BigDecimal.round(result, rounding); | ||
}; | ||
} | ||
function sqrt(x, rounding) { | ||
// from https://en.wikipedia.org/wiki/Square_root#Computation | ||
let lastResult = BigDecimal.add(x, BigDecimal.BigDecimal(1)); | ||
let result = x; | ||
while (BigDecimal.lessThan(result, lastResult)) { | ||
lastResult = result; | ||
result = BigDecimal.divide(BigDecimal.add(BigDecimal.divide(x, result, rounding), result), BigDecimal.BigDecimal(2), rounding); | ||
} | ||
return result; | ||
} | ||
BigDecimal.log = tryToMakeCorrectlyRounded(1, function log(x, rounding) { | ||
if (!BigDecimal.greaterThan(x, BigDecimal.BigDecimal(0))) { | ||
throw new RangeError(); | ||
} | ||
// https://ru.wikipedia.org/wiki/Логарифм#Разложение_в_ряд_и_вычисление_натурального_логарифма | ||
const internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log2(rounding.maximumSignificantDigits + 0.5) * BASE_LOG2_INV), | ||
roundingMode: "half-even" | ||
}; | ||
if (true) { | ||
//! ln(f * BASE**k) = ln(f) + k * ln(BASE), where (1/BASE) <= f <= BASE | ||
let k = getCountOfDigits(x) - 1n; | ||
let f = BigDecimal.multiply(exponentiate(BASE, -k), x); | ||
let ff = BigDecimal.round(BigDecimal.multiply(f, f), {maximumSignificantDigits: 3, roundingMode: "half-even"}); | ||
if (BigDecimal.greaterThan(ff, exponentiate(BASE, 1n))) { | ||
k += 1n; | ||
f = BigDecimal.multiply(exponentiate(BASE, -1n), f); | ||
} | ||
if (BigDecimal.lessThan(ff, exponentiate(BASE, -1n))) { | ||
k -= 1n; | ||
f = BigDecimal.multiply(exponentiate(BASE, 1n), f); | ||
} | ||
if (k !== 0n) { | ||
return BigDecimal.add(BigDecimal.log(f, internalRounding), BigDecimal.multiply(BigDecimal.BigDecimal(2n * k), BigDecimal.log(sqrt(BigDecimal.BigDecimal(BASE), internalRounding), internalRounding))); | ||
} | ||
} | ||
//! log(x) = log((1 + g) / (1 - g)) = 2*(g + g**3/3 + g**5/5 + ...) | ||
const g = BigDecimal.divide(BigDecimal.subtract(x, BigDecimal.BigDecimal(1)), BigDecimal.add(x, BigDecimal.BigDecimal(1)), internalRounding); | ||
let n = 1; | ||
let term = BigDecimal.BigDecimal(1); | ||
let sum = term; | ||
let lastSum = BigDecimal.BigDecimal(0); | ||
const gg = BigDecimal.multiply(g, g, internalRounding); | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
n += 2; | ||
term = BigDecimal.multiply(term, BigDecimal.BigDecimal(n - 2)); | ||
term = BigDecimal.multiply(term, gg); | ||
term = BigDecimal.divide(term, BigDecimal.BigDecimal(n), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
} | ||
return BigDecimal.multiply(BigDecimal.multiply(BigDecimal.BigDecimal(2), g), sum); | ||
}, "log"); | ||
function fromNumberApproximate(number) { | ||
return BigDecimal.divide(BigDecimal.BigDecimal(Math.floor(number * (Number.MAX_SAFE_INTEGER + 1))), | ||
BigDecimal.add(BigDecimal.BigDecimal(Number.MAX_SAFE_INTEGER), BigDecimal.BigDecimal(1)), | ||
{maximumSignificantDigits: Math.floor(Math.log2(Number.MAX_SAFE_INTEGER + 1) * BASE_LOG2_INV + 0.5), roundingMode: "half-even"}); | ||
} | ||
BigDecimal.exp = tryToMakeCorrectlyRounded(0, function exp(x, rounding) { | ||
//! k = round(x / ln(BASE)); | ||
//! exp(x) = exp(x - k * ln(BASE) + k * ln(BASE)) = exp(x - k * ln(BASE)) * BASE**k | ||
const internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log2(rounding.maximumSignificantDigits + 0.5) * BASE_LOG2_INV), | ||
roundingMode: "half-even" | ||
}; | ||
if (!BigDecimal.equal(x, BigDecimal.BigDecimal(0))) { | ||
const logBASEApproximate = fromNumberApproximate(Math.log(BASE)); | ||
const kApproximate = BigDecimal.round(BigDecimal.divide(x, logBASEApproximate, {maximumSignificantDigits: Math.max(Number(getCountOfDigits(x)), 1), roundingMode: "half-even"}), {maximumFractionDigits: 0, roundingMode: "half-even"}); | ||
if (!BigDecimal.equal(kApproximate, BigDecimal.BigDecimal(0))) { | ||
const logBASE = BigDecimal.log(BigDecimal.BigDecimal(BASE), {maximumSignificantDigits: internalRounding.maximumSignificantDigits + Number(getCountOfDigits(kApproximate)), roundingMode: "half-even"}); | ||
const k = BigDecimal.round(BigDecimal.divide(x, logBASE, {maximumSignificantDigits: Math.max(Number(getCountOfDigits(x)), 1), roundingMode: "half-even"}), {maximumFractionDigits: 0, roundingMode: "half-even"}); | ||
if (!BigDecimal.equal(k, BigDecimal.BigDecimal(0))) { | ||
const r = BigDecimal.subtract(x, BigDecimal.multiply(k, logBASE)); | ||
return BigDecimal.multiply(exponentiate(BASE, BigDecimal.toBigInt(k)), BigDecimal.exp(r, internalRounding)); | ||
} | ||
} | ||
} | ||
// https://en.wikipedia.org/wiki/Exponential_function#Computation | ||
let n = 0; | ||
let term = BigDecimal.BigDecimal(1); | ||
let sum = term; | ||
let lastSum = BigDecimal.BigDecimal(0); | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
n += 1; | ||
term = BigDecimal.multiply(term, x); | ||
term = BigDecimal.divide(term, BigDecimal.BigDecimal(n), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
} | ||
return sum; | ||
}, "exp"); | ||
function divideByHalfOfPI(x, rounding) { // x = k*pi/2 + r + 2*pi*n, where |r| < pi/4 | ||
const quarterOfPiApproximated = fromNumberApproximate(Math.PI / 4); | ||
if (BigDecimal.greaterThan(BigDecimal.abs(x), quarterOfPiApproximated)) { | ||
//TODO: FIX | ||
const internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + significandDigits(x) + Number(getCountOfDigits(x)) + 1 + Math.ceil(42 * BASE_LOG2_INV), | ||
roundingMode: "half-even" | ||
}; | ||
const halfOfPi = BigDecimal.multiply(BigDecimal.BigDecimal(2), BigDecimal.atan(BigDecimal.BigDecimal(1), internalRounding)); | ||
const i = BigDecimal.round(BigDecimal.divide(x, halfOfPi, {maximumSignificantDigits: Math.max(Number(getCountOfDigits(x)), 1), roundingMode: "half-even"}), {maximumFractionDigits: 0, roundingMode: "half-even"}); | ||
const remainder = BigDecimal.subtract(x, BigDecimal.multiply(i, halfOfPi)); | ||
return {remainder: remainder, k: (Number(BigDecimal.toBigInt(i) % 4n) + 4) % 4}; | ||
} | ||
return {remainder: x, k: 0}; | ||
} | ||
function _cos(x, rounding, subtractHalfOfPi) { | ||
const tmp = divideByHalfOfPI(x, rounding); | ||
const a = tmp.remainder; | ||
const k = (tmp.k + (subtractHalfOfPi ? -1 + 4 : 0)) % 4; | ||
// https://en.wikipedia.org/wiki/Lookup_table#Computing_sines | ||
// https://en.wikipedia.org/wiki/Trigonometric_functions#Power_series_expansion | ||
const internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log2(rounding.maximumSignificantDigits + 0.5) * BASE_LOG2_INV), | ||
roundingMode: "half-even" | ||
}; | ||
let n = k === 1 || k === 3 ? 1 : 0; | ||
let term = BigDecimal.BigDecimal(1); | ||
let sum = term; | ||
let lastSum = BigDecimal.BigDecimal(0); | ||
const aa = BigDecimal.multiply(a, a); | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
n += 2; | ||
term = BigDecimal.multiply(term, aa); | ||
term = BigDecimal.divide(term, BigDecimal.BigDecimal(-n * (n - 1)), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
} | ||
if (k === 1 || k === 2) { | ||
sum = BigDecimal.unaryMinus(sum); | ||
} | ||
return k === 1 || k === 3 ? BigDecimal.multiply(a, sum) : sum; | ||
} | ||
BigDecimal.sin = tryToMakeCorrectlyRounded(0, function (x, rounding) { | ||
return _cos(x, rounding, true); | ||
}, "sin"); | ||
BigDecimal.cos = tryToMakeCorrectlyRounded(0, function (x, rounding) { | ||
return _cos(x, rounding, false); | ||
}, "cos"); | ||
BigDecimal.atan = tryToMakeCorrectlyRounded(0, function (x, rounding) { | ||
if (BigDecimal.greaterThan(BigDecimal.abs(x), BigDecimal.BigDecimal(1))) { | ||
//Note: rounding to maximumFractionDigits | ||
const internalRounding = { | ||
maximumFractionDigits: rounding.maximumSignificantDigits + 1, | ||
roundingMode: "half-even" | ||
}; | ||
const halfOfPi = BigDecimal.multiply(BigDecimal.atan(BigDecimal.BigDecimal(1), internalRounding), BigDecimal.BigDecimal(2)); | ||
return BigDecimal.multiply(BigDecimal.BigDecimal(BigDecimal.lessThan(x, BigDecimal.BigDecimal(0)) ? -1 : +1), BigDecimal.subtract(halfOfPi, BigDecimal.atan(BigDecimal.divide(BigDecimal.BigDecimal(1), BigDecimal.abs(x), internalRounding), internalRounding))); | ||
} | ||
// https://en.wikipedia.org/wiki/Inverse_trigonometric_functions#:~:text=Alternatively,%20this%20can%20be%20expressed%20as | ||
const internalRounding = { | ||
maximumSignificantDigits: rounding.maximumSignificantDigits + Math.ceil(Math.log2(rounding.maximumSignificantDigits + 0.5) * BASE_LOG2_INV), | ||
roundingMode: "half-even" | ||
}; | ||
let n = 0; | ||
const xx = BigDecimal.multiply(x, x); | ||
const xxplus1 = BigDecimal.add(BigDecimal.BigDecimal(1), xx); | ||
let term = BigDecimal.divide(BigDecimal.BigDecimal(1), xxplus1, internalRounding); | ||
let sum = term; | ||
let lastSum = BigDecimal.BigDecimal(0); | ||
while (!BigDecimal.equal(lastSum, sum)) { | ||
n += 1; | ||
term = BigDecimal.multiply(term, BigDecimal.multiply(BigDecimal.BigDecimal(2 * n), xx)); | ||
term = BigDecimal.divide(term, BigDecimal.multiply(BigDecimal.BigDecimal(2 * n + 1), xxplus1), internalRounding); | ||
lastSum = sum; | ||
sum = BigDecimal.add(sum, term, internalRounding); | ||
} | ||
return BigDecimal.multiply(x, sum); | ||
}, "atan"); | ||
BigDecimal.sqrt = function (x, rounding) { | ||
if (BigDecimal.lessThan(x, BigDecimal.BigDecimal(0))) { | ||
throw new RangeError(); | ||
} | ||
if (BigDecimal.equal(x, BigDecimal.BigDecimal(0))) { | ||
return x; | ||
} | ||
// https://en.wikipedia.org/wiki/Nth_root#Using_Newton's_method | ||
const e = getCountOfDigits(x) / 2n; | ||
const t = exponentiate(BASE, e); | ||
const y = BigDecimal.multiply(x, exponentiate(BASE, -(2n * e))); | ||
const k = Math.floor(Math.log2(Number.MAX_SAFE_INTEGER + 1) * BASE_LOG2_INV) - 1; | ||
const xn = BigDecimal.toNumber(BigDecimal.round(BigDecimal.multiply(y, exponentiate(BASE, k)), {maximumFractionDigits: 0, roundingMode: "half-even"})) / BASE**k; | ||
const r = Math.sqrt(xn); | ||
//TODO: fix | ||
const resultSignificantDigits = 2 * (rounding.maximumSignificantDigits || (rounding.maximumFractionDigits + Math.ceil(significandDigits(x) / 2)) || 1); | ||
let result = BigDecimal.multiply(BigDecimal.BigDecimal(Math.sign(r) * Math.floor(Math.abs(r) * BASE**k + 0.5)), exponentiate(BASE, -k)); | ||
const iteration = function (result, internalRounding) { | ||
return BigDecimal.divide(BigDecimal.add(y, BigDecimal.multiply(result, result)), BigDecimal.multiply(BigDecimal.BigDecimal(2), result), internalRounding); | ||
}; | ||
for (let i = Math.max(k - 1, 1); i <= resultSignificantDigits; i *= 2) { | ||
const internalRounding = {maximumSignificantDigits: i, roundingMode: "half-even"}; | ||
result = iteration(result, internalRounding); | ||
} | ||
result = iteration(result, rounding); | ||
return BigDecimal.multiply(result, t); | ||
const tmp = getDecimalSignificantAndExponent(this, fractionDigits + 1, roundingMode); | ||
return (BigDecimal.cmp(this, convert(0)) < 0 ? "-" : "") + toExponential(tmp.significand, tmp.exponent, fractionDigits); | ||
}; | ||
@@ -1032,3 +884,4 @@ | ||
const BigFloat = factory(2); | ||
const Decimal128 = factory(10, 'decimal128'); | ||
export {BigDecimal, BigFloat}; | ||
export {BigDecimal, BigFloat, Decimal128}; |
{ | ||
"name": "@yaffle/bigdecimal", | ||
"version": "1.0.36", | ||
"version": "2.0.0", | ||
"description": "Arbitrary precision decimal arithmetic library. Polyfill for decimal proposal. Implemented on the top of BigInt.", | ||
@@ -23,6 +23,7 @@ "main": "BigDecimal.js", | ||
"BigDecimal.js", | ||
"BigDecimalMath.js", | ||
"BigDecimal.d.ts" | ||
], | ||
"author": "Viktor Mukhachev", | ||
"license": "ISC", | ||
"license": "$$$", | ||
"bugs": { | ||
@@ -34,4 +35,5 @@ "url": "https://github.com/Yaffle/BigDecimal/issues" | ||
"devDependencies": { | ||
"decimal.js": "^10.2.0" | ||
"decimal.js": "^10.2.0", | ||
"http-server": "^14.1.1" | ||
} | ||
} |
@@ -20,4 +20,2 @@ # BigDecimal | ||
a.toExponential(fractionDigits[, roundingMode = "half-up"]) | ||
BigDecimal.toBigInt(a) // (not in the spec) | ||
BigDecimal.toNumber(a) // (not in the spec, only integers) | ||
@@ -36,7 +34,8 @@ | ||
BigDecimal.equal(a, b) | ||
BigDecimal.lessThan(a, b) | ||
BigDecimal.greaterThan(a, b) | ||
BigDecimal.cmp(a, b) | ||
## Math: (not in the spec) | ||
To use: | ||
import addMath from './BigDecimalMath.js'; | ||
addMath(BigDecimal, 10); | ||
@@ -43,0 +42,0 @@ BigDecimal.abs(a) |
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
Misc. License Issues
License(Experimental) A package's licensing information has fine-grained problems.
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
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
56489
6
0
1281
2
1
111