Skip to content

Commit 37006eb

Browse files
committed
Implement f{16,32,64,128}::{erf,erfc}
Also add ```rust // #[unstable(feature = "float_gamma", issue = "99842")] ``` to `gamma`-function-related methods on `f16` & `f128`, as per rust-lang#136324 (comment)
1 parent 021fb9c commit 37006eb

File tree

5 files changed

+280
-0
lines changed

5 files changed

+280
-0
lines changed

library/std/src/f128.rs

+74
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ impl f128 {
12261226
#[inline]
12271227
#[rustc_allow_incoherent_impl]
12281228
#[unstable(feature = "f128", issue = "116909")]
1229+
// #[unstable(feature = "float_gamma", issue = "99842")]
12291230
#[must_use = "method returns a new number and does not mutate the original value"]
12301231
pub fn gamma(self) -> f128 {
12311232
unsafe { cmath::tgammaf128(self) }
@@ -1260,10 +1261,83 @@ impl f128 {
12601261
#[inline]
12611262
#[rustc_allow_incoherent_impl]
12621263
#[unstable(feature = "f128", issue = "116909")]
1264+
// #[unstable(feature = "float_gamma", issue = "99842")]
12631265
#[must_use = "method returns a new number and does not mutate the original value"]
12641266
pub fn ln_gamma(self) -> (f128, i32) {
12651267
let mut signgamp: i32 = 0;
12661268
let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) };
12671269
(x, signgamp)
12681270
}
1271+
1272+
/// Error function.
1273+
///
1274+
/// # Unspecified precision
1275+
///
1276+
/// The precision of this function is non-deterministic. This means it varies by platform,
1277+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1278+
///
1279+
/// This function currently corresponds to the `erff128` from libc on Unix
1280+
/// and Windows. Note that this might change in the future.
1281+
///
1282+
/// # Examples
1283+
///
1284+
/// ```
1285+
/// #![feature(f128)]
1286+
/// #![feature(float_erf)]
1287+
/// # #[cfg(reliable_f128_math)] {
1288+
/// /// The error function relates what percent of a normal distribution lies
1289+
/// /// within `x` standard deviations (scaled by `1/sqrt(2)`).
1290+
/// fn within_standard_deviations(x: f128) -> f128 {
1291+
/// (x * std::f128::consts::FRAC_1_SQRT_2).erf() * 100.0
1292+
/// }
1293+
///
1294+
/// // 68% of a normal distribution is within one standard deviation
1295+
/// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01);
1296+
/// // 95% of a normal distribution is within two standard deviations
1297+
/// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01);
1298+
/// // 99.7% of a normal distribution is within three standard deviations
1299+
/// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01);
1300+
/// # }
1301+
/// ```
1302+
#[rustc_allow_incoherent_impl]
1303+
#[must_use = "method returns a new number and does not mutate the original value"]
1304+
#[unstable(feature = "f128", issue = "116909")]
1305+
// #[unstable(feature = "float_erf", issue = "136321")]
1306+
#[inline]
1307+
pub fn erf(self) -> f128 {
1308+
unsafe { cmath::erff128(self) }
1309+
}
1310+
1311+
/// Complementary error function.
1312+
///
1313+
/// # Unspecified precision
1314+
///
1315+
/// The precision of this function is non-deterministic. This means it varies by platform,
1316+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1317+
///
1318+
/// This function currently corresponds to the `erfcf128` from libc on Unix
1319+
/// and Windows. Note that this might change in the future.
1320+
///
1321+
/// # Examples
1322+
///
1323+
/// ```
1324+
/// #![feature(f128)]
1325+
/// #![feature(float_erf)]
1326+
/// # #[cfg(reliable_f128_math)] {
1327+
/// let x: f128 = 0.123;
1328+
///
1329+
/// let one = x.erf() + x.erfc();
1330+
/// let abs_difference = (one - 1.0).abs();
1331+
///
1332+
/// assert!(abs_difference <= f128::EPSILON);
1333+
/// # }
1334+
/// ```
1335+
#[rustc_allow_incoherent_impl]
1336+
#[must_use = "method returns a new number and does not mutate the original value"]
1337+
#[unstable(feature = "f128", issue = "116909")]
1338+
// #[unstable(feature = "float_erf", issue = "136321")]
1339+
#[inline]
1340+
pub fn erfc(self) -> f128 {
1341+
unsafe { cmath::erfcf128(self) }
1342+
}
12691343
}

library/std/src/f16.rs

