Add gamma and ln_gamma functions to f32 and f64
This commit is contained in:
parent
a17c7968b7
commit
fcecaff16e
7 changed files with 158 additions and 1 deletions
|
@ -957,4 +957,46 @@ impl f32 {
|
||||||
pub fn atanh(self) -> f32 {
|
pub fn atanh(self) -> f32 {
|
||||||
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gamma function.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(float_gamma)]
|
||||||
|
/// let x = 5.0f32;
|
||||||
|
///
|
||||||
|
/// let abs_difference = (x.gamma() - 24.0).abs();
|
||||||
|
///
|
||||||
|
/// assert!(abs_difference <= f32::EPSILON);
|
||||||
|
/// ```
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||||
|
#[unstable(feature = "float_gamma", issue = "99842")]
|
||||||
|
#[inline]
|
||||||
|
pub fn gamma(self) -> f32 {
|
||||||
|
unsafe { cmath::tgammaf(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the natural logarithm of the gamma function.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(float_gamma)]
|
||||||
|
/// let x = 2.0f32;
|
||||||
|
///
|
||||||
|
/// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
|
||||||
|
///
|
||||||
|
/// assert!(abs_difference <= f32::EPSILON);
|
||||||
|
/// ```
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||||
|
#[unstable(feature = "float_gamma", issue = "99842")]
|
||||||
|
#[inline]
|
||||||
|
pub fn ln_gamma(self) -> (f32, i32) {
|
||||||
|
let mut signgamp: i32 = 0;
|
||||||
|
let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) };
|
||||||
|
(x, signgamp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -652,6 +652,38 @@ fn test_atanh() {
|
||||||
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
|
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gamma() {
|
||||||
|
// precision can differ between platforms
|
||||||
|
assert_approx_eq!(1.0f32.gamma(), 1.0f32);
|
||||||
|
assert_approx_eq!(2.0f32.gamma(), 1.0f32);
|
||||||
|
assert_approx_eq!(3.0f32.gamma(), 2.0f32);
|
||||||
|
assert_approx_eq!(4.0f32.gamma(), 6.0f32);
|
||||||
|
assert_approx_eq!(5.0f32.gamma(), 24.0f32);
|
||||||
|
assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt());
|
||||||
|
assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt());
|
||||||
|
assert_eq!(0.0f32.gamma(), f32::INFINITY);
|
||||||
|
assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY);
|
||||||
|
assert!((-1.0f32).gamma().is_nan());
|
||||||
|
assert!((-2.0f32).gamma().is_nan());
|
||||||
|
assert!(f32::NAN.gamma().is_nan());
|
||||||
|
assert!(f32::NEG_INFINITY.gamma().is_nan());
|
||||||
|
assert_eq!(f32::INFINITY.gamma(), f32::INFINITY);
|
||||||
|
assert_eq!(171.71f32.gamma(), f32::INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ln_gamma() {
|
||||||
|
assert_approx_eq!(1.0f32.ln_gamma().0, 0.0f32);
|
||||||
|
assert_eq!(1.0f32.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!(2.0f32.ln_gamma().0, 0.0f32);
|
||||||
|
assert_eq!(2.0f32.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!(3.0f32.ln_gamma().0, 2.0f32.ln());
|
||||||
|
assert_eq!(3.0f32.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!((-0.5f32).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln());
|
||||||
|
assert_eq!((-0.5f32).ln_gamma().1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_real_consts() {
|
fn test_real_consts() {
|
||||||
use super::consts;
|
use super::consts;
|
||||||
|
|
|
@ -957,4 +957,46 @@ impl f64 {
|
||||||
pub fn atanh(self) -> f64 {
|
pub fn atanh(self) -> f64 {
|
||||||
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gamma function.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(float_gamma)]
|
||||||
|
/// let x = 5.0f64;
|
||||||
|
///
|
||||||
|
/// let abs_difference = (x.gamma() - 24.0).abs();
|
||||||
|
///
|
||||||
|
/// assert!(abs_difference <= f64::EPSILON);
|
||||||
|
/// ```
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||||
|
#[unstable(feature = "float_gamma", issue = "99842")]
|
||||||
|
#[inline]
|
||||||
|
pub fn gamma(self) -> f64 {
|
||||||
|
unsafe { cmath::tgamma(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the natural logarithm of the gamma function.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(float_gamma)]
|
||||||
|
/// let x = 2.0f64;
|
||||||
|
///
|
||||||
|
/// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
|
||||||
|
///
|
||||||
|
/// assert!(abs_difference <= f64::EPSILON);
|
||||||
|
/// ```
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
#[must_use = "method returns a new number and does not mutate the original value"]
|
||||||
|
#[unstable(feature = "float_gamma", issue = "99842")]
|
||||||
|
#[inline]
|
||||||
|
pub fn ln_gamma(self) -> (f64, i32) {
|
||||||
|
let mut signgamp: i32 = 0;
|
||||||
|
let x = unsafe { cmath::lgamma_r(self, &mut signgamp) };
|
||||||
|
(x, signgamp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -635,6 +635,38 @@ fn test_atanh() {
|
||||||
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
|
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_gamma() {
|
||||||
|
// precision can differ between platforms
|
||||||
|
assert_approx_eq!(1.0f64.gamma(), 1.0f64);
|
||||||
|
assert_approx_eq!(2.0f64.gamma(), 1.0f64);
|
||||||
|
assert_approx_eq!(3.0f64.gamma(), 2.0f64);
|
||||||
|
assert_approx_eq!(4.0f64.gamma(), 6.0f64);
|
||||||
|
assert_approx_eq!(5.0f64.gamma(), 24.0f64);
|
||||||
|
assert_approx_eq!(0.5f64.gamma(), consts::PI.sqrt());
|
||||||
|
assert_approx_eq!((-0.5f64).gamma(), -2.0 * consts::PI.sqrt());
|
||||||
|
assert_eq!(0.0f64.gamma(), f64::INFINITY);
|
||||||
|
assert_eq!((-0.0f64).gamma(), f64::NEG_INFINITY);
|
||||||
|
assert!((-1.0f64).gamma().is_nan());
|
||||||
|
assert!((-2.0f64).gamma().is_nan());
|
||||||
|
assert!(f64::NAN.gamma().is_nan());
|
||||||
|
assert!(f64::NEG_INFINITY.gamma().is_nan());
|
||||||
|
assert_eq!(f64::INFINITY.gamma(), f64::INFINITY);
|
||||||
|
assert_eq!(171.71f64.gamma(), f64::INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ln_gamma() {
|
||||||
|
assert_approx_eq!(1.0f64.ln_gamma().0, 0.0f64);
|
||||||
|
assert_eq!(1.0f64.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!(2.0f64.ln_gamma().0, 0.0f64);
|
||||||
|
assert_eq!(2.0f64.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!(3.0f64.ln_gamma().0, 2.0f64.ln());
|
||||||
|
assert_eq!(3.0f64.ln_gamma().1, 1);
|
||||||
|
assert_approx_eq!((-0.5f64).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln());
|
||||||
|
assert_eq!((-0.5f64).ln_gamma().1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_real_consts() {
|
fn test_real_consts() {
|
||||||
use super::consts;
|
use super::consts;
|
||||||
|
|
|
@ -286,6 +286,7 @@
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
#![feature(exclusive_wrapper)]
|
#![feature(exclusive_wrapper)]
|
||||||
#![feature(extend_one)]
|
#![feature(extend_one)]
|
||||||
|
#![feature(float_gamma)]
|
||||||
#![feature(float_minimum_maximum)]
|
#![feature(float_minimum_maximum)]
|
||||||
#![feature(float_next_up_down)]
|
#![feature(float_next_up_down)]
|
||||||
#![feature(hasher_prefixfree_extras)]
|
#![feature(hasher_prefixfree_extras)]
|
||||||
|
|
|
@ -30,4 +30,8 @@ extern "C" {
|
||||||
pub fn tanf(n: f32) -> f32;
|
pub fn tanf(n: f32) -> f32;
|
||||||
pub fn tanh(n: f64) -> f64;
|
pub fn tanh(n: f64) -> f64;
|
||||||
pub fn tanhf(n: f32) -> f32;
|
pub fn tanhf(n: f32) -> f32;
|
||||||
|
pub fn tgamma(n: f64) -> f64;
|
||||||
|
pub fn tgammaf(n: f32) -> f32;
|
||||||
|
pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
|
||||||
|
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![cfg(not(test))]
|
#![cfg(not(test))]
|
||||||
|
|
||||||
use libc::{c_double, c_float};
|
use libc::{c_double, c_float, c_int};
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn acos(n: c_double) -> c_double;
|
pub fn acos(n: c_double) -> c_double;
|
||||||
|
@ -23,6 +23,10 @@ extern "C" {
|
||||||
pub fn sinh(n: c_double) -> c_double;
|
pub fn sinh(n: c_double) -> c_double;
|
||||||
pub fn tan(n: c_double) -> c_double;
|
pub fn tan(n: c_double) -> c_double;
|
||||||
pub fn tanh(n: c_double) -> c_double;
|
pub fn tanh(n: c_double) -> c_double;
|
||||||
|
pub fn tgamma(n: c_double) -> c_double;
|
||||||
|
pub fn tgammaf(n: c_float) -> c_float;
|
||||||
|
pub fn lgamma_r(n: c_double, s: &mut c_int) -> c_double;
|
||||||
|
pub fn lgammaf_r(n: c_float, s: &mut c_int) -> c_float;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::shims::*;
|
pub use self::shims::*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue