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

Commit 178d876

Browse files
committed
WIP
1 parent 2c6a197 commit 178d876

File tree

3 files changed

+245
-152
lines changed

3 files changed

+245
-152
lines changed

src/Decimal128.mts

+14-2
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ export class Decimal128 {
500500
: POSITIVE_INFINITY;
501501
}
502502

503-
let rounded = this.round(n + 1);
503+
let rounded = this.round(n);
504504
let roundedRendered = rounded.emitDecimal();
505505

506506
if (roundedRendered.match(/[.]/)) {
@@ -1087,7 +1087,19 @@ export class Decimal128 {
10871087
let q = this.quantum() as number;
10881088

10891089
let roundedV = v.round(numDecimalDigits, mode);
1090-
return new Decimal128(new Decimal({ cohort: roundedV, quantum: q }));
1090+
1091+
if (roundedV.isZero()) {
1092+
return new Decimal128(
1093+
new Decimal({
1094+
cohort: v.isNegative ? "-0" : "0",
1095+
quantum: 0 - numDecimalDigits,
1096+
})
1097+
);
1098+
}
1099+
1100+
return new Decimal128(
1101+
new Decimal({ cohort: roundedV, quantum: 0 - numDecimalDigits })
1102+
);
10911103
}
10921104

10931105
negate(): Decimal128 {

src/Rational.mts

+130-23
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import {
22
countFractionalDigits,
33
countSignificantDigits,
44
Digit,
5+
ROUNDING_MODE_CEILING,
6+
ROUNDING_MODE_FLOOR,
7+
ROUNDING_MODE_HALF_EVEN,
8+
ROUNDING_MODE_HALF_EXPAND,
59
ROUNDING_MODE_TRUNCATE,
610
RoundingMode,
711
} from "./common.mjs";
@@ -411,6 +415,83 @@ export class Rational {
411415
return (this.isNegative ? "-" : "") + result;
412416
}
413417

418+
private static roundHalfEven(
419+
initialPart: Rational,
420+
penultimateDigit: Digit,
421+
finalDigit: Digit,
422+
quantum: Rational
423+
): Rational {
424+
if (finalDigit < 5) {
425+
return initialPart;
426+
}
427+
428+
if (finalDigit > 5) {
429+
return Rational.add(
430+
initialPart,
431+
initialPart.isNegative ? quantum.negate() : quantum
432+
);
433+
}
434+
435+
if (penultimateDigit % 2 === 0) {
436+
return initialPart;
437+
}
438+
439+
return Rational.add(
440+
initialPart,
441+
initialPart.isNegative ? quantum.negate() : quantum
442+
);
443+
}
444+
445+
private static roundHalfExpand(
446+
initialPart: Rational,
447+
penultimateDigit: Digit,
448+
finalDigit: Digit,
449+
quantum: Rational
450+
): Rational {
451+
if (finalDigit < 5) {
452+
return initialPart;
453+
}
454+
455+
return Rational.add(
456+
initialPart,
457+
initialPart.isNegative ? quantum.negate() : quantum
458+
);
459+
}
460+
461+
private static roundCeil(
462+
initialPart: Rational,
463+
penultimateDigit: Digit,
464+
finalDigit: Digit,
465+
quantum: Rational
466+
): Rational {
467+
if (initialPart.isNegative) {
468+
return initialPart;
469+
}
470+
471+
if (finalDigit === 0) {
472+
return initialPart;
473+
}
474+
475+
return Rational.add(initialPart, quantum);
476+
}
477+
478+
private static roundFloor(
479+
initialPart: Rational,
480+
penultimateDigit: Digit,
481+
finalDigit: Digit,
482+
quantum: Rational
483+
): Rational {
484+
if (initialPart.isNegative) {
485+
if (finalDigit === 0) {
486+
return initialPart;
487+
}
488+
489+
return Rational.subtract(initialPart, quantum);
490+
}
491+
492+
return initialPart;
493+
}
494+
414495
round(numFractionalDigits: number, mode: RoundingMode): Rational {
415496
if (!Number.isInteger(numFractionalDigits)) {
416497
throw new TypeError(
@@ -424,43 +505,69 @@ export class Rational {
424505
);
425506
}
426507

427-
if (numFractionalDigits > 1) {
428-
return this.scale10(1)
429-
.round(numFractionalDigits - 1, mode)
430-
.scale10(-1);
431-
}
432-
let s = this.toFixed(1);
508+
let s = this.toFixed(numFractionalDigits + 1);
433509

434510
let [integerPart, fractionalPart] = s.split(".");
435511

436-
if (mode === ROUNDING_MODE_TRUNCATE) {
437-
return Rational.fromString(integerPart);
438-
}
512+
let quantum = Rational.fromString(
513+
numFractionalDigits === 0
514+
? "1"
515+
: "0" + "." + "0".repeat(numFractionalDigits - 1) + "1"
516+
);
517+
let truncated = Rational.fromString(
518+
integerPart + "." + fractionalPart.substring(0, numFractionalDigits)
519+
);
439520

440521
let penultimateDigit = parseInt(
441-
integerPart.charAt(integerPart.length - 1)
522+
numFractionalDigits === 0
523+
? integerPart.charAt(integerPart.length - 1)
524+
: fractionalPart.charAt(numFractionalDigits - 1)
525+
) as Digit;
526+
let finalDigit = parseInt(
527+
fractionalPart.charAt(numFractionalDigits)
442528
) as Digit;
443-
let finalDigit = parseInt(fractionalPart.charAt(0)) as Digit;
444529

445-
if (finalDigit < 5) {
446-
return Rational.fromString(integerPart);
530+
if (mode === ROUNDING_MODE_TRUNCATE) {
531+
return truncated;
447532
}
448533

449-
if (finalDigit > 5) {
450-
return Rational.add(
451-
Rational.fromString(integerPart),
452-
Rational.fromString("1")
534+
if (mode === ROUNDING_MODE_HALF_EVEN) {
535+
return Rational.roundHalfEven(
536+
truncated,
537+
penultimateDigit,
538+
finalDigit,
539+
quantum
453540
);
454541
}
455542

456-
if (penultimateDigit % 2 === 0) {
457-
return Rational.fromString(integerPart);
543+
if (mode === ROUNDING_MODE_CEILING) {
544+
return Rational.roundCeil(
545+
truncated,
546+
penultimateDigit,
547+
finalDigit,
548+
quantum
549+
);
458550
}
459551

460-
return Rational.add(
461-
Rational.fromString(integerPart),
462-
Rational.fromString("1")
463-
);
552+
if (mode === ROUNDING_MODE_FLOOR) {
553+
return Rational.roundFloor(
554+
truncated,
555+
penultimateDigit,
556+
finalDigit,
557+
quantum
558+
);
559+
}
560+
561+
if (mode === ROUNDING_MODE_HALF_EXPAND) {
562+
return Rational.roundHalfExpand(
563+
truncated,
564+
penultimateDigit,
565+
finalDigit,
566+
quantum
567+
);
568+
}
569+
570+
throw new RangeError("Unsupported rounding mode: " + mode);
464571
}
465572

466573
cmp(x: Rational): -1 | 0 | 1 {

0 commit comments

Comments
 (0)