调用pow()时四舍五入结果的差异
Differences in rounded result when calling pow()
好的,我知道有很多关于pow函数和将结果转换为int的问题,但是我找不到这个有点具体问题的答案。
好的,这是C代码:#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int i = 5;
int j = 2;
double d1 = pow(i,j);
double d2 = pow(5,2);
int i1 = (int)d1;
int i2 = (int)d2;
int i3 = (int)pow(i,j);
int i4 = (int)pow(5,2);
printf("%d %d %d %d",i1,i2,i3,i4);
return 0;
}
输出:"25 25 24 25"。注意,只有在第三种情况下,pow的参数不是字面量,我们才会得到错误的结果,这可能是由舍入错误引起的。没有显式强制转换也会发生同样的事情。有人能解释一下这四种情况下发生了什么吗?
我在Windows 7中使用CodeBlocks,以及附带的MinGW gcc编译器
pow
运算的结果是2500000加上或减去一些舍入误差。如果舍入误差为正或零,则转换为整数后的结果为25。如果舍入误差为负,则结果为24。
内部最可能发生的情况是,在一种情况下,直接使用更高精度的80位FPU值,而在另一种情况下,结果从FPU写入内存(作为64位double),然后再读回(将其转换为稍微不同的80位值)。这可以使最终结果产生微小的差异,这就是将25.0000000001更改为24.999999997所需要的全部
另一种可能性是编译器识别传递给pow
的常量并自己进行计算,将结果替换为对pow
的调用。你的编译器可能会使用一个内部任意精度的数学库,也可能只是使用一个不同的。
这是由两个问题共同引起的:
- 您正在使用的
pow
实施质量不高。在许多情况下,浮点运算必须是近似的,但是好的实现会注意确保像pow(5, 2)
这样的简单情况返回精确的结果。您正在使用的pow
返回的结果小于25,其值大于0,但小于或等于2 -49 。例如,它可能返回25-2 -50。 - 您使用的C实现有时使用64位浮点格式,有时使用80位浮点格式。只要数字保持在80位格式,它就保留
pow
返回的完整值。如果将此值转换为整数,则会产生24,因为该值小于25,转换为整数会被截断;它不圆。当数字转换为64位格式时,它是四舍五入的。在浮点格式之间进行转换,使结果四舍五入到最接近的可表示值25。之后,转换为整数产生25。
当C实现混合浮点格式时是很麻烦的,因为用户通常无法预测或控制格式之间的转换何时发生。这导致结果不容易重现,并干扰推导或控制软件的数值特性。C实现可以设计成始终使用单一格式并避免其中一些问题,但是您的C实现显然不是这样设计的。
在这里添加其他答案:在处理浮点值时,通常要非常小心。
我强烈推荐阅读这篇文章(尽管它很长):http://hal.archives-ouvertes.fr/docs/00/28/14/29/PDF/floating-point-article.pdf
跳过第3节的实际例子,但不要忽略前面的章节!
我很确定这可以通过"中间舍入"来解释,并且pow
不是简单地循环j
乘以i
,而是使用exp(log(i)*j)
作为浮点计算来计算。中间舍入可以很好地将24.99999999999996转换为25000000000 -即使任意存储和重新加载值也可能导致这种行为的差异,因此根据代码的生成方式,它可能会对确切的结果产生影响。
当然,在某些情况下,编译器甚至可能"知道"pow
实际实现了什么,并将计算结果替换为常数。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- valgrind-hellgrind与泄漏检查的结果不同
- 用C++20 fmt限制结果的总大小
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 如何返回一个类的两个对象相加的结果
- 使用QProcess执行命令,并将结果存储在QStringList中
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 序列化,没有库的整数,得到奇怪的结果
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 在更改for循环的第三部分后,未使用for循环结果
- 使用++运算符会导致意外的结果
- 为什么在逗号分隔符上下文中将预增量的结果强制转换为void
- C++Brute Force攻击函数不会返回结果
- 在除法中不需要四舍五入
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 算术运算的结果类似于:C浮点变量中的1/3
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 密码登录程序将永远循环并显示不正确的结果
- 调用pow()时四舍五入结果的差异