浮点值,运算符和函数的可靠性如何?

需要

当一个不精确的值会造成灾难时,我不想引入浮点数,因此我有几个问题,关于何时可以真正安全地使用它们。

只要您不使有效数字溢出,它们是否对整数准确?这两个测试是否总是正确的:

double d = 2.0;
if (d + 3.0 == 5.0) ...
if (d * 3.0 == 6.0) ...

您可以依靠哪些数学函数?这些测试是否总是正确的:

#include <math.h>

double d = 100.0;
if (log10(d) == 2.0) ...
if (pow(d, 2.0) == 10000.0) ...
if (sqrt(d) == 10.0) ...

这个怎么样:

int v = ...;
if (log2((double) v) > 16.0) ... /* gonna need more than 16 bits to store v */
if (log((double) v) / log(2.0) > 16.0) ... /* C89 */

我猜您可以将这个问题总结为:1)浮点类型是否可以容纳所有整数的精确值,直到float.h中它们的有效位数为止?2)是否所有浮点运算符和函数都保证结果与实际数学结果最接近?

Tmyklebu

我也发现错误的结果令人反感。

在通用的硬件,你可以依靠+-*/,和sqrt工作,并提供正确的舍入结果。也就是说,它们提供最接近其一个或多个自变量的和,差,乘积,商或平方根的浮点数。

一些库函数,特别是log2andlog10exp2andexp10传统上具有可怕的实现,甚至没有如实地实现。忠实舍入意味着函数提供两个浮点数之一,将精确结果括起来。大多数现代pow实现都有类似的问题。这些功能很多甚至会打击确切的情况,例如log10(10000)pow(7, 2)因此,即使在确切的情况下,涉及这些功能的相等性比较也会带来麻烦。

sincostanatanexp,并log有忠实全面的实现每个平台上,我最近遇到。在过去的糟糕日子里,在使用x87 FPU评估sincos和的处理器上tan对于笨拙的输入,您将得到非常错误的输出,而对于较大的输入,则将得到输入。CRlibm具有正确的实现;有人告诉我,这些不是主流,因为与传统的全面实现相比,它们有更糟糕的最坏情况。

之类的东西copysign,并nextafterisfinite所有工作正常。ceilandfloorrintand朋友总是能提供准确的结果。fmod和朋友也一样。frexp和朋友一起工作。fminfmax工作。

有人认为通过将计算取整为a ,然后将结果和取整为a来做fma(x,y,z)计算是一个绝妙的主意您可以在现代平台上找到此行为。这很愚蠢,我讨厌。x*y+zx*ydoublezdouble

我没有使用C库中的双曲三角函数,gamma或Bessel函数的经验。

我还应该提到,针对32位x86的流行编译器会使用一组不同的破碎规则。由于x87是唯一受支持的浮点指令集,并且所有x87算术均使用扩展的指数进行,因此以双精度引起下溢或上溢的计算可能无法下溢或上溢。此外,由于x87在默认情况下也使用扩展的有效数字,因此您可能无法获得所需的结果。更糟糕的是,编译器有时会将中间结果溢出到精度较低的变量中,因此您甚至不能依靠doubles以扩展精度进行计算(Java有一个技巧,可以使用80位寄存器来执行64位数学运算,但是这很昂贵。)

long double如果您的目标是32位x86,我建议对s坚持算术编译器应该设置FLT_EVAL_METHOD为适当的值,但是我不知道这是否是通用的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章