#[cfg(feature = "special-beta")]
use slatec_sys::special::beta as beta_raw;
#[cfg(feature = "special-gamma")]
use slatec_sys::special::gamma as gamma_raw;
use super::super::{SpecialFunctionError, runtime};
#[cfg(feature = "special-gamma")]
fn gamma_argument(function: &'static str, x: f64) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive(function, "x", x, 30.0)
}
#[cfg(feature = "special-beta")]
fn beta_arguments(function: &'static str, a: f64, b: f64) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive(function, "a", a, 30.0)?;
runtime::bounded_positive(function, "b", b, 30.0)
}
#[cfg(feature = "special-gamma")]
fn incomplete_gamma_arguments(
function: &'static str,
a: f64,
x: f64,
) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive(function, "a", a, 30.0)?;
if x.is_finite() && (0.0..=30.0).contains(&x) {
Ok(())
} else {
Err(SpecialFunctionError::Domain {
function,
argument: "x",
value: x,
})
}
}
#[cfg(feature = "special-gamma")]
pub fn reciprocal_gamma(x: f64) -> Result<f64, SpecialFunctionError> {
gamma_argument("reciprocal_gamma", x)?;
let _guard = runtime::lock_fnlib();
let mut x = x;
Ok(unsafe { gamma_raw::dgamr(&mut x) })
}
#[cfg(feature = "special-gamma")]
pub fn log_gamma(x: f64) -> Result<f64, SpecialFunctionError> {
gamma_argument("log_gamma", x)?;
let _guard = runtime::lock_fnlib();
let mut x = x;
Ok(unsafe { gamma_raw::dlngam(&mut x) })
}
#[cfg(feature = "special-beta")]
pub fn beta(a: f64, b: f64) -> Result<f64, SpecialFunctionError> {
beta_arguments("beta", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut b) = (a, b);
Ok(unsafe { beta_raw::dbeta(&mut a, &mut b) })
}
#[cfg(feature = "special-beta")]
pub fn log_beta(a: f64, b: f64) -> Result<f64, SpecialFunctionError> {
beta_arguments("log_beta", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut b) = (a, b);
Ok(unsafe { beta_raw::dlbeta(&mut a, &mut b) })
}
#[cfg(feature = "special-beta")]
pub fn regularized_beta(x: f64, a: f64, b: f64) -> Result<f64, SpecialFunctionError> {
runtime::closed_unit("regularized_beta", "x", x)?;
beta_arguments("regularized_beta", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut x, mut a, mut b) = (x, a, b);
Ok(unsafe { beta_raw::dbetai(&mut x, &mut a, &mut b) })
}
#[cfg(feature = "special-gamma")]
pub fn incomplete_gamma_lower(a: f64, x: f64) -> Result<f64, SpecialFunctionError> {
incomplete_gamma_arguments("incomplete_gamma_lower", a, x)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut x) = (a, x);
Ok(unsafe { gamma_raw::dgami(&mut a, &mut x) })
}
#[cfg(feature = "special-gamma")]
pub fn incomplete_gamma_upper(a: f64, x: f64) -> Result<f64, SpecialFunctionError> {
incomplete_gamma_arguments("incomplete_gamma_upper", a, x)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut x) = (a, x);
Ok(unsafe { gamma_raw::dgamic(&mut a, &mut x) })
}
#[cfg(feature = "special-gamma")]
pub fn tricomi_incomplete_gamma(a: f64, x: f64) -> Result<f64, SpecialFunctionError> {
incomplete_gamma_arguments("tricomi_incomplete_gamma", a, x)?;
if x == 0.0 {
return Err(SpecialFunctionError::Domain {
function: "tricomi_incomplete_gamma",
argument: "x",
value: x,
});
}
let _guard = runtime::lock_fnlib();
let (mut a, mut x) = (a, x);
Ok(unsafe { gamma_raw::dgamit(&mut a, &mut x) })
}
#[cfg(feature = "special-gamma")]
pub fn digamma(x: f64) -> Result<f64, SpecialFunctionError> {
gamma_argument("digamma", x)?;
let _guard = runtime::lock_fnlib();
let mut x = x;
Ok(unsafe { gamma_raw::dpsi(&mut x) })
}
#[cfg(feature = "special-gamma")]
pub fn factorial(n: i32) -> Result<f64, SpecialFunctionError> {
if !(0..=170).contains(&n) {
return Err(SpecialFunctionError::Domain {
function: "factorial",
argument: "n",
value: f64::from(n),
});
}
let _guard = runtime::lock_fnlib();
let mut n = runtime::integer("factorial", "n", n)?;
Ok(unsafe { gamma_raw::dfac(&mut n) })
}
#[cfg(feature = "special-gamma")]
pub fn binomial_coefficient(n: i32, m: i32) -> Result<f64, SpecialFunctionError> {
if n < 0 || m < 0 || m > n || n > 60 {
return Err(SpecialFunctionError::Domain {
function: "binomial_coefficient",
argument: "n_or_m",
value: f64::from(n.max(m)),
});
}
let _guard = runtime::lock_fnlib();
let (mut n, mut m) = (
runtime::integer("binomial_coefficient", "n", n)?,
runtime::integer("binomial_coefficient", "m", m)?,
);
Ok(unsafe { gamma_raw::dbinom(&mut n, &mut m) })
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
fn gamma_argument_f32(function: &'static str, x: f32) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive_f32(function, "x", x, 30.0)
}
#[cfg(all(feature = "special-f32", feature = "special-beta"))]
fn beta_arguments_f32(function: &'static str, a: f32, b: f32) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive_f32(function, "a", a, 30.0)?;
runtime::bounded_positive_f32(function, "b", b, 30.0)
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
fn incomplete_gamma_arguments_f32(
function: &'static str,
a: f32,
x: f32,
) -> Result<(), SpecialFunctionError> {
runtime::bounded_positive_f32(function, "a", a, 30.0)?;
if x.is_finite() && (0.0..=30.0).contains(&x) {
Ok(())
} else {
Err(SpecialFunctionError::Domain {
function,
argument: "x",
value: f64::from(x),
})
}
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
macro_rules! unary_f32 {
($name:ident, $raw:ident, $doc:literal) => {
#[doc = $doc]
pub fn $name(x: f32) -> Result<f32, SpecialFunctionError> {
gamma_argument_f32(stringify!($name), x)?;
let _guard = runtime::lock_fnlib();
let mut x = x;
Ok(unsafe { gamma_raw::$raw(&mut x) })
}
};
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
unary_f32!(
gamma_f32,
gamma,
"Single-precision gamma for `0 < x <= 30`, using `GAMMA`."
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
unary_f32!(
reciprocal_gamma_f32,
gamr,
"Single-precision reciprocal gamma, using `GAMR`."
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
unary_f32!(
log_gamma_f32,
alngam,
"Single-precision log absolute gamma, using `ALNGAM`."
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
unary_f32!(
digamma_f32,
psi,
"Single-precision digamma for positive x, using `PSI`."
);
#[cfg(all(feature = "special-f32", feature = "special-beta"))]
pub fn beta_f32(a: f32, b: f32) -> Result<f32, SpecialFunctionError> {
beta_arguments_f32("beta_f32", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut b) = (a, b);
Ok(unsafe { beta_raw::beta(&mut a, &mut b) })
}
#[cfg(all(feature = "special-f32", feature = "special-beta"))]
pub fn log_beta_f32(a: f32, b: f32) -> Result<f32, SpecialFunctionError> {
beta_arguments_f32("log_beta_f32", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut a, mut b) = (a, b);
Ok(unsafe { beta_raw::albeta(&mut a, &mut b) })
}
#[cfg(all(feature = "special-f32", feature = "special-beta"))]
pub fn regularized_beta_f32(x: f32, a: f32, b: f32) -> Result<f32, SpecialFunctionError> {
runtime::closed_unit_f32("regularized_beta_f32", "x", x)?;
beta_arguments_f32("regularized_beta_f32", a, b)?;
let _guard = runtime::lock_fnlib();
let (mut x, mut a, mut b) = (x, a, b);
Ok(unsafe { beta_raw::betai(&mut x, &mut a, &mut b) })
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
macro_rules! incomplete_gamma_f32 {
($name:ident, $raw:ident, $doc:literal, $nonzero:expr) => {
#[doc = $doc]
pub fn $name(a: f32, x: f32) -> Result<f32, SpecialFunctionError> {
incomplete_gamma_arguments_f32(stringify!($name), a, x)?;
if $nonzero && x == 0.0 {
return Err(SpecialFunctionError::Domain {
function: stringify!($name),
argument: "x",
value: 0.0,
});
}
let _guard = runtime::lock_fnlib();
let (mut a, mut x) = (a, x);
Ok(unsafe { gamma_raw::$raw(&mut a, &mut x) })
}
};
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
incomplete_gamma_f32!(
incomplete_gamma_lower_f32,
gami,
"Single-precision lower incomplete gamma using `GAMI`.",
false
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
incomplete_gamma_f32!(
incomplete_gamma_upper_f32,
gamic,
"Single-precision complementary incomplete gamma using `GAMIC`.",
false
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
incomplete_gamma_f32!(
tricomi_incomplete_gamma_f32,
gamit,
"Single-precision Tricomi incomplete gamma using `GAMIT`.",
true
);
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
pub fn factorial_f32(n: i32) -> Result<f32, SpecialFunctionError> {
if !(0..=33).contains(&n) {
return Err(SpecialFunctionError::Domain {
function: "factorial_f32",
argument: "n",
value: f64::from(n),
});
}
let _guard = runtime::lock_fnlib();
let mut n = runtime::integer("factorial_f32", "n", n)?;
Ok(unsafe { gamma_raw::fac(&mut n) })
}
#[cfg(all(feature = "special-f32", feature = "special-gamma"))]
pub fn binomial_coefficient_f32(n: i32, m: i32) -> Result<f32, SpecialFunctionError> {
if n < 0 || m < 0 || m > n || n > 30 {
return Err(SpecialFunctionError::Domain {
function: "binomial_coefficient_f32",
argument: "n_or_m",
value: f64::from(n.max(m)),
});
}
let _guard = runtime::lock_fnlib();
let (mut n, mut m) = (
runtime::integer("binomial_coefficient_f32", "n", n)?,
runtime::integer("binomial_coefficient_f32", "m", m)?,
);
Ok(unsafe { gamma_raw::binom(&mut n, &mut m) })
}