From 2eb79a4f64f40528fbe9263bd033a88c0c839111 Mon Sep 17 00:00:00 2001 From: dcode Date: Mon, 10 Feb 2025 15:12:44 +0100 Subject: [PATCH] Add isSafeInteger to test if a Long can be safely represented as a JS number --- README.md | 3 +++ index.js | 16 ++++++++++++++++ tests/index.js | 13 +++++++++++++ types.d.ts | 5 +++++ 4 files changed, 37 insertions(+) diff --git a/README.md b/README.md index 1b64a94..6f551c9 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,9 @@ API * Long#**isPositive**(): `boolean`
Tests if this Long's value is positive or zero. +* Long#**isSafeInteger**(): `boolean`
+ Tests if this Long can be safely represented as a JavaScript number. + * Long#**isZero**/**eqz**(): `boolean`
Tests if this Long's value equals zero. diff --git a/index.js b/index.js index bfcb1a4..ca2615d 100644 --- a/index.js +++ b/index.js @@ -645,6 +645,22 @@ LongPrototype.getNumBitsAbs = function getNumBitsAbs() { return this.high != 0 ? bit + 33 : bit + 1; }; +/** + * Tests if this Long can be safely represented as a JavaScript number. + * @this {!Long} + * @returns {boolean} + */ +LongPrototype.isSafeInteger = function isSafeInteger() { + // 2^53-1 is the maximum safe value + var top11Bits = this.high >> 21; + // [0, 2^53-1] + if (!top11Bits) return true; + // > 2^53-1 + if (this.unsigned) return false; + // [-2^53, -1] except -2^53 + return top11Bits === -1 && !(this.low === 0 && this.high === -0x200000); +}; + /** * Tests if this Long's value equals zero. * @this {!Long} diff --git a/tests/index.js b/tests/index.js index eb478db..4ee1183 100644 --- a/tests/index.js +++ b/tests/index.js @@ -232,6 +232,19 @@ var tests = [ // BEGIN TEST CASES var signedFromUnsigned = Long.fromBigInt(values[i].unsigned); assert.strictEqual(signedFromUnsigned.toBigInt(), values[i].signed); } + }, + + function testSafeInteger() { + assert(Long.fromNumber(0).isSafeInteger()); + assert(Long.fromNumber(1).isSafeInteger()); + assert(Long.fromNumber(-1).isSafeInteger()); + assert(!Long.fromNumber(-1).toUnsigned().isSafeInteger()); + assert(Long.fromNumber(Math.pow(2, 32)).isSafeInteger()); + assert(Long.fromNumber(-Math.pow(2, 32)).isSafeInteger()); + assert(Long.fromNumber(Math.pow(2, 53) - 1).isSafeInteger()); + assert(Long.fromNumber(-Math.pow(2, 53) + 1).isSafeInteger()); + assert(!Long.fromNumber(Math.pow(2, 53)).isSafeInteger()); + assert(!Long.fromNumber(-Math.pow(2, 53)).isSafeInteger()); } ]; // END TEST CASES diff --git a/types.d.ts b/types.d.ts index 6c8a731..7fc3f9b 100644 --- a/types.d.ts +++ b/types.d.ts @@ -225,6 +225,11 @@ export declare class Long { */ isPositive(): boolean; + /** + * Tests if this Long can be safely represented as a JavaScript number. + */ + isSafeInteger(): boolean; + /** * Tests if this Long's value equals zero. */