javascript problem with big numbers and bitwise operation

155 Views Asked by At

In my program I generate the code from the incoming number "int". Sometimes I need to do the reverse action, translate the code into a number. With small numbers, it works fine.

const int = 10203040

const code1 = (int >> 16) & 0xFFFF

const code2 = int & 0xFFFF

const myCode = `${code1},${code2}` // 155,44960

const returnInt = ((code1 & 0xFFFF) << 16) + (code2 & 0xFFFF) // 10203040

Problems arise when working with large numbers. What to use to get the number 9007199254740991 again in the example below?

const int = 9007199254740991

const code1 = (int >> 16) & 0xFFFF

const code2 = int & 0xFFFF

const myCode = `${code1},${code2}` // 65535,65535

const returnInt = ((code1 & 0xFFFF) << 16) + (code2 & 0xFFFF) // -1

Tried to work with the library long.js, but failed, lack of knowledge

2

There are 2 best solutions below

5
BIS Tech On

The problem here is that two 16-bit chunks are not enough to store a 53-bit number. In order to store a number as large as 9007199254740991, you would need at least three 16-bit chunks.

const int = BigInt(9007199254740991);

const code1 = (int >> 32n) & 0xFFFFn;
const code2 = (int >> 16n) & 0xFFFFn;
const code3 = int & 0xFFFFn;

const myCode = `${code1},${code2},${code3}`; // 262143,65535,65535

const returnInt = (BigInt(code1) << 32n) + (BigInt(code2) << 16n) + BigInt(code3); // 9007199254740991n

Using Long

const Long = require('long');

const int = Long.fromString('9007199254740991');

const code1 = (int.shiftRightUnsigned(32)).and(0xFFFF);
const code2 = (int.shiftRightUnsigned(16)).and(0xFFFF);
const code3 = int.and(0xFFFF);

const myCode = `${code1},${code2},${code3}`; // 262143,65535,65535

const returnInt = (code1.shiftLeft(32)).add(code2.shiftLeft(16)).add(code3); // 9007199254740991
0
jmrk On

Your code is splitting the input number into two 16-bit chunks (by masking it with 0xFFFF, which has 16 bits set). In two 16-bit chunks, you can store a 32-bit (integer) number. 9007199254740991 is a 53-bit number, so two 16-bit chunks are not enough to store it.

Another issue is that the bitwise operators in JavaScript implicitly truncate their inputs to 32 bits. That's the part where using BigInts helps -- but you'll still have to use more than two 16-bit chunks.

For example, you could use four 16-bit chunks, then you can store up to 64-bit numbers. That would look like this:

const int = 9007199254740991n;
const code1 = (int >> 48n) & 0xFFFFn;  // bits 49 - 64
const code2 = (int >> 32n) & 0xFFFFn;  // bits 33 - 48
const code3 = (int >> 16n) & 0xFFFFn;  // bits 17 - 32
const code4 = int & 0xFFFFn;           // bits 1 - 16

const myCode = `${code1},${code2},${code3},${code4}`  // '31,65535,65535,65535'

const returnInt = (code1 << 48n) + (code2 << 32n) + (code3 << 16n) + code4;

(You don't need to mask the chunks again when computing returnInt.)