【问题标题】:calculating the Gamma function for negative real values (C++, Boost)计算负实数值的 Gamma 函数(C++,Boost)
【发布时间】:2020-07-23 14:10:00
【问题描述】:

以下无限严重需要计算非整数、负数、实数的阶乘:

(这是一种计算椭圆周长的方法,a和b是半长轴和半短轴,h定义为:
h = (a-b)^2/(a+b)^2)

阶乘函数可以通过 Gamma 函数扩展为负值,该函数为所有非负整数的实数定义。

在编写严重代码时,我尝试了 boost::math::factorial 和 boost::math::tgamma,它只给出了 -1(不包括)-1.5 的结果,例如给出了一个错误。

    #include <iostream>
    #include <boost/math/special_functions/factorials.hpp>

    int main()
    {
        double x;
        double f;
        double tg;

        x = -0.5;
        f = boost::math::factorial<double>(x);
        tg = boost::math::tgamma<double>(x);
        cout << "factorial of " << x << " = " << f << endl;
        cout << "tgamma of " << x << " = " << tg << endl << endl;

        x = -1.5;
        f = boost::math::factorial<double>(x);
        tg = boost::math::tgamma<double>(x);
        cout << "factorial of " << x << " = " << f << endl;
        cout << "tgamma of " << x << " = " << tg << endl << endl;
    
        return 0;
    }

输出:

-0.5 = 1的阶乘
-0.5 的 tgamma = -3.54491
在抛出 'boost::exception_detail::clone_implboost::exception_detail::error_info_injector<:domain_error>' 的实例后调用终止 what():函数 boost::math::tgamma(long double) 中的错误:在负整数 0 处评估 tgamma。 中止(核心转储)

提升阶乘: boost factorial
提升 tgamma: boost tgamma

我的问题:

  1. 是否有替代 boost 的方法可以计算其负域的 gamma 函数?
  2. 我在上面提到的阶乘和 tgamma 函数的实现域的链接的 boost 文档中找不到。事实上,我可能只是错误地使用它们。确定什么是域/正确用法的方法是什么?

谢谢。

【问题讨论】:

标签: c++ boost c++17 factorial gamma-function


【解决方案1】:

我明白出了什么问题。 boost::math::factorial 函数采用unsigned 整数根据定义

template <class T>
inline T factorial(unsigned i)
{
   return factorial<T>(i, policies::policy<>());
}

这意味着如果你用双精度调用它,它将被隐式转换为无符号。那不是你想要的。此外,factorial 最终在内部使用 tgamma,所以你得到了这个:

#include <boost/math/special_functions/factorials.hpp>
#include <iostream>

void foo(long double x) {
    using namespace boost::math;
    try {
        auto f = factorial<long double>(x);
        std::cout << "factorial of " << static_cast<unsigned>(x) << " = " << f << "\n";
    } catch(std::exception const& e) {
        std::cout << "error at " << static_cast<unsigned>(x) << ": " << std::quoted(e.what()) << "\n";
    }
}

int main() {
    std::cout << std::unitbuf;
    foo(-2);
}

最终会这样做:

#0  boost::math::tgamma<long double, boost::math::policies::policy<boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy> > (a=4294967295, z=...)
    at /home/sehe/custom/boost_1_73_0/boost/math/special_functions/gamma.hpp:1994
No locals.
#1  0x0000555555558eb3 in boost::math::factorial<long double, boost::math::policies::policy<boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy, boost::math::policies::default_policy> > (i=4294967294, pol=...)
    at /home/sehe/custom/boost_1_73_0/boost/math/special_functions/factorials.hpp:44
        result = -0.667762310955655363645
#2  0x0000555555558674 in boost::math::factorial<long double> (i=4294967294)
    at /home/sehe/custom/boost_1_73_0/boost/math/special_functions/factorials.hpp:53
No locals.
#3  0x0000555555557792 in foo (x=-2) at /home/sehe/Projects/stackoverflow/test.cpp:7
        f = <invalid float value>
#4  0x000055555555791f in main () at /home/sehe/Projects/stackoverflow/test.cpp:16
No locals.

所以它试图给你boost::math::factorial&lt;long double&gt; (i=4294967294)

修复

不要将factorials 用于非负整数以外的整数。

Live On Compiler Explorer

#include <boost/math/special_functions/factorials.hpp>
#include <iostream>

void foo(long double x) {
    using namespace boost::math;
    try {
        auto tg = tgamma<long double>(x);
        std::cout << "tgamma    of " << x << " = " << tg << "\n" << std::endl;
    } catch(std::exception const& e) {
        std::cout << "error at " << x << ": " << std::quoted(e.what()) << std::endl;
    }
}

int main() {
    for (auto x : { 1., 2., 3., 4., 5., -.2, -2., -.5, -1.5 })
        foo(x);
}

打印:

tgamma    of 1 = 1

tgamma    of 2 = 1

tgamma    of 3 = 2

tgamma    of 4 = 6

tgamma    of 5 = 24

tgamma    of -0.2 = -5.82115

error at -2: "Error in function boost::math::tgamma<long double>(long double): Evaluation of tgamma at a negative integer -2."
tgamma    of -0.5 = -3.54491

tgamma    of -1.5 = 2.36327

-2 处溢出是可以理解的,但这是正确的。

【讨论】:

  • 非常感谢。我尝试了 std::tgamma 和你的代码,两者都有效。非常感谢。
【解决方案2】:

Gamma 函数自 C++11 [1] 起成为标准库的一部分。

用法如下:

#include <cmath>

std::tgamma(-0.5) # -3.5449077
std::lgamma(-0.5) # 1.2655121

您不妨将tgammaltgammaf 分别用于long doublefloat 类型。

  1. https://en.cppreference.com/w/cpp/numeric/math

【讨论】:

    【解决方案3】:

    我刚刚尝试在 Mac 上使用 g++-10 重现您的问题,使用 boost.math 提交哈希 87929356790ad0(当前 develop),但我明白了:

    factorial of -0.5 = 1
    tgamma of -0.5 = -3.54491
    
    factorial of -1.5 = 1
    tgamma of -1.5 = 2.36327
    

    因此需要更多信息,B​​oost 版本、操作系统、编译器等。

    【讨论】:

    • 也许您也可以提供您的平台详细信息?
    • @user14717 非常感谢您,至少现在我知道,即使不在我拥有的版本中,它也应该可以工作,我的平台详细信息:Ubuntu 18.04 gcc 版本 9.3.0 (Ubuntu 9.3 .0-11ubuntu0~18.04.1) libboost-dev 版本 1.65.1.0ubuntu1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-22
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-05
    相关资源
    最近更新 更多