哪些编程语言向开发人员暴露IEEE 754陷阱?

9

我希望能以教育为目的玩弄那些陷阱。

数字计算中默认行为的一个普遍问题是,我们“错过”了出现在错误操作中的NaN(或+-inf)。默认行为是贯穿整个计算,但某些操作(如比较)会打破链条并丢失NaN,并且处理的其余部分将继续而不承认算法先前步骤中的奇异性。

有时我们有应对这种情况的方法:延长函数(“在我的情况下,0/0 = 12”),或者在时间域模拟中将步骤抛弃并尝试其他设置(例如预测器、步长或其他任何东西)。

因此,我的问题是:您是否知道哪些语言向开发人员公开IEEE754陷阱?我不想用汇编来搞定。

4个回答

3
据我所知,在C和C++中,浮点异常处理有两种选择:
首先,如果禁用/屏蔽浮点异常(大多数环境默认情况下都是这样),您可以通过调用fetestexcept来查看是否发生了任何浮点异常。在Visual C++中,fetestexcept不可用,但是您可以轻松地窃取MinGW Runtime的实现。 (它在公共领域中。)一旦异常被标记,直到您调用feclearexcept,它才会清除,因此您可以在一系列计算结束时调用fetestexcept,以查看是否引发了任何异常。这并没有给您想要的陷阱,但它确实让您测试是否出现了NaN或+/-inf等问题,并根据需要做出反应。

其次,您可以在Linux中调用feenableexcept或在Windows中调用_controlfp来启用/取消浮点异常。操作系统如何处理由处理器生成的浮点异常取决于您的操作系统。

在Linux中,操作系统会发送一个SIGFPE信号,因此您可以安装一个信号处理程序来捕获该信号并设置一个标志,告诉您的例程以适当的方式进行反应。
在Windows中,操作系统调用结构化异常处理来将处理器异常转换为语言异常,您可以使用C中的__try/__catch块或C++中的try/catch块来捕获它。
更新:对于Mac OS X,如this answer所述,您应该能够使用xmmintrin.h中的_MM_SET_EXCEPTION_MASK启用/取消掩码异常,并且只要您使用默认编译器选项(即不禁用SSE),您就应该能够使用SIGFPE捕获异常。
(如果您感兴趣,我在this blog posting中写了更多关于C和C ++中的浮点问题。)

这是一个很好的观点,我只是在玩这个,因为我感到幸运,我使用的是Mac,有两个平台特定的问题: http://www.gnu.org/software/hello/manual/gnulib/feenableexcept.html http://lists.apple.com/archives/Darwin-dev/2006/Mar/msg00102.html - nraynaud
我添加的链接中的信息在我的有限测试中似乎对我有效。 - Josh Kelley
感谢提供 Mac OS X 链接,这使得处理变得非常不规则,因为它仅适用于 SSE 类型(float 和 double),而不适用于 long double,这是 x87 特定的。 此外,启用异常会对整个进程生效,而不是当前线程,这使得使用它变得困难。 - nraynaud
好的观点。我不知道还有什么其他的尝试方法,很抱歉。就我的知识而言,因为我远非浮点数方面的专家,是否有任何特定的原因,使用fetestexcept在事后检查异常不起作用? - Josh Kelley
想象一下,你正在尝试反转一个大矩阵,当明确它不可逆时,你希望尽快退出这个大计算。一直进行下去只会浪费时间。 - nraynaud

0

请问您能否再具体一些呢? 我在文档中找不到相关内容,我找到了如何操作标志位,但是没有找到如何设置陷阱的方法: http://www.opengroup.org/onlinepubs/000095399/basedefs/fenv.h.html - nraynaud
感谢提供的链接。 在查看了C程序之后(我认为我看得很仔细,但在所有这些预处理器噪音中,很难确定),我没有看到陷阱被公开为这样的情况。我只看到了标志操作。SIG_FPE处理程序似乎是一个特殊情况,适用于某个平台。 - nraynaud

0

我不确定标准是什么,但可以告诉你我的经验,因为这可能有用。我曾在C++中编写代码,NaN有时是我的噩梦。它们会默默地出现并通过计算一直传播到最后,直到我只有无用的输出。我经常不得不创建额外的代码来专门检测导致NaN的情况。我使用的是Visual C++ 2008,所以我希望它会按照IEEE标准进行。


是的,这是完全标准的。但是标准定义了三个使用级别:1)传播NaN和infs 2)可以检查的标志 3)软件陷阱。也许您的用法对于保持默认行为来说过于高级。 - nraynaud

0

Maple的编程语言具有遵守IEEE-754的数字模型,并允许您设置自己的陷阱处理程序(如果需要)。以下是一些链接:

Maple的一个不常见的特性是默认的浮点数是十进制(而不是二进制)且具有任意精度。如果你想处理64位二进制浮点数,可以将它们包装在HFloat中。例如,0.2表示十进制数的精确值,而HFloat(0.2)表示在C语言中将0.2赋给double类型所得到的相同数值。这可以通过运行以下示例来证明:

a := HFloat(0.2);
b := 0.2;
evalf[20](a - b);

这使用20位小数算术计算ab之间的差异,结果为0.11E-16


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接