为什么在 std::vector 内部使用 std::complex<double> 时,机器 epsilon 的阶数会有所不同?

Why am I getting a difference on the order of machine epsilon when using std::complex<double> from inside a std::vector?

提问人:user1139069 提问时间:1/22/2023 最后编辑:user1139069 更新时间:1/22/2023 访问量:105

问:

在尝试调试一些单元测试时,我发现在尝试比较使用 .在第一种情况下,我直接进行评估。在第二种情况下,我从内部访问这些。当我比较它们时,我得到了使用时机器 epsilon 的顺序差异。最小大小写示例如下所示std::powstd::complex<double>std::powstd::vector-O3

perlmutter:~/bug> cat test.cpp
#include <complex>
#include <iostream>
#include <vector>

int main(int argc, const char * argv[]) {
    std::vector<std::complex<double>> base(1, 4.0);
    std::vector<std::complex<double>> exp(1, -0.23);

    std::cout << std::pow(std::complex(4.0), std::complex(-0.23)) - 
                 std::pow(base.at(0),        exp.at(0)) << std::endl;
    
    return 0;
}
perlmutter:~/bug> /opt/cray/pe/gcc/11.2.0/bin/c++ --version
c++ (GCC) 11.2.0 20210728 (Cray Inc.)
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

perlmutter:~/bug> /opt/cray/pe/gcc/11.2.0/bin/c++ -O3 -o test test.cpp
perlmutter:~/bug> ./test
(1.11022e-16,-0)

这是在 AMD EPYC 7713 64 核处理器上运行的。使用 、 或 时未看到此错误。floatdoublestd::complex<float>

使用 gcc 12.1.0 重新测试显示相同的错误。

(base) perlmutter:~/bug> gcc --version
gcc (GCC) 12.1.0 20220506 (HPE)
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

perlmutter:~/bug> g++ -O3 -o test test.cpp
perlmutter:~/bug> ./test
(1.11022e-16,-0)
C++ 复数 浮点精度

评论

0赞 Sam Varshavchik 1/22/2023
无法使用 gcc 12 重现。我明白了.(0,0)
0赞 user1139069 1/22/2023
@SamVarshavchik 有趣,因为我可以。您在哪个 CPU 上运行?
0赞 Sam Varshavchik 1/22/2023
AMD Ryzen 2950X,在英特尔至强上也有相同的结果。
4赞 Artyer 1/22/2023
看起来它们正好相差 1 个 ULP:godbolt.org/z/q8176Tq95 是常量折叠的,但在运行时调用库并返回略有不同的结果。请参阅此类似问题:stackoverflow.com/q/31418209。 导致 gcc 在运行时调用,即使使用常量(因为舍入可能与编译时不同),这会导致它们相等。std::pow(std::complex(4.0), std::complex(-0.23))std::pow(base.at(0), exp.at(0))cpow-frounding-mathcpow
4赞 user17732522 1/22/2023
对精确值进行单元测试可能没有多大意义。它没有指定有多准确,即使编译器和标准库指定它精确到四舍五入到可表示的值,那么通常仍然有两种可能的结果。std::pow

答: 暂无答案