正面与负面的nans

时间:2014-01-25 11:18:45

标签: math floating-point nan

我有一些在AMD64 Linux上开发的数字代码(使用LLVM 3.2)。

我最近使用XCode将其移植到OSX 10.9。它运行正常,但它失败了许多单元测试:似乎在Linux上返回NaN(或-NaN)的一些计算现在返回OSX,-NaN(或NaN)。

我能否安全地假设正负NaN是等价的并调整我的单元测试以接受成功,或者这是否是更严重的错误信号?

2 个答案:

答案 0 :(得分:10)

IEEE-754算术中没有“负NaN”的概念。 NaN编码仍然有一个符号位,并且有一个“符号位”操作的概念,它使用或影响该位(copysign,abs,其他几个),但是当解释NaN编码时它没有任何意义作为一种价值。许多打印程序碰巧将该位打印为负号,但它在形式上毫无意义,因此标准中没有太多可以控制其值应该是什么(除了上述函数之外)。

以下是IEEE-754(2008)的相关部分:

  

将支持格式的安静NaN转换为外部字符序列应生成语言定义的“nan”或除了大小写(例如“NaN”)之外的等效序列,并带有可选的前一个符号。 (本标准不解释NaN的符号。)

因此,您的平台的转换函数可能会打印NaN值的“符号”,但它没有任何意义,您不应该将其视为测试目的。

编辑得更强一点:将NaN数据的“符号位”附加意义几乎总是一个错误。

答案 1 :(得分:3)

完全取决于 你的单元测试正在测试什么。

除非您正在进行的测试实际上是IEEE754浮点软件本身或打印它们的C运行时代码,否则您很可能将它们视为等效的。否则,如果使用您正在测试的内容的代码将它们视为相同,则应将它们视为相同的

这是因为测试应该在每个环境中回应您的实际使用情况。一个(公认的做作)例子是你正在测试函数doCalc(),它返回一个double。如果只是这样使用过:

x = doCalc()
if x is any sort of Nan:
    doSomethingWithNan()

然后您的测试应将所有NaN值视为等效值。但是,如果您这样使用它:

x = doCalc()
if x is +Nan:
    doSomethingForPositive()
else:
    if x is -Nan:
        doSomethingForNegative()

那么你会希望将它们视为截然不同。

同样,如果您的实现在小数位中创建了有用的有效负载(见下文),并且您的实际代码使用,则也应该通过单元测试进行检查。


由于NaN只是指数中的所有1位而且除了分数中的所有零位以外的其他位置,因此符号位可以是正为负,并且小数位可以是宽的各种价值观。但是,它仍然是一个超出数据类型表示的值或结果,因此,如果您只是期望它,它可能对符号或有效负载包含的内容没什么影响。

在检查NaN值的文本输出方面,the Wikipedia page on NaN表示不同的实现可能会为您提供各种各样的输出,其中包括:

nan
NaN
NaN%
NAN
NaNQ
NaNS
qNaN
sNaN
1.#SNAN
1.#QNAN
-1.#IND

甚至变种显示对其NaN-ness没有影响的变化符号和有效负载:

-NaN
NaN12345
-sNaN12300
-NaN(s1234)

因此,如果您希望在单元测试中大规模移植,您会注意到所有输出表示栏中都有一些字符串nan的变体。因此,对字符串nanind的值进行不区分大小写的搜索会将它们全部选中。这可能不适用于所有环境,但它的覆盖范围非常大。

对于它的价值,C标准有关于使用%f%F使用大写字母)输出浮点值的说法:

  

代表double的{​​{1}}参数将转换为其中一种样式NaN[-]nan - 哪种样式以及任何[-]nan(n-char-sequence)的含义,是实现定义的。

因此,只需检查其中的某个值是否为n-char-sequence就足够了。