Java – The results are different in Python v 3.5.2 and v 2.7.12, but is v 2.7.12 correct?

The results are different in Python v 3.5.2 and v 2.7.12, but is v 2.7.12 correct?… here is a solution to the problem.

The results are different in Python v 3.5.2 and v 2.7.12, but is v 2.7.12 correct?

Let me start by saying that I know that around Python 3, “infinite length” is integrated into int, so effective ints in Python can be as large as your RAM.

I’m comparing Java and Python.
Below are Python and Java programs, respectively. They do the same thing.

python :

def answer(n):
    count = 0
    t = int(n)
    while (t!=1):
        t = t+1 if (t%2==1) else t/2
        count += 1
    return count

Java:

static int answer(String n){
    int count = 0;
    BigInteger t = new BigInteger(n)

while(!t.equals(BigInteger.ONE)){
        t = ((t.remainder(new BigInteger("2"))).equals(BigInteger.ONE))
            ?t.add(new BigInteger("1"))
            :t.divide(new BigInteger("2"));
        count++;
    }
    return count;
}

Then I wrote a simple bash script to run java and python (versions 2.7.12 and 3.5.2) and compare their outputs.

#!/bin/bash
    i=$1
    a=`java    Solution    $i`
    b=`python  Solution.py $i`
    c=`python3 Solution.py $1`

echo "INPUT: $1"
    echo ""
    echo "LANGUAGE: VERSION:  RESULT:"
    echo "--------  --------- ------"
    echo "Java      1.8.0_151   $a"
    echo "Python    2.7.12      $b"
    echo "Python3   3.5.2       $c"

Here are some example runs. The result column is important.

INPUT: 123

LANGUAGE: VERSION:  RESULT:
--------  --------- ------
Java      1.8.0_151   9
Python    2.7.12      9
Python3   3.5.2       9

INPUT: 123456789

LANGUAGE: VERSION:  RESULT:
--------  --------- ------
Java      1.8.0_151   39
Python    2.7.12      39
Python3   3.5.2       39

INPUT: 12345678998765

LANGUAGE: VERSION:  RESULT:
--------  --------- ------
Java      1.8.0_151   61
Python    2.7.12      61
Python3   3.5.2       61

INPUT: 123456789987654321

LANGUAGE: VERSION:  RESULT:
--------  --------- ------
Java      1.8.0_151   84
Python    2.7.12      84
Python3   3.5.2       82

So they almost all produce the same result until the input becomes large enough and then you can see that the last result is different. Almost every number greater than this produces different results.

Shouldn’t Python3’s int and Java’s BigInteger get the same result?

Shouldn’t Python v.2 be the version that gets different results?

Which one is actually wrong and why? Java and Python3 or just Python v.2.7.12?

How do I correct errors to get the right output?

Solution

This issue is really not related to the limitation of integer literals in Python 2. That’s just a matter of distraction. Your real problem is that the division operator / behaves differently in Python 2 than it does in Python 3.

PEP 238 documents this change :

The current division (/) operator has an ambiguous meaning for numerical arguments: it returns the floor of the mathematical result of division if the arguments are ints or longs, but it returns a reasonable approximation of the division result if the arguments are floats or complex. This makes expressions expecting float or complex results error-prone when integers are not expected but possible as inputs.

We propose to fix this by introducing different operators for different operations: x/y to return a reasonable approximation of the mathematical result of the division (“true division”), x// y to return the floor (“floor division”). We call the current, mixed meaning of x/y “classic division”.

Because of severe backwards compatibility issues, not to mention a major flamewar on c.l.py, we propose the following transitional measures (starting with Python 2.2):

  • Classic division will remain the default in the Python 2.x series;
    true division will be standard in Python 3.0.

  • The // operator will be available to request floor division
    unambiguously.

  • The future division statement, spelled from __future__ import<br/>
    division
    , will change the / operator to mean true division throughout
    the module.

  • A command line option will enable run-time warnings for classic
    division applied to int or long arguments; another command line
    option will make true division the default.

  • The standard library will use the future division statement and the
    // operator when appropriate, so as to completely avoid classic
    division.

So, if you want your Python code to run correctly when input is 123456789987654321, you need to use the floor division operator :

def answer(n):
    count = 0
    t = int(n)
    while t != 1:
        t = t + 1 if (t % 2==1) else t // 2
        count += 1
    return count

Related Problems and Solutions