gamma
Returns the gamma function of x, gamma(x) = factorial(x - 1) for integer x.
Special Cases:
- gamma(+-nan) = nan
- gamma(-inf) = nan
- gamma(n) = nan for negative integers
- gamma(-0.0) = -inf
- gamma(+0.0) = +inf
- gamma(+inf) = +inf
Function parameters
Parameters
- T:type
- x:T
Returns the gamma function of x,
Functions
Source
Implementation
pub fn gamma(comptime T: type, x: T) T {
if (T != f32 and T != f64) {
@compileError("gamma not implemented for " ++ @typeName(T));
}
// common integer case first
if (x == @trunc(x)) {
// gamma(-inf) = nan
// gamma(n) = nan for negative integers
if (x < 0) {
return std.math.nan(T);
}
// gamma(-0.0) = -inf
// gamma(+0.0) = +inf
if (x == 0) {
return 1 / x;
}
if (x < integer_result_table.len) {
const i = @as(u8, @intFromFloat(x));
return @floatCast(integer_result_table[i]);
}
}
// below this, result underflows, but has a sign
// negative for (-1, 0)
// positive for (-2, -1)
// negative for (-3, -2)
// ...
const lower_bound = if (T == f64) -184 else -42;
if (x < lower_bound) {
return if (@mod(x, 2) > 1) -0.0 else 0.0;
}
// above this, result overflows
// gamma(+inf) = +inf
const upper_bound = if (T == f64) 172 else 36;
if (x > upper_bound) {
return std.math.inf(T);
}
const abs = @abs(x);
// perfect precision here
if (abs < 0x1p-54) {
return 1 / x;
}
const base = abs + lanczos_minus_half;
const exponent = abs - 0.5;
// error of y for correction, see
// https://github.com/python/cpython/blob/5dc79e3d7f26a6a871a89ce3efc9f1bcee7bb447/Modules/mathmodule.c#L286-L324
const e = if (abs > lanczos_minus_half)
base - abs - lanczos_minus_half
else
base - lanczos_minus_half - abs;
const correction = lanczos * e / base;
const initial = series(T, abs) * @exp(-base);
// use reflection formula for negatives
if (x < 0) {
const reflected = -std.math.pi / (abs * sinpi(T, abs) * initial);
const corrected = reflected - reflected * correction;
const half_pow = std.math.pow(T, base, -0.5 * exponent);
return corrected * half_pow * half_pow;
} else {
const corrected = initial + initial * correction;
const half_pow = std.math.pow(T, base, 0.5 * exponent);
return corrected * half_pow * half_pow;
}
}