Мне нужно запустить воспроизводимые трассы Монте-Карло.Это означает, что я использую известное начальное число, которое храню вместе со своими результатами, и использую это начальное число, если мне нужно запустить один и тот же экземпляр задачи, используя те же случайные числа.Это обычная практика.
При исследовании влияния числовой точности я столкнулся со следующей проблемой: Для того же семени Мерсенна Твистера std::uniform_real_distribution<float>(-1, 1)
возвращает значения, отличные от std::uniform_real_distribution<double>(-1, 1)
и std::uniform_real_distribution<long double>(-1, 1)
, так какследующий пример показывает:
#include <iomanip>
#include <iostream>
#include <random>
template < typename T >
void numbers( int seed ) {
std::mt19937 gen( seed );
std::uniform_real_distribution< T > dis( -1, 1 );
auto p = std::numeric_limits< T >::max_digits10;
std::cout << std::setprecision( p ) << std::scientific << std::setw( p + 7 )
<< dis( gen ) << "\n"
<< std::setw( p + 7 ) << dis( gen ) << "\n"
<< std::setw( p + 7 ) << dis( gen ) << "\n"
<< "**********\n";
}
int main() {
int seed = 123;
numbers< float >( seed );
numbers< double >( seed );
numbers< long double >( seed );
}
Результат:
$ /usr/bin/clang++ -v
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ /usr/bin/clang++ bug.cpp -std=c++17
$ ./a.out
3.929383755e-01
4.259105921e-01
-4.277213216e-01
**********
4.25910643160561708e-01
-1.43058149942132062e-01
3.81769702875451866e-01
**********
4.259106431605616525145e-01
-1.430581499421320209545e-01
3.817697028754518623166e-01
**********
Как вы можете видеть, double
и long double
оба начинаются примерно с одного номера (сохраняя различия в точности) и продолжаютсяпринося одинаковые значения.С другой стороны, float
начинается с совершенно другого числа, и его второе число похоже на первое число, производимое double
и long double
.
Видите ли вы такое же поведение в вашемкомпилятор?Есть ли причина для такого неожиданного (для меня) расхождения?
Подход
Ответы дают понять, что нет никаких оснований ожидать, что значения, сгенерированные с различной базовой точностью, будут одинаковыми.
Подход, который я выберу для создания воспроизводимых прогонов, заключается в том, чтобы всегда генерировать значения с максимально возможной точностью и приводить их к более низкой точности по требованию (например, float x = y
, где y
равно double
или long double
, в зависимости от обстоятельств).