Reputation: 17564
I need to convert numbers to a flat file format 0.57 becomes 000000000000000057 in this format (padding zeroes) My method
My method
def toAmount18(a):
return str(int(a*100)).zfill(18)
For 0.57 it outputes 000000000000000056
The problem lies in a*100 it outputs 56.99999999999999 instead of 57. Ideas?
Upvotes: 0
Views: 98
Reputation: 4075
You could avoid maths altogether and invite regex to the party:
re.search(r'\.(\d{,2})', str(0.5)).group(1).zfill(18)
'000000000000000005'
re.search(r'\.(\d{,2})', str(0.57)).group(1).zfill(18)
'000000000000000057'
re.search(r'\.(\d{,2})', str(0.571)).group(1).zfill(18)
'000000000000000057'
re.search(r'\.(\d{,2})', str(0.579)).group(1).zfill(18)
'000000000000000057'
Might need some more sample inputs to get this tuned correctly for the expected output.
Upvotes: 0
Reputation: 149185
It is a floating point accuracy problem. In the early days of Fortran IV, we learned that the conversion from a float to an integer value was I = F + .5
Here you can still use the same trick:
def toAmount18(a):
return str(int(a*100 + .5)).zfill(18)
or use more modern tools like round
return str(round(a*100)).zfill(18)
The nice point with the manual method is that you can specify the truncation magnitude to your needs:
return str(int(a*100 + .00005)).zfill(18)
will only round after the 4th decimal.
Upvotes: 1
Reputation: 1
Using int() as default works like a floor on the input number.
Try to use round() method instead of int() as shown in example: https://www.programiz.com/python-programming/methods/built-in/round
You can also add an extra security layer (try statement) which will handle wrong type exceptions.
Upvotes: 0