ceil、floor 和 round 在转换为整数时会遇到精度损失问题吗?



我记得在某处读过一个例子,它说将双精度/浮点值转换为整数可能会导致错误,因为精度损失。例如

int a = 5.0000;

不能保证 a 等于 5,因为实际上 5.0000 可以存储为 4.9999 或其他东西......

我想知道使用ceil,地板和圆形是否会遇到类似的问题。例如,请考虑以下代码。

double a = ***; //some double-precision value
int b = ceil(a);
long c = floor(a);
long long d = round(a);

如果 a 的值在整数值范围内,b、c、d 的值是否保证正确?

更新:

感谢您的友好回答。基于这些答案,我发布了一个后续问题。

ceil、地板和圆形函数放大精度损失问题的严重程度如何,以及如何消除这些影响?

实际上5.0000可以存储为4.9999

IEEE浮点数(简称"floats",我不是指floatC++数据类型)的情况并非如此。5.0完全可以表示为 IEEE 浮点数,所有适合尾数的整数也是如此(即具有

对于大小大于尾数大小的值,IEEE浮点数根本没有分数分量(但相邻浮点数之间的距离可能大于1)。例如,在尾数小于 100 位的 IEEE 浮点数中,最接近pow(2, 100) + 1的可表示浮点数pow(2, 100)(例如常见的 64 位和 32 位浮点数)。roundceilfloor当然会返回pow(2, 100)(这不适合常见的整数类型,可能会导致错误)。

此外,ceilroundfloor不会引入错误,但它们可能会放大现有的错误。5.0是完全可表示的,但计算1.1 + 3.9可能不会产生5.0,因为1.13.9不完全可表示。在这种情况下,这些函数可能会(正确)从指定到的5舍入,这可能不是您的意图。我怀疑这就是你引用的材料所谈论的,也是你感到困惑的:"精度损失"发生在四舍五入之前,随后的四舍五入放大了这个错误(但实际上并没有错误地舍入)。


也就是说,C++不能保证IEEE浮点格式(它只是迄今为止最常见的一种)。实现可能使用完全不同的格式。

floorceilround是精确的运算。

但是,您的代码使用其中一个函数,后跟整数强制转换。整数转换不是精确操作,因为并非所有整数值双精度都可以表示为实际整数。

但是,给定您指定的约束,前提是 a 的值在整数值范围内,则强制转换也将是准确的。

但是(这是很多但是)首先没有什么可以修复不准确的数据。如果您的变量的值为 4.99999999,但正确的值是 5.0,则调用floor将给出不正确的值 4。

是的,他们会的。

floorceil无法补偿并非所有整数都是 可代表。考虑:

float f = 16'777'217.5f;
cout << setprecision(20);
cout << ceil(f)  << endl;
cout << floor(f) << endl;

它将为两者打印16777218,如果float是 32 位 IEEE 754

见 http://coliru.stacked-crooked.com/a/894c8cb0ee517b16

最新更新