Skip to content

Instantly share code, notes, and snippets.

@bigshans
Created March 9, 2022 10:14
Show Gist options
  • Save bigshans/2d0ef27166cc287b467d71e7bdfe1251 to your computer and use it in GitHub Desktop.
Save bigshans/2d0ef27166cc287b467d71e7bdfe1251 to your computer and use it in GitHub Desktop.
BigDecimal
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;
}
/**
* 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