Pete Lavelle
Pete Lavelle

Reputation: 103

ceil() function not returning expected value

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

Answers (2)

Serge Ballesta
Serge Ballesta

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 :

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

Upvotes: 3

Jan Vlcinsky
Jan Vlcinsky

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

Related Questions