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);
Related
When I was reading a doc about Symbol on MDN, I noticed these things can trun string into number which I've never seen before.
Quote:
When trying to convert a symbol to a number, a TypeError will be
thrown (e.g. +sym or sym | 0).
For example:
+"15"
will return
15
which is number type.
Also
"15" | 0
can do the same thing.
I am wondering how does this trick work.
Can you help?
+"15" is casting the "15" to a number type, the same way -15 works.
eg.
>> -"15" === -15
>> true
The second case, "15" | 0 is doing the same thing, casting to an integer in order to perform a Bitwise OR.
Which means taking the bits of 15 and ORing them with the bits of zero.
15 in binary is, for example 00001111 and zero is 00000000 so each bit is or'd with each other resulting in 15 again which is returned.
Unary Plus Operator
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Unary_plus_()
The unary plus operator precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a number, because it does not perform any other operations on the number. It can convert string representations of integers and floats, as well as the non-string values true, false, and null. Integers in both decimal and hexadecimal ("0x"-prefixed) formats are supported. Negative numbers are supported (though not for hex). If it cannot parse a particular value, it will evaluate to NaN.
+"6";//6
+6;//6
+-6;//-6
+undefined;//NaN
+false;//0
+true;//1
+null;//0
+{};//NaN
+[];//0
+function(){};//NaN
Bitwise OR Operator
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#.7c_%28Bitwise_OR%29
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Each bit in the first operand is paired with the corresponding bit in the second operand: first bit to first bit, second bit to second bit, and so on.
The operator is applied to each pair of bits, and the result is constructed bitwise.
The Bitwise OR Operator first converts both operands to 32-bit integers and each bit is compared. When comparing the two bits, if any of the bits is 1, 1 is returned. If both bits are 0, 0 is returned.
Example:
2|1;//produces 3
--------
00000010 //2 in binary
00000001 //1 in binary
--------
00000011 //3 in binary
I have noticed a weird behaviour using bitwise AND operator in JS:
console.log((0xd41ddb80 & 0xd41ddb80).toString(16))
The result is -2be22480, but I was expecting 0xd41ddb80
What can be the cause of this behaviour?
From MDN
The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.
When interpreted as a signed 32-bit integer, the value 0xd41ddb80 represents the number -736240768. Using any bitwise operator on this number will coerce it into a signed 32-bit integer:
console.log(0xd41ddb80)
console.log(~~0xd41ddb80)
console.log(0xd41ddb80 & 0xffffffff)
console.log(0xd41ddb80 | 0)
The the base-16 equivalent of -736240768 is -2be22480, and that is what you are seeing .
You can observe similar behavior for any number greater than or equal to 0x80000000.
Why a positive number operated with bitwise or 0 not always positive in Javascript
For example:
3391700000|0
-903267296
4260919000|0
-34048296
2884900000|0
-1410067296
I'm using chrome 64-bit on Linux
related to: https://stackoverflow.com/a/12837315/1620210
Because JavaScript uses 32bit integers at most, but keep in mind every number is kind of a float in this language
If you want to truncate them to an unsigned 32bit value:
(3391700000|0) >>> 0
In JavaScript, the operands of bitwise operators are converted to signed 32-bit integers in 2's complement format. Thats why you got some loss of data and the truncated values are sometimes negative because of signed two's complement representation.
You can refer to Why bitwise shift with 0 in JavaScript yields weird results in some cases thread which was asked by myself some time ago and some answers pointed out the possible issue with bitwise operators where your operands exceed 32-bit integers very comprehensively.
This is mostly just a sanity-check.
Mozilla says that
The operands of all bitwise operators are converted to signed 32-bit
integers in two's complement format.
and that
The numbers -2147483648 and 2147483647 are the minimum and the maximum
integers representable through a 32bit signed number.
Since 2147483647 is 0x7FFFFFFF, I believe that 0x40000000 (that is to say, not 0x80000000) is the maximum number I can safely use as a javascript flag value. But I'd like to make sure I haven't missed something or that there aren't other gotchas. Thank you in advance!
The value range is a complete 32-bit value, ie. 0 to 0xffffffff (or 232-1). If it will be signed or not depends. If it will be signed initially then this will produce -1:
document.write(0xffffffff>>0);
But you can use unsigned values too which means the range is [0, 4294967295]:
document.write(0xffffffff>>>0);
The number 0x40000000 is only gonna give you half your range (in the negative range, in the positive it would be 0x40000000-1, or 0x3fffffff) so this is not the safe number for a 32-bit signed range.
You safe-range for signed number would be [0x80000000, 0x7fffffff], so the common safe-margin mask would be 0x7fffffff, however, you would need to preserve the sign-bit:
number = number < 0 ? number & 0xffffffff : 0x7fffffff;
And for unsigned your mask would always be 0xffffffff.
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).