@@ -4,6 +4,8 @@ use std::ops::{Add, Div, Mul, Rem, Sub};
44trait TestableFloat : Sized {
55 /// Unsigned int with the same size, for converting to/from bits.
66 type Int ;
7+ /// Signed int with the same size.
8+ type SInt ;
79 /// Set the default tolerance for float comparison based on the type.
810 const APPROX : Self ;
911 /// Allow looser tolerance for f32 on miri
@@ -44,6 +46,7 @@ trait TestableFloat: Sized {
4446
4547impl TestableFloat for f16 {
4648 type Int = u16 ;
49+ type SInt = i16 ;
4750 const APPROX : Self = 1e-3 ;
4851 const _180_TO_RADIANS_APPROX: Self = 1e-2 ;
4952 const PI_TO_DEGREES_APPROX : Self = 0.125 ;
@@ -71,6 +74,7 @@ impl TestableFloat for f16 {
7174
7275impl TestableFloat for f32 {
7376 type Int = u32 ;
77+ type SInt = i32 ;
7478 const APPROX : Self = 1e-6 ;
7579 /// Miri adds some extra errors to float functions; make sure the tests still pass.
7680 /// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
@@ -100,6 +104,7 @@ impl TestableFloat for f32 {
100104
101105impl TestableFloat for f64 {
102106 type Int = u64 ;
107+ type SInt = i64 ;
103108 const APPROX : Self = 1e-6 ;
104109 const ZERO : Self = 0.0 ;
105110 const ONE : Self = 1.0 ;
@@ -125,6 +130,7 @@ impl TestableFloat for f64 {
125130
126131impl TestableFloat for f128 {
127132 type Int = u128 ;
133+ type SInt = i128 ;
128134 const APPROX : Self = 1e-9 ;
129135 const ZERO : Self = 0.0 ;
130136 const ONE : Self = 1.0 ;
@@ -1632,6 +1638,66 @@ float_test! {
16321638 }
16331639}
16341640
1641+ // Test the `float_exact_integer_constants` feature
1642+ float_test ! {
1643+ name: exact_integer_constants,
1644+ attrs: {
1645+ f16: #[ cfg( any( miri, target_has_reliable_f16) ) ] ,
1646+ f128: #[ cfg( any( miri, target_has_reliable_f128) ) ] ,
1647+ } ,
1648+ test<Float > {
1649+ {
1650+ // The maximum integer that converts to a unique floating point
1651+ // value.
1652+ const MAX_EXACT_INTEGER : <Float as TestableFloat >:: SInt = Float :: MAX_EXACT_INTEGER ;
1653+
1654+ let max_minus_one = ( MAX_EXACT_INTEGER - 1 ) as Float as <Float as TestableFloat >:: SInt ;
1655+ let max_plus_one = ( MAX_EXACT_INTEGER + 1 ) as Float as <Float as TestableFloat >:: SInt ;
1656+ let max_plus_two = ( MAX_EXACT_INTEGER + 2 ) as Float as <Float as TestableFloat >:: SInt ;
1657+
1658+ // Lossless roundtrips.
1659+ assert!( MAX_EXACT_INTEGER - 1 == max_minus_one) ;
1660+ assert!( MAX_EXACT_INTEGER == MAX_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt ) ;
1661+ assert!( MAX_EXACT_INTEGER + 1 == max_plus_one) ;
1662+ // The first non-unique conversion, which roundtrips to one less
1663+ // than the starting value.
1664+ assert!( MAX_EXACT_INTEGER + 2 != max_plus_two) ;
1665+
1666+ // max-1 | max+0 | max+1 | max+2
1667+ // After roundtripping, +1 and +2 will equal each other.
1668+ assert!( max_minus_one != MAX_EXACT_INTEGER ) ;
1669+ assert!( MAX_EXACT_INTEGER != max_plus_one) ;
1670+ assert!( max_plus_one == max_plus_two) ;
1671+ }
1672+
1673+ {
1674+ // The minimum integer that converts to a unique floating point
1675+ // value.
1676+ const MIN_EXACT_INTEGER : <Float as TestableFloat >:: SInt = Float :: MIN_EXACT_INTEGER ;
1677+
1678+ // Same logic as the previous block, but we work our way leftward
1679+ // across the number line from (min_exact + 1) to (min_exact - 2).
1680+ let min_plus_one = ( MIN_EXACT_INTEGER + 1 ) as Float as <Float as TestableFloat >:: SInt ;
1681+ let min_minus_one = ( MIN_EXACT_INTEGER - 1 ) as Float as <Float as TestableFloat >:: SInt ;
1682+ let min_minus_two = ( MIN_EXACT_INTEGER - 2 ) as Float as <Float as TestableFloat >:: SInt ;
1683+
1684+ // Lossless roundtrips.
1685+ assert!( MIN_EXACT_INTEGER + 1 == min_plus_one) ;
1686+ assert!( MIN_EXACT_INTEGER == MIN_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt ) ;
1687+ assert!( MIN_EXACT_INTEGER - 1 == min_minus_one) ;
1688+ // The first non-unique conversion, which roundtrips to one
1689+ // greater than the starting value.
1690+ assert!( MIN_EXACT_INTEGER - 2 != min_minus_two) ;
1691+
1692+ // min-2 | min-1 | min | min+1
1693+ // After roundtripping, -2 and -1 will equal each other.
1694+ assert!( min_plus_one != MIN_EXACT_INTEGER ) ;
1695+ assert!( MIN_EXACT_INTEGER != min_minus_one) ;
1696+ assert!( min_minus_one == min_minus_two) ;
1697+ }
1698+ }
1699+ }
1700+
16351701// FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
16361702// float_test! {
16371703// name: from_u64_i64,
0 commit comments