diff --git a/js/src/util/bn.ts b/js/src/util/bn.ts index 8f6dfe258fc8d..8eed3909246d3 100644 --- a/js/src/util/bn.ts +++ b/js/src/util/bn.ts @@ -91,11 +91,14 @@ export function bigNumToNumber>(bn: T, scale?: number) number |= word * (BigInt(1) << BigInt(64 * i++)); } } - if (typeof scale === 'number') { - const denominator = BigInt(Math.pow(10, scale)); + if (typeof scale === 'number' && scale > 0) { + const denominator = BigInt('1'.padEnd(scale + 1, '0')); const quotient = number / denominator; - const remainder = number % denominator; - return bigIntToNumber(quotient) + (bigIntToNumber(remainder) / bigIntToNumber(denominator)); + const remainder = negative? -(number % denominator) : number % denominator; + const integerPart = bigIntToNumber(quotient); + const fractionPart = `${remainder}`.padStart(scale, '0'); + const sign = negative && integerPart === 0 ? '-' : ''; + return +`${sign}${integerPart}.${fractionPart}`; } return bigIntToNumber(number); } diff --git a/js/test/unit/bn-tests.ts b/js/test/unit/bn-tests.ts index 2ea8f6055db2c..510b8c2cd664e 100644 --- a/js/test/unit/bn-tests.ts +++ b/js/test/unit/bn-tests.ts @@ -16,7 +16,7 @@ // under the License. import * as Arrow from 'apache-arrow'; -const { BN } = Arrow.util; +const { BN, bigNumToNumber } = Arrow.util; describe(`BN`, () => { test(`to detect signed numbers, unsigned numbers and decimals`, () => { @@ -98,4 +98,15 @@ describe(`BN`, () => { // const n6 = new BN(new Uint32Array([0x00000000, 0x00000000, 0x00000000, 0x80000000]), false); // expect(n6.valueOf(1)).toBe(1.7014118346046923e+37); }); + + test(`bigNumToNumber`, () => { + const n1 = new BN(new Uint32Array([3, 2, 1, 0])); + expect(() => bigNumToNumber(n1)).toThrow('18446744082299486211'); + /* eslint-disable @typescript-eslint/no-loss-of-precision */ + expect(bigNumToNumber(n1, 10)).toBeCloseTo(1844674408.2299486); + expect(bigNumToNumber(n1, 15)).toBeCloseTo(18446.744082299486); + expect(bigNumToNumber(n1, 20)).toBeCloseTo(0.18446744082299486); + expect(bigNumToNumber(n1, 25)).toBeCloseTo(0.0000018446744082299486); + /* eslint-enable @typescript-eslint/no-loss-of-precision */ + }); });