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

Rat*_*man 5 c++ floating-point precision double

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

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

我知道双重预测(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());

}
Run Code Online (Sandbox Code Playgroud)

或简而言之:

value = 0.6999999999999999555910790149937383830547332763671875;
int scaledvalue_a = (double)(1000 * value);  // =  699??
int scaledvalue_b = (double)(1000 * 0.6999999999999999555910790149937383830547332763671875);  // =  700
// scaledvalue_a = 699
// scaledvalue_b = 700
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚这里出了什么问题.

输出:

convert FloatValue[0.700000] multi with 1000 to get 700.000000 = 700 or 699 or 700[699]
Run Code Online (Sandbox Code Playgroud)

vendor_id:GenuineIntel

cpu系列:6

型号:54

型号名称:Intel(R)Atom(TM)CPU N2600 @ 1.60GHz

Pet*_*ker 1

这有点让人手忙脚乱。昨晚我看小熊队赢得世界大赛时起得太晚了,所以不要坚持精确。

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

double f();
double g();
double d = f() + g(); // 1
double dd1 = 1.6 * d; // 2
double dd2 = 1.6 * (f() + g()); // 3
Run Code Online (Sandbox Code Playgroud)

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

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

通常,编译器在计算 的值时会保留 80 位值f() + g()并使用它,而不是存储在 中的值。这是一种不合格的优化,但据我所知,每个编译器默认都会执行此类操作。它们都有命令行开关来强制执行严格要求的行为,因此如果您想要较慢的代码,您可以得到它。<g>ddd1

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