Внезапно происходит сбой boost::iform_on_sphere после нескольких миллионов правильных реализаций, но только на определенных хостах
Эта проблема
После правильного генерирования случайных векторов в двух измерениях в течение некоторого времени, boost::uniform_on_sphere
распределение неожиданно генерирует вектор со значениями -nan
, Я тестировал включенную программу на трех машинах - ошибка наблюдалась на двух из них, но не на третьей. Кто-нибудь имеет представление о том, что может происходить?
редактировать: это происходит на всех хостах, если используется один и тот же тип.
Хозяева
Host 1
- AMD Opteron (tm) Процессор 6174
- g ++ (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4)
- терпит неудачу после 3802480 реализаций
Хост 2
- Процессор Intel(R) Core(TM) i5 650 с частотой 3,20 ГГц
- g++ (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)
- терпит неудачу после 3802480 реализаций
Host 3
- Процессор Intel® Rom Atom ™ D2700 с частотой 2,13 ГГц
- g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
- терпит неудачу после 3802480 реализаций, с немного отличным выводом
Реализации
На хостах 1 и 2:
3802470: -4.8961880803e-01 , -8.7193667889e-01
3802471: 9.9225074053e-01 , -1.2425158173e-01
3802472: 6.5411877632e-01 , -7.5639182329e-01
3802473: -9.8332953453e-01 , -1.8183253706e-01
3802474: 7.1217632294e-01 , -7.0200067759e-01
3802475: -9.9968332052e-01 , 2.5166392326e-02
3802476: 9.9412262440e-01 , 1.0826008022e-01
3802477: -6.2786966562e-01 , 7.7831840515e-01
3802478: 5.7143938541e-01 , 8.2064425945e-01
3802479: 5.8261138201e-01 , 8.1275087595e-01
3802480: -nan , -nan
3802481: 9.2151606083e-01 , 3.8834002614e-01
3802482: 8.6448800564e-01 , -5.0265353918e-01
3802483: -9.1891586781e-01 , 3.9445358515e-01
3802484: -9.1544634104e-01 , 4.0244001150e-01
На хосте 3, используя float
вместо float_t
:
3802470: -4.8961877823e-01 , -8.7193661928e-01
3802471: 9.9225074053e-01 , -1.2425158918e-01
3802472: 6.5411871672e-01 , -7.5639182329e-01
3802473: -9.8332953453e-01 , -1.8183253706e-01 <- exactly the same as above
3802474: 7.1217626333e-01 , -7.0200061798e-01
3802475: -9.9968332052e-01 , 2.5166388601e-02
3802476: 9.9412262440e-01 , 1.0826008022e-01
3802477: -6.2786966562e-01 , 7.7831846476e-01
3802478: 5.7143932581e-01 , 8.2064431906e-01 <- slightly different
3802479: 5.8261138201e-01 , 8.1275087595e-01 <- exactly the same
3802480: -nan , -nan
3802481: 9.2151612043e-01 , 3.8834002614e-01
3802482: 8.6448800564e-01 , -5.0265347958e-01
3802483: -9.1891586781e-01 , 3.9445355535e-01
3802484: -9.1544634104e-01 , 4.0244001150e-01
Программа
Это было скомпилировано просто с g++ bug.cpp
, Включение -O3
оптимизации не изменили результат.
#include <boost/circular_buffer.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/uniform_on_sphere.hpp>
#include <boost/random.hpp>
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, const char *argv[])
{
typedef boost::mt19937 GeneratorType;
typedef boost::uniform_on_sphere<float_t> DistributionType;
typedef boost::variate_generator<GeneratorType, DistributionType > VariateType;
typedef boost::circular_buffer<DistributionType::result_type> BufferType;
GeneratorType gen;
DistributionType dist(2);
VariateType variate(gen,dist);
const int BUFSIZE = 10;
gen.seed(11);
BufferType buf(BUFSIZE);
long n(0);
while (1){
cout << "n: " << n << "\r" << flush;
DistributionType::result_type tmp = variate();
buf.push_back(tmp);
if (isnan(tmp[0])) {
cout << "n: " << n << " " << endl;
cout << tmp[0] << " , " << tmp[1] << endl;
ofstream fout("debug.out");
for (int i=0; i<BUFSIZE; i++)
fout << buf[i][0] << " " << buf[i][1] << endl;
fout.close();
ofstream gen_out("gen.out");
gen_out << gen;
gen_out.close();
exit(1);
}
n++;
}
return 0;
}
Буду очень признателен за любую помощь!
2 ответа
Это происходит из-за ошибки в boost/random/uniform_on_sphere.hpp
, В N измерениях N нормально распределенных чисел генерируются как компоненты N-вектора, который затем нормализуется. В 2d вероятность получения двух нулей, по-видимому, не пренебрежимо мала, что приводит к вычислению 0/0=NaN
для каждого компонента в связи с нормализацией.
Обходным путем будет просто запрограммировать это распределение вручную для небольших размеров.
Одна большая разница между x86-32 и x86-64 заключается в разнице между x87 (80-битная FP) и SSE (64-битная FP). Т.е. 32-битный Atom имеет 16 дополнительных битов для работы.