Skip to content

Commit

Permalink
WIP for subnormal values
Browse files Browse the repository at this point in the history
  • Loading branch information
jessealama committed Nov 9, 2023
1 parent 4bc34c9 commit cfc7b71
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 25 deletions.
52 changes: 37 additions & 15 deletions src/decimal128.mts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function cutoffAfterSignificantDigits(s: string, n: number): string {
return s.substring(0, n + 2);
}

return s.substring(0, n + 1);
return s.substring(0, n + 1).replace(/[.]/, "");
}

function propagateCarryFromRight(s: string): string {
Expand Down Expand Up @@ -233,11 +233,10 @@ function handleExponentialNotation(s: string): Decimal128Constructor {

function handleDecimalNotation(s: string): Decimal128Constructor {
let withoutUnderscores = s.replace(/_/g, "");
let normalized = normalize(withoutUnderscores);
let isNegative = !!normalized.match(/^-/);
let sg = significand(normalized);
let exp = exponent(normalized);
let numSigDigits = countSignificantDigits(normalized);
let isNegative = !!s.match(/^-/);
let sg = significand(withoutUnderscores);
let exp = exponent(withoutUnderscores);
let numSigDigits = countSignificantDigits(withoutUnderscores);
let isInteger = exp >= 0;

if (!isInteger && numSigDigits > MAX_SIGNIFICANT_DIGITS) {
Expand All @@ -246,7 +245,7 @@ function handleDecimalNotation(s: string): Decimal128Constructor {
if (lastDigit === 5) {
if (penultimateDigit % 2 === 0) {
let rounded = cutoffAfterSignificantDigits(
normalized,
withoutUnderscores,
MAX_SIGNIFICANT_DIGITS - 1
);
sg = significand(rounded);
Expand All @@ -256,7 +255,7 @@ function handleDecimalNotation(s: string): Decimal128Constructor {
cutoffAfterSignificantDigits(
propagateCarryFromRight(
cutoffAfterSignificantDigits(
normalized,
withoutUnderscores,
MAX_SIGNIFICANT_DIGITS - 1
)
),
Expand All @@ -267,22 +266,24 @@ function handleDecimalNotation(s: string): Decimal128Constructor {
} else {
let rounded =
cutoffAfterSignificantDigits(
normalized,
withoutUnderscores,
MAX_SIGNIFICANT_DIGITS - 2
) + `${penultimateDigit + 1}`;
sg = significand(rounded);
exp = exponent(rounded);
}
} else if (lastDigit > 5) {
let cutoff = normalize(
cutoffAfterSignificantDigits(normalized, MAX_SIGNIFICANT_DIGITS)
let cutoff = cutoffAfterSignificantDigits(
withoutUnderscores,
MAX_SIGNIFICANT_DIGITS
);
let rounded = normalize(propagateCarryFromRight(cutoff));
let rounded = propagateCarryFromRight(cutoff);
sg = significand(rounded);
exp = exponent(rounded);
} else {
let rounded = normalize(
cutoffAfterSignificantDigits(normalized, MAX_SIGNIFICANT_DIGITS)
let rounded = cutoffAfterSignificantDigits(
withoutUnderscores,
MAX_SIGNIFICANT_DIGITS
);
sg = significand(rounded);
exp = exponent(rounded);
Expand Down Expand Up @@ -509,7 +510,28 @@ export class Decimal128 {
return (this.isNegative ? "-" : "") + "0";
}

return this.rat.toDecimalPlaces(MAX_SIGNIFICANT_DIGITS);
let exp = this.exponent;
let sig = this.significand;
let prefix = this.isNegative ? "-" : "";

if (exp === 0) {
return prefix + sig;
}

if (exp < 0) {
return (
prefix +
sig.substring(0, sig.length + exp) +
"." +
sig.substring(sig.length + exp)
);
}

if (exp >= sig.length) {
return prefix + sig + "0".repeat(exp - sig.length);
}

return prefix + sig + "0".repeat(exp);
}

/**
Expand Down
25 changes: 15 additions & 10 deletions tests/string.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,31 @@ describe("to exponential string", () => {
}
});

describe("normalization", () => {
describe("leading zeros are removed", () => {
let tests = [
["0123.456", "123.456"],
["123.4560", "123.456"],
["123.0", "123"],
["00.123", "0.123"],
["0.0", "0"],
["-0.0", "-0"],
["00.0", "0"],
["-00.0", "-0"],
["0.00", "0"],
["-0.00", "-0"],
["0.0", "0.0"],
["-0.0", "-0.0"],
["00.0", "0.0"],
["-00.0", "-0.0"],
];
for (let [a, b] of tests) {
test(`${a} is actually ${b}`, () => {
test(`leading zeros of ${a} get removed`, () => {
expect(new Decimal128(a).toString()).toStrictEqual(b);
});
}
});

describe("subnormal values", () => {
let tests = ["123.4560", "0.0", "-0.0", "0.00", "-0.00"];
for (let [a, b] of tests) {
test(`trailing zeros of ${a} are preserved`, () => {
expect(new Decimal128(a).toString()).toStrictEqual(a);
});
}
});

describe("NaN", () => {
expect(new Decimal128("NaN").toString()).toStrictEqual("NaN");
});
Expand Down

0 comments on commit cfc7b71

Please sign in to comment.