Я пытаюсь отладить свою библиотеку параллелизма для языка программирования D.Недавно было зарегистрировано сообщение об ошибке , которое указывает на то, что младшие биты некоторых операций с плавающей запятой, которые выполняются с помощью задач, являются недетерминированными при выполнении.(Если вы читаете отчет, обратите внимание, что параллельное сокращение работает под капотом, создавая задачи детерминированным способом.)
Это не похоже на проблему режима округления, потому что я пытался установить режим округления вручную,Я также уверен, что это не ошибка параллелизма.Библиотека хорошо протестирована (включая прохождение стресс-теста 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. См. сообщение об ошибке, которое я только что подал.