@bignum/core
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -0,1 +1,9 @@ | ||
type DivideOptions = { | ||
/** The maximum number of decimal places. */ | ||
maxDp?: bigint; | ||
/** The maximum number of precision when having decimals. */ | ||
maxDecimalPrecision?: bigint; | ||
}; | ||
/** This is used in negative pows. */ | ||
type PowOptions = DivideOptions; | ||
declare class Internal { | ||
@@ -5,3 +13,2 @@ #private; | ||
static readonly O: Internal; | ||
static readonly N_O: Internal; | ||
readonly inf = false; | ||
@@ -23,6 +30,6 @@ /** int value */ | ||
multiply(multiplicand: Internal | Inf): Internal | Inf | null; | ||
divide(divisor: Internal, maxDp?: bigint): Internal; | ||
divide(divisor: Internal | Inf, maxDp?: bigint): Internal | Inf; | ||
modulo(divisor: Internal | Inf): Internal | Inf; | ||
pow(n: Internal | Inf): Internal | Inf | null; | ||
divide(divisor: Internal, options?: DivideOptions): Internal; | ||
divide(divisor: Internal | Inf, options?: DivideOptions): Internal | Inf; | ||
modulo(divisor: Internal | Inf): Internal | Inf | null; | ||
pow(n: Internal | Inf, options?: PowOptions): Internal | Inf | null; | ||
scaleByPowerOfTen(n: Internal | Inf): Internal | Inf | null; | ||
@@ -51,3 +58,3 @@ trunc(): Internal; | ||
pow(n: Inf | Internal): Internal | Inf; | ||
scaleByPowerOfTen(n: Inf | Internal): Inf | null; | ||
scaleByPowerOfTen(n: Inf | Internal): this | null; | ||
compareTo(n: Inf | Internal): 1 | 0 | -1; | ||
@@ -78,7 +85,4 @@ abs(): Inf; | ||
* Returns a BigNum whose value is (this / divisor) | ||
* @param options.maxDp The maximum number of decimal places. Default is 20. | ||
*/ | ||
divide(divisor: BigNum | string | number | bigint, options?: { | ||
maxDp?: bigint; | ||
}): BigNum; | ||
divide(divisor: BigNum | string | number | bigint, options?: DivideOptions): BigNum; | ||
/** | ||
@@ -88,4 +92,7 @@ * Returns a BigNum whose value is (this % divisor) | ||
modulo(divisor: BigNum | string | number | bigint): BigNum; | ||
/** Returns a BigNum whose value is (this**n). */ | ||
pow(n: BigNum | string | number | bigint): BigNum; | ||
/** | ||
* Returns a BigNum whose value is (this**n). | ||
* @param options.maxDp The maximum number of decimal places. This is used in negative pows. Default is 20. | ||
*/ | ||
pow(n: BigNum | string | number | bigint, options?: PowOptions): BigNum; | ||
/** Returns a BigNum whose numerical value is equal to (this * 10 ** n). */ | ||
@@ -111,2 +118,2 @@ scaleByPowerOfTen(n: BigNum | string | number | bigint): BigNum; | ||
export { BigNum }; | ||
export { BigNum, type DivideOptions, type PowOptions }; |
108
lib/index.js
@@ -44,7 +44,4 @@ // src/index.mts | ||
} | ||
static { | ||
this.N_O = _Internal.O.negate(); | ||
} | ||
signum() { | ||
return this.i === 0n ? 0 : this.i > 0n ? 1 : -1; | ||
return !this.i ? 0 : this.i > 0n ? 1 : -1; | ||
} | ||
@@ -73,17 +70,25 @@ negate() { | ||
} | ||
divide(divisor, maxDp) { | ||
divide(divisor, options) { | ||
if (divisor.inf) | ||
return _Internal.Z; | ||
if (divisor.i === 0n) | ||
if (!divisor.i) | ||
return this.d >= 0 ? Inf.P : Inf.N; | ||
if (this.i === 0n) | ||
if (!this.i) | ||
return this; | ||
const alignMultiplicand = new _Internal(10n ** divisor.#decimalCount(), 0n); | ||
const alignMultiplicand = new _Internal(10n ** divisor.#dp(), 0n); | ||
const alignedTarget = this.multiply(alignMultiplicand).#simplify(); | ||
const alignedDivisor = divisor.multiply(alignMultiplicand).#simplify(); | ||
let minQuotientExponent = alignedTarget.e > -20n ? -20n : alignedTarget.e; | ||
const under = []; | ||
const maxPr = options?.maxDecimalPrecision; | ||
const maxDp = options?.maxDp; | ||
if (maxPr != null) { | ||
under.push((dp, p) => dp <= 0n || BigInt(p) <= maxPr); | ||
} | ||
if (maxDp != null) { | ||
minQuotientExponent = maxDp; | ||
under.push((dp) => dp <= maxDp); | ||
} else if (!under.length) { | ||
const max = alignedTarget.e > -20n ? 20n : -alignedTarget.e; | ||
under.push((dp) => dp <= max); | ||
} | ||
if (alignedTarget.i % alignedDivisor.i === 0n) { | ||
if (!(alignedTarget.i % alignedDivisor.i)) { | ||
const candidate = new _Internal( | ||
@@ -93,3 +98,3 @@ alignedTarget.i / alignedDivisor.i, | ||
); | ||
if (candidate.#decimalCount() <= -minQuotientExponent) | ||
if (under.every((fn) => fn(candidate.#dp(), candidate.#precision()))) | ||
return candidate; | ||
@@ -99,17 +104,16 @@ } | ||
const absTarget = alignedTarget.abs(); | ||
const absDivisor = alignedDivisor.abs().toBigInt(); | ||
const absDivisor = alignedDivisor.abs().#trunc(); | ||
let remainder = absTarget.i; | ||
const quotientNumbers = []; | ||
let quotientExponent = BigInt( | ||
String(remainder).length - String(absDivisor).length + 2 | ||
); | ||
const digitExponent = BigInt(length(remainder) - length(absDivisor) + 1); | ||
let powOfTen; | ||
if (quotientExponent >= 0n) { | ||
powOfTen = 10n ** quotientExponent; | ||
if (digitExponent >= 0n) { | ||
powOfTen = 10n ** digitExponent; | ||
} else { | ||
powOfTen = 1n; | ||
remainder *= 10n ** -quotientExponent; | ||
remainder *= 10n ** -digitExponent; | ||
} | ||
while (remainder > 0n && quotientExponent + absTarget.e > minQuotientExponent) { | ||
quotientExponent--; | ||
let exponent = digitExponent + absTarget.e; | ||
while (remainder > 0n && under.every((fn) => fn(-exponent + 1n, quotientNumbers.length + 1))) { | ||
exponent--; | ||
if (powOfTen > 1n) { | ||
@@ -139,3 +143,3 @@ powOfTen /= 10n; | ||
BigInt(quotientSign + (quotientNumbers.join("") || "0")), | ||
quotientExponent + absTarget.e | ||
exponent | ||
); | ||
@@ -146,15 +150,26 @@ } | ||
return this; | ||
const times = this.divide(divisor, 0n); | ||
if (!divisor.i) | ||
return null; | ||
const times = this.divide(divisor, { maxDp: 0n }); | ||
return this.subtract(divisor.multiply(times)); | ||
} | ||
pow(n) { | ||
pow(n, options) { | ||
if (n.inf) { | ||
return this.i === 0n ? n.s < 0 ? Inf.P : _Internal.Z : this.compareTo(_Internal.O) === 0 || this.compareTo(_Internal.N_O) === 0 ? null : n.s < 0 ? _Internal.Z : Inf.P; | ||
return !this.i ? n.s < 0 ? Inf.P : _Internal.Z : this.abs().compareTo(_Internal.O) === 0 ? null : n.s < 0 ? _Internal.Z : Inf.P; | ||
} | ||
const bn = n.toBigInt(); | ||
return new _Internal(this.i ** bn, this.e * bn); | ||
if (bn >= 0n) | ||
return new _Internal(this.i ** bn, this.e * bn); | ||
const divideOptions = { | ||
maxDecimalPrecision: 20n, | ||
...options | ||
}; | ||
let result = _Internal.O; | ||
for (let i = bn; i < 0; i++) | ||
result = result.divide(this, divideOptions); | ||
return result; | ||
} | ||
scaleByPowerOfTen(n) { | ||
if (n.inf) | ||
return n.s < 0 ? _Internal.Z : this.i === 0n ? null : this.i >= 0n ? Inf.P : Inf.N; | ||
return n.s < 0 ? _Internal.Z : !this.i ? null : this.i >= 0n ? Inf.P : Inf.N; | ||
const bn = n.toBigInt(); | ||
@@ -164,3 +179,3 @@ return new _Internal(this.i, this.e + bn); | ||
trunc() { | ||
return this.i === 0n || this.e === 0n ? this : new _Internal(this.#trunc(), 0n); | ||
return !this.i || !this.e ? this : new _Internal(this.#trunc(), 0n); | ||
} | ||
@@ -213,5 +228,11 @@ round() { | ||
} | ||
#decimalCount() { | ||
#dp() { | ||
return -this.#simplify().e; | ||
} | ||
#precision() { | ||
let n = String(this.abs().i); | ||
while (n.endsWith("0")) | ||
n = n.slice(0, -1); | ||
return n.length || 1; | ||
} | ||
#simplify() { | ||
@@ -275,6 +296,6 @@ for (let e = -this.e; e > 0n; e--) { | ||
multiply(multiplicand) { | ||
return multiplicand.signum() === 0 ? null : multiplicand.signum() === this.signum() ? _Inf.P : _Inf.N; | ||
return !multiplicand.signum() ? null : multiplicand.signum() === this.s ? _Inf.P : _Inf.N; | ||
} | ||
divide(divisor) { | ||
return divisor.inf ? null : divisor.signum() >= 0 === this.signum() >= 0 ? _Inf.P : _Inf.N; | ||
return divisor.inf ? null : divisor.i >= 0n === this.s >= 0 ? _Inf.P : _Inf.N; | ||
} | ||
@@ -287,3 +308,3 @@ modulo() { | ||
return n.s < 0 ? Internal.Z : _Inf.P; | ||
if (n.i === 0n) | ||
if (!n.i) | ||
return Internal.O; | ||
@@ -295,4 +316,3 @@ if (n.i < 0n) | ||
scaleByPowerOfTen(n) { | ||
const m = new Internal(10n, 0n).pow(n); | ||
return m ? this.multiply(m) : null; | ||
return n.inf ? n.s > 0 ? this : null : this; | ||
} | ||
@@ -387,7 +407,6 @@ compareTo(n) { | ||
* Returns a BigNum whose value is (this / divisor) | ||
* @param options.maxDp The maximum number of decimal places. Default is 20. | ||
*/ | ||
divide(divisor, options) { | ||
const b = valueOf(divisor).#p; | ||
return b ? new _BigNum(this.#p?.divide(b, options?.maxDp)) : _BigNum.#nan; | ||
return b ? new _BigNum(this.#p?.divide(b, options)) : _BigNum.#nan; | ||
} | ||
@@ -401,6 +420,9 @@ /** | ||
} | ||
/** Returns a BigNum whose value is (this**n). */ | ||
pow(n) { | ||
/** | ||
* Returns a BigNum whose value is (this**n). | ||
* @param options.maxDp The maximum number of decimal places. This is used in negative pows. Default is 20. | ||
*/ | ||
pow(n, options) { | ||
const b = valueOf(n).#p; | ||
return b ? new _BigNum(this.#p?.pow(b)) : _BigNum.#nan; | ||
return b ? new _BigNum(this.#p?.pow(b, options)) : _BigNum.#nan; | ||
} | ||
@@ -444,3 +466,3 @@ /** Returns a BigNum whose numerical value is equal to (this * 10 ** n). */ | ||
isFinite() { | ||
return !this.#p || !this.#p.inf; | ||
return this.#p != null && !this.#p.inf; | ||
} | ||
@@ -469,4 +491,10 @@ toString() { | ||
} | ||
function length(a) { | ||
let t = a; | ||
for (let i = 0; ; i++) | ||
if (!(t /= 10n)) | ||
return i; | ||
} | ||
export { | ||
BigNum | ||
}; |
{ | ||
"name": "@bignum/core", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Arbitrary-precision decimal arithmetic with BigInt.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
@@ -50,4 +50,2 @@ # @bignum/core | ||
If `divider` is give a zero value, an error will be raised. | ||
An object can be given as an option. | ||
@@ -57,5 +55,6 @@ | ||
| Name | Type | Default | Description | | ||
| :---- | :----- | :------ | :------------------------------------ | | ||
| maxDp | bigint | `20n` | The maximum number of decimal places. | | ||
| Name | Type | Description | | ||
| :------------------ | :----- | :--------------------------------------------------------------------------------------------------- | | ||
| maxDp | bigint | The maximum number of decimal places. If `maxDecimalPrecision` is not specified, 20n is the default. | | ||
| maxDecimalPrecision | bigint | The maximum number of precision. | | ||
@@ -70,3 +69,3 @@ ### BigNum.prototype.modulo(divisor): BigNum | ||
### BigNum.prototype.pow(n): BigNum | ||
### BigNum.prototype.pow(n, [options]): BigNum | ||
@@ -77,2 +76,11 @@ Returns a BigNum whose value is (this \*\* n). | ||
An object can be given as an option. It's the same option for `divide()`. This is used in negative pows. | ||
Options: | ||
| Name | Type | Description | | ||
| :------------------ | :----- | :---------------------------------------------------------------------- | | ||
| maxDp | bigint | The maximum number of decimal places. | | ||
| maxDecimalPrecision | bigint | The maximum number of precision when having decimals. Default is `20n`. | | ||
### BigNum.prototype.scaleByPowerOfTen(n): BigNum | ||
@@ -114,4 +122,8 @@ | ||
Returns true if this is NaN. | ||
Returns `true` if this is NaN. | ||
### BigNum.prototype.isFinite(): boolean | ||
Returns `true` if this is finite number. | ||
## 🛸 Prior Art | ||
@@ -118,0 +130,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
40487
1106
133