Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 01608a4

Browse files
committed
WIP
1 parent f18f0a7 commit 01608a4

File tree

4 files changed

+94
-82
lines changed

4 files changed

+94
-82
lines changed

src/Decimal128.mts

+80-38
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const MAX_SIGNIFICANT_DIGITS = 34;
2323

2424
const bigTen = BigInt(10);
2525
const bigOne = BigInt(1);
26+
const ratOne = new Rational(1n, 1n);
27+
const ratTen = new Rational(10n, 1n);
2628

2729
type NaNValue = "NaN";
2830
type InfiniteValue = "Infinity" | "-Infinity";
@@ -264,8 +266,6 @@ export class Decimal128 {
264266
let q = this.quantum() as number;
265267
let s = v;
266268
let e = q;
267-
const ratTen = new Rational(bigTen, bigOne);
268-
const ratOne = new Rational(bigOne, bigOne);
269269

270270
while (s.cmp(ratOne) < 0) {
271271
s = s.scale10(1);
@@ -281,13 +281,34 @@ export class Decimal128 {
281281
}
282282

283283
public exponent(): number {
284-
let [_, e] = this.significandAndExponent();
285-
return e;
284+
let mantissa = this.mantissa();
285+
let mantissaQuantum = mantissa.quantum();
286+
let ourQuantum = this.quantum();
287+
return ourQuantum - mantissaQuantum;
286288
}
287289

288290
public mantissa(): Decimal128 {
289-
let [sig, _] = this.significandAndExponent();
290-
return new Decimal128(sig.toFixed(MAX_SIGNIFICANT_DIGITS));
291+
if (this.isZero()) {
292+
throw new RangeError("Zero does not have a mantissa");
293+
}
294+
295+
if (this.isNegative()) {
296+
return this.neg().mantissa().neg();
297+
}
298+
299+
let x: Decimal128 = this;
300+
let decimalOne = new Decimal128("1");
301+
let decimalTen = new Decimal128("10");
302+
303+
while (0 <= x.cmp(decimalTen)) {
304+
x = x.scale10(-1);
305+
}
306+
307+
while (x.cmp(decimalOne) === -1) {
308+
x = x.scale10(1);
309+
}
310+
311+
return x;
291312
}
292313

293314
public scale10(n: number): Decimal128 {
@@ -311,35 +332,37 @@ export class Decimal128 {
311332
let q = this.quantum() as number;
312333

313334
return new Decimal128(
314-
new Decimal({ cohort: v.scale10(n), quantum: q - n })
335+
new Decimal({ cohort: v.scale10(n), quantum: q + n })
315336
);
316337
}
317338

318-
private significand(): Rational {
319-
let [s, _] = this.significandAndExponent();
320-
return s;
339+
private significand(): bigint {
340+
if (this.isZero()) {
341+
throw new RangeError("Zero does not have a significand");
342+
}
343+
344+
let d = this.d as Decimal;
345+
return d.coefficient();
321346
}
322347

323348
private emitExponential(): string {
324-
let prefix = this.isNegative() ? "-" : "";
325-
let sg = this.significand().toString();
326-
let exp = this.exponent();
349+
let v = this.cohort();
350+
let q = this.quantum();
351+
let p = this._isNegative ? "-" : "";
327352

328-
let adjustedExponent = exp + sg.length - 1;
353+
if (v === "0" || v === "-0") {
354+
if (q < 0) {
355+
return p + v + "." + "0".repeat(0 - q);
356+
}
329357

330-
if (sg.length === 1) {
331-
return prefix + sg + "e" + (exp < 0 ? "" : "+") + exp;
358+
return v;
332359
}
333360

334-
return (
335-
prefix +
336-
sg.substring(0, 1) +
337-
"." +
338-
sg.substring(1) +
339-
"e" +
340-
(adjustedExponent < 0 ? "" : "+") +
341-
adjustedExponent
342-
);
361+
let m = this.mantissa();
362+
let e = this.exponent();
363+
let mAsString = m.toFixed({ digits: Infinity });
364+
let expPart = (e < 0 ? "-" : "+") + Math.abs(e);
365+
return p + mAsString + "e" + expPart;
343366
}
344367

345368
private emitDecimal(): string {
@@ -453,8 +476,14 @@ export class Decimal128 {
453476
throw new RangeError("Argument must be greater than or equal to 0");
454477
}
455478

479+
if (n === Infinity) {
480+
return this.emitDecimal();
481+
}
482+
456483
if (!Number.isInteger(n)) {
457-
throw new RangeError("Argument must be an integer");
484+
throw new RangeError(
485+
"Argument must be an integer or positive infinity"
486+
);
458487
}
459488

460489
if (this.isNaN()) {
@@ -727,13 +756,29 @@ export class Decimal128 {
727756
return this.neg().add(x.neg()).neg();
728757
}
729758

759+
if (this.isZero()) {
760+
return x.clone();
761+
}
762+
763+
if (x.isZero()) {
764+
return this.clone();
765+
}
766+
730767
let ourCohort = this.cohort() as Rational;
731768
let theirCohort = x.cohort() as Rational;
732769
let ourQuantum = this.quantum() as number;
733770
let theirQuantum = x.quantum() as number;
734771
let sum = Rational.add(ourCohort, theirCohort);
735772
let preferredQuantum = Math.min(ourQuantum, theirQuantum);
736773

774+
if (sum.isZero()) {
775+
if (this._isNegative) {
776+
return new Decimal128("-0");
777+
}
778+
779+
return new Decimal128("0");
780+
}
781+
737782
return new Decimal128(
738783
new Decimal({
739784
cohort: sum,
@@ -916,37 +961,34 @@ export class Decimal128 {
916961
let dividendCoefficient = this.significand();
917962
let divisorCoefficient = x.significand();
918963

919-
if (!dividendCoefficient.isZero()) {
920-
while (dividendCoefficient.cmp(divisorCoefficient) === -1) {
921-
dividendCoefficient = dividendCoefficient.scale10(1);
964+
if (dividendCoefficient !== 0n) {
965+
while (dividendCoefficient < divisorCoefficient) {
966+
dividendCoefficient = dividendCoefficient * 10n;
922967
adjust++;
923968
}
924969
}
925970

926-
while (dividendCoefficient.cmp(divisorCoefficient.scale10(1))) {
927-
divisorCoefficient = divisorCoefficient.scale10(1);
971+
while (dividendCoefficient > divisorCoefficient * 10n) {
972+
divisorCoefficient = divisorCoefficient * 10n;
928973
adjust--;
929974
}
930975

931976
let resultCoefficient = 0n;
932977
let done = false;
933978

934979
while (!done) {
935-
while (divisorCoefficient.cmp(dividendCoefficient) <= 0) {
936-
dividendCoefficient = Rational.subtract(
937-
dividendCoefficient,
938-
divisorCoefficient
939-
);
980+
while (divisorCoefficient <= dividendCoefficient) {
981+
dividendCoefficient = dividendCoefficient - divisorCoefficient;
940982
resultCoefficient++;
941983
}
942984
if (
943-
(dividendCoefficient.isZero() && adjust >= 0) ||
985+
(dividendCoefficient === 0n && adjust >= 0) ||
944986
resultCoefficient.toString().length > MAX_SIGNIFICANT_DIGITS
945987
) {
946988
done = true;
947989
} else {
948990
resultCoefficient = resultCoefficient * 10n;
949-
dividendCoefficient = dividendCoefficient.scale10(1);
991+
dividendCoefficient = dividendCoefficient * 10n;
950992
adjust++;
951993
}
952994
}

src/Rational.mts

+5-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ export class Rational {
306306
}
307307

308308
public toFixed(n: number): string {
309-
if (!Number.isInteger(n)) {
309+
if (n !== Infinity && !Number.isInteger(n)) {
310310
throw new TypeError(
311311
"Cannot enumerate a non-integer number of decimal places"
312312
);
@@ -350,6 +350,10 @@ export class Rational {
350350
digit = digitGenerator.next();
351351
}
352352

353+
if (Infinity === n) {
354+
return result;
355+
}
356+
353357
let numFractionalDigits = countFractionalDigits(result);
354358

355359
if (numFractionalDigits >= n) {

tests/Decimal128/add.test.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe("addition", () => {
1515
});
1616
test("one plus minus one equals zero", () => {
1717
expect(one.add(minusOne).toString()).toStrictEqual("0");
18-
expect(minusOne.add(one).toString()).toStrictEqual("0");
18+
expect(minusOne.add(one).toString()).toStrictEqual("-0");
1919
});
2020
test("minus zero plus zero", () => {
2121
expect(minusZero.add(zero).toString()).toStrictEqual("0");
@@ -60,7 +60,7 @@ describe("addition", () => {
6060
expect(
6161
new Decimal128("1.0")
6262
.add(new Decimal128("1.0"))
63-
.toString({ normalize: false })
63+
.toString({ preserveTrailingZeroes: true })
6464
).toStrictEqual("2.0");
6565
});
6666
});
@@ -130,14 +130,12 @@ describe("examples from the General Decimal Arithmetic specification", () => {
130130
expect(
131131
new Decimal128("12")
132132
.add(new Decimal128("7.00"))
133-
.toString({ normalize: false })
133+
.toString({ preserveTrailingZeroes: true })
134134
).toStrictEqual("19.00");
135135
});
136136
test("example two", () => {
137137
expect(
138-
new Decimal128("1E+2")
139-
.add(new Decimal128("1E+4"))
140-
.toString({ format: "exponential" })
138+
new Decimal128("1E+2").add(new Decimal128("1E+4")).toExponential()
141139
).toStrictEqual("1.01e+4");
142140
});
143141
});

tests/Decimal128/tostring.test.js

+5-37
Original file line numberDiff line numberDiff line change
@@ -27,46 +27,14 @@ describe("infinity", () => {
2727
});
2828
});
2929

30-
describe("to decimal places", function () {
31-
const d = "123.456";
32-
const decimalD = new Decimal128(d);
33-
test("more digits than available means digits get added", () => {
34-
expectDecimal128(
35-
decimalD.toString({ numDecimalDigits: 4 }),
36-
"123.4560"
37-
);
38-
});
39-
test("same number of digits as available means no change", () => {
40-
expectDecimal128(decimalD.toString({ numDecimalDigits: 3 }), "123.456");
41-
});
42-
test("cutoff if number has more digits than requested (1)", () => {
43-
expectDecimal128(decimalD.toString({ numDecimalDigits: 2 }), "123.45");
44-
});
45-
test("cutoff if number has more digits than requested (2)", () => {
46-
expectDecimal128(decimalD.toString({ numDecimalDigits: 1 }), "123.4");
47-
});
48-
test("zero decimal places", () => {
49-
expectDecimal128(decimalD.toString({ numDecimalDigits: 0 }), "123");
50-
});
51-
test("negative number of decimal places", () => {
52-
expect(decimalD.toString({ numDecimalDigits: -1 })).toStrictEqual(
53-
"123.456"
54-
);
55-
});
56-
test("non-integer number of decimal places reverts to default", () => {
57-
expect(decimalD.toString({ numDecimalDigits: 1.5 })).toStrictEqual(
58-
"123.456"
59-
);
60-
});
61-
});
62-
6330
describe("normalization", () => {
31+
let d = new Decimal128("1.20");
6432
test("on by default", () => {
65-
expect(new Decimal128("1.20").toString()).toStrictEqual("1.2");
33+
expect(d.toString()).toStrictEqual("1.2");
6634
});
6735
test("can be disabled", () => {
68-
expect(
69-
new Decimal128("1.20").toString({ normalize: false })
70-
).toStrictEqual("1.20");
36+
expect(d.toString({ preserveTrailingZeroes: true })).toStrictEqual(
37+
"1.20"
38+
);
7139
});
7240
});

0 commit comments

Comments
 (0)