【问题标题】:Why does setting a const variable (which will be stored with the same value) lead to a different result once divided?为什么设置一个 const 变量(将存储相同的值)会导致除以不同的结果?
【发布时间】:2019-02-15 10:09:01
【问题描述】:

漂亮basic代码:

#include <iostream>

int main() {
    std::cout.precision(100);

    double a            = 9.79999999999063220457173883914947509765625;
    double b            = 0.057762265046662104872599030613855575211346149444580078125;
    const double bConst = 0.057762265046662104872599030613855575211346149444580078125;
    double c            = a * b;

    std::cout << "        a: " << a << std::endl;
    std::cout << "        b: " << b << std::endl;
    std::cout << "   bConst: " << bConst << std::endl;
    std::cout << "        c: " << c << std::endl << std::endl;  
    std::cout << "      c/b: " << c / b << std::endl;   
    std::cout << " c/bConst: " << c / bConst << std::endl;  
}

哪些输出:

        a: 9.79999999999063220457173883914947509765625
        b: 0.057762265046662104872599030613855575211346149444580078125
   bConst: 0.057762265046662104872599030613855575211346149444580078125
        c: 0.5660701974567474703547986791818402707576751708984375

      c/b: 9.7999999999906304282148994388990104198455810546875
 c/bConst: 9.79999999999063220457173883914947509765625

如您所见,bbConst 似乎使用相同的值进行处理 - 即它为相同的 0.057762265046662104872599030613855575211346149444580078125 值打印。 所以我猜他们是“存储”的都是一样的。唯一的区别是b 不是const

然后,我做了两次相同的c / b 操作:一次使用b,另一次使用bConst

如您所见,它会导致两种不同的结果。这让我感到好奇。

您能从技术上解释为什么会发生这种情况吗?

【问题讨论】:

  • 这里(mingw-w64 with g++ 8.1)使用 -O2 优化时,两个结果都是相同的,我使用 -Ofast 得到你的结果。
  • 我以为您在另一个问题stackoverflow.com/q/54694274/5470596中了解了-Ofast对浮动操作确定性的反作用@

标签: c++ optimization floating-point constants


【解决方案1】:

“问题”是由于-freciprocal-math 开关(由-Ofast 暗示)引起的:

如果可以进行优化,则允许使用值的倒数而不是除以该值。例如,x / y 可以替换为 x * (1/y),这在 (1/y) 受到公共子表达式消除的情况下很有用。请注意,这会降低精度并增加在该值上运行的触发器数量。

编译器可以在编译时计算d = 1/bConst并从:

c/bConst

c * d

但是乘法和除法是不同的指令,具有不同的性能和精度。

见:http://coliru.stacked-crooked.com/a/ba9770ec39ec5ac2

【讨论】:

  • 感谢您的解释...有趣!
  • 嗯...不确定是这种行为:coliru.stacked-crooked.com/a/79e5a3501af9a217。使用c * 1 / b = c / b)(给b = bConst)。相反,c * 1 / bConst 给出的结果与c / bConst 相同...所以应该有所不同。
  • 呃……等等!如果我做了c * (1 / b)(而不是c * 1 / b)就像你说的那样工作。
【解决方案2】:

您在链接中使用了-Ofast,这将启用所有-O3 优化并包括-ffast-math,而后者又包括-funsafe-math-optimizations

据我所知,启用优化后,-funsafe-math-optimizations 允许编译器降低某些计算的精度。这似乎是 c/bConst 案例中发生的情况。

【讨论】:

  • 答案是正确的。知道为什么会这样吗?
  • “根据常数导致不同的结果”是什么意思?我不应该从相同的商和股息开始得到相同的结果吗?
  • @BenjaminBihler 我正在调查。
  • @markzzz 不安全的优化往往不关心这种逻辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
  • 2022-12-28
  • 1970-01-01
相关资源
最近更新 更多