+72
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ impl f16 {
12241224
#[inline]
12251225
#[rustc_allow_incoherent_impl]
12261226
#[unstable(feature = "f16", issue = "116909")]
1227+
// #[unstable(feature = "float_gamma", issue = "99842")]
12271228
#[must_use = "method returns a new number and does not mutate the original value"]
12281229
pub fn gamma(self) -> f16 {
12291230
(unsafe { cmath::tgammaf(self as f32) }) as f16
@@ -1258,10 +1259,81 @@ impl f16 {
12581259
#[inline]
12591260
#[rustc_allow_incoherent_impl]
12601261
#[unstable(feature = "f16", issue = "116909")]
1262+
// #[unstable(feature = "float_gamma", issue = "99842")]
12611263
#[must_use = "method returns a new number and does not mutate the original value"]
12621264
pub fn ln_gamma(self) -> (f16, i32) {
12631265
let mut signgamp: i32 = 0;
12641266
let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16;
12651267
(x, signgamp)
12661268
}
1269+
1270+
/// Error function.
1271+
///
1272+
/// # Unspecified precision
1273+
///
1274+
/// The precision of this function is non-deterministic. This means it varies by platform,
1275+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1276+
///
1277+
/// This function currently corresponds to the `erff` from libc on Unix
1278+
/// and Windows. Note that this might change in the future.
1279+
///
1280+
/// # Examples
1281+
///
1282+
/// ```
1283+
/// #![feature(f16)]
1284+
/// #![feature(float_erf)]
1285+
/// # #[cfg(reliable_f16_math)] {
1286+
/// /// The error function relates what percent of a normal distribution lies
1287+
/// /// within `x` standard deviations (scaled by `1/sqrt(2)`).
1288+
/// fn within_standard_deviations(x: f16) -> f16 {
1289+
/// (x * std::f16::consts::FRAC_1_SQRT_2).erf() * 100.0
1290+
/// }
1291+
///
1292+
/// // 68% of a normal distribution is within one standard deviation
1293+
/// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01);
1294+
/// // 95% of a normal distribution is within two standard deviations
1295+
/// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01);
1296+
/// // 99.7% of a normal distribution is within three standard deviations
1297+
/// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01);
1298+
/// # }
1299+
/// ```
1300+
#[rustc_allow_incoherent_impl]
1301+
#[must_use = "method returns a new number and does not mutate the original value"]
1302+
#[unstable(feature = "f16", issue = "116909")]
1303+
// #[unstable(feature = "float_erf", issue = "136321")]
1304+
#[inline]
1305+
pub fn erf(self) -> f16 {
1306+
(unsafe { cmath::erff(self as f32) }) as f16
1307+
}
1308+
1309+
/// Complementary error function.
1310+
///
1311+
/// # Unspecified precision
1312+
///
1313+
/// The precision of this function is non-deterministic. This means it varies by platform,
1314+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1315+
///
1316+
/// This function currently corresponds to the `erfcf` from libc on Unix
1317+
/// and Windows. Note that this might change in the future.
1318+
///
1319+
/// # Examples
1320+
///
1321+
/// ```
1322+
/// #![feature(f16)]
1323+
/// #![feature(float_erf)]
1324+
/// let x: f16 = 0.123;
1325+
///
1326+
/// let one = x.erf() + x.erfc();
1327+
/// let abs_difference = (one - 1.0).abs();
1328+
///
1329+
/// assert!(abs_difference <= f16::EPSILON);
1330+
/// ```
1331+
#[rustc_allow_incoherent_impl]
1332+
#[must_use = "method returns a new number and does not mutate the original value"]
1333+
#[unstable(feature = "f16", issue = "116909")]
1334+
// #[unstable(feature = "float_erf", issue = "136321")]
1335+
#[inline]
1336+
pub fn erfc(self) -> f16 {
1337+
(unsafe { cmath::erfcf(self as f32) }) as f16
1338+
}
12671339
}

library/std/src/f32.rs

+64
Original file line numberDiff line numberDiff line change
@@ -1151,4 +1151,68 @@ impl f32 {
11511151
let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) };
11521152
(x, signgamp)
11531153
}
1154+
1155+
/// Error function.
1156+
///
1157+
/// # Unspecified precision
1158+
///
1159+
/// The precision of this function is non-deterministic. This means it varies by platform,
1160+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1161+
///
1162+
/// This function currently corresponds to the `erff` from libc on Unix
1163+
/// and Windows. Note that this might change in the future.
1164+
///
1165+
/// # Examples
1166+
///
1167+
/// ```
1168+
/// #![feature(float_erf)]
1169+
/// /// The error function relates what percent of a normal distribution lies
1170+
/// /// within `x` standard deviations (scaled by `1/sqrt(2)`).
1171+
/// fn within_standard_deviations(x: f32) -> f32 {
1172+
/// (x * std::f32::consts::FRAC_1_SQRT_2).erf() * 100.0
1173+
/// }
1174+
///
1175+
/// // 68% of a normal distribution is within one standard deviation
1176+
/// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01);
1177+
/// // 95% of a normal distribution is within two standard deviations
1178+
/// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01);
1179+
/// // 99.7% of a normal distribution is within three standard deviations
1180+
/// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01);
1181+
/// ```
1182+
#[rustc_allow_incoherent_impl]
1183+
#[must_use = "method returns a new number and does not mutate the original value"]
1184+
#[unstable(feature = "float_erf", issue = "136321")]
1185+
#[inline]
1186+
pub fn erf(self) -> f32 {
1187+
unsafe { cmath::erff(self) }
1188+
}
1189+
1190+
/// Complementary error function.
1191+
///
1192+
/// # Unspecified precision
1193+
///
1194+
/// The precision of this function is non-deterministic. This means it varies by platform,
1195+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1196+
///
1197+
/// This function currently corresponds to the `erfcf` from libc on Unix
1198+
/// and Windows. Note that this might change in the future.
1199+
///
1200+
/// # Examples
1201+
///
1202+
/// ```
1203+
/// #![feature(float_erf)]
1204+
/// let x: f32 = 0.123;
1205+
///
1206+
/// let one = x.erf() + x.erfc();
1207+
/// let abs_difference = (one - 1.0).abs();
1208+
///
1209+
/// assert!(abs_difference <= f32::EPSILON);
1210+
/// ```
1211+
#[rustc_allow_incoherent_impl]
1212+
#[must_use = "method returns a new number and does not mutate the original value"]
1213+
#[unstable(feature = "float_erf", issue = "136321")]
1214+
#[inline]
1215+
pub fn erfc(self) -> f32 {
1216+
unsafe { cmath::erfcf(self) }
1217+
}
11541218
}

