4

When I run this code here:

console.log(255<<24==0xff000000)

I get a false instead of true. Why is that?

falsetru
  • 357,413
  • 63
  • 732
  • 636
Adler
  • 69
  • 7

4 Answers4

4

Because JavaScript numbers are IEEE-754 double-precision floating point, not 32-bit integers. So 0xff000000 is a large positive number (decimal 4,278,190,080), not a negative number as it would be if that were a signed 32-bit integer.

When you do <<, the number being shifted (255 in your case) is temporarily converted to a signed 32-bit integer for the purposes of doing the bit shift:

00000000000000000000000011111111
^\                             /
| \----- significant bits ----/
+------- sign bit

When we shift that 24 places left, a 1 bit ends up in the sign bit:

11111111000000000000000000000000
^\                             /
| \----- significant bits ----/
+------- sign bit

...and so the result ends up being negative, and gets turned back into a negative IEEE-754 number (-16,777,216 decimal). -16,777,216 is not equal to 4,278,190,080.

(The range of IEEE-754 double-precision floats is larger than the range of 32-bit signed integers. I'm not quite sure why I feel that's relevant, but I do, so I guess I'll leave it in the answer...)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Note that these conversions are to be thought of as abstract operations to explain semantics - not something that actually happens – Esailija Aug 03 '13 at 19:00
  • @Esailija: An implementation can take short-cuts, so long as the result matches the description. In this case, I'm not seeing a better shortcut than actually doing what the spec describes. – T.J. Crowder Aug 03 '13 at 20:47
  • You simply just perform the bitwise operation on the integer you already have - no conversions at all. – Esailija Aug 03 '13 at 23:05
  • @Esailija: If an engine starts out with integers rather than floating-point numbers, *again*, that's an optimization, and it's allowed provided the results are as though it had started out with floats. – T.J. Crowder Aug 04 '13 at 08:37
2

Look at it this way. This should look intuitive to you:

255<<24 == 0xff000000<<0          // Returns true

Bitwise operators work on integral numbers not on number types. Consider it as an equivalent to type casting as in other languages, where you happen to be putting a larger size number into smaller one & you lose stuff...

Javascript sacrifices precision to allow larger figures due to the floating point format, adopted.

So Javascript would lose the precision for 0xff000000, the same way as it did for 255.

loxxy
  • 12,990
  • 2
  • 25
  • 56
1

Bitwise operations in javascript convert a number to a signed 32-bit integer, as described by T.J., so you only have 31 bits for safely comparing to a hex literal. If you want to preserve the unsigned number you really want (as opposed to casting your hex literal to the same negative number), do this:

255 * (1 << 24) == 0xff000000
Klaus
  • 724
  • 6
  • 14
0

0xff000000 doesn't specify bits of a 32-bit integer but a real number in hexadecimal base. For instance 0xff000000000000000000000 is 4.932417344027687e+27

All bitwise operations except >>> give the operand int32 semantics, with >>> giving uint32 semantics.

You may therefore use | 0 as a kind of int declaration or (int) cast:

255 << 24 == (0xff000000 | 0)
true
Esailija
  • 138,174
  • 23
  • 272
  • 326