Skip to content

Commit

Permalink
A POC that replaces all BigInt to JSBI.BigInt (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
amoshydra authored Nov 19, 2024
1 parent 094a0f7 commit fc0e300
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 114 deletions.
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
],
"author": "Jesse Alama <jesse@igalia.com>",
"license": "ISC",
"dependencies": {
"jsbi": "^4.3.0"
},
"devDependencies": {
"@rollup/plugin-typescript": "^12.1.1",
"@types/jest": "^29.5.1",
Expand Down
3 changes: 2 additions & 1 deletion src/Decimal.mts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import JSBI from "jsbi";
import { Rational } from "./Rational.mjs";

function _cohort(s: string): "0" | "-0" | Rational {
Expand Down Expand Up @@ -88,7 +89,7 @@ export class Decimal {
});
}

public coefficient(): bigint {
public coefficient(): JSBI {
let v = this.cohort as Rational;
let q = this.quantum;
let c = v.scale10(0 - q);
Expand Down
66 changes: 38 additions & 28 deletions src/Decimal128.mts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* @author Jesse Alama <jesse@igalia.com>
*/

import JSBI from "jsbi";

import {
RoundingMode,
ROUNDING_MODES,
Expand All @@ -28,7 +30,7 @@ const EXPONENT_MAX = 6111;
const NORMAL_EXPONENT_MAX = 6144;
const MAX_SIGNIFICANT_DIGITS = 34;

const bigTen = BigInt(10);
const bigTen = JSBI.BigInt(10);

type NaNValue = "NaN";
type InfiniteValue = "Infinity" | "-Infinity";
Expand All @@ -39,7 +41,7 @@ type Decimal128Value = NaNValue | InfiniteValue | FiniteValue;
const NAN = "NaN";
const POSITIVE_INFINITY = "Infinity";
const NEGATIVE_INFINITY = "-Infinity";
const TEN_MAX_EXPONENT = bigTen ** BigInt(MAX_SIGNIFICANT_DIGITS);
const TEN_MAX_EXPONENT = JSBI.exponentiate(bigTen, JSBI.BigInt(MAX_SIGNIFICANT_DIGITS));

function pickQuantum(
d: "0" | "-0" | Rational,
Expand Down Expand Up @@ -80,7 +82,7 @@ function adjustDecimal128(d: Decimal): Decimal128Value {

let coef = d.coefficient();

if (coef <= TEN_MAX_EXPONENT && EXPONENT_MIN <= q && q <= EXPONENT_MAX) {
if (JSBI.LE(coef, TEN_MAX_EXPONENT) && JSBI.LE(EXPONENT_MIN, q) && JSBI.LE(q, EXPONENT_MAX)) {
return d;
}

Expand Down Expand Up @@ -166,10 +168,18 @@ export class Decimal128 {
private readonly _isFinite: boolean = true;
private readonly _isNegative: boolean = false;

constructor(n: string | number | bigint | Decimal) {
constructor(n: string | number | bigint | JSBI | Decimal) {
let data;
if ("object" === typeof n) {
data = n;
if (n instanceof JSBI) {
// Note: when using babel-plugin-transform-jsbi-to-bigint,
// the condition above may get transpiled into "typeof n === 'bigint'",
// causing the condition above to always be false.
// This is fine as we will be hanlding bigint below.
data = handleDecimalNotation(n.toString())
} else {
data = n;
}
} else {
let s: string;

Expand Down Expand Up @@ -262,7 +272,7 @@ export class Decimal128 {
let decimalOne = new Decimal128("1");
let decimalTen = new Decimal128("10");

while (0 <= x.cmp(decimalTen)) {
while (JSBI.LE(0, x.cmp(decimalTen))) {
x = x.scale10(-1);
}

Expand Down Expand Up @@ -303,7 +313,7 @@ export class Decimal128 {
);
}

private coefficient(): bigint {
private coefficient(): JSBI {
let d = this.d as Decimal;
return d.coefficient();
}
Expand Down Expand Up @@ -463,7 +473,7 @@ export class Decimal128 {

let n = opts.digits;

if (n <= 0) {
if (JSBI.LE(n, 0)) {
throw new RangeError("Argument must be positive");
}

Expand All @@ -484,15 +494,15 @@ export class Decimal128 {
let [lhs, rhs] = s.split(/[.]/);
let p = this.isNegative() ? "-" : "";

if (n <= lhs.length) {
if (JSBI.LE(n, lhs.length)) {
if (lhs.length === n) {
return p + lhs;
}

return p + s.substring(0, n) + "e+" + `${lhs.length - n + 1}`;
}

if (n <= lhs.length + rhs.length) {
if (JSBI.LE(n, lhs.length + rhs.length)) {
let rounded = this.round(n - lhs.length);
return rounded.emitDecimal();
}
Expand Down Expand Up @@ -523,7 +533,7 @@ export class Decimal128 {

let n = opts.digits;

if (n <= 0) {
if (JSBI.LE(n, 0)) {
throw new RangeError("Argument must be positive");
}

Expand All @@ -539,7 +549,7 @@ export class Decimal128 {

let p = this.isNegative() ? "-" : "";

if (rhs.length <= n) {
if (JSBI.LE(rhs.length, n)) {
return p + lhs + "." + rhs + "0".repeat(n - rhs.length) + "e" + exp;
}

Expand All @@ -558,7 +568,7 @@ export class Decimal128 {
return !!rhs.match(/^0+$/);
}

toBigInt(): bigint {
toBigInt(): JSBI {
if (this.isNaN()) {
throw new RangeError("NaN cannot be converted to a BigInt");
}
Expand All @@ -573,7 +583,7 @@ export class Decimal128 {
);
}

return BigInt(this.toString());
return JSBI.BigInt(this.toString());
}

toNumber(): number {
Expand Down Expand Up @@ -931,34 +941,34 @@ export class Decimal128 {
let dividendCoefficient = this.coefficient();
let divisorCoefficient = x.coefficient();

if (dividendCoefficient !== 0n) {
while (dividendCoefficient < divisorCoefficient) {
dividendCoefficient = dividendCoefficient * 10n;
if (JSBI.notEqual(dividendCoefficient, JSBI.BigInt(0))) {
while (JSBI.LT(dividendCoefficient, divisorCoefficient)) {
dividendCoefficient = JSBI.multiply(dividendCoefficient, JSBI.BigInt(10));
adjust++;
}
}

while (dividendCoefficient > divisorCoefficient * 10n) {
divisorCoefficient = divisorCoefficient * 10n;
while (JSBI.GT(dividendCoefficient, JSBI.multiply(divisorCoefficient, JSBI.BigInt(10)))) {
divisorCoefficient = JSBI.multiply(divisorCoefficient, JSBI.BigInt(10));
adjust--;
}

let resultCoefficient = 0n;
let resultCoefficient = JSBI.BigInt(0);
let done = false;

while (!done) {
while (divisorCoefficient <= dividendCoefficient) {
dividendCoefficient = dividendCoefficient - divisorCoefficient;
resultCoefficient++;
while (JSBI.LE(divisorCoefficient, dividendCoefficient)) {
dividendCoefficient = JSBI.subtract(dividendCoefficient, divisorCoefficient);
resultCoefficient = JSBI.add(resultCoefficient, JSBI.BigInt(1));
}
if (
(dividendCoefficient === 0n && adjust >= 0) ||
(JSBI.equal(dividendCoefficient, JSBI.BigInt(0)) && adjust >= 0) ||
resultCoefficient.toString().length > MAX_SIGNIFICANT_DIGITS
) {
done = true;
} else {
resultCoefficient = resultCoefficient * 10n;
dividendCoefficient = dividendCoefficient * 10n;
resultCoefficient = JSBI.multiply(resultCoefficient, JSBI.BigInt(10));
dividendCoefficient = JSBI.multiply(dividendCoefficient, JSBI.BigInt(10));
adjust++;
}
}
Expand Down Expand Up @@ -1123,7 +1133,7 @@ export class Decimal128 {
return this.exponent();
}

scaledSignificand(): bigint {
scaledSignificand(): JSBI {
if (this.isNaN()) {
throw new RangeError("NaN does not have a scaled significand");
}
Expand All @@ -1133,7 +1143,7 @@ export class Decimal128 {
}

if (this.isZero()) {
return 0n;
return JSBI.BigInt(0);
}

let v = this.cohort() as Rational;
Expand Down
Loading

0 comments on commit fc0e300

Please sign in to comment.