Skip to content

Commit 309f9b7

Browse files
authored
Unrolled build for #152512
Rollup merge of #152512 - okaneco:exact_integer, r=tgross35 core: Implement feature `float_exact_integer_constants` Accepted ACP - rust-lang/libs-team#713 (comment) Tracking issue - #152466 Implement accepted ACP for `MAX_EXACT_INTEGER` and `MIN_EXACT_INTEGER` on `f16`, `f32`, `f64`, and `f128` Add tests to `coretests/tests/floats/mod.rs`
2 parents 3c9faa0 + 7be024f commit 309f9b7

7 files changed

Lines changed: 339 additions & 1 deletion

File tree

compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ pub(crate) fn codegen_cast(
208208
let ret_ty = if to_ty.bits() < 32 { types::I32 } else { to_ty };
209209
let name = format!(
210210
"__fix{sign}tf{size}i",
211-
sign = if from_signed { "" } else { "un" },
211+
sign = if to_signed { "" } else { "uns" },
212212
size = match ret_ty {
213213
types::I32 => 's',
214214
types::I64 => 'd',

library/core/src/num/f128.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,70 @@ impl f128 {
275275
#[unstable(feature = "f128", issue = "116909")]
276276
pub const NEG_INFINITY: f128 = -1.0_f128 / 0.0_f128;
277277

278+
/// Maximum integer that can be represented exactly in an [`f128`] value,
279+
/// with no other integer converting to the same floating point value.
280+
///
281+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
282+
/// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
283+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
284+
/// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
285+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
286+
/// "one-to-one" mapping.
287+
///
288+
/// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
289+
/// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
290+
/// ```
291+
/// #![feature(f128)]
292+
/// #![feature(float_exact_integer_constants)]
293+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
294+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
295+
/// # #[cfg(target_has_reliable_f128)] {
296+
/// let max_exact_int = f128::MAX_EXACT_INTEGER;
297+
/// assert_eq!(max_exact_int, max_exact_int as f128 as i128);
298+
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f128 as i128);
299+
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f128 as i128);
300+
///
301+
/// // Beyond `f128::MAX_EXACT_INTEGER`, multiple integers can map to one float value
302+
/// assert_eq!((max_exact_int + 1) as f128, (max_exact_int + 2) as f128);
303+
/// # }}
304+
/// ```
305+
// #[unstable(feature = "f128", issue = "116909")]
306+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
307+
pub const MAX_EXACT_INTEGER: i128 = (1 << Self::MANTISSA_DIGITS) - 1;
308+
309+
/// Minimum integer that can be represented exactly in an [`f128`] value,
310+
/// with no other integer converting to the same floating point value.
311+
///
312+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
313+
/// there is a "one-to-one" mapping between [`i128`] and [`f128`] values.
314+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f128`] and back to
315+
/// [`i128`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f128`] value
316+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
317+
/// "one-to-one" mapping.
318+
///
319+
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
320+
///
321+
/// [`MAX_EXACT_INTEGER`]: f128::MAX_EXACT_INTEGER
322+
/// [`MIN_EXACT_INTEGER`]: f128::MIN_EXACT_INTEGER
323+
/// ```
324+
/// #![feature(f128)]
325+
/// #![feature(float_exact_integer_constants)]
326+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
327+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
328+
/// # #[cfg(target_has_reliable_f128)] {
329+
/// let min_exact_int = f128::MIN_EXACT_INTEGER;
330+
/// assert_eq!(min_exact_int, min_exact_int as f128 as i128);
331+
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f128 as i128);
332+
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f128 as i128);
333+
///
334+
/// // Below `f128::MIN_EXACT_INTEGER`, multiple integers can map to one float value
335+
/// assert_eq!((min_exact_int - 1) as f128, (min_exact_int - 2) as f128);
336+
/// # }}
337+
/// ```
338+
// #[unstable(feature = "f128", issue = "116909")]
339+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
340+
pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
341+
278342
/// Sign bit
279343
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
280344

