为什么输出不同,公式如何相同?

Mig*_*igo 2 c++ floating-point

int y = 89;
int foo =  (y / 10.0 - y / 10) * 10;
int bar = (89 / 10.0 - 89 / 10) * 10;
cout << foo << ' ' << bar << '\n';
Run Code Online (Sandbox Code Playgroud)

上面的代码是想得到一个整数y的最后一位,奇怪的是foo is8和bar is 9,为什么会这样呢?两个版本的表达式有什么区别?

Eri*_*hil 5

C++ 标准允许实现以比标称格式要求的精度更高的精度计算浮点表达式。例如,float表达式可以被评估为好像它们是double或更多,并且double表达式可以被评估为好像它们是long double。这种额外的精度可能会导致计算差异,尤其是在使用不连续函数(例如转换为int)的情况下。

例如,给定y = 89y / 10.0 - y / 10将在实数算术0.9,但它是在0.9000000000000003552713678800500929355621337890625 double(IEEE-754 binary64)算术和0.89999999999999999965305530480463858111761510372161865234375 long double(Intel的80比特格式)算术,然后乘以10,并转换到int产生9或8、分别。

禁用优化后,编译器可能会y在运行时评估表达式 with和89编译期间的表达式,并且可能对它们使用不同的精度。通过优化,编译器可能会在第一个表达式中识别出y有效的常量89,并在编译期间对两个表达式求值,对两者使用相同的方法。

C++ 标准要求强制转换和赋值操作转换为标称类型,因此查看是否发生这种情况的一项测试是插入强制转换:

int foo = (double) ((double) (y / 10.0) - y / 10) * 10;
int bar = (double) ((double) (89 / 10.0) - 89 / 10) * 10;
Run Code Online (Sandbox Code Playgroud)

如果这导致foobar相同,则支持该假设。您的编译器可能具有控制如何计算浮点表达式的开关。

另一个测试是包含<cfloat>并打印 的值FLT_EVAL_METHOD。如果它是 0,则实现声称以它们的名义类型计算浮点运算,并且这种行为不应该发生。如果它是 1 或 2,则实现分别声明使用doublelong double评估double表达式,并且这种行为不应再次发生,因为这两个表达式将以相同的方式评估。如果是 ?1,则实现不会做出这些声明,并且可能会发生该行为。

要获取非负整数的最后一位数字,请使用y % 10.