我有一些在AMD64 Linux上开发的数字代码(使用LLVM 3.2)。
我最近使用XCode将其移植到OSX 10.9。它运行正常,但它失败了许多单元测试:似乎在Linux上返回NaN(或-NaN)的一些计算现在返回OSX,-NaN(或NaN)。
我能否安全地假设正负NaN是等价的并调整我的单元测试以接受成功,或者这是否是更严重的错误信号?
答案 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
的变体。因此,对字符串nan
或ind
的值进行不区分大小写的搜索会将它们全部选中。这可能不适用于所有环境,但它的覆盖范围非常大。
对于它的价值,C标准有关于使用%f
(%F
使用大写字母)输出浮点值的说法:
代表
double
的{{1}}参数将转换为其中一种样式NaN
或[-]nan
- 哪种样式以及任何[-]nan(n-char-sequence)
的含义,是实现定义的。
因此,只需检查其中的某个值是否为n-char-sequence
就足够了。