Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange results with C++ ceiling function

Tags:

c++

ceil

I've been trying the ceiling function and have been getting some strange results. If I perform the ceil operation on a decimal number multiplied by hundred I get a certain result. However if i directly perform ceil on the result of that multiplication I get a completely different output. Another twist is that these different results only occur for certain numbers. Any help would be appreciated.

#include <stdio.h>
#include <cmath>

int main ()
{
cout << "The ceiling of " << 411 << " is " << ceil(411) << endl;
cout << "The ceiling of 4.11*100  is " << ceil(4.11*100) << endl;

cout << "The ceiling of  " << 121 << " is " << ceil(121) << endl;
cout << "The ceiling of 1.21*100  is " << ceil(1.21*100) << endl;;
}


OUTPUT:

The ceiling of 411 is 411
The ceiling of 4.11*100  is 412
The ceiling of  121 is 121
The ceiling of 1.21*100  is 121
like image 665
sowmya Avatar asked Apr 06 '11 06:04

sowmya


3 Answers

The problem here is that floating-point numbers cannot be reliably represented by computer. That means, 4.11 is not represented as 4.11, but something very close to it. And when this "very close to 4.11" number is multiplied by 100, the ceil of the product turns out to be 412, much to your surprise! But once you know how floating-point numbers are stored and retrieved, it's not a surprise at all.


Just see this interesting demonstration:

float a = 3.2; //3.2 is double!
if ( a == 3.2 )
    cout << "a is equal to 3.2"<<endl;
else
    cout << "a is not equal to 3.2"<<endl;

float b = 3.2f; //3.2f is a float. Note: f is appended to make it float!
if ( b == 3.2f )
    cout << "b is equal to 3.2f"<<endl;
else
    cout << "b is not equal to 3.2f"<<endl;

Output:

a is not equal to 3.2
b is equal to 3.2f

Do experiment here at ideone: http://www.ideone.com/pAGzM

Try changing the type of the variable a from float to double, see the result again.

like image 64
Nawaz Avatar answered Sep 28 '22 06:09

Nawaz


From the FAQ:

[29.16] Why is floating point so inaccurate? Why doesn't this print 0.43?

#include <iostream>

 int main()
 {
   float a = 1000.43;
   float b = 1000.0;
   std::cout << a - b << '\n';
   ...
 }

Disclaimer: Frustration with rounding/truncation/approximation isn't really a C++ issue; it's a computer science issue. However, people keep asking about it on comp.lang.c++, so what follows is a nominal answer.

Answer: Floating point is an approximation. The IEEE standard for 32 bit float supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa. Since a normalized binary-point mantissa always has the form 1.xxxxx... the leading 1 is dropped and you get effectively 24 bits of mantissa. The number 1000.43 (and many, many others, including some really common ones like 0.1) is not exactly representable in float or double format. 1000.43 is actually represented as the following bitpattern (the "s" shows the position of the sign bit, the "e"s show the positions of the exponent bits, and the "m"s show the positions of the mantissa bits):

 seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
 01000100011110100001101110000101

The shifted mantissa is 1111101000.01101110000101 or 1000 + 7045/16384. The fractional part is 0.429992675781. With 24 bits of mantissa you only get about 1 part in 16M of precision for float. The double type provides more precision (53 bits of mantissa).

Also, see [29.17] Why doesn't my floating-point comparison work?

like image 23
NPE Avatar answered Sep 28 '22 06:09

NPE


The ceil(x) function returns the smallest integral number not less then x.

Since the constants you type (like 4.11 or 1.21) is not represented precisely - they may happen to be represented with slightly smaller number or with slightly larger number or in rare cases with equal numbers. E.g. your compiler represents constant 4.11 as a slightly larger number so 4.11*100 happens to be slightly larger than 411 so ceil(4.11*100) == 412 (because 412 is the smallest number not less than the number slightly larger than 411), but 1.21 is represented as slightly smaller number so 1.21*100 is slightly smaller than 121 so ceil(1.21*100)==121.

Also note that multiplication is not precise too.

like image 26
Serge Dundich Avatar answered Sep 28 '22 07:09

Serge Dundich