library/core/src/num/f16.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,70 @@ impl f16 {
269269
#[unstable(feature = "f16", issue = "116909")]
270270
pub const NEG_INFINITY: f16 = -1.0_f16 / 0.0_f16;
271271

272+
/// Maximum integer that can be represented exactly in an [`f16`] value,
273+
/// with no other integer converting to the same floating point value.
274+
///
275+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
276+
/// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
277+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
278+
/// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
279+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
280+
/// "one-to-one" mapping.
281+
///
282+
/// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
283+
/// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
284+
/// ```
285+
/// #![feature(f16)]
286+
/// #![feature(float_exact_integer_constants)]
287+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
288+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
289+
/// # #[cfg(target_has_reliable_f16)] {
290+
/// let max_exact_int = f16::MAX_EXACT_INTEGER;
291+
/// assert_eq!(max_exact_int, max_exact_int as f16 as i16);
292+
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f16 as i16);
293+
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f16 as i16);
294+
///
295+
/// // Beyond `f16::MAX_EXACT_INTEGER`, multiple integers can map to one float value
296+
/// assert_eq!((max_exact_int + 1) as f16, (max_exact_int + 2) as f16);
297+
/// # }}
298+
/// ```
299+
// #[unstable(feature = "f16", issue = "116909")]
300+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
301+
pub const MAX_EXACT_INTEGER: i16 = (1 << Self::MANTISSA_DIGITS) - 1;
302+
303+
/// Minimum integer that can be represented exactly in an [`f16`] value,
304+
/// with no other integer converting to the same floating point value.
305+
///
306+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
307+
/// there is a "one-to-one" mapping between [`i16`] and [`f16`] values.
308+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f16`] and back to
309+
/// [`i16`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f16`] value
310+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
311+
/// "one-to-one" mapping.
312+
///
313+
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
314+
///
315+
/// [`MAX_EXACT_INTEGER`]: f16::MAX_EXACT_INTEGER
316+
/// [`MIN_EXACT_INTEGER`]: f16::MIN_EXACT_INTEGER
317+
/// ```
318+
/// #![feature(f16)]
319+
/// #![feature(float_exact_integer_constants)]
320+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
321+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
322+
/// # #[cfg(target_has_reliable_f16)] {
323+
/// let min_exact_int = f16::MIN_EXACT_INTEGER;
324+
/// assert_eq!(min_exact_int, min_exact_int as f16 as i16);
325+
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f16 as i16);
326+
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f16 as i16);
327+
///
328+
/// // Below `f16::MIN_EXACT_INTEGER`, multiple integers can map to one float value
329+
/// assert_eq!((min_exact_int - 1) as f16, (min_exact_int - 2) as f16);
330+
/// # }}
331+
/// ```
332+
// #[unstable(feature = "f16", issue = "116909")]
333+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
334+
pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
335+
272336
/// Sign bit
273337
pub(crate) const SIGN_MASK: u16 = 0x8000;
274338

library/core/src/num/f32.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,64 @@ impl f32 {
513513
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
514514
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
515515

516+
/// Maximum integer that can be represented exactly in an [`f32`] value,
517+
/// with no other integer converting to the same floating point value.
518+
///
519+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
520+
/// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
521+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
522+
/// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
523+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
524+
/// "one-to-one" mapping.
525+
///
526+
/// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
527+
/// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
528+
/// ```
529+
/// #![feature(float_exact_integer_constants)]
530+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
531+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
532+
/// let max_exact_int = f32::MAX_EXACT_INTEGER;
533+
/// assert_eq!(max_exact_int, max_exact_int as f32 as i32);
534+
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f32 as i32);
535+
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f32 as i32);
536+
///
537+
/// // Beyond `f32::MAX_EXACT_INTEGER`, multiple integers can map to one float value
538+
/// assert_eq!((max_exact_int + 1) as f32, (max_exact_int + 2) as f32);
539+
/// # }
540+
/// ```
541+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
542+
pub const MAX_EXACT_INTEGER: i32 = (1 << Self::MANTISSA_DIGITS) - 1;
543+
544+
/// Minimum integer that can be represented exactly in an [`f32`] value,
545+
/// with no other integer converting to the same floating point value.
546+
///
547+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
548+
/// there is a "one-to-one" mapping between [`i32`] and [`f32`] values.
549+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f32`] and back to
550+
/// [`i32`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f32`] value
551+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
552+
/// "one-to-one" mapping.
553+
///
554+
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
555+
///
556+
/// [`MAX_EXACT_INTEGER`]: f32::MAX_EXACT_INTEGER
557+
/// [`MIN_EXACT_INTEGER`]: f32::MIN_EXACT_INTEGER
558+
/// ```
559+
/// #![feature(float_exact_integer_constants)]
560+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
561+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
562+
/// let min_exact_int = f32::MIN_EXACT_INTEGER;
563+
/// assert_eq!(min_exact_int, min_exact_int as f32 as i32);
564+
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f32 as i32);
565+
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f32 as i32);
566+
///
567+
/// // Below `f32::MIN_EXACT_INTEGER`, multiple integers can map to one float value
568+
/// assert_eq!((min_exact_int - 1) as f32, (min_exact_int - 2) as f32);
569+
/// # }
570+
/// ```
571+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
572+
pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
573+
516574
/// Sign bit
517575
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
518576

