diff --git a/std/src/f128.rs b/std/src/f128.rs index cff0bf4ccf4c4..14ce2b69ca427 100644 --- a/std/src/f128.rs +++ b/std/src/f128.rs @@ -1226,6 +1226,7 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f128 { unsafe { cmath::tgammaf128(self) } @@ -1260,10 +1261,83 @@ impl f128 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f128, i32) { let mut signgamp: i32 = 0; let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) }; (x, signgamp) } + + /// Error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erff128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_erf)] + /// # #[cfg(reliable_f128_math)] { + /// /// The error function relates what percent of a normal distribution lies + /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). + /// fn within_standard_deviations(x: f128) -> f128 { + /// (x * std::f128::consts::FRAC_1_SQRT_2).erf() * 100.0 + /// } + /// + /// // 68% of a normal distribution is within one standard deviation + /// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01); + /// // 95% of a normal distribution is within two standard deviations + /// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01); + /// // 99.7% of a normal distribution is within three standard deviations + /// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01); + /// # } + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erf(self) -> f128 { + unsafe { cmath::erff128(self) } + } + + /// Complementary error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erfcf128` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f128)] + /// #![feature(float_erf)] + /// # #[cfg(reliable_f128_math)] { + /// let x: f128 = 0.123; + /// + /// let one = x.erf() + x.erfc(); + /// let abs_difference = (one - 1.0).abs(); + /// + /// assert!(abs_difference <= f128::EPSILON); + /// # } + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "f128", issue = "116909")] + // #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erfc(self) -> f128 { + unsafe { cmath::erfcf128(self) } + } } diff --git a/std/src/f16.rs b/std/src/f16.rs index f6a553b1d0fa2..bdbe3e2199466 100644 --- a/std/src/f16.rs +++ b/std/src/f16.rs @@ -1224,6 +1224,7 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn gamma(self) -> f16 { (unsafe { cmath::tgammaf(self as f32) }) as f16 @@ -1258,10 +1259,81 @@ impl f16 { #[inline] #[rustc_allow_incoherent_impl] #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_gamma", issue = "99842")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn ln_gamma(self) -> (f16, i32) { let mut signgamp: i32 = 0; let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16; (x, signgamp) } + + /// Error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erff` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_erf)] + /// # #[cfg(reliable_f16_math)] { + /// /// The error function relates what percent of a normal distribution lies + /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). + /// fn within_standard_deviations(x: f16) -> f16 { + /// (x * std::f16::consts::FRAC_1_SQRT_2).erf() * 100.0 + /// } + /// + /// // 68% of a normal distribution is within one standard deviation + /// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.1); + /// // 95% of a normal distribution is within two standard deviations + /// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.1); + /// // 99.7% of a normal distribution is within three standard deviations + /// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.1); + /// # } + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erf(self) -> f16 { + (unsafe { cmath::erff(self as f32) }) as f16 + } + + /// Complementary error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erfcf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(f16)] + /// #![feature(float_erf)] + /// let x: f16 = 0.123; + /// + /// let one = x.erf() + x.erfc(); + /// let abs_difference = (one - 1.0).abs(); + /// + /// assert!(abs_difference <= f16::EPSILON); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "f16", issue = "116909")] + // #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erfc(self) -> f16 { + (unsafe { cmath::erfcf(self as f32) }) as f16 + } } diff --git a/std/src/f32.rs b/std/src/f32.rs index 260c499b7f4b9..295eee8700af2 100644 --- a/std/src/f32.rs +++ b/std/src/f32.rs @@ -1151,4 +1151,68 @@ impl f32 { let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) }; (x, signgamp) } + + /// Error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erff` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_erf)] + /// /// The error function relates what percent of a normal distribution lies + /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). + /// fn within_standard_deviations(x: f32) -> f32 { + /// (x * std::f32::consts::FRAC_1_SQRT_2).erf() * 100.0 + /// } + /// + /// // 68% of a normal distribution is within one standard deviation + /// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01); + /// // 95% of a normal distribution is within two standard deviations + /// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01); + /// // 99.7% of a normal distribution is within three standard deviations + /// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erf(self) -> f32 { + unsafe { cmath::erff(self) } + } + + /// Complementary error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erfcf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_erf)] + /// let x: f32 = 0.123; + /// + /// let one = x.erf() + x.erfc(); + /// let abs_difference = (one - 1.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_erf", issue = "136321")] + #[inline] + pub fn erfc(self) -> f32 { + unsafe { cmath::erfcf(self) } + } } diff --git a/std/src/f64.rs b/std/src/f64.rs index 7af646f8cfd60..0d713ecbc7312 100644 --- a/std/src/f64.rs +++ b/std/src/f64.rs @@ -1151,4 +1151,68 @@ impl f64 { let x = unsafe { cmath::lgamma_r(self, &mut signgamp) }; (x, signgamp) } + + /// Error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erf` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_erf)] + /// /// The error function relates what percent of a normal distribution lies + /// /// within `x` standard deviations (scaled by `1/sqrt(2)`). + /// fn within_standard_deviations(x: f64) -> f64 { + /// (x * std::f64::consts::FRAC_1_SQRT_2).erf() * 100.0 + /// } + /// + /// // 68% of a normal distribution is within one standard deviation + /// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01); + /// // 95% of a normal distribution is within two standard deviations + /// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01); + /// // 99.7% of a normal distribution is within three standard deviations + /// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01); + /// ``` + #[rustc_allow_incoherent_impl] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "float_erf", issue = "136321")] + #[inline] + pub fn erf(self) -> f64 { + unsafe { cmath::erf(self) } + } + + /// Complementary error function. + /// + /// # Unspecified precision + /// + /// The precision of this function is non-deterministic. This means it varies by platform, + /// Rust version, and can even differ within the same execution from one invocation to the next. + /// + /// This function currently corresponds to the `erfc` from libc on Unix + /// and Windows. Note that this might change in the future. + /// + /// # Examples + /// + /// ``` + /// #![feature(float_erf)] + /// let x: f64 = 0.123; + /// + /// let one = x.erf() + x.erfc(); + /// let abs_difference = (one - 1.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_erf", issue = "136321")] + #[inline] + pub fn erfc(self) -> f64 { + unsafe { cmath::erfc(self) } + } } diff --git a/std/src/sys/cmath.rs b/std/src/sys/cmath.rs index e3f41f4fdbbb6..c9969b4e376ea 100644 --- a/std/src/sys/cmath.rs +++ b/std/src/sys/cmath.rs @@ -28,6 +28,10 @@ unsafe extern "C" { pub fn lgamma_r(n: f64, s: &mut i32) -> f64; #[cfg(not(target_os = "aix"))] pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; + pub fn erf(n: f64) -> f64; + pub fn erff(n: f32) -> f32; + pub fn erfc(n: f64) -> f64; + pub fn erfcf(n: f32) -> f32; pub fn acosf128(n: f128) -> f128; pub fn asinf128(n: f128) -> f128; @@ -43,6 +47,8 @@ unsafe extern "C" { pub fn tanhf128(n: f128) -> f128; pub fn tgammaf128(n: f128) -> f128; pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128; + pub fn erff128(n: f128) -> f128; + pub fn erfcf128(n: f128) -> f128; cfg_if::cfg_if! { if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {