9

我正在尝试为 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 VM 上运行此代码时,我对两个线程都得到了相同的答案。

回答: 事实证明,根本原因是浮点状态在主线程上的初始化方式与在 D 中 Windows 上的其他线程上的初始化方式不同。请参阅我刚刚提交的错误报告。

4

1 回答 1

2

这是一篇论文,解释了相同的 C 代码可能导致结果略有不同的许多原因。在您的情况下,最可能的原因是 CPU 内部指令重新排序。

期望浮点计算在低位是确定性的,这是完全错误的。这不是浮点数的设计目的。

于 2011-04-16T15:14:42.943 回答