Reputation: 123
I have problem with following code:
#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);
}
This code executes properly as a standalone program. Unfortunately, under Valgrind the assertion is unsatisfied. The problem occurs only for T == long double
, i.e. double
and float
cases are not problematic.
Can you explain the nature of the problem?
(I work with GCC 9.3.0 and Valgrind 3.15.0 on GNU/Linux x86_64. I used -O0 -g flags for GCC and --leak-check=full --show-leak-kinds=all --errors-for-leak-kinds=all --run-cxx-freeres=yes for Valgrind.)
Upvotes: 2
Views: 120
Reputation: 26272
The problem here is that Valgrind doesn't fully support long double
. The manual 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. ...
Consider this simple code:
int main() {
auto max = static_cast<long double>(std::numeric_limits<double>::max());
std::cout << std::hexfloat << max << std::endl;
}
The output is the same if run standalone and under Valgrind:
0xf.ffffffffffff8p+1020
Now let's try to print the next representable value by adding the line
max = std::nextafter(max, std::numeric_limits<long double>::max());
We get the expected output without Valgrind, but different output under Valgrind:
0xf.ffffffffffff801p+1020 // no Valgrind
0xf.ffffffffffff8p+1020 // under Valgrind
Similar inconsistency is observed if we try to print std::numeric_limits<long double>::max()
value itself:
0xf.fffffffffffffffp+16380 // no Valgrind
0x8p+16381 // under Valgrind
No wonder that std::uniform_real_distribution<long double>
fails, in some implementation-dependent way, with std::numeric_limits<long double>::max()
.
Upvotes: 4