c++ (double)0.700 * int(1000) => 699(不是 double 问题)

标签 c++ floating-point double precision

使用 g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

我尝试了 scaledvalue2 的不同类型转换,但直到我将乘法存储在 double 变量中,然后存储到 int 中,我才能得到期望的结果..但我无法解释为什么???

我知道 double (0.6999999999999999555910790149937383830547332763671875)是一个问题,但我不明白为什么一种方法可以,另一种不行??

如果精度有问题,我预计两者都会失败。

我不需要解决方案来修复它..但只是一个为什么?? (问题已修复)

void main()
{
    double value = 0.7;
    int scaleFactor = 1000;

    double doubleScaled = (double)scaleFactor * value; 
    int scaledvalue1 = doubleScaled; // = 700

    int scaledvalue2 = (double)((double)(scaleFactor) * value);  // = 699 ??

    int scaledvalue3 = (double)(1000.0 * 0.7);  // = 700 

    std::ostringstream oss;
    oss << scaledvalue2;
    printf("convert FloatValue[%f] multi with %i to get %f = %i or %i or %i[%s]\r\n",
      value,scaleFactor,doubleScaled,scaledvalue1,scaledvalue2,scaledvalue3,oss.str().c_str());

}

或者简而言之:

value = 0.6999999999999999555910790149937383830547332763671875;
int scaledvalue_a = (double)(1000 * value);  // =  699??
int scaledvalue_b = (double)(1000 * 0.6999999999999999555910790149937383830547332763671875);  // =  700
// scaledvalue_a = 699
// scaledvalue_b = 700

我不知道这里出了什么问题。

输出:

convert FloatValue[0.700000] multi with 1000 to get 700.000000 = 700 or 699 or 700[699]

vendor_id : GenuineIntel

cpu family : 6

model : 54

model name : Intel(R) Atom(TM) CPU N2600 @ 1.60GHz

最佳答案

这会有点麻烦;我昨晚看小熊队赢得世界大赛冠军时起得太晚了,所以不要坚持精确。

评估浮点表达式的规则有些灵活,编译器通常比规则正式允许的更灵活地对待浮点表达式。这使得浮点表达式的计算速度更快,但代价是结果的可预测性有所降低。速度对于浮点计算很重要。 Java 最初犯了对浮点表达式强加精确要求的错误,数字社区痛得尖叫。 Java 不得不向现实世界屈服并放宽这些要求。

double f();
double g();
double d = f() + g(); // 1
double dd1 = 1.6 * d; // 2
double dd2 = 1.6 * (f() + g()); // 3

在 x86 硬件上(即,几乎所有现有的桌面系统),浮点计算实际上以 80 位精度完成(除非你设置了一些会降低性能的开关,如 Java 所要求的),即使 doublefloat 分别是 64 位和 32 位。因此,对于算术运算,操作数最多转换为 80 位,结果转换回 64 或 32 位。这很慢,因此生成的代码通常会尽可能长时间地延迟转换,以 80 位精度进行所有计算。

但是 C 和 C++ 都要求,当一个值存储到一个浮点变量中时,必须进行转换。因此,正式地,在//1 行中,编译器必须将总和转换回 64 位以将其存储到变量 d 中。然后,在//2 行中计算的 dd1 的值必须使用存储到 d 中的值(即 64 位值)进行计算,而该值在行//3 中计算的 dd2 可以使用 f() + g() 计算,即完整的 80 位值。这些额外的位可能会有所不同,dd1 的值可能与 dd2 的值不同。

编译器通常会保留 f() + g() 的 80 位值,并使用它代替存储在 d 中的值计算 dd1 的值。这是一个不符合规范的优化,但据我所知,默认情况下每个编译器都会做这种事情。它们都有命令行开关来强制执行严格要求的行为,所以如果你想要更慢的代码,你可以得到它。

对于严肃的数字运算,速度至关重要,因此欢迎这种灵 active ,并且仔细编写数字运算代码以避免对这种细微差异敏感。人们获得博士学位是因为弄清楚了如何使浮点代码快速有效,所以不要因为看到的结果似乎没有意义而难过。它们没有,但它们足够接近,如果小心处理,它们可以在不影响速度的情况下给出正确的结果。

关于c++ (double)0.700 * int(1000) => 699(不是 double 问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40400991/

相关文章:

printf 格式说明符和 pow 函数中的 C float 或 double

c++ - 在 C++ 中检查 double (或 float )是否为 NaN

c++ - 任意大小的枚举值

c++ - 如何在 Linux 上的 C++ 程序中使用 yaml-cpp?

c++ - 为什么这两个代码片段会产生不同的结果? ( float , double )

c++ - double to hex string & hex string to double

c++ - 返回值优化与右值引用

c++ - 静态分析检查未能发现琐碎的 C++ 问题

haskell - 在 Haskell 中将字符串转换为整数/ float ?

python - 为什么 SQL Server 返回 0.759999 而 MySQL 返回 0.76?