Skip to content

Commit

Permalink
Remove inofficial rounding modes
Browse files Browse the repository at this point in the history
These rounding modes are optional/unsupported in IEEE Decimal128 and
thus may not be supported in compiler libraries or hardware.
  • Loading branch information
jessealama committed Apr 30, 2024
1 parent fad956a commit e779054
Show file tree
Hide file tree
Showing 3 changed files with 1 addition and 311 deletions.
195 changes: 1 addition & 194 deletions src/decimal128.mts
Original file line number Diff line number Diff line change
Expand Up @@ -393,41 +393,6 @@ function roundFloor(x: SignedSignificandExponent): SignedSignificandExponent {
};
}

function roundExpand(x: SignedSignificandExponent): SignedSignificandExponent {
let sig = x.significand.toString();
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
let penultimateDigit = parseInt(
sig.charAt(MAX_SIGNIFICANT_DIGITS - 1)
) as Digit;
let excessDigits = sig.substring(MAX_SIGNIFICANT_DIGITS);
let numExcessDigits = excessDigits.length;
let exp = x.exponent + numExcessDigits; // we will chop off the excess digits

let finalDigit = roundIt(
x.isNegative,
penultimateDigit,
lastDigit,
ROUNDING_MODE_EXPAND
);

if (finalDigit < 10) {
return {
isNegative: x.isNegative,
significand: BigInt(`${cutoff}${finalDigit}`),
exponent: exp,
};
}

let rounded = propagateCarryFromRight(cutoff);

return {
isNegative: x.isNegative,
significand: BigInt(`${rounded}0`),
exponent: exp,
};
}

function roundTrunc(x: SignedSignificandExponent): SignedSignificandExponent {
let sig = x.significand.toString();
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
Expand All @@ -453,43 +418,6 @@ function roundTrunc(x: SignedSignificandExponent): SignedSignificandExponent {
};
}

function roundHalfExpand(
x: SignedSignificandExponent
): SignedSignificandExponent {
let sig = x.significand.toString();
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
let penultimateDigit = parseInt(
sig.charAt(MAX_SIGNIFICANT_DIGITS - 1)
) as Digit;
let excessDigits = sig.substring(MAX_SIGNIFICANT_DIGITS);
let numExcessDigits = excessDigits.length;
let exp = x.exponent + numExcessDigits; // we will chop off the excess digits

let finalDigit = roundIt(
x.isNegative,
penultimateDigit,
lastDigit,
ROUNDING_MODE_HALF_EXPAND
);

if (finalDigit < 10) {
return {
isNegative: x.isNegative,
significand: BigInt(`${cutoff}${finalDigit}`),
exponent: exp,
};
}

let rounded = propagateCarryFromRight(cutoff);

return {
isNegative: x.isNegative,
significand: BigInt(`${rounded}0`),
exponent: exp,
};
}

function roundHalfCeil(
x: SignedSignificandExponent
): SignedSignificandExponent {
Expand Down Expand Up @@ -517,70 +445,6 @@ function roundHalfCeil(
};
}

function roundHalfFloor(
x: SignedSignificandExponent
): SignedSignificandExponent {
let sig = x.significand.toString();
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
let penultimateDigit = parseInt(
sig.charAt(MAX_SIGNIFICANT_DIGITS - 1)
) as Digit;
let excessDigits = sig.substring(MAX_SIGNIFICANT_DIGITS);
let numExcessDigits = excessDigits.length;
let exp = x.exponent + numExcessDigits; // we will chop off the excess digits

let finalDigit = roundIt(
x.isNegative,
penultimateDigit,
lastDigit,
ROUNDING_MODE_HALF_FLOOR
);

if (finalDigit < 10) {
return {
isNegative: x.isNegative,
significand: BigInt(`${cutoff}${finalDigit}`),
exponent: exp,
};
}

let rounded = propagateCarryFromRight(cutoff);

return {
isNegative: x.isNegative,
significand: BigInt(`${rounded}0`),
exponent: exp,
};
}

function roundHalfTrunc(
x: SignedSignificandExponent
): SignedSignificandExponent {
let sig = x.significand.toString();
let lastDigit = parseInt(sig.charAt(MAX_SIGNIFICANT_DIGITS)) as Digit;
let cutoff = cutoffAfterSignificantDigits(sig, MAX_SIGNIFICANT_DIGITS - 1);
let penultimateDigit = parseInt(
sig.charAt(MAX_SIGNIFICANT_DIGITS - 1)
) as Digit;
let excessDigits = sig.substring(MAX_SIGNIFICANT_DIGITS);
let numExcessDigits = excessDigits.length;
let exp = x.exponent + numExcessDigits; // we will chop off the excess digits

let finalDigit = roundIt(
x.isNegative,
penultimateDigit,
lastDigit,
ROUNDING_MODE_HALF_TRUNCATE
);

return {
isNegative: x.isNegative,
significand: BigInt(`${cutoff}${finalDigit}`),
exponent: exp,
};
}

