Question

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
Was it helpful?

Solution

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 :

  • two numbers x and y are to be considered as equals if | x - y | < ε
  • the greatest integer inferior to x is floor(x + ε)
  • the least integer greater than x is 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.

OTHER TIPS

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top