From 4274b5d8397ff579a1c8ec5390d2f1079ac979dc Mon Sep 17 00:00:00 2001 From: ncave <777696+ncave@users.noreply.github.com> Date: Tue, 12 Mar 2019 18:43:49 -0700 Subject: [PATCH] Fixed #1784 --- src/fable-library/Decimal.ts | 32 +++++++++++++++----------------- src/fable-library/lib/big.js | 26 +++++++++++++++++--------- tests/Main/ArithmeticTests.fs | 21 ++++++++++++++++++++- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/fable-library/Decimal.ts b/src/fable-library/Decimal.ts index df6bb5213c..261e14fa9b 100644 --- a/src/fable-library/Decimal.ts +++ b/src/fable-library/Decimal.ts @@ -98,15 +98,15 @@ export function toNumber(x: Decimal) { function decimalToHex(dec: Uint8Array, bitSize: number) { const hex = new Uint8Array(bitSize / 4 | 0); let hexCount = 1; - for (const d of dec) { - let val = d; + for (let d = 0; d < dec.length; d++) { + let value = dec[d]; for (let i = 0; i < hexCount; i++) { - const digit = hex[i] * 10 + val | 0; + const digit = hex[i] * 10 + value | 0; hex[i] = digit & 0xF; - val = digit >> 4; + value = digit >> 4; } - if (val !== 0) { - hex[hexCount++] = val; + if (value !== 0) { + hex[hexCount++] = value; } } return hex.slice(0, hexCount); // digits in reverse order @@ -115,8 +115,8 @@ function decimalToHex(dec: Uint8Array, bitSize: number) { function hexToDecimal(hex: Uint8Array, bitSize: number) { const dec = new Uint8Array(bitSize * 301 / 1000 + 1 | 0); let decCount = 1; - for (const d of hex) { - let carry = d; + for (let d = hex.length - 1; d >= 0; d--) { + let carry = hex[d]; for (let i = 0; i < decCount; i++) { const val = dec[i] * 16 + carry | 0; dec[i] = (val % 10) | 0; @@ -160,15 +160,13 @@ export function fromParts(low: number, mid: number, high: number, isNegative: bo setInt32Bits(hexDigits, low, 0); setInt32Bits(hexDigits, mid, 8); setInt32Bits(hexDigits, high, 16); - const decDigits = hexToDecimal(hexDigits.reverse(), bitSize); - const sign = isNegative ? "-" : ""; - const pos = scale & 0x7F; - let decStr = ""; - for (let i = 0; i < decDigits.length; i++) { - if (i === pos) { decStr = "." + decStr; } - decStr = "0123456789".charAt(decDigits[i]) + decStr; - } - const d = new Decimal(sign + decStr); + const decDigits = hexToDecimal(hexDigits, bitSize); + scale = scale & 0x7F; + const big = new Decimal(0); + big.c = Array.from(decDigits.reverse()); + big.e = decDigits.length - scale - 1; + big.s = isNegative ? -1 : 1; + const d = new Decimal(big); return d; } diff --git a/src/fable-library/lib/big.js b/src/fable-library/lib/big.js index fc993dcd26..1ce9a8f1b6 100644 --- a/src/fable-library/lib/big.js +++ b/src/fable-library/lib/big.js @@ -49,7 +49,7 @@ var P = { * (JavaScript numbers: -7) * -1000000 is the minimum recommended exponent value of a Big. */ - NE = -7, // 0 to -1000000 + NE = -29, // 0 to -1000000 /* * The positive exponent (PE) at and above which toString returns exponential notation. @@ -57,7 +57,7 @@ var P = { * 1000000 is the maximum recommended exponent value of a Big. * (This limit is not enforced or checked.) */ - PE = 21, // 0 to 1000000 + PE = 29, // 0 to 1000000 /**************************************************************************************************/ @@ -345,15 +345,23 @@ P.cmp = function (y) { // Compare exponents. if (k != l) return k > l ^ isneg ? 1 : -1; - j = (k = xc.length) < (l = yc.length) ? k : l; - // Compare digit by digit. - for (i = -1; ++i < j;) { - if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; + j = Math.max(xc.length, yc.length); + for (i = 0; i < j; i++) { + k = i < xc.length ? xc[i] : 0; + l = i < yc.length ? yc[i] : 0; + if (k != l) return k > l ^ isneg ? 1 : -1; } - - // Compare lengths. - return k == l ? 0 : k > l ^ isneg ? 1 : -1; + return 0; + + // old version (doesn't compare well trailing zeroes, e.g. 1.0 with 1.00) + // j = (k = xc.length) < (l = yc.length) ? k : l; + // // Compare digit by digit. + // for (i = -1; ++i < j;) { + // if (xc[i] != yc[i]) return xc[i] > yc[i] ^ isneg ? 1 : -1; + // } + // // Compare lengths. + // return k == l ? 0 : k > l ^ isneg ? 1 : -1; }; diff --git a/tests/Main/ArithmeticTests.fs b/tests/Main/ArithmeticTests.fs index 3fc2b311ee..b69104bd4f 100644 --- a/tests/Main/ArithmeticTests.fs +++ b/tests/Main/ArithmeticTests.fs @@ -103,13 +103,32 @@ let tests = equal (System.Decimal.MaxValue, 79228162514264337593543950335M) equal (System.Decimal.MinValue, -79228162514264337593543950335M) + testCase "Decimal.ToString works" <| fun () -> + equal (string 001.23456M, "1.23456") + equal (string 1.23456M, "1.23456") + equal (string 0.12345M, "0.12345") + equal (string 0.01234M, "0.01234") + equal (string 0.00123M, "0.00123") + equal (string 0.00012M, "0.00012") + equal (string 0.00001M, "0.00001") + equal (string 0.00000M, "0.00000") + equal (string 0.12300M, "0.12300") + equal (string 0.0M, "0.0") + equal (string 0M, "0") + equal (string 1M, "1") + equal (string -1M, "-1") + equal (string 00000000000000000000000000000.M, "0") + equal (string 0.0000000000000000000000000000M, "0.0000000000000000000000000000") + equal (string 79228162514264337593543950335M, "79228162514264337593543950335") + equal (string -79228162514264337593543950335M, "-79228162514264337593543950335") + testCase "Decimal precision is kept" <| fun () -> let items = [ 290.8M 290.8M 337.12M 6.08M -924.8M ] - equal(List.sum items, 0M) + equal (List.sum items, 0M) testCase "Decimal Infix add can be generated" <| fun () -> equal (4.0868M + 2.289348M, 6.376148M)