对于未设置的值,使用IEEE754浮点NaN是一个好主意吗?

对于非数学原因未定义的值,使用IEEE754浮点NaN(非数字)是一个好主意吗?

在我们的情况下,它们尚未设置,因为尚未从其他设备接收到值。 上下文是使用IEC1131 REAL32值的嵌入式系统。 编辑:编程语言是C,所以我们很可能使用来自C99的NAN和isnanf(x)。 虽然我们可能需要一些额外的扭曲来将这些扭曲到我们的操作系统兼容性层中。

编程语言中的默认设置似乎是初始化具有正零的浮点变量,其内部表示全为零。 这对我们来说是不可用的,因为0在有效值的范围内。

使用NaN似乎是一个干净的解决方案,但也许它比它的价值更麻烦,我们应该选择其他一些价值?

刚刚注意到这个问题。

这是IEEE 754委员会考虑的NaN的用途之一(我是委员会成员)。 算术中NaN的传播规则使其非常有吸引力,因为如果您有一系列涉及某些初始化数据的计算结果,则不会将结果误认为是有效结果。 它还可以通过计算回溯,以便更直接地找到使用初始化数据的位置。

也就是说,有一些缺陷超出了754委员会的控制范围:正如其他人所指出的那样,并非所有硬件都支持NaN值,这可能会导致性能危害。 幸运的是,在性能关键设置中,通常不会对初始化数据执行大量操作。

NaNs是“无价值”句子的合理选择(例如,D编程语言将它们用于未初始化的值),但由于涉及它们的任何比较都是错误的,您可以得到一些惊喜:

  • if (result == DEFAULT_VALUE) ,如果DEFAULT_VALUE是NaN,则无法按预期工作,如Jon所述。

  • 如果你不小心,它们也可能导致范围检查问题。 考虑function:

 bool isOutsideRange(double x,double minValue,double maxValue)
 {
     return x  maxValue;
 }

如果x是NaN,则此函数会错误地报告x介于minValue和maxValue之间。

如果你只想要一个神奇的值供用户测试,我建议使用正或负无穷大而不是NaN,因为它没有相同的陷阱。 当你想要它的属性时使用NaN,NaN上的任何操作都会导致NaN:例如,当你不想依赖调用者检查值时,它很方便。

[编辑:我最初设法输入“任何涉及他们的比较将是真实的”,这不是我的意思,是错的,他们都是假的,除了NaN!= NaN,这是真的]

我之所以在类似的情况下使用NaN只是因为:通常的默认初始化值0也是有效值。 到目前为止,NaNs工作正常。

顺便说一句,这是一个很好的问题,为什么默认的初始化值通常是(例如,在Java原始类型中)0而不是NaN。 难道不是42或其他什么? 我想知道零的基本原理是什么。

我认为一般来说这是一个坏主意。 要记住的一件事是,大多数CPU对Nan的处理要比“通常”浮动慢得多。 并且很难保证在通常情况下你永远不会有Nan。 我在数值计算方面的经验是,它经常带来比它更值得的麻烦。

正确的解决方案是避免在float中编码“缺少值”,而是以另一种方式发出信号。 但是,这并不总是实用的,具体取决于您的代码库。

小心NaN的……如果你不小心,他们可以像野火一样传播。

它们是浮点数的完全有效值,但涉及它们的任何赋值也将等于NaN,因此它们通过您的代码传播。 如果你抓住它,它作为一个调试工具是相当不错的,但如果你带来一些东西要发布并且某处有一个边缘情况它也可能是一个真正的麻烦。

D使用它作为默认情况下赋予浮点数NaN的基本原理。 (我不确定我同意。)

我的感觉是它有点hacky,但至少你使用这个NaN值进行操作的其他所有数字都会给出NaN作为结果 – 当你在错误报告中看到NaN时,至少你知道你正在寻找什么样的错误。

如果您的基本需求是浮点值不代表可能从设备接收到的任何数字, 并且如果设备保证它永远不会返回NaN,那么这对我来说似乎是合理的。

请记住,根据您的环境,您可能需要一种特殊的方法来检测NaN(不要只使用if (x == float.NaN)或等价物。)

对我来说这听起来很好用。 希望我已经想到了……

当然,它们应该像病毒一样传播,这就是重点。

我想我会使用nan而不是其中一个无穷大。 使用信令nan并使它在第一次使用时引起事件可能会很好,但到那时为时已晚它应该在第一次使用时保持安静。

使用NaN作为默认值是合理的。

请注意,某些表达式(如(0.0 / 0.0))返回NaN。