0

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?

Dalalama231123
  • 101
  • 1
  • 1
  • 7
  • 1
    I'd say the "more elegant way" *is* scientific notation. Is there any way of fixing the rest of your code to accept it that way, rather than "bugging out"? – Steve Summit Nov 18 '22 at 22:47
  • No, the api interface requires a decimal. So, changing it to decimal in my code would be the most possible way, I think. – Dalalama231123 Nov 18 '22 at 22:50
  • "But that causes the rest of my code to bug out as it expects a decimal number." Why would it cause a bug? You understand, the way the *object is printed* doesn't really matter... what, precisely, is the problem? – juanpa.arrivillaga Nov 18 '22 at 23:47
  • @Dalalama231123 what does it mean to say "the api interface requires a decimal". You understand, the way it displays by default **doesn't change anything about the nature of the `float` object itself**. So please provide **an actual description of your problem**. – juanpa.arrivillaga Nov 18 '22 at 23:48
  • If I pass it on 0.0000001 as float with 7 precision, it works (:.7f). If I pass it on without that, it gets an error of invalid characters. - updated problem description. – Dalalama231123 Nov 19 '22 at 00:02
  • 0.0000000000232 is not “way below zero.” It is above zero. – Eric Postpischil Nov 19 '22 at 00:28
  • 1
    What API are you using? Is it taking numbers as text strings? Where is its documentation? What version of Python are you using? – Eric Postpischil Nov 19 '22 at 00:30
  • `print ("%.9999f" % x).rstrip("0")` might do what you want. It formats the number with 9,999 digits after the decimal point and then removes trailing zeros. That is inefficient; there may be a better way to do it. – Eric Postpischil Nov 19 '22 at 00:37
  • "The decimals way below zero are displayed as scientific notation" --> Below zero? Maybe below _one_. – chux - Reinstate Monica Nov 19 '22 at 01:37

1 Answers1

1

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?

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622