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

Commit c3d58cd

Browse files
committed
Switch off normalization when we're testing non-normal values
1 parent 09a594e commit c3d58cd

6 files changed

+64
-71
lines changed

src/decimal128.mts

+38-55
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ const DEFAULT_CONSTRUCTOR_OPTIONS: FullySpecifiedConstructorOptions = {
871871
};
872872

873873
type ToStringFormat = "decimal" | "exponential";
874-
const TO_STRING_FORMATS: string[] = ["decimal", "exponential"];
874+
const TOSTRING_FORMATS: string[] = ["decimal", "exponential"];
875875

876876
interface ToStringOptions {
877877
format?: ToStringFormat;
@@ -883,15 +883,15 @@ interface FullySpecifiedToStringOptions {
883883
numDecimalDigits: number | undefined;
884884
}
885885

886-
const DEFAULT_TO_STRING_OPTIONS: FullySpecifiedToStringOptions = {
886+
const DEFAULT_TOSTRING_OPTIONS: FullySpecifiedToStringOptions = {
887887
format: "decimal",
888888
numDecimalDigits: undefined,
889889
};
890890

891891
function ensureFullySpecifiedConstructorOptions(
892892
options?: ConstructorOptions
893893
): FullySpecifiedConstructorOptions {
894-
let opts = DEFAULT_CONSTRUCTOR_OPTIONS;
894+
let opts = { ...DEFAULT_CONSTRUCTOR_OPTIONS };
895895

896896
if (undefined === options) {
897897
return opts;
@@ -904,9 +904,7 @@ function ensureFullySpecifiedConstructorOptions(
904904
opts.roundingMode = options.roundingMode;
905905
}
906906

907-
if (undefined === options.normalize) {
908-
opts.normalize = CONSTRUCTOR_SHOULD_NORMALIZE;
909-
} else {
907+
if ("boolean" === typeof options.normalize) {
910908
opts.normalize = options.normalize;
911909
}
912910

@@ -916,18 +914,15 @@ function ensureFullySpecifiedConstructorOptions(
916914
function ensureFullySpecifiedToStringOptions(
917915
options?: ToStringOptions
918916
): FullySpecifiedToStringOptions {
919-
let opts: FullySpecifiedToStringOptions = {
920-
format: "decimal",
921-
numDecimalDigits: undefined,
922-
};
917+
let opts: FullySpecifiedToStringOptions = { ...DEFAULT_TOSTRING_OPTIONS };
923918

924919
if (undefined === options) {
925920
return opts;
926921
}
927922

928923
if (
929924
"string" === typeof options.format &&
930-
TO_STRING_FORMATS.includes(options.format)
925+
TOSTRING_FORMATS.includes(options.format)
931926
) {
932927
opts.format = options.format;
933928
}
@@ -1055,7 +1050,7 @@ export class Decimal128 {
10551050
function emitDecimal(): string {
10561051
if (exp >= 0) {
10571052
return ensureDecimalDigits(
1058-
prefix + (sg + "0".repeat(exp)).replace(/^0+$/, "0"),
1053+
prefix + sg + "0".repeat(exp),
10591054
options.numDecimalDigits
10601055
);
10611056
}
@@ -1108,13 +1103,6 @@ export class Decimal128 {
11081103
return emitDecimal();
11091104
}
11101105

1111-
/**
1112-
* Is this Decimal128 actually an integer? That is: is there nothing after the decimal point?
1113-
*/
1114-
private isInteger(): boolean {
1115-
return !!this.toString().match(/^-?[0-9]+([.]0+)?$/);
1116-
}
1117-
11181106
/**
11191107
* Return the absolute value of this Decimal128 value.
11201108
*
@@ -1168,9 +1156,8 @@ export class Decimal128 {
11681156
* Add this Decimal128 value to one or more Decimal128 values.
11691157
*
11701158
* @param x
1171-
* @param options
11721159
*/
1173-
add(x: Decimal128, options?: ConstructorOptions): Decimal128 {
1160+
add(x: Decimal128): Decimal128 {
11741161
if (this.isNaN() || x.isNaN()) {
11751162
return new Decimal128(NAN);
11761163
}
@@ -1187,33 +1174,31 @@ export class Decimal128 {
11871174
return this.clone();
11881175
}
11891176

1190-
if (!this.isFinite()) {
1191-
return this.clone();
1192-
}
1193-
11941177
if (!x.isFinite()) {
11951178
return x.clone();
11961179
}
11971180

11981181
if (this.isNegative && x.isNegative) {
1199-
return this.negate().add(x.negate(), options).negate();
1182+
return this.negate().add(x.negate()).negate();
12001183
}
12011184

12021185
let resultRat = Rational.add(this.rat, x.rat);
12031186
let initialResult = new Decimal128(
1204-
resultRat.toDecimalPlaces(MAX_SIGNIFICANT_DIGITS + 1),
1205-
options
1187+
resultRat.toDecimalPlaces(MAX_SIGNIFICANT_DIGITS + 1)
1188+
);
1189+
let adjusted = initialResult.setExponent(
1190+
Math.min(this.exponent, x.exponent)
12061191
);
1207-
return initialResult.setExponent(Math.min(this.exponent, x.exponent));
1192+
1193+
return new Decimal128(adjusted.toString(), { normalize: false });
12081194
}
12091195

12101196
/**
12111197
* Subtract another Decimal128 value from one or more Decimal128 values.
12121198
*
12131199
* @param x
1214-
* @param options
12151200
*/
1216-
subtract(x: Decimal128, options?: ConstructorOptions): Decimal128 {
1201+
subtract(x: Decimal128): Decimal128 {
12171202
if (this.isNaN() || x.isNaN()) {
12181203
return new Decimal128(NAN);
12191204
}
@@ -1235,7 +1220,7 @@ export class Decimal128 {
12351220
}
12361221

12371222
if (x.isNegative) {
1238-
return this.add(x.negate(), options);
1223+
return this.add(x.negate());
12391224
}
12401225

12411226
let rendered = Rational.subtract(this.rat, x.rat).toDecimalPlaces(
@@ -1246,7 +1231,7 @@ export class Decimal128 {
12461231
let adjusted = initialResult.setExponent(
12471232
Math.min(this.exponent, x.exponent)
12481233
);
1249-
return new Decimal128(adjusted.toString(), options);
1234+
return new Decimal128(adjusted.toString(), { normalize: false });
12501235
}
12511236

12521237
/**
@@ -1255,9 +1240,8 @@ export class Decimal128 {
12551240
* If no arguments are given, return this value.
12561241
*
12571242
* @param x
1258-
* @param options
12591243
*/
1260-
multiply(x: Decimal128, options?: ConstructorOptions): Decimal128 {
1244+
multiply(x: Decimal128): Decimal128 {
12611245
if (this.isNaN() || x.isNaN()) {
12621246
return new Decimal128(NAN);
12631247
}
@@ -1287,19 +1271,20 @@ export class Decimal128 {
12871271
}
12881272

12891273
if (this.isNegative) {
1290-
return this.negate().multiply(x, options).negate();
1274+
return this.negate().multiply(x).negate();
12911275
}
12921276

12931277
if (x.isNegative) {
1294-
return this.multiply(x.negate(), options).negate();
1278+
return this.multiply(x.negate()).negate();
12951279
}
12961280

12971281
let resultRat = Rational.multiply(this.rat, x.rat);
12981282
let initialResult = new Decimal128(
1299-
resultRat.toDecimalPlaces(MAX_SIGNIFICANT_DIGITS + 1),
1300-
options
1283+
resultRat.toDecimalPlaces(MAX_SIGNIFICANT_DIGITS + 1)
13011284
);
1302-
return initialResult.setExponent(this.exponent + x.exponent);
1285+
let adjusted = initialResult.setExponent(this.exponent + x.exponent);
1286+
1287+
return new Decimal128(adjusted.toString(), { normalize: false });
13031288
}
13041289

13051290
private isZero(): boolean {
@@ -1319,7 +1304,7 @@ export class Decimal128 {
13191304
*
13201305
* @param x
13211306
*/
1322-
divide(x: Decimal128, options?: ConstructorOptions): Decimal128 {
1307+
divide(x: Decimal128): Decimal128 {
13231308
if (this.isNaN() || x.isNaN()) {
13241309
return new Decimal128(NAN);
13251310
}
@@ -1353,11 +1338,11 @@ export class Decimal128 {
13531338
}
13541339

13551340
if (this.isNegative) {
1356-
return this.negate().divide(x, options).negate();
1341+
return this.negate().divide(x).negate();
13571342
}
13581343

13591344
if (x.isNegative) {
1360-
return this.divide(x.negate(), options).negate();
1345+
return this.divide(x.negate()).negate();
13611346
}
13621347

13631348
let adjust = 0;
@@ -1402,10 +1387,7 @@ export class Decimal128 {
14021387
}
14031388

14041389
let resultExponent = this.exponent - (x.exponent + adjust);
1405-
return new Decimal128(
1406-
`${resultCoefficient}E${resultExponent}`,
1407-
options
1408-
);
1390+
return new Decimal128(`${resultCoefficient}E${resultExponent}`);
14091391
}
14101392

14111393
/**
@@ -1473,30 +1455,29 @@ export class Decimal128 {
14731455
let s = this.toString();
14741456

14751457
if (s.match(/^-/)) {
1476-
return new Decimal128(s.substring(1));
1458+
return new Decimal128(s.substring(1), { normalize: false });
14771459
}
14781460

1479-
return new Decimal128("-" + s);
1461+
return new Decimal128("-" + s, { normalize: false });
14801462
}
14811463

14821464
/**
14831465
* Return the remainder of this Decimal128 value divided by another Decimal128 value.
14841466
*
14851467
* @param d
1486-
* @param options
14871468
* @throws RangeError If argument is zero
14881469
*/
1489-
remainder(d: Decimal128, options?: ConstructorOptions): Decimal128 {
1470+
remainder(d: Decimal128): Decimal128 {
14901471
if (this.isNaN() || d.isNaN()) {
14911472
return new Decimal128(NAN);
14921473
}
14931474

14941475
if (this.isNegative) {
1495-
return this.negate().remainder(d, options).negate();
1476+
return this.negate().remainder(d).negate();
14961477
}
14971478

14981479
if (d.isNegative) {
1499-
return this.remainder(d.negate(), options);
1480+
return this.remainder(d.negate());
15001481
}
15011482

15021483
if (!this.isFinite()) {
@@ -1512,7 +1493,7 @@ export class Decimal128 {
15121493
}
15131494

15141495
let q = this.divide(d).round(0, ROUNDING_MODE_TRUNCATE);
1515-
return this.subtract(d.multiply(q), options).abs();
1496+
return this.subtract(d.multiply(q)).abs();
15161497
}
15171498

15181499
normalize(): Decimal128 {
@@ -1527,7 +1508,9 @@ export class Decimal128 {
15271508
let newExp = exp - 1;
15281509
let newSig = sig + "0";
15291510

1530-
return new Decimal128(`${prefix}${newSig}E${newExp}`);
1511+
return new Decimal128(`${prefix}${newSig}E${newExp}`, {
1512+
normalize: false,
1513+
});
15311514
}
15321515

15331516
private setExponent(newExp: number): Decimal128 {

tests/add.test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ describe("addition", () => {
120120
describe("examples from the General Decimal Arithmetic specification", () => {
121121
test("example one", () => {
122122
expect(
123-
new Decimal128("12").add(new Decimal128("7.00")).toString()
123+
new Decimal128("12")
124+
.add(new Decimal128("7.00", { normalize: false }))
125+
.toString()
124126
).toStrictEqual("19.00");
125127
});
126128
test("example two", () => {

tests/constructor.test.js

+13-9
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ describe("constructor", () => {
135135
expect(val.toString()).toStrictEqual(s);
136136
});
137137
test("decimal number with trailing zero", () => {
138-
let val = new Decimal128("0.67890");
138+
let val = new Decimal128("0.67890", { normalize: false });
139139
expect(val.significand).toStrictEqual("67890");
140140
expect(val.exponent).toStrictEqual(-5);
141141
});
@@ -202,20 +202,24 @@ describe("constructor", () => {
202202
expect(new Decimal128("-00").toString()).toStrictEqual("-0");
203203
});
204204
test("zero point zero", () => {
205-
expect(new Decimal128("0.0").toString()).toStrictEqual("0.0");
205+
expect(
206+
new Decimal128("0.0", { normalize: false }).toString()
207+
).toStrictEqual("0.0");
206208
});
207209
test("minus zero point zero", () => {
208-
expect(new Decimal128("-0.0").toString()).toStrictEqual("-0.0");
210+
expect(
211+
new Decimal128("-0.0", { normalize: false }).toString()
212+
).toStrictEqual("-0.0");
209213
});
210214
test("multiple trailing zeros", () => {
211-
expect(new Decimal128("0.000").toString()).toStrictEqual(
212-
"0.000"
213-
);
215+
expect(
216+
new Decimal128("0.000", { normalize: false }).toString()
217+
).toStrictEqual("0.000");
214218
});
215219
test("multiple trailing zeros (negative)", () => {
216-
expect(new Decimal128("-0.000").toString()).toStrictEqual(
217-
"-0.000"
218-
);
220+
expect(
221+
new Decimal128("-0.000", { normalize: false }).toString()
222+
).toStrictEqual("-0.000");
219223
});
220224
});
221225
});

tests/divide.test.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ describe("examples from the General Decimal Arithmetic Specification", () => {
169169
});
170170
test("example seven", () => {
171171
expect(
172-
new Decimal128("2.400").divide(new Decimal128("2.0")).toString()
172+
new Decimal128("2.400", { normalize: false })
173+
.divide(new Decimal128("2.0", { normalize: false }))
174+
.toString()
173175
).toStrictEqual("1.20");
174176
});
175177
test("example eight", () => {

tests/multiply.test.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ const examples = [
2222

2323
function checkProduct(a, b, c) {
2424
expect(
25-
new Decimal128(a)
26-
.multiply(new Decimal128(b), { normalize: false })
25+
new Decimal128(a, { normalize: false })
26+
.multiply(new Decimal128(b, { normalize: false }))
2727
.toString()
2828
).toStrictEqual(c);
2929
}
@@ -164,7 +164,9 @@ describe("multiplication", () => {
164164
describe("examples from the General Decimal Arithmetic specification", () => {
165165
test("example one", () => {
166166
expect(
167-
new Decimal128("1.20").multiply(new Decimal128("3")).toString()
167+
new Decimal128("1.20", { normalize: false })
168+
.multiply(new Decimal128("3"))
169+
.toString()
168170
).toStrictEqual("3.60");
169171
});
170172
test("example two", () => {

tests/subtract.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe("subtraction", () => {
88
test("subtract decimal part", () => {
99
expectDecimal128(
1010
new Decimal128("123.456").subtract(new Decimal128("0.456")),
11-
"123"
11+
"123.000"
1212
);
1313
});
1414
test("minus negative number", () => {
@@ -143,7 +143,7 @@ describe("examples from the General Decimal Arithmetic specification", () => {
143143
expect(
144144
new Decimal128("1.3")
145145
.subtract(new Decimal128("1.30", { normalize: false }))
146-
.toString()
146+
.toString({ normalize: false })
147147
).toStrictEqual("0.00");
148148
});
149149
test("example three", () => {

0 commit comments

Comments
 (0)