std::uniform_real_distribution<T> 和 std::numeric_limits<T>::max() 对于 T == long double 在 Valgrind 下的问题
Problem with std::uniform_real_distribution<T> and std::numeric_limits<T>::max() for T == long double under Valgrind
我对以下代码有疑问:
#include <cassert>
#include <limits>
#include <random>
int main() {
using T = long double;
std::mt19937 engine{ std::random_device{}() };
const auto max = std::numeric_limits<T>::max();
const auto res = std::uniform_real_distribution<T>(0., max)(engine);
assert(res < max);
}
此代码作为独立程序正确执行。不幸的是,在 Valgrind 下,断言是不满足的。该问题仅发生在 T == long double
,即 double
和 float
情况下没有问题。
你能解释一下问题的本质吗?
(我在 GNU/Linux x86_64 上使用 GCC 9.3.0 和 Valgrind 3.15.0。我为 GCC 使用了 -O0 -g 标志, --leak-check=full --show-leak-kinds=all --errors-for-leak-kinds=all --运行-cxx-freeres=yes对于 Valgrind。)
这里的问题是 Valgrind 不完全支持 long double
。手册 reads:
Valgrind has the following limitations in its implementation of x86/AMD64 floating point relative to IEEE754.
There is no support for 80 bit arithmetic. Internally, Valgrind represents all such "long double" numbers in 64 bits, and so there may be some differences in results. ...
考虑这个简单的代码:
int main() {
auto max = static_cast<long double>(std::numeric_limits<double>::max());
std::cout << std::hexfloat << max << std::endl;
}
如果 运行 独立和在 Valgrind 下,输出是相同的:
0xf.ffffffffffff8p+1020
现在让我们尝试通过添加行
来打印下一个可表示的值
max = std::nextafter(max, std::numeric_limits<long double>::max());
我们在没有 Valgrind 的情况下得到了预期的输出,但在 Valgrind 下得到了不同的输出:
0xf.ffffffffffff801p+1020 // no Valgrind
0xf.ffffffffffff8p+1020 // under Valgrind
如果我们尝试打印 std::numeric_limits<long double>::max()
值本身,则会观察到类似的不一致:
0xf.fffffffffffffffp+16380 // no Valgrind
0x8p+16381 // under Valgrind
难怪 std::uniform_real_distribution<long double>
以某种依赖于实现的方式失败,std::numeric_limits<long double>::max()
。
我对以下代码有疑问:
#include <cassert>
#include <limits>
#include <random>
int main() {
using T = long double;
std::mt19937 engine{ std::random_device{}() };
const auto max = std::numeric_limits<T>::max();
const auto res = std::uniform_real_distribution<T>(0., max)(engine);
assert(res < max);
}
此代码作为独立程序正确执行。不幸的是,在 Valgrind 下,断言是不满足的。该问题仅发生在 T == long double
,即 double
和 float
情况下没有问题。
你能解释一下问题的本质吗?
(我在 GNU/Linux x86_64 上使用 GCC 9.3.0 和 Valgrind 3.15.0。我为 GCC 使用了 -O0 -g 标志, --leak-check=full --show-leak-kinds=all --errors-for-leak-kinds=all --运行-cxx-freeres=yes对于 Valgrind。)
这里的问题是 Valgrind 不完全支持 long double
。手册 reads:
Valgrind has the following limitations in its implementation of x86/AMD64 floating point relative to IEEE754.
There is no support for 80 bit arithmetic. Internally, Valgrind represents all such "long double" numbers in 64 bits, and so there may be some differences in results. ...
考虑这个简单的代码:
int main() {
auto max = static_cast<long double>(std::numeric_limits<double>::max());
std::cout << std::hexfloat << max << std::endl;
}
如果 运行 独立和在 Valgrind 下,输出是相同的:
0xf.ffffffffffff8p+1020
现在让我们尝试通过添加行
来打印下一个可表示的值max = std::nextafter(max, std::numeric_limits<long double>::max());
我们在没有 Valgrind 的情况下得到了预期的输出,但在 Valgrind 下得到了不同的输出:
0xf.ffffffffffff801p+1020 // no Valgrind
0xf.ffffffffffff8p+1020 // under Valgrind
如果我们尝试打印 std::numeric_limits<long double>::max()
值本身,则会观察到类似的不一致:
0xf.fffffffffffffffp+16380 // no Valgrind
0x8p+16381 // under Valgrind
难怪 std::uniform_real_distribution<long double>
以某种依赖于实现的方式失败,std::numeric_limits<long double>::max()
。