2

I need to perform certain operations with bitwise operators, let's say we have this 40 bit unsigned integer:

1071698660929 when I apply to it a OR operator and an unsigned right shift operator I got this negative integer

Input: (1071698660929 >>> 0) | 0b0

Output: -2043163071

I noticed that as long as the number is 31 bit long I don't have any problem adding a 0B0 but when the number is greater than 31 bit it becomes negative even though I'm using the unsigned right shift operator:

32 bits binary return -1: (0b11111111111111111111111111111111 >>> 0) | 0

31 bits binary return 2147483647 : (0b1111111111111111111111111111111 >>> 0) | 0

So I have a couple of questions:

  1. Why the numbers above are becoming negative if I'm using a right shift operator? What I understand is that the MAX safe integer in javascript is 53 bit long Number.MAX_SAFE_INTEGER.toString(2).length so I'm within the integer safe boundaries.
  2. What could I do to make this (1071698660929 >>> 0) | 0b0 returns 1071698660929 instead of -2043163071?
  • Wow! @raina77ow thanks so much for this marvelous explanation, what happened above I got negative values because some bits were discarded even the bit that indicates the (unsigned right shift)? – OMartinez-NeT Jul 29 '22 at 18:11
  • The type of operation doesn't have to do anything with it; it's that explicit conversion done on operand itself. – raina77ow Jul 29 '22 at 18:17
  • 1
    @raina77ow Care to make that an answer? – Bergi Jul 29 '22 at 19:55

1 Answers1

2

Bitwise operators implicitly convert their operands to 32-bit integers (signed or unsigned, depending on operator). In process, numbers with more than 32 bits get their most significant bits discarded:

Before: 11100110111110100000000000000110000000000001
After:              10100000000000000110000000000001

The only exception of this rule is (relatively) new kid on the primitive block, BigInt type: all the bitwise ops (&, |, ^) and almost all the shifts are overloaded for that type.

This opens a way out of your problem: just use BigInt instead of plain number, either explicitly, like this:

const bigIntee = BigInt(1071698660929); // note no `new` here!

... or, if you actually have to use literal, by appending n to it:

const bigIntee = 1071698660929n; // also works

Note that if one operand is BigInt, another should be BigInt as well. So this...

bigIntee | 0

... will make JS angry with your pathetic attempts of getting back to happy type-anarchy times of 90s. To be more specific, you'll get a TypeError thrown right at you:

Cannot mix BigInt and other types, use explicit conversions

This is easily fixable, though: just apply either of aforementioned conversion tricks to the second operand as well.

bigIntee | 0n 
// or bigIntee | BigInt(0)

Both works. Disregard 0 being, well, not really a Biggus Integerus kind; type safety reigns here.

Still, there's a problem: >>> (unsigned right shift operator) cannot be used on BigInts. If you attempt to go with it, you'll get a pretty specific error:

bigIntee >>> 0n
// Uncaught TypeError: BigInts have no unsigned right shift, use >> instead

... which makes total sense (and us wishing all the errors thrown by JS were that specific).

raina77ow
  • 103,633
  • 15
  • 192
  • 229