负无穷大

50

我正在尝试弄清楚如何将负无穷大的值赋给一个float或double变量。看起来,包括标准库limits库,可以得到正无穷大的表示,并且我知道(非常确定),在其前面加上负号(-infinity)可能会导致我在IEEE754浮点标准中寻找的值(就像0x7FFFFFFF可能会导致0xFFFFFFFF一样),但是我甚至不确定这一点,更别提可能还存在其他标准(如果有的话)。

是否有一种好的方法可以独立于平台和实现获得负无穷大的值?否则,我可能会使用#define指令,每个人都喜欢预处理。


11
我有一个图表,想确定哪个邻居是最好的选择(这是某种游戏AI),但分配给每个邻居节点的函数可能会返回极大的负数。为了检查最大值,我想将变量初始化为一个值,该值与任何其他值比较都会始终得到“小于”的结果。当然还有其他方法可以做到这一点,但是当我发现没有 -inf 常数时,我感到很好奇,因为我所知道的所有其他编程语言都定义了正无穷和负无穷的值。 - Setzer22
这个相关问题的链接是否有所帮助? - Roger Rowland
1
也许你应该使用第一个元素来达到这个目的,而不是负无穷大? - John Dvorak
2
当然,你总是可以使用-1/.0。非常适合高尔夫球。 - John Dvorak
2
@Setzer22 - 如果你所说的“数学上准确”是指“与实数完全一致”,那么浮点数运算中没有任何东西是“数学上准确”的。浮点数运算有其自己的规则,你必须按照它定义的系统进行操作,而不是按照你习惯的方式。 <g> 它与实数的运算结果非常接近,但并不相同。 - Pete Becker
显示剩余2条评论
3个回答

40

只要std::numeric_limits::is_iec559(IEEE 754)为true(这保证了std::numeric_limits::has_infinity也是true),您可以按照您已经说明的方式表示正无穷和负无穷值。

维基百科简要解释IEEE 754-1985无穷大的值:

... ...

偏指数字段填充所有1位,以指示计算结果的无穷大或无效。

正无穷和负无穷

正无穷和负无穷的表示如下:

 sign = 0 for positive infinity, 1 for negative infinity.
 biased exponent = all 1 bits.
 fraction = all 0 bits.

断言

下面的例子将按预期工作,或在目标平台不支持IEEE 754浮点数时导致编译时错误。

#include <cstdlib>
#include <cmath>
#include <cassert>
#include <limits>

int main(void)
{
    //Asserts floating point compatibility at compile time
    static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 required");

    //C99
    float negative_infinity1 = -INFINITY;
    float negative_infinity2 = -1 * INFINITY;

    float negative_infinity3 = -std::numeric_limits<float>::infinity();
    float negative_infinity4 = -1 * std::numeric_limits<float>::infinity();

    assert(std::isinf(negative_infinity1) && negative_infinity1 < std::numeric_limits<float>::lowest());
    assert(std::isinf(negative_infinity2) && negative_infinity2 < std::numeric_limits<float>::lowest());
    assert(std::isinf(negative_infinity3) && negative_infinity3 < std::numeric_limits<float>::lowest());
    assert(std::isinf(negative_infinity4) && negative_infinity4 < std::numeric_limits<float>::lowest());

    return EXIT_SUCCESS;
}

4
顺便说一下,在C++中不需要使用int main()return EXIT_SUCCESS;,而是应该使用int main(void) - jhasse
int main(void) 不是有效的 C++。 - Clearer
我非常确定一元负号必须计算一个值,但-infinity可能是NaN甚至是==infinity。你可以测试-infinity() < lowest() - Spencer
如果我不能使用std,例如在金属着色器中怎么办? - user1663023
你需要澄清的是,std::copysign 是否保证当正无穷大有效时,负无穷大也有效。 - Spencer
还有一个问题,就是简单地测试-std::numeric_limits<T>::infinity < std::numeric_limits<T>::lowest()怎么样? - Spencer

13
如果 std::numeric_limits<double>::is_iec559true 的话,使用以下代码应该是安全的: double negative_infinity = - std::numeric_limits<double>::infinity(); (IEC559 是 IEEE754 的 ISO 等效标准)
如果 false,那么需要大量工作,因为我认为 C++ 标准并没有提供任何帮助。

1
std::numeric_limits<double>::has_infinity 理论上即使在非 IEEE754 平台上也可能为真,尽管我怀疑这样的平台很少存在。 - Alan Stokes
是的,但这只能保证会有正无穷大。在使用的任何系统下,负无穷大可能仍然无法表示,并且我认为没有任何一种测试方法。 - Ian Cook

8

我不知道你在使用什么编译器,但是在gcc和MinGw中可以使用-std::numeric_limits<double>::infinity(),请参阅Infinity-and-NaN。此外,我在MSVC上运行了以下代码并返回了true:

double infinity(std::numeric_limits<double>::infinity());
double neg_infinity(-std::numeric_limits<double>::infinity());
double lowest(std::numeric_limits<double>::lowest());

bool lower_than_lowest(neg_infinity < lowest);
std::cout << "lower_than_lowest: " << lower_than_lowest << std::endl;

然而,考虑在您的应用程序中使用lowest而不是负无穷可能会更有价值,因为这很可能会导致更具可移植性的解决方案。


使用最小值而不是-inf是个好主意,你说得很对。实际上,在我提问的时候,我已经找到了更好的解决方案,只是出于好奇才提问的。但我会记住这个建议,以备将来遇到类似问题时使用。 - Setzer22

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