When I try to perform bitwise XOR operation in php and js, they are producing different results in some cases , for example
2166136261 ^ 101 = -2128831072 on browsers (js)
2166136261 ^ 101 = 2166136224(php)
My understanding is because php is running 64 bit as opposed to 32 bit js.
Can anyone tell me the exact reason and if this could be solved so that both operations result in same value. Thanks!
2,147,483,647 is the biggest possible positive value for an integer in 32 bit computing, (it's 2^16, half of the 32 bits we have, the other half are reserved for negative numbers.)
Once you use a number bigger than that in a 32 bit system you start getting screwy results as the computer thinks it's a negative number. see https://en.wikipedia.org/wiki/Integer_(computer_science)
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.
In R if I do bitXor(2496638211, -1798328965) I get 120 returned.
In nodeJS 2496638211 ^ -1798328965; returns 120.
How do I do this in C#? (Think I'm struggling to understand c# type declaration and the way R & nodeJS presumably convert to 32 bits)
In C# you would have to use unchecked and cast to int:
unchecked
{
int result = (int)2496638211 ^ -1798328965;
Console.WriteLine(result); // Prints 120
}
You could write a method to do this:
public static int XorAsInts(long a, long b)
{
unchecked
{
return (int)a ^ (int)b;
}
}
Then call it:
Console.WriteLine(XorAsInts(2496638211, -1798328965)); // Prints 120
Note that by casting to int, you are throwing away the top 32 bits of the long. This is what bitXor() is doing, but are you really sure this is the behaviour you want?
2496638211 is larger than an 32bit integer and in 64 bit systems with C# integers defaults long thus the hex value representation is0x94CFAD03. That 9 overlaps with the sign bits. This is also means that -1798328965 results in 0xFFFFFFFF94CFAD7B due to the negative number representation. So C# gets 0xFFFFFFFF00000078 that is the correct answer.
JS XOR uses 32 bit operands so it truncates 2496638211. Thus JS gets 0x00000078 that is not technically the correct answer. My assumption is that R does the same or similar.
In JS use Number.isSafeInteger() as well as Number.MAX_SAFE_INTEGER. In C# check int.MaxValue vs long.MaxValue to see the difference vs JS.
To recreate the JS behavior in C# wrap it in an unchecked block as per Matthew Watson post. The unchecked keyword is used to suppress overflow-checking for integral-type arithmetic operations and conversions.
I have this Java code:
nextDouble = 0.2515933907977884;
long numerator = (long) (nextDouble * (1L << 53));
I would like to be able to produce the same output this line produces in Java but within JavaScript.
nextDouble = 0.2515933907977884;
const numerator = nextDouble * (1 << 53);
Has anybody got an idea for how to replicate a long within JavaScript ? I know there is BigInt in JavaScript but thing is, it doesn't support floating point numbers, so I am a bit stuck on what to do. Does anybody know any interesting libraries, that could solve this issue ?
Thank you in advance !
The problem is what 1<<53 does in javascript. It doesn't do what you think it does.
Here, try this in the console:
1<<30
1073741824
// okay.. looks good
1<<31
> -2147483648
// a negative num.. wha??
1<<32
> 1
// WHAA????????
1<<53
> 2097152
// That seems VERY low to me
1<<21
> 2097152
// How is that the same? as 1<<53??
numbers in javascript are forced into being doubles, and doing bit shifts on a double is utterly ridiculous. Javascript nevertheless lets you, because, well, javascript. When you do silly things in javascript, javascript will give you silly answers, and in that way javascript is rather worthless - programmers doing crazy stuff that cannot reasonably be interpreted as having any particular meaning should be answered with a clear error and not a wild stab in the dark. But that's just how javascript is. The usual way to deal with this crazy behaviour is to never ask javascript silly things, as it will give you silly answers. Such as 1<<32 being 1*.
You may be wondering 'but how is asking to bit shift 1 by 53 positions 'crazy'? - and the answer is, that bit shifts, given that they make no sense on doubles, are interpreted as: "You wish to emulate 32-bit signed int behaviour", and that is exactly what javascript does, notably including the weirdish java/C-ism that only the bottom 5 bits of the number on the RHS count. In other words, <<32 is the same thing as <<0 - after all, the bottom 5 bits of 32.. is 0. Said differently, take the right hand side number, divide it by 32, toss the result, keep the remainder ('modulo'). 32 divided by 32 leaves a remainder of 0. 53 divided by 32 leaves a remainder of 21, and that's why 1<<53 in javascript prints 2097152.
So, in javascript your code is effectively doing the double multiplied by 2 to the 21st power, or theDouble * 2097152, whereas in java it is doing the double multiplied by 2 to the 53rd power, or theDouble * 9007199254740992.
Rather obviously then your answers are wildly different.
The fix seems trivial. 1<<53 may look like a nice way to convey the notion of 2 to 53rd power or in bits, a 1 bit, followed by 53 zeroes, but as syntax goes it just does not work that way in javascript. You can't use that syntax for this purpose. Try literally 9007199254740992.
var d = 0.2515933907977884;
const n = d * 9007199254740992;
n
> 2266151802091599
so that works.
If you have a need to derive the value 9007199254740992 from the value 53:
Math.pow(2, 53)
> 9007199254740992
note that you're dancing on the edge of disaster here. standard IEEE doubles use 53 bits for the exponent, so you're at the very edges. Soon you'll get into the territory where 'x + 1' is equal to 'x' because the gap between representable numbers is larger than 1. You'll need to get cracking on BigInt if you want to move away from the precipice.
*) It is specced behaviour. But surely you agree this is highly surprising. How many people do you know that just know off-hand that javascripts << is specced to convert to a 32-bit signed integer, take the RHS and modulo 32 it, and then operate, and then convert back to double afterwards?
I am not an expert in bitwise operators, but i often see a pattern which is used by programmers of 256k demos at competitions. Instead of using Math.floor() function, double bitwise NOT operator is used ~~ ( maybe faster ? ).
Like this:
Math.floor(2.1); // 2
~~2.1 // 2
Search revealed that there are more patterns that used the same way:
2.1 | 0 // 2
2.1 >> 0 // 2
When playing with this in the dev console, i have noticed a behavior that i'm not sure i understand fully.
Math.floor(2e+21); // 2e+21
~~2e+21; // -1119879168
2e+21 | 0; // -1119879168
What is happening under the hood ?
As Felix King pointed out, the numbers are being converted to 32 bit signed integers. 2e9 is less than the maximum positive value of a signed int, so this works:
~~(2e9) //2000000000
But when you go to 2e10, it can't use all the bits, so it just takes the lowest 32 bits and converts that to an int:
~~(2e10) //-1474836480
You can verify this by using another bitwise operator and confirming that it's grabbing the lowest 32 bits:
2e10 & 0xFFFFFFFF // also -1474836480
~~(2e10 & 0xFFFFFFFF) // also -1474836480
Math.floor is built to account for large numbers, so if accuracy over a big range is important then you should use it.
Also of note: The ~~ is doing truncation, which is the same as flooring for positive numbers only. It won't work for negatives:
Math.floor(-2.1) // -3
~~(-2.1) // -2
As stated in the MDN Docs, and here I quote,
The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.
This means tha when you apply a bitwise operator, for instance ~, to 2.1 it is first converted to an integer, and only then is the operator applied. This effectively achieves the rounding down (floor) effect for positive numbers.
As to why these operators are used, instead of the much nicer to grasp Math.floor, there are two main reasons. For one, these operators may be considerably faster to achieve the same result. Besides performance, some people just want the shortest code possible. All three operators you mentioned achieve the same effect, but ~~ just happens to be the shortest, and arguably the easiest to remember.
Given that the float to integer conversion happens before the bitwise operators are applied, let's see what happens with ~~. I'll represent our target number (2, after the convertion from 2.1) using 8 bits, instead of 32, for shortness.
2: 0000 0010
~2: 1111 1101 (-3)
~~2: 0000 0010
So, you see, we apply an operator to retrieve only the integer part, but we can't apply only one bitwise not, because it would mess up the result. We revert it to the desired value applying the second operator.
Regarding your last example, take into account that the number you're testing with, 2e+21, is a relatively big number. It's a 2 followed by twenty-one zeroes. It simply doesn't fit as a 32-bit integer (the data-type it is being converted to, when you apply the bitwise operators). Just look at the difference between your number and what a 32-bit signed integer can represent.
Max. Integer: 2147483647
2e+21: 2000000000000000000000
How about binary?
Max. Integer: 01111111111111111111111111111111
2e+21: 11011000110101110010011010110111000101110111101010000000000000000000000
Quite big, huh?
What really happens under the hood is that Javascript is truncating your big number to what it can represent in 32 bits.
110110001101011100100110101101110001011 10111101010000000000000000000000
^---- Junk ----^
When we convert our truncated number to decimal, we get back what you're seeing.
Bin: 10111101010000000000000000000000
Dec: -1119879168
Conversely, Math.floor accounts for the big numbers and avoids truncating them, which is one of the possible reasons for it being slower, although accurate.
As I see in examples, the functionality if ~~ and Math.floor is the same. Both of them round a number downward (Am I think correct?)
Also I should mention that according to this test ~~ is faster than Math.floor: jsperf.com/math-round-vs
So I want to know, is there any difference between ~~ and Math.floor?
Yes, bitwise operators generally don’t play well with negative numbers. f.ex:
~~-6.8 == -6 // doesn’t round down, simply removes the decimals
Math.floor(-6.8) == -7
And you also get 0 instead of NaN, f.ex:
~~'a' == 0
Math.floor('a') == NaN
In addition to David answer:
One of the things that I have noticed about bitwise operations in JavaScript is that it can be convenient for smaller values, but doesn’t always work for larger values. The reason this is the case is that bitwise operators will only work fully for operands which can be fully expressed in a 32-bit signed format. In other words, using bitwise operations will only produce numbers that are in the range of -2147483648 (-231) to 2147483647 (231 – 1). In addition, if one of the operands used is outside of that range, the last 32 bits of the number will be used instead of the specified number.
http://cwestblog.com/2011/07/27/limits-on-bitwise-operators-in-javascript/
This limitation can easily be found when working with Date, assume you are rounding a milliseconds value:
Math.floor(1559125440000.6) // 1559125440000
~~1559125440000.6 // 52311552