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

Commit 5ead135

Browse files
committed
Use the official IEEE 754 rounding mode names
1 parent 7c34396 commit 5ead135

File tree

5 files changed

+188
-171
lines changed

5 files changed

+188
-171
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [15.0.0] - 2024-05-07
11+
12+
- Use the official IEEE 754 rounding names rather than "trunc", "ceil", etc. This is a breaking change if you're using those rounding modes. If not, you shouldn't see any change.
13+
1014
## [14.1.0] - 2024-05-06
1115

1216
### Added

examples/floor.mts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Decimal128 } from "../src/decimal128.mjs";
22

33
function floor(d: Decimal128): Decimal128 {
4-
return d.round(0, "floor");
4+
return d.round(0, "roundTowardNegative");
55
}
66

77
export { floor };

src/decimal128.mts

+60-49
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ function roundHalfEven(
333333
};
334334
}
335335

336-
function roundCeiling(x: SignedSignificandExponent): SignedSignificandExponent {
336+
function roundHalfExpand(
337+
x: SignedSignificandExponent
338+
): SignedSignificandExponent {
337339
let sig = x.significand.toString();
338340
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
339341
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
@@ -348,17 +350,27 @@ function roundCeiling(x: SignedSignificandExponent): SignedSignificandExponent {
348350
x.isNegative,
349351
penultimateDigit,
350352
lastDigit,
351-
ROUNDING_MODE_CEILING
353+
ROUNDING_MODE_HALF_EXPAND
352354
);
353355

356+
if (finalDigit < 10) {
357+
return {
358+
isNegative: x.isNegative,
359+
significand: BigInt(`${cutoff}${finalDigit}`),
360+
exponent: exp,
361+
};
362+
}
363+
364+
let rounded = propagateCarryFromRight(cutoff);
365+
354366
return {
355367
isNegative: x.isNegative,
356-
significand: BigInt(`${cutoff}${finalDigit}`),
368+
significand: BigInt(`${rounded}0`),
357369
exponent: exp,
358370
};
359371
}
360372

361-
function roundFloor(x: SignedSignificandExponent): SignedSignificandExponent {
373+
function roundCeiling(x: SignedSignificandExponent): SignedSignificandExponent {
362374
let sig = x.significand.toString();
363375
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
364376
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
@@ -373,27 +385,17 @@ function roundFloor(x: SignedSignificandExponent): SignedSignificandExponent {
373385
x.isNegative,
374386
penultimateDigit,
375387
lastDigit,
376-
ROUNDING_MODE_FLOOR
388+
ROUNDING_MODE_CEILING
377389
);
378390

379-
if (finalDigit < 10) {
380-
return {
381-
isNegative: x.isNegative,
382-
significand: BigInt(`${cutoff}${finalDigit}`),
383-
exponent: exp,
384-
};
385-
}
386-
387-
let rounded = propagateCarryFromRight(cutoff);
388-
389391
return {
390392
isNegative: x.isNegative,
391-
significand: BigInt(`${rounded}0`),
393+
significand: BigInt(`${cutoff}${finalDigit}`),
392394
exponent: exp,
393395
};
394396
}
395397

396-
function roundTrunc(x: SignedSignificandExponent): SignedSignificandExponent {
398+
function roundFloor(x: SignedSignificandExponent): SignedSignificandExponent {
397399
let sig = x.significand.toString();
398400
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
399401
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
@@ -408,19 +410,27 @@ function roundTrunc(x: SignedSignificandExponent): SignedSignificandExponent {
408410
x.isNegative,
409411
penultimateDigit,
410412
lastDigit,
411-
ROUNDING_MODE_TRUNCATE
413+
ROUNDING_MODE_FLOOR
412414
);
413415

416+
if (finalDigit < 10) {
417+
return {
418+
isNegative: x.isNegative,
419+
significand: BigInt(`${cutoff}${finalDigit}`),
420+
exponent: exp,
421+
};
422+
}
423+
424+
let rounded = propagateCarryFromRight(cutoff);
425+
414426
return {
415427
isNegative: x.isNegative,
416-
significand: BigInt(`${cutoff}${finalDigit}`),
428+
significand: BigInt(`${rounded}0`),
417429
exponent: exp,
418430
};
419431
}
420432

421-
function roundHalfCeil(
422-
x: SignedSignificandExponent
423-
): SignedSignificandExponent {
433+
function roundTrunc(x: SignedSignificandExponent): SignedSignificandExponent {
424434
let sig = x.significand.toString();
425435
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
426436
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
@@ -435,7 +445,7 @@ function roundHalfCeil(
435445
x.isNegative,
436446
penultimateDigit,
437447
lastDigit,
438-
ROUNDING_MODE_HALF_CEILING
448+
ROUNDING_MODE_TRUNCATE
439449
);
440450

441451
return {
@@ -458,8 +468,8 @@ function adjustNonInteger(
458468
return roundFloor(x);
459469
case ROUNDING_MODE_TRUNCATE:
460470
return roundTrunc(x);
461-
case ROUNDING_MODE_HALF_CEILING:
462-
return roundHalfCeil(x);
471+
case ROUNDING_MODE_HALF_EXPAND:
472+
return roundHalfExpand(x);
463473
default:
464474
return roundHalfEven(x);
465475
}
@@ -572,14 +582,13 @@ function handleInfinity(s: string): Decimal128Constructor {
572582
};
573583
}
574584

575-
export const ROUNDING_MODE_CEILING: RoundingMode = "ceil";
576-
export const ROUNDING_MODE_FLOOR: RoundingMode = "floor";
577-
export const ROUNDING_MODE_TRUNCATE: RoundingMode = "trunc";
578-
export const ROUNDING_MODE_HALF_EVEN: RoundingMode = "halfEven";
579-
export const ROUNDING_MODE_HALF_CEILING: RoundingMode = "halfCeil";
585+
export const ROUNDING_MODE_CEILING: RoundingMode = "roundTowardPositive";
586+
export const ROUNDING_MODE_FLOOR: RoundingMode = "roundTowardNegative";
587+
export const ROUNDING_MODE_TRUNCATE: RoundingMode = "roundTowardZero";
588+
export const ROUNDING_MODE_HALF_EVEN: RoundingMode = "roundTiesToEven";
589+
export const ROUNDING_MODE_HALF_EXPAND: RoundingMode = "roundTiesToAway";
580590

581-
const ROUNDING_MODE_DEFAULT = ROUNDING_MODE_HALF_EVEN;
582-
const CONSTRUCTOR_SHOULD_NORMALIZE = false;
591+
const ROUNDING_MODE_DEFAULT: RoundingMode = ROUNDING_MODE_HALF_EVEN;
583592

584593
function roundIt(
585594
isNegative: boolean,
@@ -610,12 +619,8 @@ function roundIt(
610619
return digitToRound;
611620
case ROUNDING_MODE_TRUNCATE:
612621
return digitToRound;
613-
case ROUNDING_MODE_HALF_CEILING:
622+
case ROUNDING_MODE_HALF_EXPAND:
614623
if (decidingDigit >= 5) {
615-
if (isNegative) {
616-
return digitToRound;
617-
}
618-
619624
return (digitToRound + 1) as DigitOrTen;
620625
}
621626

@@ -637,14 +642,19 @@ function roundIt(
637642
}
638643
}
639644

640-
type RoundingMode = "ceil" | "floor" | "trunc" | "halfEven" | "halfCeil";
645+
type RoundingMode =
646+
| "roundTowardPositive"
647+
| "roundTowardNegative"
648+
| "roundTowardZero"
649+
| "roundTiesToEven"
650+
| "roundTiesToAway";
641651

642652
const ROUNDING_MODES: RoundingMode[] = [
643-
"ceil",
644-
"floor",
645-
"trunc",
646-
"halfEven",
647-
"halfCeil",
653+
"roundTowardPositive",
654+
"roundTowardNegative",
655+
"roundTowardZero",
656+
"roundTiesToEven",
657+
"roundTiesToAway",
648658
];
649659

650660
const digitStrRegExp =
@@ -659,14 +669,11 @@ interface ConstructorOptions {
659669

660670
interface FullySpecifiedConstructorOptions {
661671
roundingMode: RoundingMode;
662-
normalize: boolean;
663672
}
664673

665-
const DEFAULT_CONSTRUCTOR_OPTIONS: FullySpecifiedConstructorOptions =
666-
Object.freeze({
667-
roundingMode: ROUNDING_MODE_DEFAULT,
668-
normalize: CONSTRUCTOR_SHOULD_NORMALIZE,
669-
});
674+
const DEFAULT_CONSTRUCTOR_OPTIONS: FullySpecifiedConstructorOptions = {
675+
roundingMode: ROUNDING_MODE_DEFAULT,
676+
};
670677

671678
type ToStringFormat = "decimal" | "exponential";
672679
const TOSTRING_FORMATS: string[] = ["decimal", "exponential"];
@@ -1349,6 +1356,10 @@ export class Decimal128 {
13491356
return this.clone();
13501357
}
13511358

1359+
if (!ROUNDING_MODES.includes(mode)) {
1360+
throw new RangeError(`Invalid rounding mode "${mode}"`);
1361+
}
1362+
13521363
if (numDecimalDigits < 0) {
13531364
numDecimalDigits = 0;
13541365
}

tests/constructor.test.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,11 @@ describe("rounding options", () => {
462462
describe("negative value, final decimal digit is five, penultimate digit is less than nine", () => {
463463
let val = "-1234567890123456789012345678901234.5";
464464
let answers = {
465-
ceil: "-1234567890123456789012345678901234",
466-
floor: "-1234567890123456789012345678901235",
467-
trunc: "-1234567890123456789012345678901234",
468-
halfEven: "-1234567890123456789012345678901234",
469-
halfCeil: "-1234567890123456789012345678901234",
465+
roundTowardPositive: "-1234567890123456789012345678901234",
466+
roundTowardNegative: "-1234567890123456789012345678901235",
467+
roundTowardZero: "-1234567890123456789012345678901234",
468+
roundTiesToEven: "-1234567890123456789012345678901234",
469+
roundTiesAway: "-1234567890123456789012345678901234",
470470
};
471471
for (const [mode, expected] of Object.entries(answers)) {
472472
test(`constructor with rounding mode "${mode}"`, () => {
@@ -479,11 +479,11 @@ describe("rounding options", () => {
479479
describe("negative value, final decimal digit is five, penultimate digit is nine", () => {
480480
let roundNineVal = "-1234567890123456789012345678901239.5";
481481
let roundUpAnswers = {
482-
ceil: "-1234567890123456789012345678901239",
483-
floor: "-1234567890123456789012345678901240",
484-
trunc: "-1234567890123456789012345678901239",
485-
halfEven: "-1234567890123456789012345678901240",
486-
halfCeil: "-1234567890123456789012345678901239",
482+
roundTowardPositive: "-1234567890123456789012345678901239",
483+
roundTowardNegative: "-1234567890123456789012345678901240",
484+
roundTowardZero: "-1234567890123456789012345678901239",
485+
roundTiesToEven: "-1234567890123456789012345678901240",
486+
roundTiesAway: "-1234567890123456789012345678901240",
487487
};
488488
for (const [mode, expected] of Object.entries(roundUpAnswers)) {
489489
test(`constructor with rounding mode "${mode}"`, () => {

0 commit comments

Comments
 (0)