【问题标题】:Why the output is different how ever the formula is the same?为什么输出不同而公式相同?
【发布时间】:2020-06-12 00:30:41
【问题描述】:
int y = 89;
int foo =  (y / 10.0 - y / 10) * 10;
int bar = (89 / 10.0 - 89 / 10) * 10;
cout << foo << ' ' << bar << '\n';

上面的代码是为了获取整数y的最后一位,奇怪的是foo是8而bar是9,为什么会这样呢?两个版本的表达式有什么区别?

【问题讨论】:

  • 这个test 给出了9 9 顺便说一句,为什么不使用y % 10(取模运算)来获得最后一位?
  • @TedLyngmo 我使用代码块编译器 17.12
  • 我很确定它支持模数运算。试试std::cout &lt;&lt; y % 10 &lt;&lt; '\n';,你会得到最后一个数字。
  • @TedLyngmo 我知道模 10 会给出预期的答案,我只是想看看这两个版本之间是否存在差异。
  • @TarekDakhran:您未能在您的环境中重现该问题的事实并不能证明该问题不存在。

标签: c++ floating-point


【解决方案1】:

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

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

在禁用优化的情况下,编译器可能会在运行时评估带有y 的表达式,并在编译期间评估带有89 的表达式,并且可能对它们使用不同的精度。通过优化,编译器可能会在第一个表达式中识别出y 实际上是一个常量89,并在编译期间评估这两个表达式,对两者使用相同的方法。

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

int foo = (double) ((double) (y / 10.0) - y / 10) * 10;
int bar = (double) ((double) (89 / 10.0) - 89 / 10) * 10;

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

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

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

【讨论】:

    猜你喜欢
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-07
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多