Я пытаюсь отлаживать свою библиотеку параллелизма для языка программирования D. Недавно был отправлен отчет об ошибке, в котором указано, что младшие биты некоторых плавающих точечные операции, выполняемые с помощью задач, недетерминированы между запусками. (Если вы читали отчет, обратите внимание, что parallel reduce работает под капотом, создавая задачи детерминированным образом.)
Похоже, это не проблема режима округления, потому что я пытался установить режим округления вручную. Я также почти уверен, что это не ошибка параллелизма. Библиотека хорошо протестирована (включая прохождение стресс-теста Jinx), проблема всегда ограничивается низкоуровневым порядка битов, и это происходит даже на одноядерных машинах, где проблемы с низкоуровневой моделью памяти не представляют большой проблемы. По каким другим причинам результаты с плавающей запятой могут отличаться в зависимости от того, в каком потоке запланированы операции?
Редактировать: я занимаюсь отладкой printf здесь, и кажется, что результаты для отдельных задач иногда различаются при выполнении.
Редактировать № 2: Следующий код воспроизводит эту проблему гораздо проще. Он суммирует элементы массива в основном потоке, а затем запускает новый поток для выполнения той же самой функции. Проблема определенно не в моей библиотеке, потому что этот код даже не использует мою библиотеку.
import std.algorithm, core.thread, std.stdio, core.stdc.fenv;
real sumRange(const(real)[] range) {
writeln("Rounding mode: ", fegetround); // 0 from both threads.
return reduce!"a + b"(range);
}
void main() {
immutable n = 1_000_000;
immutable delta = 1.0 / n;
auto terms = new real[1_000_000];
foreach(i, ref term; terms) {
immutable x = ( i - 0.5 ) * delta;
term = delta / ( 1.0 + x * x ) * 1;
}
immutable res1 = sumRange(terms);
writefln("%.19f", res1);
real res2;
auto t = new Thread( { res2 = sumRange(terms); } );
t.start();
t.join();
writefln("%.19f", res2);
}
Выход:
Режим округления: 0
0.7853986633972191094
Режим округления: 0
0.7853986633972437348
Еще одно изменение
Вот вывод, когда я печатаю в шестнадцатеричном формате:
Режим округления: 0
0x1.921fc60b39f1331cp-1
Режим округления: 0
0x1.921fc60b39ff1p-1
Кроме того, это, похоже, происходит только в Windows. Когда я запускаю этот код на виртуальной машине Linux, я получаю одинаковый ответ для обоих потоков.
ОТВЕТ. Оказывается, основной причиной является то, что состояние с плавающей запятой инициализируется в основном потоке иначе, чем в других потоках в Windows в D. См. отчет об ошибке, который я только что отправил.