int () truncates its result to 32 bits

Open Beginner friendly
#911 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
javascript, python
Domain
compilers

Research direction

Start at line 291 of builtin.js, where int() currently uses the JavaScript bitwise conversion, and review development/automated_tests/transcrypt/div_issues/init.py for the Issue 911 testlet. Make the large-integer checks pass while preserving truncation toward zero for negative floats, then run the testlet under Node with the stated compiler options.

Written by the indexing model from the issue text.

Description

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.

Dominant language
Python
Stars
2.9k
Forks
218
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from TranscryptOrg/Transcrypt

All issues in TranscryptOrg/Transcrypt

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.