Skip to content

Commit f57853b

Browse files
Rollup merge of rust-lang#131304 - RalfJung:float-core, r=tgross35
float types: move copysign, abs, signum to libcore These operations are explicitly specified to act "bitwise", i.e. they just act on the sign bit and do not even quiet signaling NaNs. We also list them as ["non-arithmetic operations"](https://doc.rust-lang.org/nightly/std/primitive.f32.html#nan-bit-patterns), and all the other non-arithmetic operations are in libcore. There's no reason to expect them to require any sort of runtime support, and from [these experiments](rust-lang#50145 (comment)) it seems like LLVM indeed compiles them in a way that does not require any sort of runtime support. Nominating for `@rust-lang/libs-api` since this change takes immediate effect on stable. Part of rust-lang#50145.
2 parents 6439774 + a461cf9 commit f57853b

File tree

9 files changed

+374
-414
lines changed

9 files changed

+374
-414
lines changed

core/src/fmt/float.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ macro_rules! impl_general_format {
1313
($($t:ident)*) => {
1414
$(impl GeneralFormat for $t {
1515
fn already_rounded_value_should_use_exponential(&self) -> bool {
16-
let abs = $t::abs_private(*self);
16+
let abs = $t::abs(*self);
1717
(abs != 0.0 && abs < 1e-4) || abs >= 1e+16
1818
}
1919
})*

core/src/num/f128.rs

+100-14
Original file line numberDiff line numberDiff line change
@@ -285,17 +285,6 @@ impl f128 {
285285
self != self
286286
}
287287

288-
// FIXME(#50145): `abs` is publicly unavailable in core due to
289-
// concerns about portability, so this implementation is for
290-
// private use internally.
291-
#[inline]
292-
pub(crate) const fn abs_private(self) -> f128 {
293-
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
294-
unsafe {
295-
mem::transmute::<u128, f128>(mem::transmute::<f128, u128>(self) & !Self::SIGN_MASK)
296-
}
297-
}
298-
299288
/// Returns `true` if this value is positive infinity or negative infinity, and
300289
/// `false` otherwise.
301290
///
@@ -345,10 +334,11 @@ impl f128 {
345334
#[inline]
346335
#[must_use]
347336
#[unstable(feature = "f128", issue = "116909")]
337+
#[rustc_allow_const_fn_unstable(const_float_methods)] // for `abs`
348338
pub const fn is_finite(self) -> bool {
349339
// There's no need to handle NaN separately: if self is NaN,
350340
// the comparison is not true, exactly as desired.
351-
self.abs_private() < Self::INFINITY
341+
self.abs() < Self::INFINITY
352342
}
353343

354344
/// Returns `true` if the number is [subnormal].
@@ -836,8 +826,8 @@ impl f128 {
836826
const HI: f128 = f128::MAX / 2.;
837827

838828
let (a, b) = (self, other);
839-
let abs_a = a.abs_private();
840-
let abs_b = b.abs_private();
829+
let abs_a = a.abs();
830+
let abs_b = b.abs();
841831

842832
if abs_a <= HI && abs_b <= HI {
843833
// Overflow is impossible
@@ -1281,4 +1271,100 @@ impl f128 {
12811271
}
12821272
self
12831273
}
1274+
1275+
/// Computes the absolute value of `self`.
1276+
///
1277+
/// This function always returns the precise result.
1278+
///
1279+
/// # Examples
1280+
///
1281+
/// ```
1282+
/// #![feature(f128)]
1283+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1284+
///
1285+
/// let x = 3.5_f128;
1286+
/// let y = -3.5_f128;
1287+
///
1288+
/// assert_eq!(x.abs(), x);
1289+
/// assert_eq!(y.abs(), -y);
1290+
///
1291+
/// assert!(f128::NAN.abs().is_nan());
1292+
/// # }
1293+
/// ```
1294+
#[inline]
1295+
#[unstable(feature = "f128", issue = "116909")]
1296+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1297+
#[must_use = "method returns a new number and does not mutate the original value"]
1298+
pub const fn abs(self) -> Self {
1299+
// FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
1300+
// We don't do this now because LLVM has lowering bugs for f128 math.
1301+
Self::from_bits(self.to_bits() & !(1 << 127))
1302+
}
1303+
1304+
/// Returns a number that represents the sign of `self`.
1305+
///
1306+
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
1307+
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
1308+
/// - NaN if the number is NaN
1309+
///
1310+
/// # Examples
1311+
///
1312+
/// ```
1313+
/// #![feature(f128)]
1314+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1315+
///
1316+
/// let f = 3.5_f128;
1317+
///
1318+
/// assert_eq!(f.signum(), 1.0);
1319+
/// assert_eq!(f128::NEG_INFINITY.signum(), -1.0);
1320+
///
1321+
/// assert!(f128::NAN.signum().is_nan());
1322+
/// # }
1323+
/// ```
1324+
#[inline]
1325+
#[unstable(feature = "f128", issue = "116909")]
1326+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1327+
#[must_use = "method returns a new number and does not mutate the original value"]
1328+
pub const fn signum(self) -> f128 {
1329+
if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
1330+
}
1331+
1332+
/// Returns a number composed of the magnitude of `self` and the sign of
1333+
/// `sign`.
1334+
///
1335+
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
1336+
/// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
1337+
/// returned.
1338+
///
1339+
/// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
1340+
/// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
1341+
/// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
1342+
/// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
1343+
/// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
1344+
/// info.
1345+
///
1346+
/// # Examples
1347+
///
1348+
/// ```
1349+
/// #![feature(f128)]
1350+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1351+
///
1352+
/// let f = 3.5_f128;
1353+
///
1354+
/// assert_eq!(f.copysign(0.42), 3.5_f128);
1355+
/// assert_eq!(f.copysign(-0.42), -3.5_f128);
1356+
/// assert_eq!((-f).copysign(0.42), 3.5_f128);
1357+
/// assert_eq!((-f).copysign(-0.42), -3.5_f128);
1358+
///
1359+
/// assert!(f128::NAN.copysign(1.0).is_nan());
1360+
/// # }
1361+
/// ```
1362+
#[inline]
1363+
#[unstable(feature = "f128", issue = "116909")]
1364+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1365+
#[must_use = "method returns a new number and does not mutate the original value"]
1366+
pub const fn copysign(self, sign: f128) -> f128 {
1367+
// SAFETY: this is actually a safe intrinsic
1368+
unsafe { intrinsics::copysignf128(self, sign) }
1369+
}
12841370
}

core/src/num/f16.rs

+99-12
Original file line numberDiff line numberDiff line change
@@ -279,15 +279,6 @@ impl f16 {
279279
self != self
280280
}
281281

282-
// FIXMxE(#50145): `abs` is publicly unavailable in core due to
283-
// concerns about portability, so this implementation is for
284-
// private use internally.
285-
#[inline]
286-
pub(crate) const fn abs_private(self) -> f16 {
287-
// SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
288-
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
289-
}
290-
291282
/// Returns `true` if this value is positive infinity or negative infinity, and
292283
/// `false` otherwise.
293284
///
@@ -335,10 +326,11 @@ impl f16 {
335326
#[inline]
336327
#[must_use]
337328
#[unstable(feature = "f16", issue = "116909")]
329+
#[rustc_allow_const_fn_unstable(const_float_methods)] // for `abs`
338330
pub const fn is_finite(self) -> bool {
339331
// There's no need to handle NaN separately: if self is NaN,
340332
// the comparison is not true, exactly as desired.
341-
self.abs_private() < Self::INFINITY
333+
self.abs() < Self::INFINITY
342334
}
343335

344336
/// Returns `true` if the number is [subnormal].
@@ -821,8 +813,8 @@ impl f16 {
821813
const HI: f16 = f16::MAX / 2.;
822814

823815
let (a, b) = (self, other);
824-
let abs_a = a.abs_private();
825-
let abs_b = b.abs_private();
816+
let abs_a = a.abs();
817+
let abs_b = b.abs();
826818

827819
if abs_a <= HI && abs_b <= HI {
828820
// Overflow is impossible
@@ -1256,4 +1248,99 @@ impl f16 {
12561248
}
12571249
self
12581250
}
1251+
1252+
/// Computes the absolute value of `self`.
1253+
///
1254+
/// This function always returns the precise result.
1255+
///
1256+
/// # Examples
1257+
///
1258+
/// ```
1259+
/// #![feature(f16)]
1260+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1261+
///
1262+
/// let x = 3.5_f16;
1263+
/// let y = -3.5_f16;
1264+
///
1265+
/// assert_eq!(x.abs(), x);
1266+
/// assert_eq!(y.abs(), -y);
1267+
///
1268+
/// assert!(f16::NAN.abs().is_nan());
1269+
/// # }
1270+
/// ```
1271+
#[inline]
1272+
#[unstable(feature = "f16", issue = "116909")]
1273+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1274+
#[must_use = "method returns a new number and does not mutate the original value"]
1275+
pub const fn abs(self) -> Self {
1276+
// FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
1277+
Self::from_bits(self.to_bits() & !(1 << 15))
1278+
}
1279+
1280+
/// Returns a number that represents the sign of `self`.
1281+
///
1282+
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
1283+
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
1284+
/// - NaN if the number is NaN
1285+
///
1286+
/// # Examples
1287+
///
1288+
/// ```
1289+
/// #![feature(f16)]
1290+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1291+
///
1292+
/// let f = 3.5_f16;
1293+
///
1294+
/// assert_eq!(f.signum(), 1.0);
1295+
/// assert_eq!(f16::NEG_INFINITY.signum(), -1.0);
1296+
///
1297+
/// assert!(f16::NAN.signum().is_nan());
1298+
/// # }
1299+
/// ```
1300+
#[inline]
1301+
#[unstable(feature = "f16", issue = "116909")]
1302+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1303+
#[must_use = "method returns a new number and does not mutate the original value"]
1304+
pub const fn signum(self) -> f16 {
1305+
if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
1306+
}
1307+
1308+
/// Returns a number composed of the magnitude of `self` and the sign of
1309+
/// `sign`.
1310+
///
1311+
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
1312+
/// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
1313+
/// returned.
1314+
///
1315+
/// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
1316+
/// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
1317+
/// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
1318+
/// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
1319+
/// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
1320+
/// info.
1321+
///
1322+
/// # Examples
1323+
///
1324+
/// ```
1325+
/// #![feature(f16)]
1326+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
1327+
///
1328+
/// let f = 3.5_f16;
1329+
///
1330+
/// assert_eq!(f.copysign(0.42), 3.5_f16);
1331+
/// assert_eq!(f.copysign(-0.42), -3.5_f16);
1332+
/// assert_eq!((-f).copysign(0.42), 3.5_f16);
1333+
/// assert_eq!((-f).copysign(-0.42), -3.5_f16);
1334+
///
1335+
/// assert!(f16::NAN.copysign(1.0).is_nan());
1336+
/// # }
1337+
/// ```
1338+
#[inline]
1339+
#[unstable(feature = "f16", issue = "116909")]
1340+
#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
1341+
#[must_use = "method returns a new number and does not mutate the original value"]
1342+
pub const fn copysign(self, sign: f16) -> f16 {
1343+
// SAFETY: this is actually a safe intrinsic
1344+
unsafe { intrinsics::copysignf16(self, sign) }
1345+
}
12591346
}

0 commit comments

Comments
 (0)