library/core/src/num/f64.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,64 @@ impl f64 {
512512
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
513513
pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
514514

515+
/// Maximum integer that can be represented exactly in an [`f64`] value,
516+
/// with no other integer converting to the same floating point value.
517+
///
518+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
519+
/// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
520+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
521+
/// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
522+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
523+
/// "one-to-one" mapping.
524+
///
525+
/// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
526+
/// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
527+
/// ```
528+
/// #![feature(float_exact_integer_constants)]
529+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
530+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
531+
/// let max_exact_int = f64::MAX_EXACT_INTEGER;
532+
/// assert_eq!(max_exact_int, max_exact_int as f64 as i64);
533+
/// assert_eq!(max_exact_int + 1, (max_exact_int + 1) as f64 as i64);
534+
/// assert_ne!(max_exact_int + 2, (max_exact_int + 2) as f64 as i64);
535+
///
536+
/// // Beyond `f64::MAX_EXACT_INTEGER`, multiple integers can map to one float value
537+
/// assert_eq!((max_exact_int + 1) as f64, (max_exact_int + 2) as f64);
538+
/// # }
539+
/// ```
540+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
541+
pub const MAX_EXACT_INTEGER: i64 = (1 << Self::MANTISSA_DIGITS) - 1;
542+
543+
/// Minimum integer that can be represented exactly in an [`f64`] value,
544+
/// with no other integer converting to the same floating point value.
545+
///
546+
/// For an integer `x` which satisfies `MIN_EXACT_INTEGER <= x <= MAX_EXACT_INTEGER`,
547+
/// there is a "one-to-one" mapping between [`i64`] and [`f64`] values.
548+
/// `MAX_EXACT_INTEGER + 1` also converts losslessly to [`f64`] and back to
549+
/// [`i64`], but `MAX_EXACT_INTEGER + 2` converts to the same [`f64`] value
550+
/// (and back to `MAX_EXACT_INTEGER + 1` as an integer) so there is not a
551+
/// "one-to-one" mapping.
552+
///
553+
/// This constant is equivalent to `-MAX_EXACT_INTEGER`.
554+
///
555+
/// [`MAX_EXACT_INTEGER`]: f64::MAX_EXACT_INTEGER
556+
/// [`MIN_EXACT_INTEGER`]: f64::MIN_EXACT_INTEGER
557+
/// ```
558+
/// #![feature(float_exact_integer_constants)]
559+
/// # // FIXME(#152635): Float rounding on `i586` does not adhere to IEEE 754
560+
/// # #[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))] {
561+
/// let min_exact_int = f64::MIN_EXACT_INTEGER;
562+
/// assert_eq!(min_exact_int, min_exact_int as f64 as i64);
563+
/// assert_eq!(min_exact_int - 1, (min_exact_int - 1) as f64 as i64);
564+
/// assert_ne!(min_exact_int - 2, (min_exact_int - 2) as f64 as i64);
565+
///
566+
/// // Below `f64::MIN_EXACT_INTEGER`, multiple integers can map to one float value
567+
/// assert_eq!((min_exact_int - 1) as f64, (min_exact_int - 2) as f64);
568+
/// # }
569+
/// ```
570+
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
571+
pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
572+
515573
/// Sign bit
516574
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
517575

0 commit comments

Comments
 (0)