7

I am trying convert a byte array to a number and for large numbers, I see that the bit shift is giving -ve results. Can one of you please why we see this issue? Do you see any drawbacks using "multiplication" instead of "bit-shift"?

For example,

<script language="JavaScript">
    var myVar = 1000000;
    document.write("Bit shift Result: " + (myVar << 8));
    document.write("<br>");
    document.write("Multiplication Result: " + parseInt(myVar *256));
</script>

Output:

Bit shift Result : 256000000

Multiplication Result: 256000000

Upon adding one more zero to myVar, you see the issue I am talking about

<script language="JavaScript">
    var myVar = 10000000;
    document.write("Bit shift Result: " + (myVar << 8));
    document.write("<br>");
    document.write("Multiplication Result: " + parseInt(myVar *256));
</script>

Output:
Bit shift Result: -1734967296

Multiplication Result: 2560000000

Barmar
  • 741,623
  • 53
  • 500
  • 612
user3101143
  • 137
  • 1
  • 3
  • 10
  • To summarize the answers: it is because JavaScript is whack. It is institutionalized insanity - as in, specified madness, well-defined inanity, thoroughly-documented craziness. – Claudiu Dec 14 '13 at 00:16
  • @Claudiu I have no idea what you're talking about, you'd get similar results in other programming languages (Java, C#, C, etc) too. – Benjamin Gruenbaum Dec 14 '13 at 00:21
  • 1
    @BenjaminGruenbaum: I mean that all JavaScript numbers are `double`s, but they behave like int32's in certain cases just for the heck of it. If you bitshift a double in C, it will, um.. shift the bits. This is not the case here. Plus there's other wackery which my comment was referring to, like how all array indices are actually strings which, if they are convertible to an integer, act as integers into the array, but if they aren't, act like properties. great stuff, and it's all in the spec. – Claudiu Dec 14 '13 at 01:13
  • @Claudiu right, because typing is based on behavior in JavaScript. Internally engines _will_ use actual C like arrays (or 32 bit ints) when it's possible and as a developer you don't have to worry about it. Your development experience is no different than in C, or Java, or C#, or Python. I do agree that the language makes it really easy to mess with it (like adding keys like 'name' to arrays) but that doesn't mean anyone should/would do that :) All that 'inconsistency' is in the spec for a reason and that reason is not just being 'well defined' or being in a spec. – Benjamin Gruenbaum Dec 14 '13 at 01:17

3 Answers3

4

In JavaScript, all bitwise operators first invoke [ToInt32] on the operands. This includes shift operators.

Then the bitwise operators (i.e. <<) work on signed two's-complement 32-bit integers. After the shift the resulting bit pattern represents a negative number.

00000000 10011000 10010110 10000000 - original value, after [ToInt32], as bits
10011000 10010110 10000000 00000000 - value after shift; a negative bit pattern

I would use multiplication except in cases where this behavior is desired.

(Of course, if writing a PC emulator then every little trick counts .. but prefer multiplication.)

user2864740
  • 60,010
  • 15
  • 145
  • 220
4

To answer both your questions:

Can one of you please why we see this issue?

JavaScript numbers are standard IEEE doubles.

The largest integer value JavaScript can hold is: 9007199254740992

However, the bitshift operator works on 32 bit ints.

And I quote the language specification:

5 . Let lnum be ToInt32(lval).

...

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.

Do you see any drawbacks using "multiplication" instead of "bit-shift"?

It still is kind of slower, but you should really avoid working directly with very large numbers in JavaScript most of the time anyway.

There are libraries that deal with very large numbers and there are features that are being discuss to add better support to large numbers to the language (ES7 value types).

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • @user2864740 how about: I've actually read the code for implementing this logic in different JavaScript engines and the way it's currently implemented in v8 it _is_ slower (at least initially). Is that enough reason for you? – Benjamin Gruenbaum Dec 13 '13 at 23:57
  • 1
    Technically this is not true: "The largest integer value JavaScript can hold is: 9007199254740992" It can *precisely* hold 9007199254740994, 9007199254740996, etc. and many other larger integers. The way I usually state this idea is that 9007199254740993 is the smallest positive integer which JavaScript *cannot* hold. – Matt Dec 13 '13 at 23:59
  • @Matt here - this is me holding a number with 1000 zeros as a stirng in JavaScript : "1e1000" - what I meant there - is that 9007199254740992 is the largest number you can hold without having to worry about precision, the largest number you can _store_ in JS is `179769313486232000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000` – Benjamin Gruenbaum Dec 14 '13 at 00:05
  • 2
    Of course - I know the underlying issue is transparent to both of us, and I knew precisely what you meant. I'm just trying to find the best way to articulate these ideas to other readers which is both succinct and precise.. – Matt Dec 14 '13 at 00:12
1

Internally, JavaScript represents all numbers using 64-bit floating point with a 52-bit mantissa. However, you can also do bit operations, but only as signed 32-bit integers, which go from -2147483648 to +2147483647. To go outside of this range, you must use regular arithmetic, not bit operations.

Matt
  • 20,108
  • 1
  • 57
  • 70