function adjustNonInteger(
x: SignedSignificandExponent,
options: FullySpecifiedConstructorOptions
Expand All @@ -592,18 +456,10 @@ function adjustNonInteger(
return roundCeiling(x);
case ROUNDING_MODE_FLOOR:
return roundFloor(x);
case ROUNDING_MODE_EXPAND:
return roundExpand(x);
case ROUNDING_MODE_TRUNCATE:
return roundTrunc(x);
case ROUNDING_MODE_HALF_EXPAND:
return roundHalfExpand(x);
case ROUNDING_MODE_HALF_CEILING:
return roundHalfCeil(x);
case ROUNDING_MODE_HALF_FLOOR:
return roundHalfFloor(x);
case ROUNDING_MODE_HALF_TRUNCATE:
return roundHalfTrunc(x);
default:
return roundHalfEven(x);
}
Expand Down Expand Up @@ -718,13 +574,9 @@ function handleInfinity(s: string): Decimal128Constructor {

export const ROUNDING_MODE_CEILING: RoundingMode = "ceil";
export const ROUNDING_MODE_FLOOR: RoundingMode = "floor";
export const ROUNDING_MODE_EXPAND: RoundingMode = "expand";
export const ROUNDING_MODE_TRUNCATE: RoundingMode = "trunc";
export const ROUNDING_MODE_HALF_EVEN: RoundingMode = "halfEven";
export const ROUNDING_MODE_HALF_EXPAND: RoundingMode = "halfExpand";
export const ROUNDING_MODE_HALF_CEILING: RoundingMode = "halfCeil";
export const ROUNDING_MODE_HALF_FLOOR: RoundingMode = "halfFloor";
export const ROUNDING_MODE_HALF_TRUNCATE: RoundingMode = "halfTrunc";

const ROUNDING_MODE_DEFAULT = ROUNDING_MODE_HALF_EVEN;
const CONSTRUCTOR_SHOULD_NORMALIZE = false;
Expand Down Expand Up @@ -756,8 +608,6 @@ function roundIt(
}

return digitToRound;
case ROUNDING_MODE_EXPAND:
return (digitToRound + 1) as DigitOrTen;
case ROUNDING_MODE_TRUNCATE:
return digitToRound;
case ROUNDING_MODE_HALF_CEILING:
Expand All @@ -769,36 +619,6 @@ function roundIt(
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
case ROUNDING_MODE_HALF_FLOOR:
if (decidingDigit === 5) {
if (isNegative) {
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
}

if (decidingDigit > 5) {
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
case ROUNDING_MODE_HALF_TRUNCATE:
if (decidingDigit === 5) {
return digitToRound;
}

if (decidingDigit > 5) {
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
case ROUNDING_MODE_HALF_EXPAND:
if (decidingDigit >= 5) {
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
default: // ROUNDING_MODE_HALF_EVEN:
if (decidingDigit === 5) {
Expand All @@ -817,27 +637,14 @@ function roundIt(
}
}

type RoundingMode =
| "ceil"
| "floor"
| "expand"
| "trunc"
| "halfEven"
| "halfExpand"
| "halfCeil"
| "halfFloor"
| "halfTrunc";
type RoundingMode = "ceil" | "floor" | "trunc" | "halfEven" | "halfCeil";

const ROUNDING_MODES: RoundingMode[] = [
"ceil",
"floor",
"expand",
"trunc",
"halfEven",
"halfExpand",
"halfCeil",
"halfFloor",
"halfTrunc",
];

const digitStrRegExp =
Expand Down
8 changes: 0 additions & 8 deletions tests/constructor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -464,13 +464,9 @@ describe("rounding options", () => {
let answers = {
ceil: "-1234567890123456789012345678901234",
floor: "-1234567890123456789012345678901235",
expand: "-1234567890123456789012345678901235",
trunc: "-1234567890123456789012345678901234",
halfEven: "-1234567890123456789012345678901234",
halfExpand: "-1234567890123456789012345678901235",
halfCeil: "-1234567890123456789012345678901234",
halfFloor: "-1234567890123456789012345678901235",
halfTrunc: "-1234567890123456789012345678901234",
};
for (const [mode, expected] of Object.entries(answers)) {
test(`constructor with rounding mode "${mode}"`, () => {
Expand All @@ -485,13 +481,9 @@ describe("rounding options", () => {
let roundUpAnswers = {
ceil: "-1234567890123456789012345678901239",
floor: "-1234567890123456789012345678901240",
expand: "-1234567890123456789012345678901240",
trunc: "-1234567890123456789012345678901239",
halfEven: "-1234567890123456789012345678901240",
halfExpand: "-1234567890123456789012345678901240",
halfCeil: "-1234567890123456789012345678901239",
halfFloor: "-1234567890123456789012345678901240",
halfTrunc: "-1234567890123456789012345678901239",
};
for (const [mode, expected] of Object.entries(roundUpAnswers)) {
test(`constructor with rounding mode "${mode}"`, () => {
Expand Down
Loading

0 comments on commit e779054

Please sign in to comment.