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

Commit

Permalink
Improve coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
jessealama committed Jun 28, 2024
1 parent 178d876 commit 5104b9e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 191 deletions.
147 changes: 9 additions & 138 deletions src/Decimal.mts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ function _cohort(s: string): "0" | "-0" | Rational {
return "-0";
}

if (c === "-0") {
return "0";
}

return c.negate();
return (c as Rational).negate();
}

if (s.match(/^00+/)) {
Expand All @@ -26,11 +22,7 @@ function _cohort(s: string): "0" | "-0" | Rational {
return "0";
}

if (s.match(/^-?0[eE][+-]?[0-9]+$/)) {
if (s.match(/^-/)) {
return "-0";
}

if (s.match(/^0[eE][+-]?[0-9]+$/)) {
return "0";
}

Expand Down Expand Up @@ -79,7 +71,11 @@ export class Decimal {
}

if (!Number.isInteger(q)) {
throw new Error("The quantum must be an integer.");
throw new RangeError("The quantum must be an integer.");
}

if (Object.is(q, -0)) {
throw new RangeError("The quantum cannot be negative zero.");
}

if (v instanceof Rational) {
Expand All @@ -96,144 +92,19 @@ export class Decimal {
this.quantum = q;
}

public isZero(): boolean {
let v = this.cohort;
return v === "0" || v === "-0";
}

public isInteger(): boolean {
let v = this.cohort;

if (v === "0" || v === "-0") {
return true;
}

return v.isInteger();
}

public isNegative(): boolean {
let v = this.cohort;

if (v === "0") {
return false;
}

if (v === "-0") {
return true;
}

return v.isNegative;
}

public scale10(n: number, adjustQuantum?: boolean): Decimal {
if (!Number.isInteger(n)) {
throw new Error("The scale factor must be an integer.");
}

if (0 === n) {
return this;
}

let v = this.cohort;
let newQuantum = this.quantum;

if (typeof adjustQuantum === "boolean" && adjustQuantum) {
if (n < 0) {
newQuantum -= n;
} else {
newQuantum += n;
}
}

if (v === "0" || v === "-0") {
return new Decimal({ cohort: v, quantum: newQuantum });
}

return new Decimal({
cohort: v.scale10(n),
quantum: newQuantum,
});
}

public negate(): Decimal {
let v = this.cohort;

if (v === "0") {
return new Decimal({ cohort: "-0", quantum: this.quantum });
}

if (v === "-0") {
return new Decimal({ cohort: "0", quantum: this.quantum });
}
let v = this.cohort as Rational;

return new Decimal({
cohort: v.negate(),
quantum: this.quantum,
});
}

public significand(): Rational {
if (this.isNegative()) {
return this.negate().significand();
}

let v = this.cohort;

if (v === "0" || v === "-0") {
throw new RangeError("Cannot compute coefficient of zero.");
}

while (ratTen.lessThan(v) || ratTen.equals(v)) {
v = v.scale10(-1);
}

while (v.lessThan(ratOne)) {
v = v.scale10(1);
}

return v;
}

public exponent(): number {
if (this.isNegative()) {
return this.negate().exponent();
}

let v = this.cohort;

if (v === "0" || v === "-0") {
throw new RangeError("Cannot compute coefficient of zero.");
}

let e = 0;

while (ratTen.lessThan(v) || ratTen.equals(v)) {
v = v.scale10(-1);
e++;
}

while (v.lessThan(ratOne)) {
v = v.scale10(1);
e--;
}

return e;
}

public coefficient(): bigint {
let v = this.cohort;

if (v === "0" || v === "-0") {
throw new RangeError("Cannot compute coefficient of zero.");
}

let v = this.cohort as Rational;
let q = this.quantum;
let c = v.scale10(0 - q);

if (!c.isInteger()) {
throw new TypeError("The coefficient is not an integer.");
}

return c.numerator;
}
}
53 changes: 0 additions & 53 deletions src/common.mts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export function countFractionalDigits(s: string): number {
}

export type Digit = -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; // -1 signals that we're moving from the integer part to the decimal part of a decimal number
export type DigitOrTen = Digit | 10;

export const ROUNDING_MODE_CEILING = "ceil";
export const ROUNDING_MODE_FLOOR = "floor";
Expand All @@ -62,55 +61,3 @@ export const ROUNDING_MODES: RoundingMode[] = [
ROUNDING_MODE_HALF_EVEN,
ROUNDING_MODE_HALF_EXPAND,
];

function roundIt(
isNegative: boolean,
digitToRound: Digit,
decidingDigit: Digit,
roundingMode: RoundingMode
): DigitOrTen {
switch (roundingMode) {
case ROUNDING_MODE_CEILING:
if (isNegative) {
return digitToRound;
}

if (0 === decidingDigit) {
return digitToRound;
}

return (digitToRound + 1) as DigitOrTen;
case ROUNDING_MODE_FLOOR:
if (0 === decidingDigit) {
return digitToRound;
}

if (isNegative) {
return (digitToRound + 1) as DigitOrTen;
}

return digitToRound;
case ROUNDING_MODE_TRUNCATE:
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) {
if (digitToRound % 2 === 0) {
return digitToRound;
}

return (digitToRound + 1) as DigitOrTen;
}

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

return digitToRound;
}
}
20 changes: 20 additions & 0 deletions tests/Decimal/constructor.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Decimal } from "../../src/Decimal.mjs";
import { Rational } from "../../src/Rational.mjs";

describe("Decimal constructor", () => {
test("fails if given zero", () => {
expect(
() => new Decimal({ cohort: new Rational(0n, 1n), quantum: 0 })
).toThrow(RangeError);
});
test("fails if quantum is a non-integer", () => {
expect(
() => new Decimal({ cohort: new Rational(1n, 1n), quantum: 1.5 })
).toThrow(RangeError);
});
test("fails if quantum is minus zero", () => {
expect(
() => new Decimal({ cohort: new Rational(1n, 1n), quantum: -0 })
).toThrow(RangeError);
});
});

0 comments on commit 5104b9e

Please sign in to comment.