boost:math:factorial2在计算-1的二重阶乘时抛出错误



C++中boost库的官方文档证实了-1!!定义。然而,当我试图计算-1的二重阶乘时,它会抛出以下错误"函数boost::math::tgamma中的错误gamma的结果太大,无法表示"。我可以实现基于迭代的代码来计算相同的代码(如果需要的话(,但我希望尽可能使用优化的库。对纠正这个问题有什么建议吗?

#include <iostream>
#include  <boost/math/special_functions/factorials.hpp>
int main(int argc, char const *argv[]) {
double t  = boost::math::double_factorial<double>(-1);
std::cout << t <<"n";
return 0;
}

这是最小的工作示例。

这就是boost::math::double_factorial的声明方式:

namespace boost{ namespace math{
template <class T>
T double_factorial(unsigned i);
template <class T, class Policy>
T double_factorial(unsigned i, const Policy&);
}} // namespaces

根据boost::math::double_factorial文件

double_factoral的参数类型为unsigned,即使技术上-1!!定义。

这意味着,尽管在数学上-1!!定义良好,函数不支持负输入。事实上,-1将被静默地转换为unsigned,这将导致一个大的数字,从而导致溢出。

作为一种变通方法,您可以在namespace boost::math中声明一个额外的double_factorial函数

例如,为了简单起见,我只允许-1!!。

#include <iostream>
#include <exception>
#include  <boost/math/special_functions/factorials.hpp>
namespace boost { namespace math {
template <class T>
T double_factorial(int i) { if (i == -1) return T{1}; else throw(std::runtime_error("Unknown double factorial")); }
} }
int main(int argc, char const *argv[]) {
double t  = boost::math::double_factorial<double>(-1);
std::cout << t <<"n";
return 0;
}

在Coliru 上实时观看

警告

此解决方案将起作用,因为当您使用负参数调用double_factorial时,编译器将在同一命名空间内选择新的重载。然而,这是潜在的危险:如果boost的未来版本允许负值,代码可能不再编译,或者忽略新的boost版本。

一个更好的解决方案是将double_gamma封装到您定义的函数中,如下所示

template <class T>
T my_double_factorial(int i) {
if (i > 0)
return boost::math::double_factorial<T>(i);
else if (i == -1)
return T{1};
else
throw(std::runtime_error("Unknown double factorial"));
}

函数被声明为

template <class T>
T double_factorial(unsigned i);

并且CCD_ 9是一个非常大的数字。

最新更新