Why does 0x80000000 >> 1 in JavaScript produce a negative value? - javascript

Doing some tests with bitwise operations / shifting with JavaScript
0x80000000 >> 1 // returns -1073741824 (-0x40000000)
I would expect that to return 0x40000000 since
0x40000000 >> 1 // returns 0x20000000
0x20000000 >> 1 // returns 0x10000000

Its an arithmetic shift that's why the sign is preserved, to do a logical shift use >>>
0x80000000 >>> 1 // returns 1073741824 (0x40000000)

In Javascript, >> is the Signed Right Shift Operator. In §11.7.2 of the language specification it says:
Performs a sign-filling bitwise right shift operation on the left operand by the amount specified by the right operand.
Before the shifting is done, the left operand is converted to a signed 32-bit integer (step 5 of the algorithm given in the specification). In your case this conversion turns the given positive number into a negative value. After that, the actual shifting is done, preserving the negative sign of the value.

Related

How is the Number of value 0x80000000 organised in JavaScript? [duplicate]

Doing some tests with bitwise operations / shifting with JavaScript
0x80000000 >> 1 // returns -1073741824 (-0x40000000)
I would expect that to return 0x40000000 since
0x40000000 >> 1 // returns 0x20000000
0x20000000 >> 1 // returns 0x10000000
Its an arithmetic shift that's why the sign is preserved, to do a logical shift use >>>
0x80000000 >>> 1 // returns 1073741824 (0x40000000)
In Javascript, >> is the Signed Right Shift Operator. In §11.7.2 of the language specification it says:
Performs a sign-filling bitwise right shift operation on the left operand by the amount specified by the right operand.
Before the shifting is done, the left operand is converted to a signed 32-bit integer (step 5 of the algorithm given in the specification). In your case this conversion turns the given positive number into a negative value. After that, the actual shifting is done, preserving the negative sign of the value.

How to make Javascript bitwise operators behave like in C?

In Javascript the following comparison:
(0xf0000000 & 0xf0000000) == 0xf0000000
is false since the bitwise operator converts to numbers to signed int32. The result of the & is a negative number and 0xf0000000 is a positive number
Is there a way to make it behave as I would expect it to behave in C?
Section 12.9.5 of Ecma 262 7.0 (ES 2016) defines the unsigned right shift operator (>>>) to return a unsigned 32-bit integer. This has been the case at least since ES 5.
In other words, you can use this operator to turn a int32 value into a uint32 value when you shift by 0.
Therefore, you can simply change the expression to
(0xf0000000 & 0xf0000000) >>> 0 == 0xf0000000
which yields true.
Use the XOR operator and compare with 0.
(0xf0000000 & 0xf0000000) ^ 0xf0000000 === 0
A ^ B will be 0 if A === B.

Is it correct to set bit 31 in javascript?

When I try to set 31 bit 0 | 1 << 31 I get the following result:
console.log(0 | 1 << 31); // -2147483648
Which is actualy:
console.log((-2147483648).toString(2)) // -10000000000000000000000000000000
Is it correct to set 31 bit or should I restrict to 30 to prevent negative values?
Refer to ECMA5 that the bitwise operators and shift operators operate on 32-bit ints, so in that case, the max safe integer is 2^31-1, or 2147483647.
Here is one explanation.
The << operator is defined as working on signed 32-bit integers (converted from the native Number storage of double-precision float). So 1<<31 must result in a negative number.
The only JavaScript operator that works using unsigned 32-bit integers is >>>. You can exploit this to convert a signed-integer-in-Number you've been working on with the other bitwise operators to an unsigned-integer-in-Number:
(1<<31)>>>0
Most bitwise operations are specified as converting their operands to signed 32-bit integers. It is perfectly correct to use bit 31, but yes, you'll get negative values. Usually it doesn't matter if you're doing bitwise operations anyway, since all you (should) care about is the bit pattern, not the decimal value of the number.
If you do want a positive value back, you can convert it back with >>> 0, because >>> is specified to convert its operands to unsigned 32-bit integers.
console.log((0 | 1 << 31) >>> 0);

Why does a shift by 0 truncate the decimal?

