使用C++上限功能的奇怪结果

sow*_*mya 5 c++ ceil

我一直在尝试天花板功能,并得到了一些奇怪的结果.如果我对十进制数乘以百分比执行ceil操作,我得到一定的结果.但是如果我直接对该乘法的结果执行ceil,我得到一个完全不同的输出.另一个转折是这些不同的结果仅出现在某些数字上.任何帮助,将不胜感激.

#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
Run Code Online (Sandbox Code Playgroud)

Naw*_*waz 9

这里的问题是计算机无法可靠地表示浮点数.这意味着,4.11不是代表4.11,而是非常接近它.当这个"非常接近4.11"的数字乘以时100,ceil该产品的结果证明是412令人惊讶的!但是一旦你知道如何存储和检索浮点数,它就不足为奇了.


看看这个有趣的演示:

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;
Run Code Online (Sandbox Code Playgroud)

输出:

a不等于3.2
b等于3.2f

请在ideone上进行实验:http://www.ideone.com/pAGzM

试着改变变量的类型afloatdouble,请再次结果.

  • @sowmya:“如果我只是简单地乘以 4.11*100,我不应该得到 412” 不,你不应该。您将得到 411 + very_very_small_number。`ceil(411)` 将返回 411。但是 `ceil( 411 + very_very_small_number )` 返回 412。 (2认同)
  • 我会对原始答案中的措辞提出异议:浮点数在计算机上*是*准确且可靠的。问题是计算机浮点数不是实数,大多数实数不能用计算机浮点数表示,浮点运算不遵循实数运算规则。只有实数的无限小子集具有机器浮点数的表示(411 是其中之一,但 4.11 不是),并且 `a + (b + c)` 不一定与 `(a + b) + c`。) (2认同)

NPE*_*NPE 5

来自FAQ:

[29.16]为什么浮点数如此不准确?为什么不打印0.43?

#include <iostream>

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

免责声明:使用舍入/截断/近似的挫折并不是真正的C++问题; 这是一个计算机科学问题.但是,人们一直在comp.lang.c ++上询问它,所以接下来是一个名义上的答案.

:浮点是近似值.用于32位浮点的IEEE标准支持1位符号,8位指数和23位尾数.由于标准化的二进制点尾数始终具有1.xxxxx的形式...前导1被丢弃并且有效地获得24位尾数.数字1000.43(以及许多其他数据,包括一些非常常见的数字,如0.1)在浮点数或双精度格式中并不完全可表示.1000.43实际上表示为以下位模式("s"表示符号位的位置,"e"表示指数位的位置,"m"表示尾数位的位置):

 seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
 01000100011110100001101110000101
Run Code Online (Sandbox Code Playgroud)

移位的尾数是1111101000.01101110000101或1000 + 7045/16384.小数部分是0.429992675781.使用24位尾数,您只能得到大约1个16M精度的浮点数.double类型提供更高的精度(53位尾数).

另请参阅[29.17]为什么我的浮点比较不起作用?