This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
>> in javascript
Here:
var num=10;
console.log(num/2);
num=4;
console.log(num/2);
It gives me 5 and 2.
And this one:
var num=10;
console.log(num>>1);
num=4;
console.log(num>>1);
It also gives me 5 and 2.
So x/2 is the same as x>>1? But why?
For the same reason that dropping the last digit off a normal (decimal) number is the same as dividing it by 10 (ignoring, of course, any non-integer remainder).
In computers, integers are internally represented in binary (base 2). So each digit represents a power of 2 instead of a power of 10 that we're used to with the decimal system.
>> 1 just means to shift all the bits right by one, which is another way of saying "drop the last digit". Since the digits are in binary, that's equivalent to dividing by the base, which is 2.
Similarly, if you need to divide by any power of 2, you can do so using the right shift operator: To divide by 4, shift by 2; to divide by 8, shift by 3; and so on.
Note that internally, it's often more efficient to do a shift operation instead of a division operation, but any compiler worth its salt will do this optimization for you (so that you don't have to write obfuscated code to get the performance benefit -- generally, you would only use the shift operator when your intention is to manipulate bits directly, and use the division operator when your intention is to do math).
x>>1 is a bit shift, which operates on the number's binary representation. The effect is that x>>n is the same as x/(2^n) (except that bit shift is usually faster than division, as it is lower level).
When you >> something, you basically shift all its bits to the right.
When that happens, you shift the 2-place value into the 1-place value, and the 4-place value into the 2-place value, and so on.
This effectively divides a number in half.
Take the number 14, for example:
1110.
When you shift the bits, you get 111, or 7.
Take a look at this:
http://en.wikipedia.org/wiki/Division_by_two#Binary
Everything you need to know about >> can be found here and here.
Related
This question already has answers here:
Javascript's Shift right with zero-fill operator (>>>) yielding unexpected result
(2 answers)
Closed 1 year ago.
From the documentation:
The right shift operator (>>) shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Copies of the leftmost bit are shifted in from the left. Since the new leftmost bit has the same value as the previous leftmost bit, the sign bit (the leftmost bit) does not change. Hence the name "sign-propagating".
From what I understand, since 100 is 0b1100100, shifting it 100 times to the right should yield 0b0. However, when I run 100 >> 100 in Javascript (using chrome), it returns 6. Why is this the case? I am guessing it has something to do with JS's internal representation of numbers but would like to know more clearly.
Edit: The answer is still 6, even when using the unsigned >>> operator. Sign/unsigned does not seem to matter.
Unsigned operation documentation:
The unsigned right shift operator (>>>) (zero-fill right shift) shifts the first operand the specified number of bits to the right. Excess bits shifted off to the right are discarded. Zero bits are shifted in from the left. The sign bit becomes 0, so the result is always non-negative. Unlike the other bitwise operators, zero-fill right shift returns an unsigned 32-bit integer.
The value to the right is taken mod 32. (i.e. Only the last five bits are used.) If you calculate 100>>32, you get 100, which is the same thing you get when you compute 100>>0. After that, 100>>33 is 50, and the cycle repeats.
I'm looking at ways to multiply faster in JavaScript, and I found this
https://medium.com/#p_arithmetic/4-more-javascript-hacks-to-make-your-javascript-faster-1f5fd88a219e#.306ophng2
which has this text
Instead of multiplying, use the bit shift operation. it looks a little more complex, but once you get the hang of it, it’s pretty simple. The formula to multiply x * y is simply x << (y-1)
As a bonus, everyone else will think you’re really smart!
// multiply by 1
[1,2,3,4].forEach(function(n){ return n<<0; }) // 1,2,3,4
// multiply by 2
[1,2,3,4].forEach(function(n){ return n<<1; }) // 2,4,6,8
// multiply by 3
[1,2,3,4].forEach(function(n){ return n<<2; }) // 3,6,9,12
// etc
However this doesn't seem to work for me. Does anyone know what's wrong?
Thanks
Ignore that article. It's intended as humor -- the advice it's giving is intentionally terrible and wrong.
Multiplication does not involve "expensive logarithmic look up tables and extremely lucky guesses" with "dozens of guesses per second". It is a highly optimized hardware operation, and any modern CPU can perform hundreds of millions (or more!) of these operations per second.
Bitwise operations are not faster than multiplication in Javascript. In fact, they're much slower -- numbers are generally stored as double-precision floating point by default, so performing a bitwise operation requires them to be converted to integers, then back.
Bit-shifting is not equivalent to multiplication in the way that the article implies. While left-shifting by 0 and 1 are equivalent to multiplication by 1 and 2, the pattern continues with <<2 and <<3 being equivalent to a multiplication by 4 and 8, not 3 and 4.
Array.forEach does not return a value. The appropriate function to use here would be Array.map.
The other "Javascript hacks" described in the article are even worse. I won't bother going into details.
Bit shift is not the same as multiplying by any number. This is how bit shift works in decimal for example:
1234 >> 0 = 1234
1234 >> 1 = 0123 #discards the last digit.
0123 >> 2 = 0001 #discards the last two digit
So in decimal, shifting digits to the right is like integer division by 10. When shifted by two digits it's the same as dividing by 10^2.
Now computers work with binary words. So instead of a digit shift, we have bit shifts.
10101011 >> 1 = 01010101
This is basically dividing by 2^1.
10101011 >> n is simply dividing by 2^n.
Now in the same manner,
10101011 << n is multiplying by by 2^n. This adds n zeroes behind the binary word.
Hope it's clearer now :)
Cheers
Incidentally, if you want to know why it isn't working for you, you will want to use map instead of forEach since forEach ignores the return.
So do this instead:
// multiply by 1
[1,2,3,4].map(function(n){ return n<<0; }) // 1,2,3,4
// multiply by 2
[1,2,3,4].map(function(n){ return n<<1; }) // 2,4,6,8
// multiply by 4
[1,2,3,4].map(function(n){ return n<<2; }) // 4,8,12,16
// multiply by 8
[1,2,3,4].map(function(n){ return n<<3; }) // 8, 16, 24, 32
And as others have mentioned - don't use this for multiplication. Just take this as a clarity of forEach vs map...
So my problem is this, I'm writing a program that checks if number is even or odd without division. So I decided to take the number, turn it into a String with the
number.toString()
method. The problem I'm having is that if you put a number that is about 17 or more digits long the string is correct for about the first 17 digits then it's just 0's and sometimes 2's. For example,
function toStr (number)
{
return number.toString(10);
}
console.log(toStr(123456789123456789));
prints,
123456789123456780
any ideas?
The problem has nothing to do with strings or your function at all. Try going to your console and just entering the expression 123456789123456789 and pressing return.
You will likewise obtain 123456789123456780.
Why?
The expression 123456789123456789 within the JavaScript language is interpreted as a JavaScript number type, which can only be represented exactly to a certain number of base two significant figures. The input number happens to have more significant digits when expressed in base two than the number of base two significant figures available in JavaScript's representation of a number, and so the value is automatically rounded in base two as follows:
123456789123456789 =
110110110100110110100101110101100110100000101111100010101 (base two)
123456789123456780 =
110110110100110110100101110101100110100000101111100001100 (base two)
Note that you CAN accurately represent some numbers larger than a certain size in JavaScript, but only those numbers with no more significant figures in base two than JavaScript has room for. For instance, 2 times a very large power of 10, which would have only one significant figure in base two.
If you are designing this program to accept user input from a form or dialog box, then you will receive the input as a string. You only need to check the last digit in order to determine if the input number is odd or even (assuming it is indeed an integer to begin with). The other answer has suggested the standard way to obtain the last character of a string as well as the standard way to test if a string value is odd or even.
If you go beyond Javascript's max integer size (9007199254740992) you are asking for trouble: http://ecma262-5.com/ELS5_HTML.htm.
So to solve this problem, you must treat it as a string only. Then extract the last digit in the string and use it to determine whether the number is even or odd.
if(parseInt(("123456789123456789").slice(-1)) % 2)
//odd
else
//even
It's a 64-bit floating point number, using the IEEE 754 specification. A feature of this spec is that starting at 2^53 the smallest distance between two numbers is 2.
var x = Math.pow(2, 53);
console.log( x == x + 1 );
This difference is the value of the unit in the last place, or ULP.
This is similar in principle to trying to store fractional values in integral types in other languages; values like .5 can't be represented, so they are discarded. With integers, the ULP value is always 1; with floating point, the ULP value depends on how big or small the number you're trying to represent.
At the first lines of Asm.js definition there's a Asm.js-based code example that explains the bitwise operation helps to have a faster JS code:
HEAP32[p >> 2]|0
or
(x+y)|0
My question is, how this operation boost the performance and what's the reason behind using this bitwise operator many times in Asm.js or Emscripten-generated JS codes?
The bitwise operators force their operands to be integer values. It's a considerably faster way of doing the conversion than calling Math.floor, etc. Note that
p >> 2
is (for non-negative values of p) the same as Math.floor(p / 4).
Using a right bit shift (>>) by 1, is the same as dividing by 2, but it is faster than actually calculating it base 10 because the computer can just shift the binary digits in memory without having to do a calculation. It's just like in base 10 when you want to multiply a number by 10, you know you can just add a zero to the right side of the number (The reverse, division, would be taking the zero off of the right side). So, by shifting right two digits you are dividing by 2 twice (e.g. 24/2 = 12 and 12/2 = 6 or 24/4 = 6)
Apparently, (x+y)|0 is just a faster way to do a floor.
I heard that you could right-shift a number by .5 instead of using Math.floor(). I decided to check its limits to make sure that it was a suitable replacement, so I checked the following values and got the following results in Google Chrome:
2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2; // 15 9s
2.9999999999999999 >> .5 == 3; // 16 9s
After some fiddling, I found out that the highest possible value of two which, when right-shifted by .5, would yield 2 is 2.9999999999999997779553950749686919152736663818359374999999¯ (with the 9 repeating) in Chrome and Firefox. The number is 2.9999999999999997779¯ in IE.
My question is: what is the significance of the number .0000000000000007779553950749686919152736663818359374? It's a very strange number and it really piqued my curiosity.
I've been trying to find an answer or at least some kind of pattern, but I think my problem lies in the fact that I really don't understand the bitwise operation. I understand the idea in principle, but shifting a bit sequence by .5 doesn't make any sense at all to me. Any help is appreciated.
For the record, the weird digit sequence changes with 2^x. The highest possible values of the following numbers that still truncate properly:
for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth
Actually, you're simply ending up doing a floor() on the first operand, without any floating point operations going on. Since the left shift and right shift bitwise operations only make sense with integer operands, the JavaScript engine is converting the two operands to integers first:
2.999999 >> 0.5
Becomes:
Math.floor(2.999999) >> Math.floor(0.5)
Which in turn is:
2 >> 0
Shifting by 0 bits means "don't do a shift" and therefore you end up with the first operand, simply truncated to an integer.
The SpiderMonkey source code has:
switch (op) {
case JSOP_LSH:
case JSOP_RSH:
if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
return JS_FALSE;
if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
return JS_FALSE;
j &= 31;
d = (op == JSOP_LSH) ? i << j : i >> j;
break;
Your seeing a "rounding up" with certain numbers is due to the fact the JavaScript engine can't handle decimal digits beyond a certain precision and therefore your number ends up getting rounded up to the next integer. Try this in your browser:
alert(2.999999999999999);
You'll get 2.999999999999999. Now try adding one more 9:
alert(2.9999999999999999);
You'll get a 3.
This is possibly the single worst idea I have ever seen. Its only possible purpose for existing is for winning an obfusticated code contest. There's no significance to the long numbers you posted -- they're an artifact of the underlying floating-point implementation, filtered through god-knows how many intermediate layers. Bit-shifting by a fractional number of bytes is insane and I'm surprised it doesn't raise an exception -- but that's Javascript, always willing to redefine "insane".
If I were you, I'd avoid ever using this "feature". Its only value is as a possible root cause for an unusual error condition. Use Math.floor() and take pity on the next programmer who will maintain the code.
Confirming a couple suspicions I had when reading the question:
Right-shifting any fractional number x by any fractional number y will simply truncate x, giving the same result as Math.floor() while thoroughly confusing the reader.
2.999999999999999777955395074968691915... is simply the largest number that can be differentiated from "3". Try evaluating it by itself -- if you add anything to it, it will evaluate to 3. This is an artifact of the browser and local system's floating-point implementation.
If you wanna go deeper, read "What Every Computer Scientist Should Know About Floating-Point Arithmetic": https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
Try this javascript out:
alert(parseFloat("2.9999999999999997779553950749686919152736663818359374999999"));
Then try this:
alert(parseFloat("2.9999999999999997779553950749686919152736663818359375"));
What you are seeing is simple floating point inaccuracy. For more information about that, see this for example: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.
The basic issue is that the closest that a floating point value can get to representing the second number is greater than or equal to 3, whereas the closes that the a float can get to the first number is strictly less than three.
As for why right shifting by 0.5 does anything sane at all, it seems that 0.5 is just itself getting converted to an int (0) beforehand. Then the original float (2.999...) is getting converted to an int by truncation, as usual.
I don't think your right shift is relevant. You are simply beyond the resolution of a double precision floating point constant.
In Chrome:
var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;
document.write("x=" + x);
document.write(" y=" + y);
Prints out: x = 2.9999999999999996 y=3
The shift right operator only operates on integers (both sides). So, shifting right by .5 bits should be exactly equivalent to shifting right by 0 bits. And, the left hand side is converted to an integer before the shift operation, which does the same thing as Math.floor().
I suspect that converting 2.9999999999999997779553950749686919152736663818359374999999
to it's binary representation would be enlightening. It's probably only 1 bit different
from true 3.
Good guess, but no cigar.
As the double precision FP number has 53 bits, the last FP number before 3 is actually
(exact): 2.999999999999999555910790149937383830547332763671875
But why it is
2.9999999999999997779553950749686919152736663818359375
(and this is exact, not 49999... !)
which is higher than the last displayable unit ? Rounding. The conversion routine (String to number) simply is correctly programmed to round the input the the next floating point number.
2.999999999999999555910790149937383830547332763671875
.......(values between, increasing) -> round down
2.9999999999999997779553950749686919152736663818359375
....... (values between, increasing) -> round up to 3
3
The conversion input must use full precision. If the number is exactly the half between
those two fp numbers (which is 2.9999999999999997779553950749686919152736663818359375)
the rounding depends on the setted flags. The default rounding is round to even, meaning that the number will be rounded to the next even number.
Now
3 = 11. (binary)
2.999... = 10.11111111111...... (binary)
All bits are set, the number is always odd. That means that the exact half number will be rounded up, so you are getting the strange .....49999 period because it must be smaller than the exact half to be distinguishable from 3.
I suspect that converting 2.9999999999999997779553950749686919152736663818359374999999 to its binary representation would be enlightening. It's probably only 1 bit different from true 3.
And to add to John's answer, the odds of this being more performant than Math.floor are vanishingly small.
I don't know if JavaScript uses floating-point numbers or some kind of infinite-precision library, but either way, you're going to get rounding errors on an operation like this -- even if it's pretty well defined.
It should be noted that the number ".0000000000000007779553950749686919152736663818359374" is quite possibly the Epsilon, defined as "the smallest number E such that (1+E) > 1."