@@ -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,93 @@ float_test! {
16321638 }
16331639}
16341640
1641+ // Test the `float_exact_integer_constants` feature
1642+ float_test ! {
1643+ name: max_exact_integer_constant,
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+ // The maximum integer that converts to a unique floating point
1650+ // value.
1651+ const MAX_EXACT_INTEGER : <Float as TestableFloat >:: SInt = Float :: MAX_EXACT_INTEGER ;
1652+
1653+ let max_minus_one = ( MAX_EXACT_INTEGER - 1 ) as Float as <Float as TestableFloat >:: SInt ;
1654+ let max_plus_one = ( MAX_EXACT_INTEGER + 1 ) as Float as <Float as TestableFloat >:: SInt ;
1655+ let max_plus_two = ( MAX_EXACT_INTEGER + 2 ) as Float as <Float as TestableFloat >:: SInt ;
1656+
1657+ // This does an extra round trip back to float for the second operand in
1658+ // order to print the results if there is a mismatch
1659+ assert_biteq!( ( MAX_EXACT_INTEGER - 1 ) as Float , max_minus_one as Float ) ;
1660+ assert_biteq!( MAX_EXACT_INTEGER as Float , MAX_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt as Float ) ;
1661+ assert_biteq!( ( MAX_EXACT_INTEGER + 1 ) as Float , max_plus_one as Float ) ;
1662+ // The first non-unique conversion, where `max_plus_two` roundtrips to
1663+ // `max_plus_one`
1664+ assert_biteq!( ( MAX_EXACT_INTEGER + 1 ) as Float , ( MAX_EXACT_INTEGER + 2 ) as Float ) ;
1665+ assert_biteq!( ( MAX_EXACT_INTEGER + 2 ) as Float , max_plus_one as Float ) ;
1666+ assert_biteq!( ( MAX_EXACT_INTEGER + 2 ) as Float , max_plus_two as Float ) ;
1667+
1668+ // Lossless roundtrips, for integers
1669+ assert!( MAX_EXACT_INTEGER - 1 == max_minus_one) ;
1670+ assert!( MAX_EXACT_INTEGER == MAX_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt ) ;
1671+ assert!( MAX_EXACT_INTEGER + 1 == max_plus_one) ;
1672+ // The first non-unique conversion, where `max_plus_two` roundtrips to
1673+ // one less than the starting value
1674+ assert!( MAX_EXACT_INTEGER + 2 != max_plus_two) ;
1675+
1676+ // max-1 | max+0 | max+1 | max+2
1677+ // After roundtripping, +1 and +2 will equal each other
1678+ assert!( max_minus_one != MAX_EXACT_INTEGER ) ;
1679+ assert!( MAX_EXACT_INTEGER != max_plus_one) ;
1680+ assert!( max_plus_one == max_plus_two) ;
1681+ }
1682+ }
1683+
1684+ float_test ! {
1685+ name: min_exact_integer_constant,
1686+ attrs: {
1687+ f16: #[ cfg( any( miri, target_has_reliable_f16) ) ] ,
1688+ f128: #[ cfg( any( miri, target_has_reliable_f128) ) ] ,
1689+ } ,
1690+ test<Float > {
1691+ // The minimum integer that converts to a unique floating point
1692+ // value.
1693+ const MIN_EXACT_INTEGER : <Float as TestableFloat >:: SInt = Float :: MIN_EXACT_INTEGER ;
1694+
1695+ // Same logic as the `max` test, but we work our way leftward
1696+ // across the number line from (min_exact + 1) to (min_exact - 2).
1697+ let min_plus_one = ( MIN_EXACT_INTEGER + 1 ) as Float as <Float as TestableFloat >:: SInt ;
1698+ let min_minus_one = ( MIN_EXACT_INTEGER - 1 ) as Float as <Float as TestableFloat >:: SInt ;
1699+ let min_minus_two = ( MIN_EXACT_INTEGER - 2 ) as Float as <Float as TestableFloat >:: SInt ;
1700+
1701+ // This does an extra round trip back to float for the second operand in
1702+ // order to print the results if there is a mismatch
1703+ assert_biteq!( ( MIN_EXACT_INTEGER + 1 ) as Float , min_plus_one as Float ) ;
1704+ assert_biteq!( MIN_EXACT_INTEGER as Float , MIN_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt as Float ) ;
1705+ assert_biteq!( ( MIN_EXACT_INTEGER - 1 ) as Float , min_minus_one as Float ) ;
1706+ // The first non-unique conversion, which roundtrips to one
1707+ // greater than the starting value.
1708+ assert_biteq!( ( MIN_EXACT_INTEGER - 1 ) as Float , ( MIN_EXACT_INTEGER - 2 ) as Float ) ;
1709+ assert_biteq!( ( MIN_EXACT_INTEGER - 2 ) as Float , min_minus_one as Float ) ;
1710+ assert_biteq!( ( MIN_EXACT_INTEGER - 2 ) as Float , min_minus_two as Float ) ;
1711+
1712+ // Lossless roundtrips, for integers
1713+ assert!( MIN_EXACT_INTEGER + 1 == min_plus_one) ;
1714+ assert!( MIN_EXACT_INTEGER == MIN_EXACT_INTEGER as Float as <Float as TestableFloat >:: SInt ) ;
1715+ assert!( MIN_EXACT_INTEGER - 1 == min_minus_one) ;
1716+ // The first non-unique conversion, which roundtrips to one
1717+ // greater than the starting value.
1718+ assert!( MIN_EXACT_INTEGER - 2 != min_minus_two) ;
1719+
1720+ // min-2 | min-1 | min | min+1
1721+ // After roundtripping, -2 and -1 will equal each other.
1722+ assert!( min_plus_one != MIN_EXACT_INTEGER ) ;
1723+ assert!( MIN_EXACT_INTEGER != min_minus_one) ;
1724+ assert!( min_minus_one == min_minus_two) ;
1725+ }
1726+ }
1727+
16351728// FIXME(f128): Uncomment and adapt these tests once the From<{u64,i64}> impls are added.
16361729// float_test! {
16371730// name: from_u64_i64,
0 commit comments