17

Python is supposed to have "arbitrary precision integers," according to the answer in Python integer ranges. But this result is plainly not arbitrary precision:

$ python -c 'print("%d" % (999999999999999999999999/3))'
333333333333333327740928

According to PEP 237, bignum is arbitrarily large (not just the size of C's long type). And Wikipedia says Python's bignum is arbitrary precision.

So why the incorrect result from the above line of code?

smci
  • 26,085
  • 16
  • 96
  • 138
Jeff Snider
  • 740
  • 1
  • 6
  • 20
  • In my box it works as expected, even by increasing the number of 9's – Paulo Bu Jan 09 '14 at 21:06
  • Well, the problem seems to be only on Python3 and the `print` statement – Paulo Bu Jan 09 '14 at 21:08
  • 10
    Python *does* have arbitrary precision integers. The number your code creates is not an integer. –  Jan 09 '14 at 21:14
  • 1
    a mere `python3 -c "print(999999999999999999999999 / 3)"` would show you the issue immediately (it prints a float instead of integer). – jfs Jan 09 '14 at 21:42

1 Answers1

30

Actually in python3 whenever you divide ints you get float as a result. There is a // operator that does integer division:

 >>> 999999999999999999999999/3
 3.333333333333333e+23
 >>> 999999999999999999999999//3
 333333333333333333333333

 >>> type(999999999999999999999999/3)
 <class 'float'>
 >>> type(999999999999999999999999//3)
 <class 'int'>

This does give the correct arbitrary precision output:

 python -c 'print("%d" % (999999999999999999999999//3))' 
 333333333333333333333333

How to write code compatible with both python 2.2+ and 3.3

This is actually simple, just add:

 >>> from __future__ import division 

this will enable 3.X division in 2.2+ code.

>>> from sys import version 
>>> version
'2.7.6 (default, Dec 30 2013, 14:37:40) \n[GCC 4.8.2]'
>>> from __future__ import division 
>>> type(999999999999999999999999//3)
<type 'long'>
>>> type(999999999999999999999999/3)
<type 'float'>
jb.
  • 20,419
  • 16
  • 91
  • 130
  • This does give the correct arbitrary precision output: $ python -c 'print("%d" % (999999999999999999999999//3))' 333333333333333333333333 – Jeff Snider Jan 09 '14 at 21:21
  • 4
    Note that the `//` operator is available *since [Python2.2](http://www.python.org/dev/peps/pep-0238/)* (released around 2001 I believe). So it's *not* a python3 feature. – Bakuriu Jan 09 '14 at 21:24
  • 1
    @Bakuriu I think what he meant is that in python2 `//` is assumed for `/` between two integers, whereas in python3 you need to call it explicitly. – SethMMorton Jan 09 '14 at 21:25
  • @SethMMorton Yes, but it's not really clear from the answer. One might think that, since in python2 the behaviour is different there is no `//` operator. This add a bit of complexity if someone wants to write code compatible with both versions. I just wanted to make clear that using `//` does *not* introduce any problem in this sense. – Bakuriu Jan 09 '14 at 21:27