我有以下一些代码,但是当使用GCC 4.4使用各种优化标志进行编译时,我在运行时会得到一些意想不到的结果.
#include <iostream>
int main()
{
const unsigned int cnt = 10;
double lst[cnt] = { 0.0 };
const double v[4] = { 131.313, 737.373, 979.797, 731.137 };
for(unsigned int i = 0; i < cnt; ++i) {
lst[i] = v[i % 4] * i;
}
for(unsigned int i = 0; i < cnt; ++i) {
double d = v[i % 4] * i;
if(lst[i] != d) {
std::cout << "error @ : " << i << std::endl;
return …
Run Code Online (Sandbox Code Playgroud) 浮点值是不精确的,这就是为什么我们应该很少在比较中使用严格的数字相等.例如,在Java中打印false
(如ideone.com上所示):
System.out.println(.1 + .2 == .3);
// false
Run Code Online (Sandbox Code Playgroud)
通常,比较浮点计算结果的正确方法是查看某些预期值的绝对差值是否小于某个容许的epsilon.
System.out.println(Math.abs(.1 + .2 - .3) < .00000000000001);
// true
Run Code Online (Sandbox Code Playgroud)
问题是某些操作是否可以产生确切的结果.我们知道,任何非有限浮点值x
(即要么NaN
或无穷大),x - x
是ALWAYS NaN
.
但如果x
是有限的,这是否有保证?
x * -1 == -x
x - x == 0
(特别是我对Java行为最感兴趣,但也欢迎其他语言的讨论.)
对于它的价值,我认为(我可能在这里错了)答案是肯定的!我认为这归结为是否对于任何有限的IEEE-754浮点值,其加法逆是总是可计算的.由于例如float
并且double
只有一个专用位用于符号,这似乎是这种情况,因为它只需要翻转符号位来找到加法逆(即有效数应保持不变).
language-agnostic floating-point precision ieee-754 signedness