TerminalWitchcraft
TerminalWitchcraft

Reputation: 1852

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 :)

Upvotes: 6

Views: 5678

Answers (3)

André Laszlo
André Laszlo

Reputation: 15537

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

Upvotes: 1

ecatmur
ecatmur

Reputation: 157334

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'

Upvotes: 4

srowland
srowland

Reputation: 1705

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

Upvotes: 1

Related Questions