6

In Python, I am trying to convert floating point numbers to strings such that the string is exactly 12 characters long: the first character is a space and the remaining characters can be filled with the digits (and decimal point if needs be) of the number to be converted to a string. Also, the numbers need to be expressed in decimal form (no scientific notation). I am working inside a fixed format in a particular file; hence the exact parameters stated above. It can be assumed that all numbers I'm working with are less than 1e12, i.e., that all numbers can be expressed with

I am using

s = " %11f" % number

Most of the floating point numbers convert to a string fitting my formatting parameters just fine; however, some of the larger numbers don't. For example,

print " %11f" % 325918.166005444

gives 325918.166005. This takes up 13 characters, not 11.

Why is my code doing this, and how can I fix this? I'd like to keep as much precision as possible (i.e., simply truncating the fractional portion of the number is not a good enough solution).

If Python version is important, I'm using 2.7.

NeutronStar
  • 2,057
  • 7
  • 31
  • 49
  • @EvanWeissburg, each number will need a different `precision` value, depending on many whole digits there are. – NeutronStar Jun 27 '17 at 21:32
  • 2
    @EvanWeissburg I assume that's because rounding is required rather than truncating: "simply truncating the fractional portion of the number is not a good enough solution". Unless it's *my* turn to misread. – Mark Ransom Jun 27 '17 at 22:21

2 Answers2

5

You didn't specify a precision, so the default precision for floats, 6, is used. You need both width and precision to get a precise (pun not intended) output.

Also note that:

width is a decimal integer defining the minimum field width. If not specified, then the field width will be determined by the content.

So the precision does more to decide the overall width of the string here.

You could apply new style formatting to gain more control with specifying the width and precision:

>>> num = 325918.166005444
>>> w = 11
>>> " {:{w}.{p}f}".format(num, w=w, p=len(repr(num))-w-1) # subtract 1 for the dot
' 325918.1660'

This, however, assumes that your float is always larger than the width, otherwise, you could first pad the float with trailing zeros after the decimal.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
  • My float is not always larger than the width. And how could I pad a float with trailing zeroes? Floats don't store trailing zeroes. – NeutronStar Jun 27 '17 at 21:46
  • You can see https://stackoverflow.com/questions/8885663/how-to-format-a-floating-number-to-fixed-width-in-python and https://stackoverflow.com/questions/15619096/add-zeros-to-a-float-after-the-decimal-point-in-python – Moses Koledoye Jun 27 '17 at 21:51
  • 1
    When I try this solution with `num=1.1`, I get `ValueError: Format specifier missing precision`. – Mark Ransom Jun 27 '17 at 22:26
  • @MarkRansom Rightly so. Precision in that case is negative/invalid. OP never specified how they wish to handle floats that are shorter than their specified width. – Moses Koledoye Jun 27 '17 at 22:29
  • @MosesKoledoye, I never specified that the floats were to be longer than their specified width either. I do want something to handle both cases. – NeutronStar Jun 28 '17 at 00:52
  • So how should shorter lengths be handled? – Moses Koledoye Jun 28 '17 at 00:53
1

Building on Moses Koledoye's answer, here's what I got to work:

num = 325918.166005444
w = 11
p = w-len(str(int(num)))-1
if p <=0: # If it's short enough
   print " %11f" % num
else: # If it's too long
   print " {:{w}.{p}f}".format(num, w=w, p=p)
NeutronStar
  • 2,057
  • 7
  • 31
  • 49