I recently found this piece of JavaScript code:
Math.random() * 0x1000000 << 0
I understood that the first part was just generating a random number between 0 and 0x1000000 (== 16777216).
But the second part seemed odd. What's the point of performing a bit-shift by 0? I didn't think that it would do anything. Upon further investigation, however, I noticed that the shift by 0 seemed to truncate the decimal part of the number. Furthermore, it didn't matter if it was a right shift, or a left shift, or even an unsigned right shift.
> 10.12345 << 0
10
> 10.12345 >> 0
10
> 10.12345 >>> 0
10
I tested both with Firefox and Chrome, and the behavior is the same. So, what is the reason for this observation? And is it just a nuance of JavaScript, or does it occur in other languages as well? I thought I understood bit-shifting, but this has me puzzled.
You're correct; it is used to truncate the value.
The reason >> works is because it operates only on 32-bit integers, so the value is truncated. (It's also commonly used in cases like these instead of Math.floor because bitwise operators have a low operator precedence, so you can avoid a mess of parentheses.)
And since it operates only on 32-bit integers, it's also equivalent to a mask with 0xffffffff after rounding. So:
0x110000000 // 4563402752
0x110000000 >> 0 // 268435456
0x010000000 // 268435456
But that's not part of the intended behaviour since Math.random() will return a value between 0 and 1.
Also, it does the same thing as | 0, which is more common.
Math.random() returns a number between 0 (inclusive) and 1 (exclusive). Multiplying this number with a whole number results in a number that has decimal portion. The << operator is a shortcut for eliminating the decimal portion:
The operands of all bitwise operators are converted to signed 32-bit
integers in big-endian order and in two's complement format.
The above statements means that the JavaScript engine will implicitly convert both operands of << operator to 32-bit integers; for numbers it does so by chopping off the fractional portion (numbers that do not fit 32-bit integer range loose more than just the decimal portion).
And is it just a nuance of JavaScript, or does it occur in other
languages as well?
You'll notice similar behavior in loosely typed languages. PHP for example:
var_dump(1234.56789 << 0);
// int(1234)
For strongly types languages, the programs will usually refuse to compile. C# complains like this:
Console.Write(1234.56789 << 0);
// error CS0019: Operator '<<' cannot be applied to operands of type 'double' and 'int'
For these languages, you already have type-casting operators:
Console.Write((int)1234.56789);
// 1234
From the Mozilla documentation of bitwise operators (which includes the shift operators)
The operands of all bitwise operators are converted to signed 32-bit integers in big-endian order and in two's complement format.
So basically the code is using that somewhat-incidental aspect of the shift operator as the only significant thing it does due to shifting by 0 bits. Ick.
And is it just a nuance of JavaScript, or does it occur in other languages as well?
I can't speak for all languages of course, but neither Java nor C# permit double values to be the left operand a shift operator.
According to ECMAScript Language Specification:
http://ecma-international.org/ecma-262/5.1/#sec-11.7.1
The production ShiftExpression : ShiftExpression >> AdditiveExpression
is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
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.
The behavior you're observing is defined in the ECMA-262 standard
Here's an excerpt from the specification of the << left shift operator:
The production ShiftExpression : ShiftExpression << AdditiveExpression
is evaluated as follows:
Let lref be the result of evaluating ShiftExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating AdditiveExpression.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToUint32(rval).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of left shifting lnum by shiftCount bits. The result is a signed 32-bit integer.
As you can see, both operands are cast to 32 bit integers. Hence the disappearance of decimal parts.
The same applies for the other bit shift operators. You can find their respective descriptions in section 11.7 Bitwise Shift Operators of the document I linked to.
In this case, the only effect of performing the shift is type conversion. Math.random() returns a floating point value.

Bitwise operations with big integers

I am implementing decoding of BER-compressed integers and recently I've found a weird JavaScript behavior related to bitwise operations with big integers.
E.g.:
var a = 17516032; // has 25 bits
alert(a << 7) // outputs -2052915200
alert(a * 128) // outputs 2242052096
alert(2242052096 >> 16) // outputs -31325
alert(2242052096 / 65536) // outputs 34211
While the first workaround (multiplication instead of left shift) is acceptable, the second isn't.
Why it happens? How to bear with it?
17516032 in binary is 00000001000010110100011000000000. Shifting to the left by 7 gives you 10000101101000110000000000000000. This is equal to -2052915200 in two's complement (which is how almost all computers represent negative numbers).
>> is a signed right shift. That means that the leftmost bit (which determines the sign of a number) will be shifted into the left side.
e.g.
1100 >> 2 == 1111
0111 >> 2 == 0001
If you want to do an unsigned shift (which ignores the sign bit), use >>> which will zero-fill the left end of the bitstring.
Bitwise operators work on 32 bit integers, while multiplication and division works on floating point numbers.
When you shift a number, it's converted from a floating point number to a 32 bit integer before the operations, and converted back to a floating point number after the operation. The number 2242052096 has the 32nd bit set, so it is a negative number when converted to and from a 32 bit integer.
The >> right shift operator doesn't change the sign of the value, i.e. the bits that are shifted in from the left have the same value as the sign bit. Use the >>> right shift operator to shift in zero bits instead.
Reference: MDN: Bitwise operators
(2242052096 / 65536) == (2242052096 >>> 16)
Note the different shift.
Javascript normally represents numbers as (double-precision) floating point.
Almost all bitwise operations convert to a signed 32-bit integer, do whatever they're going to do, then treat the result as a signed 32-bit integer when converting back.
The exception is >>> which treats the result as an unsigned 32-bit integer when converting back.
So:
right shifts can be made to work simply by using >>> instead of >> ;
a * 128 gives the expected answer because it's never converted to a signed 32-bit integer in the first place - it's just a floating-point multiplication;
a << 7 gives an unexpected answer because it's converted to a signed 32-bit integer, and then you shift a 1 into the sign bit, resulting in a negative signed 32-bit value.
There isn't a <<<, but if you want to write your left shift as a shift, you can use
(a << 7) >>> 0
to get the expected answer (the >>> 0 effectively casts the signed 32-bit value to an unsigned 32-bit value).

Categories

Resources