C++ NaN或false作为双精度返回值
我有一个返回双精度值的函数。在某些情况下,结果为零,应该在调用方路由中相应地处理此结果。我想知道返回零(NaN、false等)代替双值数字的正确方法是什么:C++ NaN或false作为双精度返回值,c++,nan,logical-operators,double-precision,C++,Nan,Logical Operators,Double Precision,我有一个返回双精度值的函数。在某些情况下,结果为零,应该在调用方路由中相应地处理此结果。我想知道返回零(NaN、false等)代替双值数字的正确方法是什么: double foo(){ if (some_conditions) { return result_of_calculations; } else { // Which of the following is better? return std::numeric_limit
double foo(){
if (some_conditions) {
return result_of_calculations;
} else {
// Which of the following is better?
return std::numeric_limits<double>::quiet_NaN(); // (1)
return 0; // (2)
return false; // (3)
return (int) 0; // (4)
}
}
if(bar==0)
与#3和#4一起使用是否安全?我可以将它与#2一起使用吗?或者我应该做类似于fabs(bar-0)
一个人应该如何处理安静的情况?我在这个网站上读到(例如),比较NaN并不一定总是错误的。那怎么办
总之,如何返回假值来代替双精度值以供以后比较?您不应将函数计算的实际值与进一步描述结果的附加消息(即错误状态)混合使用
好办法是:
struct foo_result_t
{
double value;
bool state;
};
foo_result_t foo() {
foo_result_t r;
r.value = result_of_calculations;
r.state = some_conditions;
return r;
}
如果您需要从函数中获得更多信息,这可能是最好的方法,并且易于扩展。比如指出它为什么失败
对于简单的情况,您也可以考虑使用<代码> STD::配对< /C> > < /P> 您还可以使用
boost::optional
()double foo() {
if(some_conditions) {
return result_of_calculations;
}
else {
throw some_exception;
}
}
这看起来很优雅,但有时您可能希望保持代码无异常
bool foo(double& result) {
if(some_conditions) {
result = result_of_calculations;
return true;
}
else {
return false;
}
}
这可能是最直接的一个,并且没有开销(异常、附加结构)。但函数试图返回两个值时看起来有点奇怪,但其中一个实际上是参数您不应将函数计算的实际值与进一步描述结果的附加消息(即错误状态)混用
好办法是:
struct foo_result_t
{
double value;
bool state;
};
foo_result_t foo() {
foo_result_t r;
r.value = result_of_calculations;
r.state = some_conditions;
return r;
}
如果您需要从函数中获得更多信息,这可能是最好的方法,并且易于扩展。比如指出它为什么失败
对于简单的情况,您也可以考虑使用<代码> STD::配对< /C> > < /P> 您还可以使用
boost::optional
()double foo() {
if(some_conditions) {
return result_of_calculations;
}
else {
throw some_exception;
}
}
这看起来很优雅,但有时您可能希望保持代码无异常
bool foo(double& result) {
if(some_conditions) {
result = result_of_calculations;
return true;
}
else {
return false;
}
}
这可能是最直接的一个,并且没有开销(异常、附加结构)。但函数试图返回两个值时看起来有点奇怪,但其中一个实际上是参数没有足够的背景来完全回答这个问题。当
某些条件的计算结果为false时,听起来您希望返回一个哨兵。但什么是正确的哨兵?回答这一问题主要取决于在何处以及如何使用foo()
在大多数情况下,正确的答案都不是上述问题。也许抛出异常会更好。也许将界面更改为boolfoo(double&)
或boolfoo(double*)
会更好。也许,正如Plasmah所建议的,将其更改为boost::optional foo()
会更好
如果sentinel更好,则正确的sentinel将取决于该值。假设调用方正在进行加法或乘法运算。如果不影响结果,则sentinel应分别为0.0或1.0。如果它应该完全放弃结果,那么NaN或Inf可能更有意义
至于EPSILON问题,这取决于您希望如何处理另一个案例返回的接近零值。返回一个literal0.0
值将产生一个与0.0
精确比较的双精度值;但是,“应该”导致0.0
的计算可能不会精确地导致0.0
没有足够的上下文来完全回答这个问题。当某些条件的计算结果为false时,听起来您希望返回一个哨兵。但什么是正确的哨兵?回答这一问题主要取决于在何处以及如何使用foo()
在大多数情况下,正确的答案都不是上述问题。也许抛出异常会更好。也许将界面更改为boolfoo(double&)
或boolfoo(double*)
会更好。也许,正如Plasmah所建议的,将其更改为boost::optional foo()
会更好
如果sentinel更好,则正确的sentinel将取决于该值。假设调用方正在进行加法或乘法运算。如果不影响结果,则sentinel应分别为0.0或1.0。如果它应该完全放弃结果,那么NaN或Inf可能更有意义
至于EPSILON问题,这取决于您希望如何处理另一个案例返回的接近零值。返回一个literal0.0
值将产生一个与0.0
精确比较的双精度值;但是,“应该”导致0.0
的计算可能不会精确地导致0.0
if(bar==0)与#3和#4一起使用安全吗
#3
和#4
编译与#2
相同
我可以和#2一起使用它吗?或者我应该做一些像fabs(bar-0)
是(您可以与#2
一起使用):双栏=0代码>=>bar==0代码>
然而!如果some_conditions==true
branch可以通过一些计算返回(接近)零,并且您需要以相同的方式处理这种情况,那么在比较浮点值的相等性时,您需要使用通常的技巧
另一方面,如果some_conditions==true
分支可能返回零,但这种情况的处理方式应该与false
分支的结果不同,那么您需要使用另一种方法。丹维尔列出了有用的替代方案
对于比较NaN
,请使用
if(bar==0)与#3和#4一起使用安全吗
#3
和#4
编译与#2相同
auto hopefully( bool const cond ) -> bool { return cond; }
auto fail( string const& s ) -> bool { throw runtime_error( s ); }
auto foo()
-> double
{
double const result = calculations();
hopefully( calculations_succeeded() )
|| fail( "foo: calculations failed" );
return result;
}