Skip to content
/ rust Public
forked from rust-lang/rust

Commit f77247a

Browse files
committed
Auto merge of rust-lang#136324 - GrigorenkoPV:erf, r=tgross35
Implement `f{16,32,64,128}::{erf,erfc}` (`#![feature(float_erf)]`) Tracking issue: rust-lang#136321 try-job: x86_64-gnu-aux
2 parents 54a0f38 + 18b9ede commit f77247a

File tree

8 files changed

+295
-0
lines changed

8 files changed

+295
-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.1);
1294+
/// // 95% of a normal distribution is within two standard deviations
1295+
/// assert!((within_standard_deviations(2.0) - 95.450).abs() < 0.1);
1296+
/// // 99.7% of a normal distribution is within three standard deviations
1297+
/// assert!((within_standard_deviations(3.0) - 99.730).abs() < 0.1);
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")))] {

src/tools/miri/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(rustc_private)]
33
#![feature(cell_update)]
44
#![feature(float_gamma)]
5+
#![feature(float_erf)]
56
#![feature(map_try_insert)]
67
#![feature(never_type)]
78
#![feature(try_blocks)]

src/tools/miri/src/shims/foreign_items.rs

+8
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
742742
| "log1pf"
743743
| "expm1f"
744744
| "tgammaf"
745+
| "erff"
746+
| "erfcf"
745747
=> {
746748
let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
747749
let f = this.read_scalar(f)?.to_f32()?;
@@ -759,6 +761,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
759761
"log1pf" => f_host.ln_1p(),
760762
"expm1f" => f_host.exp_m1(),
761763
"tgammaf" => f_host.gamma(),
764+
"erff" => f_host.erf(),
765+
"erfcf" => f_host.erfc(),
762766
_ => bug!(),
763767
};
764768
let res = res.to_soft();
@@ -799,6 +803,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
799803
| "log1p"
800804
| "expm1"
801805
| "tgamma"
806+
| "erf"
807+
| "erfc"
802808
=> {
803809
let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
804810
let f = this.read_scalar(f)?.to_f64()?;
@@ -816,6 +822,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
816822
"log1p" => f_host.ln_1p(),
817823
"expm1" => f_host.exp_m1(),
818824
"tgamma" => f_host.gamma(),
825+
"erf" => f_host.erf(),
826+
"erfc" => f_host.erfc(),
819827
_ => bug!(),
820828
};
821829
let res = res.to_soft();

0 commit comments

Comments
 (0)