使用 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 所要求的),即使 double
和 float
分别是 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/