Reputation: 2712
I'm looking at some code that uses long.js and it uses the constructor
Long(low: number, high?: number, unsigned?: boolean)
I'm trying to replace it with an equivalent that uses BigInt. I can get it to work when unsigned=true
but not when false
var upper = -1234
var lower = -11
var pad = '00000000000000000000000000000000'
let bin = function (a) { return (pad + (a >>> 0).toString(2)).slice(-32) }
var bi = BigInt('0b' + bin(upper) + bin(lower))
If I pass in upper
& lower
& false
to long.js the numbers don't agree and I cant get my head around it.
Upvotes: 0
Views: 1127
Reputation: 40661
Let's look at how that constructor is defined (skipping comments for brevity):
function Long(low, high, unsigned) {
this.low = low | 0;
this.high = high | 0;
this.unsigned = !!unsigned;
}
That's straightforward to translate to BigInt operations:
... | 0
performs a truncation to 32 bits, which for BigInts can be expressed as ... & 0xFFFFFFFFn
. There are also the two helper functions BigInt.asUintN(32, ...)
and BigInt.asIntN(32, ...)
; while the latter more closely reflects what ... | 0
does for Numbers, we want to use the former since we'll shift the results around (rule of thumb: for bit fiddling operations like masking and shifting you almost always want to use unsigned interpretations, the one exception is when you need a sign-extending right-shift).Long
class implicitly considers the low
and high
value as the two halves of a 64-bit integer; for the BigInt equivalent we'll assemble this integer explicitly. So we get:function BigLong(low, high, unsigned) {
low = BigInt.asUintN(32, BigInt(low));
high = BigInt.asUintN(32, BigInt(high));
var combined = (high << 32n) | low;
return unsigned ? BigInt.asUintN(64, combined)
: BigInt.asIntN(64, combined);
}
(If you wanted to somehow save the approach of going via a string representation of the value's binary encoding, you'd have to come up with a way to force signed interpretation of the bit string. One possibility that comes to mind is a subtraction, i.e. extend your snippet with:
if (!unsigned) bi -= 2n ** 64n;
But the string detour is still less efficient and IMHO less readable than using BigInt operations.)
Upvotes: 1