2

通过不幸的情况,我发现我的标准库实现 <math.h><cmath>(C++)显然包含一个函数的定义,其原型如下:

double gamma(double x);

虽然我没有在语言标准的任何地方看到它(我可以访问的草稿)。

在 Mac OS X 上使用 gcc v4.2.1,该函数的计算结果与tgamma标准中赋予它的实际名称相同。(参考)

但是在 Ubuntu 12.04 上的 gcc v4.6.3 上,该函数的计算结果有所不同。

我完全不明白为什么一个名为gammacompiles 的函数,但为什么编译器之间的结果不一样?

这是一个简单的测试程序:

#include<iostream>
#include<sstream>
#include<math.h> // or <cmath>

int main(int argc, char **argv)
{
    std::stringstream conversionStream(argv[1]);
    double input;
    conversionStream >> input;
    std::cout << "gamma( " << input << " ) = " << gamma(input) << std::endl;
    return 0;
}

使用 1 个参数编译和运行:

$ g++ -o gamma_test gamma_test.cpp 
$ ./gamma_test 1.0
gamma( 1 ) = 1

但是 Ubuntu gcc v4.6.3 上的输出是 0!

4

2 回答 2

6

总结:历史上的混乱比比皆是;避免gamma()和使用tgamma().

实现这些功能的是数学库,而不是 gcc(编译器)。如果您在 MacOS 和 Ubuntu 上看到不同的行为,可能是因为 Ubuntu 使用 glibc 而 MacOS 使用其他东西。

gammaISO C 标准库中没有命名函数。

有称为lgamma和的标准函数tgamma。引用N1570(2011 ISO C 标准的最新草案)第 17.12.8.3 和 17.12.8.4 节:

#include <math.h>
double lgamma(double x);
float lgammaf(float x);
long double lgammal(long double x);

lgamma函数计算x的 gamma 绝对值的自然对数。如果x太大,则会发生范围错误。如果x为负整数或零,则可能会出现极点错误。

#include <math.h>
double tgamma(double x);
float tgammaf(float x);
long double tgammal(long double x);

tgamma函数计算 x 的gamma函数。如果x为负整数或零,则可能发生域错误或极点错误。如果x的幅度太大,则会出现范围误差,如果x的幅度太小,则可能会出现范围误差。

这些函数没有出现在 1990 ISO C 标准中。它们是由 C99 引入的。

引用Linux 手册页gamma

这些函数已弃用:取而代之的是,酌情使用tgamma (3) 或lgamma (3) 函数。

Gamma 函数的定义见tgamma (3)。

  • *BSD 版本

    正如人们所期望的那样,4.4BSD 和某些版本的 FreeBSD 中的 libm 具有计算 Gamma 函数的gamma () 函数。

  • glibc 版本

    Glibc 有一个gamma () 函数,它等效于lgamma (3) 并计算 Gamma 函数的自然对数。

和一个历史记录:

4.2BSD 有一个gamma () 计算 ln(|Gamma(|x|)|),将 Gamma(|x|) 的符号留在外部整数 signgam 中。在 4.3BSD 中,名称更改为lgamma (3),并且手册页承诺

“在未来的某个时候,伽玛这个名字将被恢复并用于伽玛函数”

这确实发生在 4.4BSD 中,其中gamma () 计算 Gamma 函数(对 signgam 没有影响)。然而,这来得太晚了,我们现在有了tgamma (3),即“真正的 gamma”函数。

由于gamma不是标准的 C 函数,使用gcc -std=c99 -pedanticor编译gcc -std=c11 -pedantic至少应该对任何调用它的尝试产生警告。

您可能应该使用tgamma()(或者lgamma()如果您想要自然对数)并避免使用gamma().

C 标准似乎没有说明 Gamma 函数是什么。Linux tgamma() 手册页确实如此(但如果您尝试使用它,您可能已经知道它是什么):

Gamma 函数定义为

Gamma(x) = 从 0 到无穷大的积分 t^(x-1) e^-t dt

它是为每个实数定义的,除了非正整数。
对于非负积分 m 有

伽玛(m+1) = m!

并且,更一般地,对于所有 x:

伽玛(x+1) = x * 伽玛(x)

此外,以下对于极点外的所有 x 值均有效:

Gamma(x) * Gamma(1 - x) = PI / sin(PI * x)

于 2013-08-08T01:42:01.483 回答
3

在某些平台上(linux 和 bsd pre-4.2 左右),gammalgamma(伽玛函数的日志)。在其他平台(osx 和 bsd post-4.4ish)上,它是tgamma(“真正的”伽玛函数)。这是历史的好奇。

OS X 联机帮助页中对此进行了说明:

gamma() 和 gamma_r() 已弃用,不应使用。应该使用 tgamma() 函数。但是请注意,在某些平台上,gamma() 和 gamma_r() 历史上计算的是 Gamma 函数的对数,而不是 Gamma 函数本身。从此类平台移植代码时,需要使用 lgamma() 或 lgamma_r() 代替。

长话短说,只是不要使用gamma. 反正就是不标准。使用标准函数tgammalgamma而不是(或者可能lgamma_r是可重入的posix扩展)。

于 2013-08-08T01:16:48.940 回答