Reputation: 103
I am using the ceil() function to round the result of a floating point calculation up to the nearest integer. All sorts of different inputs are experienced...
int(ceil(A*B))
Here are some examples to illustrate the problem:
int(ceil(1.01*100)) = 101
int(ceil(1.02*100)) = 102
int(ceil(1.03*100)) = 103
int(ceil(1.04*100)) = 104
int(ceil(1.05*100)) = 105
int(ceil(1.06*100)) = 106
int(ceil(1.07*100)) = 107
int(ceil(1.08*100)) = 108
int(ceil(1.09*100)) = 110 ***
int(ceil(1.10*100)) = 111 ***
int(ceil(1.11*100)) = 112 ***
int(ceil(1.12*100)) = 113 ***
int(ceil(1.13*100)) = 113
I realise this is to do with the floating point calculation being performed...
1.09*100 = 109.000000.... > 109
I have no idea how to trap this bug reliably
Although i have a couple of 'crude' methods such as the one outlined below, I do not consider this to be a robust enough solution
int(ceil((1.09*100)-0.00000001)) = 109
Upvotes: 0
Views: 4942
Reputation: 148965
Your problem is neither new nor python specific but is inherent to floating point computations. All dynosaurus that once used Fortran 4 know it : you as the programmer have to know the expected precision ε of your computation. So :
| x - y | < ε
floor(x + ε)
ceil(x - ε)
So your proposed solution is the good one, provided you have a way to know what is the good value for ε. If you are writing a module you should allow users to specify it.
Upvotes: 3
Reputation: 44112
You are right, that the problem originates in limited precision of float number.
decimal
module is your friend:
from decimal import Decimal
from math import ceil
print int(ceil(Decimal("1.10") * 100))
Note, that you really have to provide the number as string, otherwise it is first parsed by Python as float number (and here we get the problem with precision we want to avoid).
Upvotes: 2