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

boost:math:factorial2 throws an error while computing double factorial of -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;
}

这是最小的工作示例。

函数是declared as

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

unsigned(-1)是一个非常大的数字。

这就是 boost::math::double_factorial declared:

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

根据documentationboost::math::double_factorial

The argument to double_factorial is type unsigned even though technically -1!! is defined.

这意味着,虽然数学上 -1!!定义明确,函数不支持负输入。 事实上,-1 将是 silently convertedunsigned,这将导致很大的数字——因此溢出。

作为解决方法,您可以在 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;
}

看到了live on Coliru

警告

此解决方案可行,因为当您使用否定参数调用 double_factorial 时,编译器将在同一命名空间内选择您的新重载。 然而,它有潜在的危险:如果 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"));
}