c++ std 的 inf 是否表现得与常识性无穷大一样
Does c++ std's inf behave exactly as common-sensical infinity
我正在实现一个相当复杂的数值算法。
它包含一些指数,其中我发现,在打印中间结果时,有一些 double 溢出。
但是,终端打印 inf
(不是 Inf
或 NaN
),看起来它不是一个双精度数,甚至不是最小或最大可表达双精度数。
但似乎inf
表现得好像是扩展的实数系统(将正负无穷大视为真数的观点,而不是涉及极限的语句的缩写)。
我进行了测试:(g++版本:"Apple LLVM version 8.0.0 (clang-800.0.42.1)")
#include <iostream> // cout
#include <cmath> // exp, log
#include <limits> // data ranges
int main(void)
{
const double dMin =std::numeric_limits<int>::min();
const double dMax =std::numeric_limits<int>::max();
double p1 =std::exp(710);
double p2 =std::exp(750);
double p3 =std::exp(800);
double p4 =-std::log(0.0);
std::cout << "p1 :=std::exp(710) =" << p1 << '\n';
std::cout << "p2 :=std::exp(750) =" << p2 << '\n';
std::cout << "p3 :=std::exp(800) =" << p3 << '\n';
std::cout << "p4 :=-std::log(0.0) =" << p4 << '\n';
std::cout << "does p1==dMax? " << ( (p1==dMax) ? "yes" : "no" ) << '\n';
std::cout << "does p1==-dMin? " << ( (p1==-dMin) ? "yes" : "no" ) << '\n';
std::cout << "does p1==p2? " << ( (p1==p2) ? "yes" : "no" ) << '\n';
std::cout << "does p2==p3? " << ( (p2==p3) ? "yes" : "no" ) << '\n';
std::cout << "does p3==p4? " << ( (p3==p4) ? "yes" : "no" ) << '\n';
std::cout << "does 3*p1==p2/2+1? " << ( (3*p1==p2/2+1) ? "yes" : "no" ) << '\n';
std::cout << "does (-p1)*(-p2)==p3*p3*p3? " << ( ((-p1)*(-p2)==p3*p3*p3) ? "yes" : "no" ) << '\n';
std::cout << "does std::log(p2)==std::exp(p3)? " << ( (std::log(p2)==std::exp(p3)) ? "yes" : "no" ) << '\n';
}
输出:
p1 :=std::exp(710) =inf
p2 :=std::exp(750) =inf
p3 :=std::exp(800) =inf
p4 :=-std::log(0.0) =inf
does p1==dMax? no
does p1==-dMin? no
does p1==p2? yes
does p2==p3? yes
does p3==p4? yes
does 3*p1==p2/2+1? yes
does (-p1)*(-p2)==p3*p3*p3? yes
does std::log(p2)==std::exp(p3)? yes
看来inf
确实很像我们概念中的无穷大,但不等于std的max和min。
那么,假设 inf
以与常识无穷大相同的方式工作是安全的吗?
我可以依赖算法中间步骤的操作,涉及inf
,把它当作真无穷大,最后只处理它的结果吗?
或者如果没有,我应该抓住它吗?但是我怎么能,因为它不是最大或最小的两倍?
将此答案限制为 IEEE754 浮点数,+Inf 源自 1.0 / 0.0
之类的计算,-Inf 源自 -1.0 / 0.0
.
之类的计算
另一种类型,NaN
(不是数字)来自 0.0 / 0.0
。
设置为 +Inf
的两个浮点变量将相互比较 true
,同上 -Inf
。它们代表 std::numeric_limits<double>::max()
的不同数量。 +Inf
大于除自身和 NaN
.
之外的所有值
请注意,设置为 NaN
的两个浮点变量将 不会 相互比较 true
,或与其他任何东西进行比较。
(就其价值而言,std::log(0.0)
必须 return -Inf
,而不是 NaN
。参见 http://en.cppreference.com/w/cpp/numeric/math/log
Does c++ std's inf ...
C++ 标准没有对无穷大的行为方式或无穷大可以用浮点数表示的方式指定任何要求。
如果您的系统使用符合特定浮点标准的浮点数,则该标准可能指定无穷大的行为。
It seems that inf does resemble our concept of infinity, but not equal to std's max and min.
确实如此。 numeric_limits::max()
被定义为 return 最大 有限 值。
how [to catch infinity], since it is not the maximum or minimum double?
如果 catch 你的意思是你想检查一个值是否是无穷大,你可以比较 numeric_limits::infinity()
,或者如果你有 C++11,然后 std::isinf()
(检查正无穷大和负无穷大)。
正如其他答案已经提到的,浮点数的行为在标准中没有明确定义,但是 IEC-559/IEEE-754 定义得很好,大多数实现都使用它。首先要做的是检查您的实施是否有效地使用了它:
static_assert(std::numeric_limits<double>::is_iec559, "Stupid implementation!");
一旦您通过了该断言,事情就会变得容易得多!首先,您可以使用以下效用函数来获得 true 无穷大(实际上,您不需要 is_iec559
为真...):
std::numeric_limits<double>::infinity()
更好的是,IEEE-754 对无穷大的行为有非常明确的定义规则:
http://steve.hollasch.net/cgindex/coding/ieeefloat.html#operations1,例如-inf * -inf = +inf
、+inf + +inf = +Inf
等。标准数学函数也具有定义明确的无穷大行为,因此您也可以依赖它们。
因此,如果您的实现遵循 IEEE 标准,是的您可以依赖对无穷大的中间操作,并且只检查最终结果。
1 这不是官方资源,但据我所知,它是正确的。
我正在实现一个相当复杂的数值算法。
它包含一些指数,其中我发现,在打印中间结果时,有一些 double 溢出。
但是,终端打印 inf
(不是 Inf
或 NaN
),看起来它不是一个双精度数,甚至不是最小或最大可表达双精度数。
但似乎inf
表现得好像是扩展的实数系统(将正负无穷大视为真数的观点,而不是涉及极限的语句的缩写)。
我进行了测试:(g++版本:"Apple LLVM version 8.0.0 (clang-800.0.42.1)")
#include <iostream> // cout
#include <cmath> // exp, log
#include <limits> // data ranges
int main(void)
{
const double dMin =std::numeric_limits<int>::min();
const double dMax =std::numeric_limits<int>::max();
double p1 =std::exp(710);
double p2 =std::exp(750);
double p3 =std::exp(800);
double p4 =-std::log(0.0);
std::cout << "p1 :=std::exp(710) =" << p1 << '\n';
std::cout << "p2 :=std::exp(750) =" << p2 << '\n';
std::cout << "p3 :=std::exp(800) =" << p3 << '\n';
std::cout << "p4 :=-std::log(0.0) =" << p4 << '\n';
std::cout << "does p1==dMax? " << ( (p1==dMax) ? "yes" : "no" ) << '\n';
std::cout << "does p1==-dMin? " << ( (p1==-dMin) ? "yes" : "no" ) << '\n';
std::cout << "does p1==p2? " << ( (p1==p2) ? "yes" : "no" ) << '\n';
std::cout << "does p2==p3? " << ( (p2==p3) ? "yes" : "no" ) << '\n';
std::cout << "does p3==p4? " << ( (p3==p4) ? "yes" : "no" ) << '\n';
std::cout << "does 3*p1==p2/2+1? " << ( (3*p1==p2/2+1) ? "yes" : "no" ) << '\n';
std::cout << "does (-p1)*(-p2)==p3*p3*p3? " << ( ((-p1)*(-p2)==p3*p3*p3) ? "yes" : "no" ) << '\n';
std::cout << "does std::log(p2)==std::exp(p3)? " << ( (std::log(p2)==std::exp(p3)) ? "yes" : "no" ) << '\n';
}
输出:
p1 :=std::exp(710) =inf
p2 :=std::exp(750) =inf
p3 :=std::exp(800) =inf
p4 :=-std::log(0.0) =inf
does p1==dMax? no
does p1==-dMin? no
does p1==p2? yes
does p2==p3? yes
does p3==p4? yes
does 3*p1==p2/2+1? yes
does (-p1)*(-p2)==p3*p3*p3? yes
does std::log(p2)==std::exp(p3)? yes
看来inf
确实很像我们概念中的无穷大,但不等于std的max和min。
那么,假设 inf
以与常识无穷大相同的方式工作是安全的吗?
我可以依赖算法中间步骤的操作,涉及inf
,把它当作真无穷大,最后只处理它的结果吗?
或者如果没有,我应该抓住它吗?但是我怎么能,因为它不是最大或最小的两倍?
将此答案限制为 IEEE754 浮点数,+Inf 源自 1.0 / 0.0
之类的计算,-Inf 源自 -1.0 / 0.0
.
另一种类型,NaN
(不是数字)来自 0.0 / 0.0
。
设置为 +Inf
的两个浮点变量将相互比较 true
,同上 -Inf
。它们代表 std::numeric_limits<double>::max()
的不同数量。 +Inf
大于除自身和 NaN
.
请注意,设置为 NaN
的两个浮点变量将 不会 相互比较 true
,或与其他任何东西进行比较。
(就其价值而言,std::log(0.0)
必须 return -Inf
,而不是 NaN
。参见 http://en.cppreference.com/w/cpp/numeric/math/log
Does c++ std's inf ...
C++ 标准没有对无穷大的行为方式或无穷大可以用浮点数表示的方式指定任何要求。
如果您的系统使用符合特定浮点标准的浮点数,则该标准可能指定无穷大的行为。
It seems that inf does resemble our concept of infinity, but not equal to std's max and min.
确实如此。 numeric_limits::max()
被定义为 return 最大 有限 值。
how [to catch infinity], since it is not the maximum or minimum double?
如果 catch 你的意思是你想检查一个值是否是无穷大,你可以比较 numeric_limits::infinity()
,或者如果你有 C++11,然后 std::isinf()
(检查正无穷大和负无穷大)。
正如其他答案已经提到的,浮点数的行为在标准中没有明确定义,但是 IEC-559/IEEE-754 定义得很好,大多数实现都使用它。首先要做的是检查您的实施是否有效地使用了它:
static_assert(std::numeric_limits<double>::is_iec559, "Stupid implementation!");
一旦您通过了该断言,事情就会变得容易得多!首先,您可以使用以下效用函数来获得 true 无穷大(实际上,您不需要 is_iec559
为真...):
std::numeric_limits<double>::infinity()
更好的是,IEEE-754 对无穷大的行为有非常明确的定义规则:
http://steve.hollasch.net/cgindex/coding/ieeefloat.html#operations1,例如-inf * -inf = +inf
、+inf + +inf = +Inf
等。标准数学函数也具有定义明确的无穷大行为,因此您也可以依赖它们。
因此,如果您的实现遵循 IEEE 标准,是的您可以依赖对无穷大的中间操作,并且只检查最终结果。
1 这不是官方资源,但据我所知,它是正确的。