Skip to content

Commit

Permalink
fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Yaffle committed Jan 31, 2024
1 parent 10b6d22 commit 3b7c8da
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 30 deletions.
67 changes: 37 additions & 30 deletions BigDecimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const factory = function (BASE, format = null) {
const NumberSafeBits = Math.floor(Math.log2(Number.MAX_SAFE_INTEGER + 1));
const parseRegex = /^\s*([+\-])?(\d+)?\.?(\d+)?(?:e([+\-]?\d+))?\s*$/;

const defaultRounding = format === 'decimal128' ? {maximumFractionDigits: 6176, maximumSignificantDigits: 34, roundingMode: 'half-even'} : null;
const defaultRounding = format === 'decimal128' ? {maximumFractionDigits: 6176, maximumSignificantDigits: 34, maximumExponent: 6144, roundingMode: 'half-even'} : null;

function getExponent(number) {
const e = Math.floor(Math.log(Math.abs(number)) / Math.log(2)) - 1;
Expand Down Expand Up @@ -268,14 +268,23 @@ const cachedPower = cachedFunction(function (k) {
return BIGINT_BASE**BigInt(k);
});

function applyMaxExponent(x, rounding) {
const maximumExponent = rounding.maximumExponent;
if (maximumExponent != null) {
if (digits(x.significand) - 1 + x.exponent > maximumExponent) {
return x.significand === 0n ? create(0n, 0) : create(x.significand < 0n ? -1n : 1n, SPECIAL_EXPONENT);
}
}
return x;
}

function round(a, rounding) {
if (format === 'decimal128') {
if (rounding == null) {
const x = round(a, defaultRounding);
if (digits(x.significand) - 1 + x.exponent > 6144) {
return x.significand === 0n ? create(0n, 0) : create(x.significand < 0n ? -1n : 1n, SPECIAL_EXPONENT);
}
return x;
return round(a, defaultRounding);
}
if (Math.abs(a.exponent) === SPECIAL_EXPONENT) {
return a;
}
}
if (rounding != null) {
Expand Down Expand Up @@ -385,8 +394,10 @@ function round(a, rounding) {
}
}
}
return create(quotient, sum(exponent, k));
const e = sum(exponent, k);
return applyMaxExponent(create(quotient, e), rounding);
}
return applyMaxExponent(a, rounding);
}
return a;
}
Expand All @@ -396,7 +407,7 @@ BigDecimal.unaryMinus = function (a) {
if (a.exponent === -SPECIAL_EXPONENT) {
return create(0n, 0);
}
if (a.significand === 0n) {
if (a.significand === 0n && a.exponent !== SPECIAL_EXPONENT) {
return create(-1n, -SPECIAL_EXPONENT);
}
}
Expand Down Expand Up @@ -434,10 +445,10 @@ BigDecimal.add = function (a, b, rounding = defaultRounding) {
if (format != null) {
if (ae === -SPECIAL_EXPONENT || be === -SPECIAL_EXPONENT) {
if (ae === -SPECIAL_EXPONENT && be !== -SPECIAL_EXPONENT) {
return b;
return round(b, rounding);
}
if (be === -SPECIAL_EXPONENT && ae !== -SPECIAL_EXPONENT) {
return a;
return round(a, rounding);
}
return create(-1n, -SPECIAL_EXPONENT);
}
Expand Down Expand Up @@ -473,19 +484,26 @@ BigDecimal.add = function (a, b, rounding = defaultRounding) {
BigDecimal.subtract = function (a, b, rounding = defaultRounding) {
return BigDecimal.add(a, BigDecimal.unaryMinus(b), rounding);
};
function toSignedZero(a, b, p) {
if (format != null) {
if (p.significand === 0n || p.exponent === -SPECIAL_EXPONENT) {
if (a.significand < 0n) {
return toSignedZero(BigDecimal.unaryMinus(a), b, BigDecimal.unaryMinus(p));
}
if (b.significand < 0n) {
return toSignedZero(a, BigDecimal.unaryMinus(b), BigDecimal.unaryMinus(p));
}
}
}
return p;
}
BigDecimal.multiply = function (a, b, rounding = defaultRounding) {
if (format != null) {
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT) {
return fromnum(tonum(a) * tonum(b));
}
if (a.significand < 0) {
return BigDecimal.unaryMinus(BigDecimal.multiply(BigDecimal.unaryMinus(a), b, rounding));
}
if (b.significand < 0) {
return BigDecimal.unaryMinus(BigDecimal.multiply(a, BigDecimal.unaryMinus(b), rounding));
}
}
return normalize(round(create(BigInt(a.significand) * BigInt(b.significand), sum(a.exponent, b.exponent)), rounding), rounding);
return toSignedZero(a, b, normalize(round(create(BigInt(a.significand) * BigInt(b.significand), sum(a.exponent, b.exponent)), rounding), rounding));
};
function bigIntScale(a, scaling) {
if (typeof a !== 'bigint') {
Expand All @@ -504,22 +522,11 @@ BigDecimal.divide = function (a, b, rounding = defaultRounding) {
if (Math.abs(a.exponent) === SPECIAL_EXPONENT || Math.abs(b.exponent) === SPECIAL_EXPONENT || b.significand === 0n) {
return fromnum(tonum(a) / tonum(b));
}
if (a.significand < 0) {
return BigDecimal.unaryMinus(BigDecimal.divide(BigDecimal.unaryMinus(a), b, rounding));
}
if (b.significand < 0) {
return BigDecimal.unaryMinus(BigDecimal.divide(a, BigDecimal.unaryMinus(b), rounding));
}
}
if (a.significand === 0n) {
if (b.significand !== 0n) {
return a;
}
}
const exponent = diff(a.exponent, b.exponent);
let scaling = 0;
if (rounding != null && rounding.maximumSignificantDigits != null) {
scaling = rounding.maximumSignificantDigits + (digits(b.significand) - digits(a.significand));
scaling = rounding.maximumSignificantDigits + ((b.significand === 0n ? 0 : digits(b.significand)) - (a.significand === 0n ? 0 : digits(a.significand)));
} else if (rounding != null && rounding.maximumFractionDigits != null) {
//scaling = BigInt(rounding.maximumFractionDigits) + bigIntMax(a.exponent, 0n) + bigIntMax(0n - b.exponent, 0n) - bigIntMin(a.exponent - b.exponent + BigInt(digits(a.significand) - digits(b.significand)), 0n);
scaling = sum(rounding.maximumFractionDigits, exponent);
Expand Down Expand Up @@ -575,7 +582,7 @@ BigDecimal.divide = function (a, b, rounding = defaultRounding) {
}
}
}
return round(create(quotient, diff(exponent, scaling)), rounding);
return toSignedZero(a, b, round(create(quotient, diff(exponent, scaling)), rounding));
};
function cmpnum(a, b) {
return a < b ? -1 : (b < a ? +1 : (a === b ? 0 : undefined));
Expand Down
8 changes: 8 additions & 0 deletions tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ console.assert(Decimal128('1.0e6145').toString() === 'Infinity'); // bug?
console.assert(Decimal128.divide(Decimal128('1'), Decimal128('-1e-7000')).toString() === '-Infinity');
console.assert(Decimal128.divide(Decimal128('1'), Decimal128('3')).toString() === '0.3333333333333333333333333333333333');

// bugs:
console.assert(Decimal128.add(Decimal128('9e+6144'), Decimal128('1e+6144')).toString() === 'Infinity');
console.assert(Decimal128.add(Decimal128('1.5'), Decimal128('-0'), {maximumFractionDigits: 0, roundingMode: 'floor'}).toString() === '1');
console.assert(Decimal128.divide(Decimal128('-1e-32'), Decimal128('2e+6144'), {maximumFractionDigits: 6176, roundingMode: 'ceil'}).toString() === '0');

console.assert(Decimal128(3).toString() === '3');
console.assert(Decimal128(2545562323242232323n).toString() === '2545562323242232323');
console.assert(Decimal128(true).toString() === '1');
Expand Down Expand Up @@ -60,7 +65,10 @@ function testSpecialValues(name, f, f2) {
}
}
}
testSpecialValues('round', Decimal128.round, (a) => a);
testSpecialValues('unaryMinus', Decimal128.unaryMinus, (a) => -a);
testSpecialValues('add', Decimal128.add, (a, b) => a + b);
testSpecialValues('subtract', Decimal128.subtract, (a, b) => a - b);
testSpecialValues('multiply', Decimal128.multiply, (a, b) => a * b);
testSpecialValues('divide', Decimal128.divide, (a, b) => a / b);
testSpecialValues('cmp', Decimal128.cmp, (a, b) => a < b ? -1 : (b < a ? +1 : (a == b ? 0 : undefined)));
Expand Down

0 comments on commit 3b7c8da

Please sign in to comment.