我的代码中有以下函数,用于检查数字是否具有允许值(在日志空间中):
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.");
}
在使用此功能的上下文中,我使用long double。当我运行没有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上,FP算法默认在SSE2上完成,因此从FP角度来看amd64看起来更像是PowerPC而不是x86,并且与x86相比,精确度差异要小得多。
舍入:Valgrind确实观察了4个IEEE规定的舍入模式(最近,+无穷大,无穷大,为零)以进行以下转换:浮点数到整数,整数浮点数可能会丢失精度和浮动到浮动的圆角。对于所有其他FP操作,仅支持IEEE默认模式(舍入到最近)。
FP代码中的数字异常:IEEE754定义了可能发生的五种类型的数字异常:无效操作(负数的sqrt等),除零,溢出,下溢,不精确(精度损失)。
对于每个异常,IEEE754定义了两个操作过程:(1)可以调用用户定义的异常处理程序,或者(2)定义默认操作,“修复”并允许计算继续而不抛出异常。
目前Valgrind仅支持默认的修复操作。再次,对异常支持重要性的反馈将不胜感激。
当Valgrind检测到程序试图超出任何这些限制(设置异常处理程序,舍入模式或精确控制)时,它可以打印一条消息,回溯发生这种情况,并继续执行。此行为曾经是默认行为,但消息很烦人,因此默认情况下现在禁用它们。使用--show-emwarns = yes来查看它们。
上述限制准确定义了IEEE754的“默认”行为:对所有异常,舍入到最近操作以及64位精度的默认修正。
http://www.valgrind.org/docs/manual/manual-core.html#manual-core.limits
但我不确定这是否适用。 Valgrind没有打印出一条消息,正如报价中所述。它打印了这个:
terminate called after throwing an instance of 'std::underflow_error'
what(): Probability of -nan is abnormal --- possible cause underflow.
==4899==
==4899== Process terminating with default action of signal 6 (SIGABRT)
==4899== at 0x5710428: raise (raise.c:54)
==4899== by 0x5712029: abort (abort.c:89)
==4899== by 0x4EC984C: __gnu_cxx::__verbose_terminate_handler() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4899== by 0x4EC76B5: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4899== by 0x4EC7700: std::terminate() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4899== by 0x4EC7918: __cxa_throw (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
顺便说一句。我在64位系统上使用g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
,如果这与导致此行为的原因相关。
以上引用可能是我观察此事的原因,如果不是原因还有什么原因?
答案 0 :(得分:-1)