Limiting floats to two decimal points

前端 未结 28 2876
你的背包
你的背包 2020-11-21 04:57

I want a to be rounded to 13.95.

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

The ro

相关标签:
28条回答
  • 2020-11-21 05:27

    TLDR ;)

    The rounding problem of input / output has been solved definitively by Python 2.7.0 and 3.1.

    A correctly rounded number can be reversibly converted back and forth:
    str -> float() -> repr() -> float() ... or Decimal -> float -> str -> Decimal
    A Decimal type is not necessary for storage anymore.


    (Naturally, it can be necessary to round a result of addition or subtraction of rounded numbers to eliminate the accumulated last bit errors. An explicit Decimal arithmetic can be still handy, but a conversion to string by str() (that is with rounding to 12 valid digits) is good enough usually if no extreme accuracy or no extreme number of successive arithmetic operations is required.)

    Infinite test:

    import random
    from decimal import Decimal
    for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
        assert float(repr(x)) == x                # Reversible repr() conversion.
        assert float(Decimal(repr(x))) == x
        assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
        if x >= 0.1:                              # Implicit rounding to 12 significant digits
            assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
            y = 1000 * x                             # Decimal type is excessive for shopping
            assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)
    

    Documentation

    See the Release notes Python 2.7 - Other Language Changes the fourth paragraph:

    Conversions between floating-point numbers and strings are now correctly rounded on most platforms. These conversions occur in many different places: str() on floats and complex numbers; the float and complex constructors; numeric formatting; serializing and de-serializing floats and complex numbers using the marshal, pickle and json modules; parsing of float and imaginary literals in Python code; and Decimal-to-float conversion.

    Related to this, the repr() of a floating-point number x now returns a result based on the shortest decimal string that’s guaranteed to round back to x under correct rounding (with round-half-to-even rounding mode). Previously it gave a string based on rounding x to 17 decimal digits.

    The related issue


    More information: The formatting of float before Python 2.7 was similar to the current numpy.float64. Both types use the same 64 bit IEEE 754 double precision with 52 bit mantissa. A big difference is that np.float64.__repr__ is formatted frequently with an excessive decimal number so that no bit can be lost, but no valid IEEE 754 number exists between 13.949999999999999 and 13.950000000000001. The result is not nice and the conversion repr(float(number_as_string)) is not reversible with numpy. On the other hand: float.__repr__ is formatted so that every digit is important; the sequence is without gaps and the conversion is reversible. Simply: If you perhaps have a numpy.float64 number, convert it to normal float in order to be formatted for humans, not for numeric processors, otherwise nothing more is necessary with Python 2.7+.

    0 讨论(0)
  • 2020-11-21 05:28

    There are new format specifications, String Format Specification Mini-Language:

    You can do the same as:

    "{:.2f}".format(13.949999999999999)
    

    Note 1: the above returns a string. In order to get as float, simply wrap with float(...):

    float("{:.2f}".format(13.949999999999999))
    

    Note 2: wrapping with float() doesn't change anything:

    >>> x = 13.949999999999999999
    >>> x
    13.95
    >>> g = float("{:.2f}".format(x))
    >>> g
    13.95
    >>> x == g
    True
    >>> h = round(x, 2)
    >>> h
    13.95
    >>> x == h
    True
    
    0 讨论(0)
  • 2020-11-21 05:28

    The answers I saw didn't work with the float(52.15) case. After some tests, there is the solution that I'm using:

    import decimal
            
    def value_to_decimal(value, decimal_places):
        decimal.getcontext().rounding = decimal.ROUND_HALF_UP  # define rounding method
        return decimal.Decimal(str(float(value))).quantize(decimal.Decimal('1e-{}'.format(decimal_places)))
    

    (The conversion of the 'value' to float and then string is very important, that way, 'value' can be of the type float, decimal, integer or string!)

    Hope this helps anyone.

    0 讨论(0)
  • 2020-11-21 05:29

    Use

    print"{:.2f}".format(a)
    

    instead of

    print"{0:.2f}".format(a)
    

    Because the latter may lead to output errors when trying to output multiple variables (see comments).

    0 讨论(0)
提交回复
热议问题