Created
March 9, 2022 10:14
-
-
Save bigshans/2d0ef27166cc287b467d71e7bdfe1251 to your computer and use it in GitHub Desktop.
BigDecimal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class BigDecimal { | |
DECIMALS: number; | |
ROUNDED: boolean; | |
SHIFT: BigInt; | |
_n: BigInt; | |
constructor(value: number | string | BigDecimal | BigInt); | |
static fromBigInt(bigint: BigInt): BigDecimal; | |
add(num: number | string | BigDecimal | BigInt): BigDecimal; | |
substract(num: number | string | BigDecimal | BigInt): BigDecimal; | |
static _divRound(dividend: BigInt, divisor: BigInt): BigDecimal; | |
multiply(num: number | string | BigDecimal | BigInt): BigDecimal; | |
divide(num: number | string | BigDecimal | BigInt): BigDecimal; | |
toString(): string; | |
toLocaleString(): string; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Original source: https://stackoverflow.com/questions/16742578/bigdecimal-in-javascript | |
* @author: trincot | |
* @author: bigshans (Modified) | |
* @example | |
* var a = new BigDecimal("123456789123456789876"); | |
* var b = a.divide("10000000000000000000"); | |
* var c = b.add("9.000000000000000004"); | |
* console.log(b.toString()); | |
* console.log(c.toString()); | |
* console.log(c.toLocaleString()); | |
* console.log(+c); // loss of precision when converting to number | |
*/ | |
export class BigDecimal { | |
// Configuration: constants | |
DECIMALS = 3; // number of decimals on all instances | |
ROUNDED = true; // numbers are truncated (false) or rounded (true) | |
SHIFT = BigInt("1" + "0".repeat(BigDecimal.DECIMALS)); // derived constant | |
constructor(value) { | |
if (value instanceof BigDecimal) { | |
return value; | |
} | |
let [ints, decis] = String(value).split(".").concat(""); | |
this._n = | |
BigInt(ints + decis.padEnd(this.DECIMALS, "0").slice(0, this.DECIMALS)) + | |
BigInt(this.ROUNDED && decis[this.DECIMALS] >= "5"); | |
} | |
static fromBigInt(bigint) { | |
return Object.assign(Object.create(BigDecimal.prototype), { _n: bigint }); | |
} | |
add(num) { | |
return BigDecimal.fromBigInt(this._n + new BigDecimal(num)._n); | |
} | |
subtract(num) { | |
return BigDecimal.fromBigInt(this._n - new BigDecimal(num)._n); | |
} | |
static _divRound(dividend, divisor) { | |
return BigDecimal.fromBigInt( | |
dividend / divisor + | |
(this.ROUNDED ? ((dividend * 2n) / divisor) % 2n : 0n) | |
); | |
} | |
multiply(num) { | |
return BigDecimal._divRound( | |
this._n * new BigDecimal(num)._n, | |
BigDecimal.SHIFT | |
); | |
} | |
divide(num) { | |
return BigDecimal._divRound(this._n * this.SHIFT, new BigDecimal(num)._n); | |
} | |
toString() { | |
const s = this._n.toString().padStart(this.DECIMALS + 1, "0"); | |
return s.slice(0, -this.DECIMALS) + "." + s.slice(-this.DECIMALS); | |
} | |
toLocaleString() { | |
return this.toString().replace(/\d+/, function (n) { | |
return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) { | |
return $1 + ","; | |
}); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment