问题
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
回答1:
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.
回答2:
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?
回答3:
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.
来源:https://stackoverflow.com/questions/5562492/strange-results-with-c-ceiling-function