diff options
| author | bors <bors@rust-lang.org> | 2025-03-17 00:33:36 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-03-17 00:33:36 +0000 |
| commit | c3dd4eefd64da263865f28d4c39d0ef09433d5bf (patch) | |
| tree | 9e1b22f921a147410f878e894ca5262e560cca8a | |
| parent | 227690a258492c84ae9927d18289208d0180e62f (diff) | |
| parent | 7c0726521f61649d3c2192dd36180b2ac489100b (diff) | |
| download | rust-c3dd4eefd64da263865f28d4c39d0ef09433d5bf.tar.gz rust-c3dd4eefd64da263865f28d4c39d0ef09433d5bf.zip | |
Auto merge of #138363 - beetrees:f16-f128-integer-convert, r=Amanieu
Add `From<{integer}>` for `f16`/`f128` impls
This PR adds `impl From<{bool,i8,u8}> for f16` and `impl From<{bool,i8,u8,i16,u16,i32,u32}> for f128`.
The `From<{i64,u64}> for f128` impls are left commented out as adding them would allow using `f128` on stable before it is stabilised like in the following example:
```rust
fn f<T: From<u64>>(x: T) -> T { x }
fn main() {
let x = f(1.0); // the type of the literal is inferred to be `f128`
}
```
None of the impls added in this PR have this issue as they are all, at minimum, also implemented by `f64`.
This PR will need a crater run for the `From<{i32,u32}>` impls, as `f64` is no longer the only float type to implement them (similar to the cause of #125198).
cc `@bjoernager`
r? `@tgross35`
Tracking issue: #116909
| -rw-r--r-- | library/core/src/convert/num.rs | 50 | ||||
| -rw-r--r-- | library/std/tests/floats/f128.rs | 31 | ||||
| -rw-r--r-- | library/std/tests/floats/f16.rs | 12 |
3 files changed, 91 insertions, 2 deletions
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 0246d0627ca..d5cb10a5d1c 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -147,22 +147,42 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf // Note: integers can only be represented with full precision in a float if -// they fit in the significand, which is 24 bits in f32 and 53 bits in f64. +// they fit in the significand, which is: +// * 11 bits in f16 +// * 24 bits in f32 +// * 53 bits in f64 +// * 113 bits in f128 // Lossy float conversions are not implemented at this time. +// FIXME(f16_f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference +// `f16`/`f128` when they are stabilised (trait impls have to have a `#[stable]` attribute, but none +// of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable). // signed integer -> float +impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. +// impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // unsigned integer -> float +impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised. +// impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); // float -> float // FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See @@ -174,7 +194,12 @@ impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0 impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); macro_rules! impl_float_from_bool { - ($float:ty) => { + ( + $float:ty $(; + doctest_prefix: $(#[doc = $doctest_prefix:literal])* + doctest_suffix: $(#[doc = $doctest_suffix:literal])* + )? + ) => { #[stable(feature = "float_from_bool", since = "1.68.0")] impl From<bool> for $float { #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] @@ -182,12 +207,14 @@ macro_rules! impl_float_from_bool { /// /// # Examples /// ``` + $($(#[doc = $doctest_prefix])*)? #[doc = concat!("let x: ", stringify!($float)," = false.into();")] /// assert_eq!(x, 0.0); /// assert!(x.is_sign_positive()); /// #[doc = concat!("let y: ", stringify!($float)," = true.into();")] /// assert_eq!(y, 1.0); + $($(#[doc = $doctest_suffix])*)? /// ``` #[inline] fn from(small: bool) -> Self { @@ -198,8 +225,27 @@ macro_rules! impl_float_from_bool { } // boolean -> float +impl_float_from_bool!( + f16; + doctest_prefix: + // rustdoc doesn't remove the conventional space after the `///` + ///#![feature(f16)] + ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + doctest_suffix: + ///# } +); impl_float_from_bool!(f32); impl_float_from_bool!(f64); +impl_float_from_bool!( + f128; + doctest_prefix: + ///#![feature(f128)] + ///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] { + /// + doctest_suffix: + ///# } +); // no possible bounds violation macro_rules! impl_try_from_unbounded { diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs index d0e8b157e6b..b4a6c672bf0 100644 --- a/library/std/tests/floats/f128.rs +++ b/library/std/tests/floats/f128.rs @@ -983,3 +983,34 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_from() { + assert_eq!(f128::from(false), 0.0); + assert_eq!(f128::from(true), 1.0); + assert_eq!(f128::from(u8::MIN), 0.0); + assert_eq!(f128::from(42_u8), 42.0); + assert_eq!(f128::from(u8::MAX), 255.0); + assert_eq!(f128::from(i8::MIN), -128.0); + assert_eq!(f128::from(42_i8), 42.0); + assert_eq!(f128::from(i8::MAX), 127.0); + assert_eq!(f128::from(u16::MIN), 0.0); + assert_eq!(f128::from(42_u16), 42.0); + assert_eq!(f128::from(u16::MAX), 65535.0); + assert_eq!(f128::from(i16::MIN), -32768.0); + assert_eq!(f128::from(42_i16), 42.0); + assert_eq!(f128::from(i16::MAX), 32767.0); + assert_eq!(f128::from(u32::MIN), 0.0); + assert_eq!(f128::from(42_u32), 42.0); + assert_eq!(f128::from(u32::MAX), 4294967295.0); + assert_eq!(f128::from(i32::MIN), -2147483648.0); + assert_eq!(f128::from(42_i32), 42.0); + assert_eq!(f128::from(i32::MAX), 2147483647.0); + // FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added. + // assert_eq!(f128::from(u64::MIN), 0.0); + // assert_eq!(f128::from(42_u64), 42.0); + // assert_eq!(f128::from(u64::MAX), 18446744073709551615.0); + // assert_eq!(f128::from(i64::MIN), -9223372036854775808.0); + // assert_eq!(f128::from(42_i64), 42.0); + // assert_eq!(f128::from(i64::MAX), 9223372036854775807.0); +} diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 19389a9178e..ca0b8efbe83 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -953,3 +953,15 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); } + +#[test] +fn test_from() { + assert_eq!(f16::from(false), 0.0); + assert_eq!(f16::from(true), 1.0); + assert_eq!(f16::from(u8::MIN), 0.0); + assert_eq!(f16::from(42_u8), 42.0); + assert_eq!(f16::from(u8::MAX), 255.0); + assert_eq!(f16::from(i8::MIN), -128.0); + assert_eq!(f16::from(42_i8), 42.0); + assert_eq!(f16::from(i8::MAX), 127.0); +} |
