1

I'm pretty sure that I'm doing this correctly but not getting the results that I expect from Python 2.7.3 string formatting mini-language. I'm trying to format the output of a float to 3 integer values and a varying number of decimal values. Everything works except the integer values.

By itself, the following code works to get me 3 integer values...

num = 3
value = '{:03}'.format(num)

returns '003'

And floats work...

num = 3.12345
value = '{:01.2f}'.format(num)

returns '3.12'

However, combining the two does not seem to work properly. The decimal precision works, but the integer precision does not...

num = '3.12345'
value = '{:03.2f}'.format(num)

returns '3.12'

instead of the expected '003.12'

The same is true if I try any of the following formats...

value = '{:03.02f}'.format(num)
- or -
value = '{0:3.2f}'.format(num)
- or -
value = '{:3.02f}'.format(num)
- or -
value = '{0:3.02f}'.format(num)
- or -
value = '{0:03.2f}'.format(num)
- or -
value = '{0:03.02f}'.format(num)
- or -
value = '{:0>3.2f}'.format(num)
etc...

Which all return the same '3.12' instead of '003.12'

If you're curious about what I'm doing for the varying / dynamic decimal precision, the point is to keep all the values the same length, but different sets of values may not have the same precision. So I take the smaller of the longest precision value or 10 and force the others to match like this..

from decimal import Decimal

dVals = [
    abs(Decimal(val1).as_tuple().exponent), # Get the number of decimal points
    abs(Decimal(val2).as_tuple().exponent), # "" ""
    abs(Decimal(val3).as_tuple().exponent), # "" ""
    abs(Decimal(val4).as_tuple().exponent), # "" ""
    ]

    p = max(dVals)  # Get the largest value
    p = min(p, 10)  # Get the smaller of the largest value or 10

vals = [val1, val2, val3, val4]

for val in vals:
    value = '{:0>3.{prec}f}'.format(val, prec = p)
    # do whatever with value here...

Again, this all works perfectly, except that the integer value never returns with 3 precision places when I combine it with float precision. So all my efforts to ensure the values output with the same formatted length are all for naught. Ultimately, the output should look similar to...

'009.123456700'
'180.101010101'
'054.987654321'

Instead, it looks like this...

'9.123456700'
'180.101010101'
'54.987654321'

In other words, ugly. :-|

At the very least, I would accept the following output...

'  9.123456700'
'180.101010101'
' 54.987654321'

Any ideas what I'm doing wrong here? Your help is much appreciated!

Regards,

-RMWChaos

RMWChaos
  • 885
  • 1
  • 11
  • 11

2 Answers2

6

The first digit is the total width of the result, not the width before the decimal point.

>>> '{:06.2f}'.format(3.12345)
'003.12'
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 1
    `The first digit is the total width of the result`, including the dot. – KurzedMetal Jun 07 '12 at 15:14
  • Yep, that was it. First digit is the total length of the output including the decimal point, not just the length of the integer portion of the value. :facepalm: Thank you! – RMWChaos Jun 07 '12 at 15:19
1
num = '3.12345'
value = '{:03.2f}'.format(num)

Here 03 takes into account all digits (including the floating point itself). so you should do something like this:

value = '{:06.2f}'.format(num)

this will get you: '003.12'

count everything in this string '003.12', the result is 6. But you were using 3 which is even less than the count of the minimal representation, which is why you got '3.12'

Amr
  • 695
  • 4
  • 11