library/std/src/f64.rs

+64
Original file line numberDiff line numberDiff line change
@@ -1151,4 +1151,68 @@ impl f64 {
11511151
let x = unsafe { cmath::lgamma_r(self, &mut signgamp) };
11521152
(x, signgamp)
11531153
}
1154+
1155+
/// Error function.
1156+
///
1157+
/// # Unspecified precision
1158+
///
1159+
/// The precision of this function is non-deterministic. This means it varies by platform,
1160+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1161+
///
1162+
/// This function currently corresponds to the `erf` from libc on Unix
1163+
/// and Windows. Note that this might change in the future.
1164+
///
1165+
/// # Examples
1166+
///
1167+
/// ```
1168+
/// #![feature(float_erf)]
1169+
/// /// The error function relates what percent of a normal distribution lies
1170+
/// /// within `x` standard deviations (scaled by `1/sqrt(2)`).
1171+
/// fn within_standard_deviations(x: f64) -> f64 {
1172+
/// (x * std::f64::consts::FRAC_1_SQRT_2).erf() * 100.0
1173+
/// }
1174+
///
1175+
/// // 68% of a normal distribution is within one standard deviation
1176+
/// assert!((within_standard_deviations(1.0) - 68.269).abs() < 0.01);
1177+
/// // 95% of a normal distribution is within two standard deviations
1178+
/// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.01);
1179+
/// // 99.7% of a normal distribution is within three standard deviations
1180+
/// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.01);
1181+
/// ```
1182+
#[rustc_allow_incoherent_impl]
1183+
#[must_use = "method returns a new number and does not mutate the original value"]
1184+
#[unstable(feature = "float_erf", issue = "136321")]
1185+
#[inline]
1186+
pub fn erf(self) -> f64 {
1187+
unsafe { cmath::erf(self) }
1188+
}
1189+
1190+
/// Complementary error function.
1191+
///
1192+
/// # Unspecified precision
1193+
///
1194+
/// The precision of this function is non-deterministic. This means it varies by platform,
1195+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1196+
///
1197+
/// This function currently corresponds to the `erfc` from libc on Unix
1198+
/// and Windows. Note that this might change in the future.
1199+
///
1200+
/// # Examples
1201+
///
1202+
/// ```
1203+
/// #![feature(float_erf)]
1204+
/// let x: f64 = 0.123;
1205+
///
1206+
/// let one = x.erf() + x.erfc();
1207+
/// let abs_difference = (one - 1.0).abs();
1208+
///
1209+
/// assert!(abs_difference <= f64::EPSILON);
1210+
/// ```
1211+
#[rustc_allow_incoherent_impl]
1212+
#[must_use = "method returns a new number and does not mutate the original value"]
1213+
#[unstable(feature = "float_erf", issue = "136321")]
1214+
#[inline]
1215+
pub fn erfc(self) -> f64 {
1216+
unsafe { cmath::erfc(self) }
1217+
}
11541218
}

library/std/src/sys/cmath.rs

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ unsafe extern "C" {
2828
pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
2929
#[cfg(not(target_os = "aix"))]
3030
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
31+
pub fn erf(n: f64) -> f64;
32+
pub fn erff(n: f32) -> f32;
33+
pub fn erfc(n: f64) -> f64;
34+
pub fn erfcf(n: f32) -> f32;
3135

3236
pub fn acosf128(n: f128) -> f128;
3337
pub fn asinf128(n: f128) -> f128;
@@ -43,6 +47,8 @@ unsafe extern "C" {
4347
pub fn tanhf128(n: f128) -> f128;
4448
pub fn tgammaf128(n: f128) -> f128;
4549
pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
50+
pub fn erff128(n: f128) -> f128;
51+
pub fn erfcf128(n: f128) -> f128;
4652

4753
cfg_if::cfg_if! {
4854
if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {

0 commit comments

Comments
 (0)