Search code examples
pythonpython-3.xscientific-notation

Problem with Python Scientific Notation Suppress


To make things short, I have scientific notation 4.534524725984957e+16 and I am trying to get the suppression..

The correct number here is 45345247259849570...but python keeps returning wrong numbers like 45345247259849568...any ideas?


Solution

  • Recall that a Python float is a C double under the hood. It's stored in binary scientific notation.

    In binary, the 56-bit integer 45345247259849570 is represented as 10100001000110010100001100011011001011001111001101100010. Or in scientific notation, 1.0100001000110010100001100011011001011001111001101100010 × 255. (I've bolded the least-significant digits bolded for comparison.)

    The thing is, only 53 significant digits can be stored. So your number gets rounded down to 1.0100001000110010100001100011011001011001111001101100 × 255, which works out to 45345247259849568 in decimal.

    If you're not willing to accept this rounding error, the solution is to use the proper data type to store your numbers.

    The built-in int (or long if you're still using Python 2.x) can exactly store any integer (whole number) that can fit in a process's memory. Of course, it doesn't work if you have digits to the right of the decimal point.

    decimal.Decimal is a floating-point type that stores 28 decimal digits by default. It's great for financial calculations, in which “$0.01” means exactly 1/100 of a dollar, and not 0.01000000000000000020816681711721685132943093776702880859375.

    >>> from decimal import Decimal
    >>> Decimal('4.534524725984957e+16')
    Decimal('4.534524725984957E+16')
    

    However, non-decimal fractions like 1/3 are still only approximated.

    >>> Decimal(1) / Decimal(3)
    Decimal('0.3333333333333333333333333333')
    >>> _ * 3
    Decimal('0.9999999999999999999999999999')
    

    fractions.Fraction will exactly store any rational number as a numerator/denominator pair.

    >>> from fractions import Fraction
    >>> Fraction('4.534524725984957e+16')
    Fraction(45345247259849570, 1)