I am trying to translate simple JS code to C and/or Perl but I found a discrepancy in behaviour when doing arithmetic operations (+ - * / << >>
) on integers and the result overflows. I need to simulate JS exactly, even the overflows! JS variables are not explicitly BigInt but just JS var.
JS (via node.js or Firefox’s developer tools’ console):
function calc(a, b){
return (a<<b) + (a<<b);
}
var x = calc(1, 30);
result:
2147483648
C:
#include <stdio.h>
#include <stdint.h>
int main(void){
int32_t lop = 1<<30; //1073741824;
int32_t rop = 1<<30; //1073741824;
int32_t res = lop + rop;
printf("1<<30 + 1<<30 : %dn", res);
}
result:
1<<30 + 1<<30 : -2147483648
Perl:
sub to32bit { unpack("l", pack("L", $_[0])) } # Corion @ PerlMonks
print to32bit(to32bit(1<<30)+to32bit(1<<30));
result:
-2147483648
Am I right that there is a discrepancy or am I doing things wrong?
How to get this right?
As I said I need to emulate JS’s exact behaviour in C/Perl so I don’t want to fix JS code but adjust C/Perl code to do the same as JS.
See also related discussion at https://perlmonks.org/?node_id=11155911
2
Answers
Javascript "Numbers" are essentially
double
s, when doing bit arithmetics they are truncated toint32
‘s and then promoted back to doubles. So your C code should be something likeJavaScript is an implementation of ECMAScript, and ECMAScript specifies that a left-shift operation is performed as if the left operand were converted to a 32-bit two’s complement integer before the operation were performed and the right operand were converted to 32-bit unsigned integer. It also specifies that addition is performed using numbers in the IEEE-754 binary64 (“double precision”) form.
Assuming your C implementation uses binary64 for
double
, which is very common, and thatint32_t
anduint32_t
are available (in the<stdint.h>
header), then JavaScript(a<<b) + (a<<b)
is largely equivalent to:I say “largely equivalent” because details of operations involving conversion between types or handling of infinities, NaNs, and other exceptional cases may vary between ECMAScript and C.
The ECMAScript specification is explicit about the semantics of operations. If you are converting JavaScript to another language, you should get a copy of the ECMAScript Language Specification and use it.