In JavaScript, it seems:
(4294958077 | 0) == -9219
Why is it not 4294958077 ?
It suggests that there's some sort of overflow kicking in (although as I understand it a JavaScript Number type's range is +/- 9007199254740992 so that's odd in itself.)
Even if it was an overflow, surely
(4294958077 | 0) == 4294958077
should evaluate as true - but it doesn't.
Help please
It has nothing to do with floating point type or overflows. It returns -9219
because the standard mandates it, as all binary bitwise operations have to be done using signed 32-bit integers (ECMA-262 §11.10).
The production A : A # B, where # is one of the bitwise operators in the productions above, is evaluated as follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator # to lnum and rnum. The result is a signed 32 bit integer.
4294958077 converted to a signed 32-bit integer (using the algorithm in ECMA-262 §9.5) is -9219, and 0 is still 0, so the bitwise-or will return -9219.
All numbers in Javascript are 64bit floating point numbers. Bitwise operations on floats are an edge case, so internally those floats are temporarily converted to a 32bit int, then the bitwise operation is performed - hence your overflow.
JavaScript bitwise numbers are stored as signed 64-bit floats, i.e. you only have 32-bits to use for the integer, which you have exceeded, so it's gone weird by converting it to an integer as best it can and then doing the operation.
More information here (especially the 'beyond 32-bit' section) but no real solution, so unfortunately, you'll need to work around it.
Related
I am student studying programming.
As far as I know, Javascript saves number as float.
However, bitwise operator in Javascript run as a type of number is integer.
For instance,
> 1 | 2 // -> 3
> 2 << 4 // -> 32
How is it possible?
I find official documentation(mdn web docs), but I can not find the reason.
The bitwise operators in JavaScript convert numbers to 32-bit integers before performing the operation. This means that even though JavaScript saves numbers as floats, the bitwise operators treat them as 32-bit integers. This is why you are able to use the bitwise operators on numbers and get integer results.
As #rviretural_001 mentioned, JavaScript does some automatic conversions by spec. For example, in addition to IEEE 754 doubles to 32 signed integers:
0 == '0' // true
String to Integer (Shift Right)
'4' >> 1 // 2
Converting to Integer (Bitwise OR)
'1.3' | 0 // 1
This last one was used in asm.js for 32 signed integers
just to contribute to the answers above note that the conversion of a floating-point number to an integer is done by removing the fractional part of the number.
For example, if you have the number 4.5 and you use a bitwise operator on it, JavaScript will convert it to the integer 4 before performing the operation.
This tutorial might help you to find out more https://www.programiz.com/javascript/bitwise-operators
Also note that performing bitwise operations on floating-point numbers can lead to unexpected results. This is due to the way floating-point numbers are represented in memory. So, it's recommended to avoid using bitwise operators on floating-point numbers in JavaScript.
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.
I've seen some performance critical javascript code, like the one on this project that makes extensive use of bitwise OR operations with 0. Ex:
GameBoyAdvanceCPU.prototype.write8 = function (address, data) {
address = address | 0;
data = data | 0;
this.memory.memoryWrite8(address | 0, data | 0);
I know about the use case of flooring numbers with "|0", but that isn't the case here, as these are always int's. It looks a bit like asm.js, is this to tell the js engine that we are working with integers, allowing some optimizations? If so, which browsers will make those optimizations?
Any pointers to how this works would be appretiated.
According to JavaScript Performance for Madmen
Wrapping integer arithmetic expressions in ( ) | 0 allows the runtime to be sure that you're doing integer arithmetic instead of floating-point arithmetic. This allows it to avoid checking for overflow and produce faster code in many cases.
and according to the page, it's true for "most" Javascript runtimes, but doesn't say which.
As a second source, Writing Fast JavaScript For Games & Interactive Applications states
To tell JavaScript engine we want to store integer values [...] we could use bitwise or operator:
and a third source from Microsoft's Writing efficient JavaScript page:
[...] explicitly tell the JavaScript runtime to use integer arithmetic [...] use the bitwise or operator
Also, apart from in comments, none of the pages above mention asm.js, so I suspect such optimizations apply in code not explicitly marked as asm/in browsers that don't explicitly recognize it.
Referencing the Ecmascript 5 spec: 11.10 Binary Bitwise Operators, namely
The production A : A # B, where # is one of the bitwise operators in
the productions above (&; ^; |), is evaluated as follows:
Let lref be the result of evaluating A.
Let lval be GetValue(lref).
Let rref be the result of evaluating B.
Let rval be GetValue(rref).
Let lnum be ToInt32(lval).
Let rnum be ToInt32(rval).
Return the result of applying the bitwise operator# to lnum and rnum. The result is a signed 32 bit integer.
And noting that ToInt32() is defined as
Let number be the result of calling ToNumber on the input argument.
If number is NaN, +0, −0, +∞, or −∞, return +0.
Let posInt be sign(number) * floor(abs(number)).
Let int32bit be posInt modulo 2^32; that is, a finite integer value k of Number type with positive sign and less than 2^32 in magnitude such that the mathematical difference of posInt and k is mathematically an integer multiple of 2^32.
If int32bit is greater than or equal to 2^31, return int32bit − 2^32, otherwise return int32bit.
It then logically follows (which you can confirm in your own console) that for example
((Math.pow(2, 32)) + 2) | 0 === 2
(Math.pow(2, 31)) | 0 === -2147483648 === -(Math.pow(2, 31))
And so forth.
Shortly put, the operation turns the number to a 32-bit integer (which has its knacks, see the second example above and the ToInt32() definition for an explanation) and then does a logical or with zero which doesn't change the output beyond the first conversion.
Essentially it's a very cost-efficient way to turn a number into a 32-bit integer because 1) it relies on browser's built-in ToInt32(); and 2) ToInt32(0) short-circuits to 0 (see the spec above) and therefore adds practically no additional overhead.
What it actually does can be seen in this fiddle
It's probing the variable against integer type in this case and either "flooring" or set it to 0 if not an integer.
Thus, there's a tremendous differnece to a = a || 0 which would leave a value of 3.2 untouched.
| operator is bitwise OR. It's used to do a bit by bit OR operation on two integers.
The usage here is a shortcut very similar to logical OR || operator to provide default value, with the exception that the result is integer only (as opposed to string...etc)
address = address | 0;
means "if address is a number, let's use it; otherwise, set it to 0".
I'm using this code to try to find out how many bits are in a number. The hex number below has all bits turned on.
for (var i = 0x1FFFFFFFFFFFFF, m = 0; i & 1; ++m, i >>>= 1);
For some reason printing m gives 32, but in a SO post I read the following:
All numbers in JavaScript are actually IEEE-754 compliant floating-point doubles. These have a 53-bit mantissa which should mean that any integer value with a magnitude of approximately 9 quadrillion or less will be represented accurately.
Unless I'm implementing this incorrectly, I don't understand why printing m gives 32 when there are supposed to be 53 bits. Can someone please explain?
Bitwise operations are specified by the JavaScript/ECMAScript standard to truncate the number to 31 bits (round towards zero, take the modulus with 232, and interpret the most significant bit as a two's-complement sign) before anything else happens. So you need to recode it using plain arithmetic.
This is in part because FPUs which handle fractional numbers may not implement bitwise operations, at the logic circuit level.
The most naive way of testing is for ( var i = 0; i != i + 1; ++ i ) ; but that crashed Firefox when I tried it. (Was expecting a timeout, but nope!) The slightly more specific one-liner
for ( var i = 1, j = 0; i != i + 1; i *= 2, ++ j ) ;
does yield j == 53.
As an aside, note that the idiom x | 0 for rounding doesn't work with numbers greater or equal to 231. So Math.round is generally better.
Bitwise operation as >>> work on 32 bits numbers so i gets actually converted to 32bits. See this for more information.
From the speficication:
The production ShiftExpression : ShiftExpression >>> AdditiveExpression is evaluated as follows:
The Unsigned Right Shift Operator ( >>> )
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 ToUint32(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 zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The result is an unsigned 32-bit integer.
The bitwise operators in Javascript work on 32 bit integers.
That means that the floating point number in i is converted to a 32 bit integer to be used in the shift operation, and the rest of the bits are discarded.
Ref: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
"The operands of all bitwise operators are converted to signed 32-bit
integers"
Simple, really. Is 0xf12345678>>>4 always supposed to produce 0x1234567 as a result in JavaScript? Can I assume this would work in all browsers?
Yes, according to the ECMAScript 5 specification, the >>> operator performs the internal ToUInt32 algorithm.
See Section 11.7.3 of the spec:
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 ToUint32(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 zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The result is
an unsigned 32-bit integer.
It is spelled out very clearly that the result is a 32-bit integer, always.
The >>> operator is used commonly to convert to a 32-bit unsigned integer. For instance, MDN uses it in their shims. Example: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility
Should be a reliable assumption. Any JS interpreter will read the 0xf12345678 as a single operand before it computes any operations. If you want to be safe, why not (0xf12345678)>>>4?
Some details on the issue here: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
Bitwise operators treat their operands as a sequence of 32 bits (zeros
and ones), rather than as decimal, hexadecimal, or octal numbers. For
example, the decimal number nine has a binary representation of 1001.
Bitwise operators perform their operations on such binary
representations, but they return standard JavaScript numerical values.