Created
December 16, 2022 22:56
-
-
Save aljopro/712608a7fc4e400b0f770248befe8962 to your computer and use it in GitHub Desktop.
Big Decimal
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 type BigDecimalCoersable = BigDecimal | string | number | bigint | undefined; | |
export class BigDecimal { | |
// Configuration: constants | |
public static decimalPrecision = 8; // number of decimals on all instances | |
public static isRounded = true; // numbers are truncated (false) or rounded (true) | |
protected static shift = BigInt('1' + '0'.repeat(BigDecimal.decimalPrecision)); // derived constant | |
protected static fromBigInt(value: bigint) { | |
const result = new BigDecimal(); | |
result.nValue = value; | |
return result; | |
} | |
protected static divRound(dividend: bigint, divisor: bigint) { | |
const two = BigInt(2); | |
const zero = BigInt(0); | |
const roundingValue = BigDecimal.isRounded ? dividend * two / divisor % two : zero; | |
return BigDecimal.fromBigInt(dividend / divisor + roundingValue); | |
} | |
protected nValue: bigint; | |
constructor(value: BigDecimalCoersable = undefined) { | |
if (!value) { | |
this.nValue = BigInt(0); | |
return; | |
} | |
if (value instanceof BigDecimal) { | |
this.nValue = value.nValue; | |
return; | |
} | |
const [ints, decis] = String(value).split('.').concat(''); | |
this.nValue = BigInt(ints + decis.padEnd(BigDecimal.decimalPrecision, '0') | |
.slice(0, BigDecimal.decimalPrecision)) | |
+ BigInt(BigDecimal.isRounded && decis[BigDecimal.decimalPrecision] >= '5'); | |
} | |
add(num: BigDecimalCoersable) { | |
return BigDecimal.fromBigInt(this.nValue + new BigDecimal(num).nValue); | |
} | |
subtract(num: BigDecimalCoersable) { | |
return BigDecimal.fromBigInt(this.nValue - new BigDecimal(num).nValue); | |
} | |
multiply(num: BigDecimalCoersable) { | |
return BigDecimal.divRound(this.nValue * new BigDecimal(num).nValue, BigDecimal.shift); | |
} | |
divide(num: BigDecimalCoersable) { | |
return BigDecimal.divRound(this.nValue * BigDecimal.shift, new BigDecimal(num).nValue); | |
} | |
toString() { | |
const s = this.nValue.toString().padStart(BigDecimal.decimalPrecision + 1, '0'); | |
const ints = s.slice(0, -BigDecimal.decimalPrecision); | |
const decis = s.slice(-BigDecimal.decimalPrecision); | |
return `${ints}.${decis}`.replace(/\.?0+$/, ''); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment