Reputation: 2160
Right shifting a number in javascript sometimes results in a negative number. What is the reason behind that? Can that be mitigated?
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >> 8) // -4783199
Upvotes: 2
Views: 671
Reputation: 97162
Use the zero-fill right shift operator (>>>
) to always get a positive result:
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >>> 8)
The reason for the >>
operator returning the number is caused by the fact that, originally, the number is internally represented as a 64-bit floating point number:
10110101110110111000000111010000100000110
The bit shift operation will first convert the operand to a 32-bit integer. It does this by keeping only the 32 least significant bits, and discarding the rest:
10110111000000111010000100000110
Then it will shift it by the specified number of bits while maintaining the sign, i.e. shifting in 8 1
bits from the left:
11111111101101110000001110100001
Converting back to decimal, this yields:
-4783199
Upvotes: 3
Reputation: 64904
The basic issue is that 1562143596806 is too large to fit in 32 bits. It can be represented as a Number
, but when performing bitwise operations, the value is first converted to a 32bit integer and that means the "top bits" are already dropped before shifting - the upper bits of the result are therefore not filled from the original value, they are copies of the sign of that temporary 32bit value (or with >>>
, they would be zero, which is not really an improvement). That the result happens to come out negative is just an accident depending on the exact bit pattern of the input, if it had been positive it would still have been the wrong positive value.
Such large values could be safely manipulated as BigInt
, but support for that is lacking. Using floating point arithmetic can work, but requires extra care. For example you can divide by 256 and floor the result, but you cannot use the usual |0
to get rid of the fractional part, because even after dividing by 256 the value is too big to fit in 32 bits. Various non-built-in BigInt libraries exist to deal with this sort of thing too.
Upvotes: 1