代码之家  ›  专栏  ›  技术社区  ›  markzzz

为什么设置一个常量变量(它将以相同的值存储)会导致一次除法的结果不同?

  •  3
  • markzzz  · 技术社区  · 7 年前

    漂亮的 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
    

    如你所见, b 和 bConst 似乎是使用相同的值来处理的-即,它打印两个相同的值 0.057762265046662104872599030613855575211346149444580078125 价值观。 所以我猜它们的“存储”都是一样的。唯一的区别是 b类 不是 const .

    然后,我也这么做 c / b 操作两次:一次使用 b类 ,另一次使用 bConst公司 .

    如你所见,它会导致两种不同的结果。这让我想知道。

    你能从技术上解释为什么会这样吗?

    1 回复  |  直到 7 年前
        1
  •  7
  •   manlio    7 年前

    “问题”是由于 -freciprocal-math 开关(由 -Ofast ):

    允许使用值的倒数,而不是除以值(如果这允许优化)。例如 x / y 可以替换为 x * (1/y) ,如果 (1/y) 受共同子表达式消除的影响。请注意,这会降低精度并增加对该值进行操作的触发器数。

    编译器可以计算 d = 1/bConst 编译时更改为:

    c/bConst
    

    到

    c * d
    

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

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

        2
  •  3
  •   Nelfeal    7 年前

    您正在使用 -Ofast 在您的链接中,这将启用 -O3 优化,包括 -ffast-math ,依次包括 -funsafe-math-optimizations .

    从我能收集到的信息来看,启用了优化, -funsafe数学优化 允许编译器降低某些计算的精度。这似乎是未来发生的事情 c/bConst 案例。