10

I was struck by this default behavior of f-strings in python 3.7.2:

>> number = 0.0000001
>> string = f"Number: {number}"
>> print(string)
Number: 1e-07

What I expected was: Number: 0.0000001

This is very annoying especially for creation of filenames. How can I disable this automatic conversion into the scientific notation? And why is it enabled in the first place?

Basically the opposite of this question.

Edit: I would like to avoid setting a fixed length for the float via {number:.8f} since my numbers have different lengths and I don't want to have any trailing zeros. I want to use the f-strings to make filenames automatically, like this:

filename = f"number_{number:.10f}_other_number_{other_number:.10f}.json"

I am looking for a simple modifier that can disable the automatic scientific notation while keeping the original precision of the float.

mrzo
  • 2,002
  • 1
  • 14
  • 26
  • 1
    You need to define "original precision". Because `0.0000001` doesn't result in 0.0000001 but in 0.0000000999999999999999954748111825886258685613938723690807819366455078125. – Kelly Bundy Feb 26 '20 at 10:20
  • That is correct indeed. But why does it work for `number = 0.01` then? Is it because `0.01` is still in the standard precision of float? How could I make f-string to understand floats with higher precision? – mrzo Feb 26 '20 at 10:39
  • I don't know the reason, but it's more general than f-strings, `str(0.00001)` and `repr(0.00001)` also both result in `'1e-05'`. There's also an [older question](https://stackoverflow.com/q/658763/12671057) and nobody seems to have a nice answer. – Kelly Bundy Feb 26 '20 at 11:38
  • 1
    Oh, I did not find that question. https://stackoverflow.com/a/58106536/9144990 suggests numpy.format_float_positional which works for me. – mrzo Feb 26 '20 at 13:40
  • Hmm, somehow I overlooked that one. It's nice. – Kelly Bundy Feb 26 '20 at 13:56

2 Answers2

9

https://docs.python.org/3.4/library/string.html#format-specification-mini-language

>>> number = 0.0000001
>>> f"Number: {number}"
'Number: 1e-07'
>>> f"Number: {number:f}"
'Number: 0.000000'
>>> f"Number: {number:.10f}"
'Number: 0.0000001000'

By default :f has a precision of 6. You can change it to e.g. 10 with :.10f

Tin Nguyen
  • 5,250
  • 1
  • 12
  • 32
  • Thank you for your answer. I am sorry, I did not make it clear. I would like to avoid trailing zeros and adding a fixed amount of precision since my numbers have different lengths. I edited my question. – mrzo Feb 26 '20 at 09:27
  • 2
    Choose a big number and add `.rstrip('0')` on the `str` instance. If your number happens to be `"3.00000"` add `.rstrip('0').rstrip('.')` so your string doesn't end up being `"3."` – Tin Nguyen Feb 26 '20 at 09:31
  • I read the doc in your link before and there it is stated (in the table with the float modifiers under `None`): `[..] The default precision is as high as needed to represent the particular value.` Should not that mean it is printed as with the required precision by default? – mrzo Feb 26 '20 at 09:34
  • With `None` you are getting `1e-07`. This is why we are using `f` here. – Tin Nguyen Feb 26 '20 at 09:36
  • I am very sorry, I should have definitely give more context to my answer. My problem is that I would like to use the f-string as convenience to create filenames. The approach using `rstrip` would not work very well in a f-string like this: `f"number_{number:.10f}_other_number_{other_number:.10f}"`. Probably I need to work with replace or regex. – mrzo Feb 26 '20 at 09:47
  • Not saying it makes a difference, but... why link to the 3.4 documentation when the OP uses 3.7 and current is 3.8? – Kelly Bundy Feb 26 '20 at 10:10
  • 1
    @HeapOverflow my mistake. I should have matched the python version. I used the 3.4 documentation because it was linked in the other StackOverflow question which OP linked. at OP: I've been thinking of a one-liner but I don't think it is possible to achieve it in one line. You have to save the string value temporarily. – Tin Nguyen Feb 26 '20 at 10:39
1

After checking other sources, I found numpy.format_float_positional which works very nicely here:

import numpy as np
number = 0.0000001
string = f"Number: {np.format_float_positional(number)}"
mrzo
  • 2,002
  • 1
  • 14
  • 26