相关疑难解决方法(0)

Valgrind导致双打长数值问题

我的代码中具有以下功能,用于检查数字(在日志空间中)是否具有允许的值:

template<class T>
static void check_if_normal(T t)
{
    T additive_neutral_element = make_additive_neutral_element<T>();
    // probability is allowed to be 0 in logspace
    // probability also is allowed to be -inf in logspace
    if (!std::isnormal(t) && t != 0 && t != additive_neutral_element)
        throw std::underflow_error(
          "Probability of " + std::to_string(t) +
          " is abnormal --- possible cause underflow.");
}
Run Code Online (Sandbox Code Playgroud)

在使用此函数的上下文中,我排他性地使用了长双精度。当我在不使用valgrind的情况下运行程序时,一切正常,但是当我在使用valgrind的程序运行时,该函数实际上会引发异常。我怀疑valgrind所做的事情会改变长双打的格式,或者类似的行为。我找到了这个:

Valgrind在相对于IEEE754的x86 / AMD64浮点实现中具有以下限制。

精度:不支持80位算术。在内部,Valgrind用64位表示所有此类“长双精度”数字,因此结果可能有所不同。这是否很关键还有待观察。请注意,x86 / amd64 fldt / fstpt指令(读/写80位数字)已使用到64位的转换进行了正确模拟,因此,如果有人要查看,则80位数字的内存图像看起来正确。

从许多FP回归测试中观察到的印象是,准确性差异并不明显。一般而言,如果程序依赖于80位精度,则可能很难将其移植到仅支持64位FP精度的非x86 / amd64平台。即使在x86 / amd64上,该程序也可能会获得不同的结果,具体取决于它是编译为使用SSE2指令(仅64位)还是x87指令(80位)。最终结果是使FP程序的行为就像在具有64位IEEE浮点数的计算机(例如PowerPC)上运行时一样。在amd64上,FPD算术运算默认情况下是在SSE2上完成的,因此从FP角度来看,amd64看起来更像PowerPC,而不是x86,并且与x86相比,明显的精度差异要少得多。

舍入:Valgrind确实对以下转换遵循4种IEEE规定的舍入模式(至最接近,至+无限,至-无限,至零):浮于整数,整数可能浮于精度的情况,以及浮动到浮动的舍入。对于所有其他FP操作,仅支持IEEE默认模式(四舍五入到最接近)。

FP代码中的数字异常:IEEE754定义了五种可能发生的数字异常:无效操作(负数的平方等),被零除,溢出,下溢,不精确(精度损失)。

对于每个异常,IEEE754定义了两个动作过程:(1)可以调用用户定义的异常处理程序,或者(2)定义一个默认动作,该动作可以“修正”并允许计算继续进行而无需引发异常。

当前,Valgrind仅支持默认的修正操作。同样,对于异常支持的重要性的反馈将不胜感激。

当Valgrind检测到程序试图超出这些限制中的任何一个(设置异常处理程序,舍入模式或精度控制)时,它可以打印一条消息,提供对该事件发生的位置的追溯,并继续执行。此行为曾经是默认行为,但是消息很烦人,因此默认情况下现在禁用显示消息。使用--show-emwarns = yes可以查看它们。

以上限制精确地定义了IEEE754的“默认”行为:所有异常的默认修正,最近舍入操作和64位精度。 …

c++ valgrind numeric long-double

5
推荐指数
0
解决办法
332
查看次数

标签 统计

c++ ×1

long-double ×1

numeric ×1

valgrind ×1