I don't care about the placement of the decimal point, and would like to print in scientific notation when appropriate to display with maximum accuracy. However, I would like to round appropriately to maintain a fixed width, ragged left or ragged right is fine.
e.g.
>>> my_format("{:10f}", 0.0000000456)
" 4.56e-08"
>>> my_format("{:10f}", 12.345678987654321)
" 12.345679"
#or "12.34567890" because significant digits
#but not "1.2346e+01", since it is less accurate than the above representations
>>> my_format("{:10f}", 12345678987654321)
"1.2345e+16"
EDIT to clarify the examples, the width formatting specifier does not provide a fixed width. It provides a minimum width. How do I obtain a fixed width representation?
the g format specifier is generally good if you want scientific notation, i.e:
my_format = "{:.10g}".format
should do the right thing:
>>> list(my_format(v) for v in (0.0000000456, 12.345678987654321, 12345678987654321))
['4.56e-08', '12.34567899', '1.234567899e+16']
I realised later that the above function doesn't do what the OP wanted
Based on helpful comments from @a_guest I've come up with the following:
def my_format(v, length=10):
n = length
while n > 0:
i = len('%#.*g' % (n, v))
s = '%.*g' % (n + n - i, v)
if len(s) <= length:
return s
n -= 1
return s
I now get ['4.56e-08', '12.345679', '1.2346e+16'] back which is closer to what was wanted.
I've tested this by generating a lot of random numbers using:
from random import uniform
def rnd_float():
return uniform(-10, 10) * 10 ** (uniform(-1.6, 1.6) ** 11)
pretty arbitrary, but generates numbers reasonably close to the distribution I care about. I.e. mostly around 1, but some very small and large with decent probability.
I've passed numbers from this to my_format 100k times and I get appropriately formatted numbers back.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With