Skip to content

Commit c3dd4ee

Browse files
committed
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
2 parents 227690a + 7c07265 commit c3dd4ee

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

library/core/src/convert/num.rs

+48-2
Original file line numberDiff line numberDiff line change
@@ -147,22 +147,42 @@ impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.2
147147
// https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-951.pdf
148148

149149
// Note: integers can only be represented with full precision in a float if
150-
// they fit in the significand, which is 24 bits in f32 and 53 bits in f64.
150+
// they fit in the significand, which is:
151+
// * 11 bits in f16
152+
// * 24 bits in f32
153+
// * 53 bits in f64
154+
// * 113 bits in f128
151155
// Lossy float conversions are not implemented at this time.
156+
// FIXME(f16_f128): The `f16`/`f128` impls `#[stable]` attributes should be changed to reference
157+
// `f16`/`f128` when they are stabilised (trait impls have to have a `#[stable]` attribute, but none
158+
// of the `f16`/`f128` impls can be used on stable as the `f16` and `f128` types are unstable).
152159

153160
// signed integer -> float
161+
impl_from!(i8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
154162
impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
155163
impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
164+
impl_from!(i8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
156165
impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
157166
impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
167+
impl_from!(i16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
158168
impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
169+
impl_from!(i32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
170+
// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised.
171+
// impl_from!(i64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
159172

160173
// unsigned integer -> float
174+
impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
161175
impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
162176
impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
177+
impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
178+
impl_from!(u16 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
163179
impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
164180
impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
181+
impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
165182
impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
183+
impl_from!(u32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
184+
// FIXME(f16_f128): This impl would allow using `f128` on stable before it is stabilised.
185+
// impl_from!(u64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
166186

167187
// float -> float
168188
// FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See
@@ -174,20 +194,27 @@ impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0
174194
impl_from!(f64 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
175195

176196
macro_rules! impl_float_from_bool {
177-
($float:ty) => {
197+
(
198+
$float:ty $(;
199+
doctest_prefix: $(#[doc = $doctest_prefix:literal])*
200+
doctest_suffix: $(#[doc = $doctest_suffix:literal])*
201+
)?
202+
) => {
178203
#[stable(feature = "float_from_bool", since = "1.68.0")]
179204
impl From<bool> for $float {
180205
#[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")]
181206
/// The resulting value is positive `0.0` for `false` and `1.0` for `true` values.
182207
///
183208
/// # Examples
184209
/// ```
210+
$($(#[doc = $doctest_prefix])*)?
185211
#[doc = concat!("let x: ", stringify!($float)," = false.into();")]
186212
/// assert_eq!(x, 0.0);
187213
/// assert!(x.is_sign_positive());
188214
///
189215
#[doc = concat!("let y: ", stringify!($float)," = true.into();")]
190216
/// assert_eq!(y, 1.0);
217+
$($(#[doc = $doctest_suffix])*)?
191218
/// ```
192219
#[inline]
193220
fn from(small: bool) -> Self {
@@ -198,8 +225,27 @@ macro_rules! impl_float_from_bool {
198225
}
199226

200227
// boolean -> float
228+
impl_float_from_bool!(
229+
f16;
230+
doctest_prefix:
231+
// rustdoc doesn't remove the conventional space after the `///`
232+
///#![feature(f16)]
233+
///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
234+
///
235+
doctest_suffix:
236+
///# }
237+
);
201238
impl_float_from_bool!(f32);
202239
impl_float_from_bool!(f64);
240+
impl_float_from_bool!(
241+
f128;
242+
doctest_prefix:
243+
///#![feature(f128)]
244+
///# #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
245+
///
246+
doctest_suffix:
247+
///# }
248+
);
203249

204250
// no possible bounds violation
205251
macro_rules! impl_try_from_unbounded {

library/std/tests/floats/f128.rs

+31
Original file line numberDiff line numberDiff line change
@@ -983,3 +983,34 @@ fn test_total_cmp() {
983983
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f128::INFINITY));
984984
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
985985
}
986+
987+
#[test]
988+
fn test_from() {
989+
assert_eq!(f128::from(false), 0.0);
990+
assert_eq!(f128::from(true), 1.0);
991+
assert_eq!(f128::from(u8::MIN), 0.0);
992+
assert_eq!(f128::from(42_u8), 42.0);
993+
assert_eq!(f128::from(u8::MAX), 255.0);
994+
assert_eq!(f128::from(i8::MIN), -128.0);
995+
assert_eq!(f128::from(42_i8), 42.0);
996+
assert_eq!(f128::from(i8::MAX), 127.0);
997+
assert_eq!(f128::from(u16::MIN), 0.0);
998+
assert_eq!(f128::from(42_u16), 42.0);
999+
assert_eq!(f128::from(u16::MAX), 65535.0);
1000+
assert_eq!(f128::from(i16::MIN), -32768.0);
1001+
assert_eq!(f128::from(42_i16), 42.0);
1002+
assert_eq!(f128::from(i16::MAX), 32767.0);
1003+
assert_eq!(f128::from(u32::MIN), 0.0);
1004+
assert_eq!(f128::from(42_u32), 42.0);
1005+
assert_eq!(f128::from(u32::MAX), 4294967295.0);
1006+
assert_eq!(f128::from(i32::MIN), -2147483648.0);
1007+
assert_eq!(f128::from(42_i32), 42.0);
1008+
assert_eq!(f128::from(i32::MAX), 2147483647.0);
1009+
// FIXME(f16_f128): Uncomment these tests once the From<{u64,i64}> impls are added.
1010+
// assert_eq!(f128::from(u64::MIN), 0.0);
1011+
// assert_eq!(f128::from(42_u64), 42.0);
1012+
// assert_eq!(f128::from(u64::MAX), 18446744073709551615.0);
1013+
// assert_eq!(f128::from(i64::MIN), -9223372036854775808.0);
1014+
// assert_eq!(f128::from(42_i64), 42.0);
1015+
// assert_eq!(f128::from(i64::MAX), 9223372036854775807.0);
1016+
}

library/std/tests/floats/f16.rs

+12
Original file line numberDiff line numberDiff line change
@@ -953,3 +953,15 @@ fn test_total_cmp() {
953953
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::INFINITY));
954954
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
955955
}
956+
957+
#[test]
958+
fn test_from() {
959+
assert_eq!(f16::from(false), 0.0);
960+
assert_eq!(f16::from(true), 1.0);
961+
assert_eq!(f16::from(u8::MIN), 0.0);
962+
assert_eq!(f16::from(42_u8), 42.0);
963+
assert_eq!(f16::from(u8::MAX), 255.0);
964+
assert_eq!(f16::from(i8::MIN), -128.0);
965+
assert_eq!(f16::from(42_i8), 42.0);
966+
assert_eq!(f16::from(i8::MAX), 127.0);
967+
}

0 commit comments

Comments
 (0)