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