Convert scientific to decimal – dynamic float precision?

Question:

I have a random set of numbers in a SQL database:

1.2
0.4
5.1
0.0000000000232
1
7.54
0.000000000000006534

The decimals way below zero are displayed as scientific notation

num =  0.0000000000232
print(num)
> 2.23e-11

But that causes the rest of my code to bug out as the api behind it expects a decimal number. I checked it as I increased the precision with :.20f – that works fine.

Since the very small numbers are not constant with their precision, It would be unwise to simply set a static .20f.

What is a more elegant way to translate this to the correct decimal, always dynamic with the precision?

Asked By: Dalalama231123

||

Answers:

If Python provides a way to do this, they’ve hidden it very well. But a simple function can do it.

def float_to_str(x):
    to_the_left = 1 + floor(log(x, 10))
    to_the_right = sys.float_info.dig - to_the_left
    if to_the_right <= 0:
        s = str(int(x))
    else:
        s = format(x, f'0.{to_the_right}f').rstrip('0')
    return s

>>> for num in [1.2, 0.4, 5.1, 0.0000000000232, 1, 7.54, 0.000000000000006534]:
    print(float_to_str(num))

1.2
0.4
5.1
0.0000000000232
1.
7.54
0.000000000000006534

The first part uses the logarithm base 10 to figure out how many digits will be on the left of the decimal point, or the number of zeros to the right of it if the number is negative. To find out how many digits can be to the right, we take the total number of significant digits that a float can hold as given by sys.float_info.dig which should be 15 on most Python implementations, and subtract the digits on the left. If this number is negative there won’t be anything but garbage after the decimal point, so we can rely on integer conversion instead – it never uses scientific notation. Otherwise we simply conjure up the proper string to use with format. For the final step we strip off the redundant trailing zeros.

Using integers for large numbers isn’t perfect because we lose the rounding that naturally occurs with floating point string conversion. float_to_str(1e25) for example will return '10000000000000000905969664'. Since your examples didn’t contain any such large numbers I didn’t worry about it, but it could be fixed with a little more work. For the reasons behind this see Is floating point math broken?

Answered By: Mark Ransom
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.