Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python float precision with no integer precision after decimal point

While working with float precision, I stumbled across a strange fact. Why does python prints only the integer part when formatted with "%.f". I am willing to know the mechanism behind this

 >>> a = float(2.12345)
 >>> a
 2.12345
 >>> print "%.2f" % a
 2.12
 >>> print "%.1f" % a
 2.1
 >>> print "%f" % a
 2.123450
 >>> print "%.f" % a
 2                   #why?

Thanks in advance for the explanation :)

like image 254
TerminalWitchcraft Avatar asked Apr 13 '16 12:04

TerminalWitchcraft


People also ask

What is .2f in Python?

2f means to round up to two decimal places. You can play around with the code to see what happens as you change the number in the formatter.

How do you print 2 digits after a decimal in Python?

In Python, to print 2 decimal places we will use str. format() with “{:. 2f}” as string and float as a number. Call print and it will print the float with 2 decimal places.

Can float type in Python 3 represent 0.1 without error?

Python 3's float repr is designed to be round-trippable, that is, the value shown should be exactly convertible into the original value ( float(repr(f)) == f for all floats f ). Therefore, it cannot display 0.3 and 0.1*3 exactly the same way, or the two different numbers would end up the same after round-tripping.


Video Answer


3 Answers

It's been that way ever since % formatting was added back in 1993; if a . is not followed by a decimal number then precision is taken as zero.

This is undocumented, but is consistent with printf, which Python's % formatting was inspired by:

(optional) . followed by integer number or *, or neither that specifies precision of the conversion. In the case when * is used, the precision is specified by an additional argument of type int. If the value of this argument is negative, it is ignored. If neither a number nor * is used, the precision is taken as zero.

Interestingly, another undocumented feature also inspired by printf is that you can use * as precision, as above:

>>> "%6.*f" % (2, 1.234)
'  1.23'
like image 134
ecatmur Avatar answered Oct 05 '22 15:10

ecatmur


The docs for precision here don't mention a default if the precision is ommitted. I can only assume it just works this way because it does!

The docs give the default precision for a %f as 6 in the format specification mini language here. Maybe by specifying a precision with the . and then by omitting an integer value, the interpreter assumes it should be zero?

This may even behave differently on different interpreters. Interesting find anyway :).

Interestingly, using str.format throws a nice ValueError in my 2.7 interpreter:

>>> f = 234.12345676
>>> "{:.f}".format(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Format specifier missing precision
like image 43
srowland Avatar answered Oct 05 '22 13:10

srowland


The % operator has the following behavior, like you observed:

>>> "%.f" % 1.23
'1'

The parser goes through the format string, with the precision being undefined (-1) by default. When it hits the ., the precision will be set to 0. The arguments will be passed to the helper function formatfloat which uses the default precision 6 if no precision is given, and no . is used.

An interesting note is that str.format() will actually throw an exception in this case, probably for easier implementation and not letting people rely on unspecified behavior:

>>> "{:.f}".format(1.23)
Traceback (most recent call last):
  File "<ipython-input-6-677ba2e4a680>", line 1, in <module>
    "{:.f}".format(1.23)
ValueError: Format specifier missing precision
like image 34
André Laszlo Avatar answered Oct 05 '22 14:10

André Laszlo