Qin Heyang
Qin Heyang

Reputation: 1674

print floats in scientific notation without extra precision

I need some strings of floats in scientific notation such as ['5e-6','1e-5','1.5e-5','2e-5','2.5e-5',...].

So I try to generate them with [str(n*1e-6) for n in list(range(5,60,5))] yet it gives ['4.9999999999999996e-06', '9.999999999999999e-06', '1.4999999999999999e-05',...].

Then I try to format them with ["{:.1e}".format(n*1e-6) for n in list(range(5,60,5))] and it gives ['5.0e-06', '1.0e-05', '1.5e-05', '2.0e-05', '2.5e-05',...] which are still not what I want.

I wonder is there any simple way to do this other than writing a custom function? Thanks.

Upvotes: 1

Views: 462

Answers (2)

atru
atru

Reputation: 4744

This works for your specific example, but note that it's quite hardcoded:

["{:.0e}".format(n*1e-6) if not n%10 or n<10 else "{:.1e}".format(n*1e-6) for n in list(range(5,60,5))]

Here you change the format for numbers that you don't want to display with any decimal part, but you still display the x.5 numbers properly. The code makes an exception for 5, otherwise it would be printed with a decimal.

This is a version that fully addresses your question - it also removes the trailing 0 in the exponent:

["{:.0e}".format(n*1e-6).replace("e-0", "e-") if not n%10 or n<10 else "{:.1e}".format(n*1e-6).replace("e-0", "e-") for n in list(range(5,60,5))]

replace trick comes from this post - as stated in there, you'd need to extend it for e+0.

Upvotes: 1

pho
pho

Reputation: 25490

You could just replace the .0e part with e.

["{:.1e}".format(n*1e-6).replace(".0e", "e") for n in list(range(5,60,5))]

This gives

['5e-06',  '1e-05',  '1.5e-05',  '2e-05',  '2.5e-05',  '3e-05',  '3.5e-05',  '4e-05',  '4.5e-05',  '5e-05',  '5.5e-05']

Which still leaves us with the leading zero in the exponent. To get rid of that, we can use a regular expression:

(e-?)0(\d+)

Explanation: https://regex101.com/r/8bXvDH/1

  • (e-?): Match a literal e followed by an optional minus sign. Capturing group 1
  • 0: Match a literal zero
  • (\d+): Match one or more digits. Capturing group 2.

To do the substitution, we use re.sub():

# \1\2 in the replace string means capturing group 1, then capturing group 2
re.sub(r"(e-?)0(\d+)", r"\1\2", "5e-06") # Gives "5e-6"

In our list compregension:

[re.sub(r"(e-?)0(\d+)", r"\1\2", "{:.1e}".format(n*1e-6).replace(".0e", "e")) for n in list(range(5,60,5))]

gives what we want:

['5e-6',  '1e-5',  '1.5e-5',  '2e-5',  '2.5e-5',  '3e-5',  '3.5e-5',  '4e-5',  '4.5e-5',  '5e-5',  '5.5e-5']

Upvotes: 1

Related Questions