int (x) compiles to float (x) | 0. JavaScript's | converts its left operand with ToInt32, so the result is always a signed 32 bit integer. Arguments outside -2**31 ... 2**31 - 1 come back wrong, multiples of 2**32 come back as 0.
Reproducer
values = [8589934588, 9007199254740988, 2147483648, 4294967296]
for v in values:
print (v, '->', int (v))
CPython:
8589934588 -> 8589934588
9007199254740988 -> 9007199254740988
2147483648 -> 2147483648
4294967296 -> 4294967296
Transcrypt:
8589934588 -> -4
9007199254740988 -> -4
2147483648 -> -2147483648
4294967296 -> 0
Run with 3.7.16 on Python 3.7, compiled with -b -n -e 6 and executed under
node. Line 291 of __builtin__.js is identical on current master.
The failure is quiet. A memory size in kB, a file offset or a timestamp in microseconds passes 2**31 during normal operation and then yields a small or negative number instead of an error.
Testlet
For development/automated_tests/transcrypt/div_issues/__init__.py:
autoTester.check ('Issue 911') # int () truncated to 32 bits
autoTester.check (int (2147483648))
autoTester.check (int (4294967296))
autoTester.check (int (8589934588))
autoTester.check (int (9007199254740988))
autoTester.check (int (-5.7), int (5.7))
Possible fix
export function int (any) {
var f = float (any);
return f === Infinity || f === -Infinity || isNaN (f) ? 0 : Math.trunc (f);
};
This makes int () exact over the whole range where a JavaScript number is exact, up to 2**53 - 1, and leaves truncation toward zero for negative floats unchanged. With the patch applied the reproducer above matches CPython.
Math.trunc is ES6. The default target is esv 6 and javascriptVersion gates nothing in the code generator, so no version switch is needed. int has no callers inside the runtime.
Note on NaN and Infinity
NaN | 0 and Infinity | 0 currently yield 0, where CPython raises ValueError and OverflowError. The version above keeps the 0 to stay minimal. Raising instead would match CPython but changes behaviour beyond the range fix, so it seems worth deciding separately.
int (x)compiles tofloat (x) | 0. JavaScript's|converts its left operand with ToInt32, so the result is always a signed 32 bit integer. Arguments outside-2**31 ... 2**31 - 1come back wrong, multiples of2**32come back as 0.Reproducer
CPython:
Transcrypt:
Run with 3.7.16 on Python 3.7, compiled with
-b -n -e 6and executed undernode. Line 291 of
__builtin__.jsis identical on current master.The failure is quiet. A memory size in kB, a file offset or a timestamp in microseconds passes 2**31 during normal operation and then yields a small or negative number instead of an error.
Testlet
For
development/automated_tests/transcrypt/div_issues/__init__.py:Possible fix
This makes
int ()exact over the whole range where a JavaScript number is exact, up to2**53 - 1, and leaves truncation toward zero for negative floats unchanged. With the patch applied the reproducer above matches CPython.Math.truncis ES6. The default target is esv 6 andjavascriptVersiongates nothing in the code generator, so no version switch is needed.inthas no callers inside the runtime.Note on NaN and Infinity
NaN | 0andInfinity | 0currently yield 0, where CPython raisesValueErrorandOverflowError. The version above keeps the 0 to stay minimal. Raising instead would match CPython but changes behaviour beyond the range fix, so it seems worth deciding separately.