# How to solve floating number issue in GNU units-like app?

Hello Python Discourse, First of all, thank you for reading this. I hope you have a nice day. I have a question, I want to make miniature calculator app like GNU units but I am stumbling with floating-point number precision (if this word correct to describe my problem ), This the code I make;

``````import sys

length = {
"yottameter": 1e24,
"zettameter": 1e21,
"exameter": 1e18,
"petameter": 1e15,
"terameter": 1e12,
"gigameter": 1e9,
"megameter": 1e6,
"kilometer": 1e3,
"hectometer": 1e2,
"decameter": 1e1,
"meter": 1e-0,
"decimeter": 1e-1,
"centimeter": 1e-2,
"millimeter": 1e-3,
"micrometer": 1e-6,
"nanometer": 1e-9,
"picometer": 1e-12,
"femtometer": 1e-15,
"attometer": 1e-18,
"zeptometer": 1e-21,
"yoctometer": 1e-24,
}

def split_args(input_args) -> list:
list_input = input_args.split(" ", 1)
return list_input

def check_input(input: str):
args = split_args(input)
if args[1] in length.keys():
pass
else:
print("unit not implemented yet!")
sys.exit()

def check_input_wanted(input: str):
if input in length.keys():
pass
else:
print("unit not implemented yet!")
sys.exit()

def convert_to_primitive(unit: list) -> float:
primitive_value = length.get(unit[1]) * float(unit[0])
return primitive_value

def convert_to_wanted_value(primitive_value: float, wanted_result: str) -> float:
result = primitive_value / length.get(wanted_result)
return result

def main():
input_questions: str = input("You have = ")
input_wanted_result: str = input("You want = ")
check_input(input_questions)
check_input_wanted(input_wanted_result)
input_value = split_args(input_questions)
if input_wanted_result != "meter":
convert = convert_to_primitive(input_value)
result = convert_to_wanted_value(convert, input_wanted_result)
print(result, input_wanted_result)
elif input_wanted_result == "meter":
convert = convert_to_primitive(input_value)
print(convert, input_wanted_result)
else:
print("Error")

if __name__ == "__main__":
main()
``````

when the input is not too big it’s okay:

``````❯ python .\pyunits\pyunits.py
You have = 100 meter
You want = kilometer
0.1 kilometer
``````

But when the input is too big the answer will be like this:

``````❯ python .\pyunits\pyunits.py
You have = 1 meter
You want = nanometer
999999999.9999999 nanometer
``````

How do i solve this problem, any pointer will be appreciated.

Not sure if this helps, but if you limit the number of decimal places, you could do this:

``````meter = 1

nanometer = 1e-9

output = meter / nanometer

print(output)

output2="{:.6f}".format(output)

print(output2)
``````

or…
`print(round(output, 6))`

By Gunung P. Wibisono via Discussions on Python.org at 15May2022 07:27:

Hello Python Discourse, First of all, thank you for reading this. I
hope you have a nice day. I have a question, I want to make miniature
calculator app like GNU units
but I am stumbling with floating-point number precision (if this word
correct to describe my problem ), This the code I make;

``````import sys

length = {
"yottameter": 1e24,
"zettameter": 1e21,
"exameter": 1e18,
"petameter": 1e15,
"terameter": 1e12,
"gigameter": 1e9,
"megameter": 1e6,
"kilometer": 1e3,
"hectometer": 1e2,
"decameter": 1e1,
"meter": 1e-0,
"decimeter": 1e-1,
"centimeter": 1e-2,
"millimeter": 1e-3,
"micrometer": 1e-6,
"nanometer": 1e-9,
"picometer": 1e-12,
"femtometer": 1e-15,
"attometer": 1e-18,
"zeptometer": 1e-21,
"yoctometer": 1e-24,
}
``````

[…]

def convert_to_primitive(unit: list) → float:
primitive_value = length.get(unit[1]) * float(unit[0])
return primitive_value
def convert_to_wanted_value(primitive_value: float, wanted_result: str) → float:
result = primitive_value / length.get(wanted_result)
return result
[…]
if input_wanted_result != “meter”:
convert = convert_to_primitive(input_value)
result = convert_to_wanted_value(convert, input_wanted_result)
print(result, input_wanted_result)
[…]
❯ python .\pyunits\pyunits.py
You have = 1 meter
You want = nanometer
999999999.9999999 nanometer

This is because floating point is not a precise expression of fractional
decimal values. The underlying representation is base 2, and therefore
dividing by a multiple of 10, which is the product of 2*5, is inherently
inaccurate. As you can see above, not very inaccurate because floats
have quite a lot of precision; however that precision is finite.

You could do a lot of fiddly mucking about to avoid division, but even
then you’d be at the mercy of the finite resolution of a float - it has
a fixed number of significant digits.

Instead, have a look at the `decimal` module:
https://docs.python.org/3/library/decimal.html#module-decimal

It exists expressly to preform base 10 arithmetic, and should do what
you need. Make sure you set the precision to sufficient digits - its
default is 28 digits, but your scale looks like it needs at least 49
digits, plus a bit more to accomodate whatever value the user might
have.

Cheers,
Cameron Simpson cs@cskk.id.au