浮点数或双精度特殊值

6

我有一些可能是“空”的双精度浮点数(或单精度浮点数)变量,即它们没有有效值。如何使用内置类型float和double表示这种情况?

一种选择是使用一个包装器,其中包含一个float和一个布尔值,但这不起作用,因为我的库存储的是双精度浮点数而不是像双精度浮点数一样运行的对象。另一种方法是使用NaN(std::numeric_limits)。但我看不到检查变量是否为NaN的方法。

我该如何解决需要“特殊”浮点值来表示其他意义的问题?

4个回答

7
我们通过使用NaN来实现这一点:
double d = std::numeric_limits<double>::signaling_NaN();
bool isNaN = (d != d);

NaN值与自身比较相等将返回false。这是测试NaN的方法,但只有当std::numeric_limits<double>::is_iec559为true时才有效(如果是这样,则符合ieee754标准)。

在C99中,有一个名为isnan的宏在math.h中,用于检查浮点数是否为NaN值。


可能还有一个在"<cmath>"中。http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.15 - James Schek
感谢提供链接。他们正确指出这取决于实现是否包含它。在某些实现中,<cmath>会间接包含math.h,因此可能会被吞入其中。 - Johannes Schaub - litb
在我看来,直接包含math.h会更好。无论如何,我没有在标准中找到关于NaN的d == d为false的任何内容,所以我认为这更多是ieee754而不是C/C++的特性。如果我找到与该问题相关的任何信息,我将更新此答案。 - Johannes Schaub - litb
正确的 d != d -> d 是 NaN 是 ieee754 标准的一部分,而不是 C/C++ 标准... 但是,除非您需要关心 IBM 大型机,否则可以相当肯定地假设您具有 ieee754 浮点数。 - Spudd86

6
在Visual C++中,有一个非标准的_isnan(double)函数,您可以通过float.h导入。
在C语言中,有一个isnan(double)函数,您可以通过math.h导入。
在C++中,有一个isnan(double)函数,您可以通过cmath导入。
正如其他人指出的那样,使用NaN可能会带来很多麻烦。它们是一种特殊情况,必须像空指针一样处理。不同之处在于,NaN通常不会导致核心转储和应用程序故障,但它们极其难以跟踪。如果您决定使用NaN,请尽可能少地使用它们。滥用NaN是一种冒犯性的编码实践。

对于C++用户来说,<cmath>可能更可取。 - strager
我不确定cmath中的isnan是否是标准的一部分。将进行更新。 - James Schek
isnan不是标准的一部分。因此,不能保证它会出现在cmath中。当您在文件中使用时,它是实现特定的。 - Johannes Schaub - litb

2

虽然它不是内置类型,但通常我会使用 boost::optional 来处理这种情况。如果您绝对不能使用它,也许一个指针可以解决问题 -- 如果指针为NULL,则表示结果不包含有效值。


我会研究一下boost::optional。至于指针的想法,它很好,并且在大多数情况下应该可以工作。不幸的是,我的库想要存储浮点数而不是指针。 - David Reis

1

一种选择是使用一个包装器,其中有一个浮点数和一个布尔值,但这不起作用,因为我的库具有存储双精度浮点数而不是像双精度浮点数一样行为的对象的容器。

真遗憾。在C++中,创建一个模板类自动转换为实际的双精度(引用)属性非常简单。(或者任何其他类型的引用。)您只需在模板类中使用强制转换运算符。例如:operator TYPE & () { return value; } 然后,您可以在任何正常使用双精度浮点数的地方使用HasValue<double>。

另一种方法是使用NaN(std::numeric_limits)。但我看不到检查变量是否为NaN的方法。

正如litbJames Schek所指出的那样,C99为我们提供了isnan()。

但要小心! NaN值使数学和逻辑变得非常有趣!您会认为一个数字既不能是NOT>=foo也不能是NOT<=foo。但是对于NaN,它可以。

我在工具箱中保留了一个WARN-IF-NAN(X)宏的原因是我过去曾遇到一些有趣的问题。


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