5

I am calculating luminosity in Javascript using:

luminosity = (5036060 * backgroundColor.red + 9886846 * backgroundColor.green + 1920103 * backgroundColor.blue) >> 24;

For the case where the color is white, ie all 3 RGB values are 255, I am getting a result of -1. I tested explicitly and in Javascript the value "4294967295 >> 24" is -1.

Why?

David Thielen
  • 28,723
  • 34
  • 119
  • 193

2 Answers2

9

JavaScript does use 32-bit integers for bitwise operations. The unsigned value +4294967295 has just the same representation as -1 for signed 32-bit integers - a series of 32 1-bits. If you shift that using the signed right shift operator, it will get filled up with the sign bit, and -1 >> x always ends up with -1.

Use the unsigned right shift operator instead:

4294967295 >>> 24 // 255
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • So I should just do a divide then? Or is there a more efficient way to get it? – David Thielen Mar 24 '15 at 18:26
  • @DavidThielen: Yes, `Math.floor(x / (1<<24))` will work, but rather use `>>>` when you want to do integer magic. For [your particular use case](http://stackoverflow.com/a/596243/1048572), I'd recommend to just use floating-point math though. – Bergi Mar 24 '15 at 18:31
  • I used the >>> 24 as you put above. Thank you! – David Thielen Mar 24 '15 at 18:49
0

>> is defined like this:

11.7.2 - The Signed Right Shift Operator ( >> )

Performs a sign-filling bitwise right shift operation on the left operand by the amount specified by the right operand.

The production ShiftExpression : ShiftExpression >> AdditiveExpression is evaluated as follows:

  1. Let lref be the result of evaluating ShiftExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating AdditiveExpression.
  4. Let rval be GetValue(rref).
  5. Let lnum be ToInt32(lval).
  6. Let rnum be ToUint32(rval).
  7. Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
  8. Return the result of performing a sign-extending right shift of lnum by shiftCount bits. The most significant bit is propagated. The result is a signed 32-bit integer.

And ToInt32 like this:

9.5 - ToInt32: (Signed 32 Bit Integer)

The abstract operation ToInt32 converts its argument to one of 232 integer values in the range −231 through 231−1, inclusive. This abstract operation functions as follows:

  1. Let number be the result of calling ToNumber on the input argument.
  2. If number is NaN, +0, −0, +∞, or −∞, return +0.
  3. Let posInt be sign(number) * floor(abs(number)).
  4. Let int32bit be posInt modulo 232; that is, a finite integer value k of Number type with positive sign and less than 232 in magnitude such that the mathematical difference of posInt and k is mathematically an integer multiple of 232.
  5. If int32bit is greater than or equal to 231, return int32bit − 232, otherwise return int32bit.

Therefore, ToInt32(4294967295) is -1.

And -1 >> 24 is -1

Oriol
  • 274,082
  • 63
  • 437
  • 513