14

JavaScript can handle the following Math just fine:

var result = (20000000 * 48271) % 0x7FFFFFFF;

But in some programming languages, that first int*int multiplication results in a value too large to hold in a standard 32 bit integer. Is there any way to "simulate" this in JavaScript, and see what the resulting calculation would be if the multiplication resulted in an integer overflow?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
IQAndreas
  • 8,060
  • 8
  • 39
  • 74
  • 1
    possible duplicate of [Does Javascript handle integer overflow and underflow? If yes, how?](http://stackoverflow.com/questions/19054891/does-javascript-handle-integer-overflow-and-underflow-if-yes-how) – Félix Saparelli May 10 '14 at 06:30
  • 1
    @FélixSaparelli It's not a duplicate, `20000000 * 48271` is still well within the JavaScript Number's 52 bit accuracy; it will not overflow. I'm trying to simulate a **32 bit overflow**. – IQAndreas May 10 '14 at 06:33
  • I cheated by subtracting 2^32 enough times from the result, but I don't think that's very efficient or very smart :P – BoltClock May 10 '14 at 06:34
  • `if Math.abs(int * int) is greater than (2^32)/2 then log value and continue`? – Xotic750 May 10 '14 at 06:45

3 Answers3

8

It is possible to simulate 32-bit integer by "abusing" the bitwise operators available in JavaScript (since they can only return integers within that range).

To convert to a signed 32-bit integer:

x = (a * b) | 0;

To convert to an unsigned 32-bit integer:

x = (a * b) >>> 0;
IQAndreas
  • 8,060
  • 8
  • 39
  • 74
  • The source of the code is from an different question: [_StackOverflow: JavaScript Integer math incorrect results_](http://stackoverflow.com/a/3428186/617937) – IQAndreas May 27 '14 at 01:26
  • 5
    This does not handle overflow correctly. `Math.imul` must be used instead. –  Jul 09 '17 at 12:24
6

In newer browsers, Math.imul(a,b) will give you an actual 32-bit integer multiplied result, with overflow resulting the way you would expect (it gives the lower half of the 64-bit result as what it returns).

However, as far as I know there's no way to actually get the overflow, (the upper 32 bits) but the modulus you showed in your answer gets rid of that information, so I figure that's not what you want. If they were going to do overflow, they'd have to separate it based on signed and unsigned anyway.

I know this works in Chrome, Firefox, and Opera, not sure about the rest, though pretty sure IE doesn't have it (typical). You'd need to fall back to a shim such as this one.

TND
  • 271
  • 1
  • 5
  • I think you're confusing 32-bit/64-bit with unsigned/signed. – BoltClock May 10 '14 at 16:53
  • 2
    No, when you multiply two 32 bit numbers in two's complement, it produces a 64 bit result, though the lower half will be correct regardless of whether the multiplication is signed or not- it's the upper half, the overflow, that varies based on signedness. See http://stackoverflow.com/questions/14063599/why-are-signed-and-unsigned-multiplication-different-instructions-on-x86-64 – TND May 10 '14 at 21:07
  • @TND, I'm writing a hashCode like function where the algorithm I've been told to implement has a 32-bit int and expects the behavior provided by the Math.imul(). I would suggest that you remove the part about it having no way to get the upper 32 bits to make the answer clearer. – PatS Feb 07 '18 at 23:43
  • Is there also iadd? Addition with correct overflow? I need this for my Javascript based JVM – neoexpert Sep 15 '19 at 17:22
0

Another way to achieve this is to convert to a format where you can remove extra bytes before converting back to integer. That may not be optimal for JS but can be helpful in environments with really restricted operators.

For instance with hexadecimal:

var hugeInteger = 999999999999999;
var ui32 = parseInt(hugeInteger.toString(16).slice(-8), 16);
// ui32 == 2764472319

It's also possible to get the overflow from hugeInteger.toString(16).slice(0,-8)

Guillaume
  • 12,824
  • 3
  • 40
  • 48