@@ -38,8 +38,8 @@ macro_rules! assert_approx_eq {
3838 } } ;
3939
4040 ( $a: expr, $b: expr) => {
41- // accept up to 64ULP (16ULP for host floats and 16ULP for miri artificial error and 32 for any rounding errors)
42- assert_approx_eq!( $a, $b, 64 ) ;
41+ // accept up to 52ULP (16ULP for host floats, 4ULP for miri artificial error and 32 for any rounding errors)
42+ assert_approx_eq!( $a, $b, 52 ) ;
4343 } ;
4444}
4545
@@ -1006,17 +1006,52 @@ pub fn libm() {
10061006 assert_approx_eq ! ( 25f32 . powf( -2f32 ) , 0.0016f32 ) ;
10071007 assert_approx_eq ! ( 400f64 . powf( 0.5f64 ) , 20f64 ) ;
10081008
1009+ // Some inputs to powf and powi result in fixed outputs
1010+ // and thus must be exactly equal to that value
1011+ // TODO: How to test NaN inputs? f*::NAN is not guaranteed
1012+ // to be any specific bit pattern (in std).
1013+ assert_eq ! ( 1f32 . powf( 10.0 ) , 1f32 ) ;
1014+ assert_eq ! ( 1f64 . powf( 100.0 ) , 1f64 ) ;
1015+ assert_eq ! ( 1f32 . powf( f32 :: INFINITY ) , 1f32 ) ;
1016+ assert_eq ! ( 1f64 . powf( f64 :: INFINITY ) , 1f64 ) ;
1017+
1018+ assert_eq ! ( ( -1f32 ) . powf( f32 :: INFINITY ) , 1f32 ) ;
1019+ assert_eq ! ( ( -1f32 ) . powf( f32 :: NEG_INFINITY ) , 1f32 ) ;
1020+ assert_eq ! ( ( -1f64 ) . powf( f64 :: INFINITY ) , 1f64 ) ;
1021+ assert_eq ! ( ( -1f64 ) . powf( f64 :: NEG_INFINITY ) , 1f64 ) ;
1022+
1023+ assert_eq ! ( 42f32 . powf( 0.0 ) , 1f32 ) ;
1024+ assert_eq ! ( 42f32 . powf( -0.0 ) , 1f32 ) ;
1025+ assert_eq ! ( 42f64 . powf( 0.0 ) , 1f64 ) ;
1026+ assert_eq ! ( 42f64 . powf( -0.0 ) , 1f64 ) ;
1027+
1028+ assert_eq ! ( 0f32 . powi( 10 ) , 0f32 ) ;
1029+ assert_eq ! ( 0f64 . powi( 100 ) , 0f64 ) ;
1030+ assert_eq ! ( 0f32 . powi( 9 ) , 0f32 ) ;
1031+ assert_eq ! ( 0f64 . powi( 99 ) , 0f64 ) ;
1032+
1033+ assert_eq ! ( ( -0f32 ) . powi( 10 ) , 0f32 ) ;
1034+ assert_eq ! ( ( -0f64 ) . powi( 100 ) , 0f64 ) ;
1035+ assert_eq ! ( ( -0f32 ) . powi( 9 ) , -0f32 ) ;
1036+ assert_eq ! ( ( -0f64 ) . powi( 99 ) , -0f64 ) ;
1037+
10091038 assert_approx_eq ! ( 1f32 . exp( ) , f32 :: consts:: E ) ;
10101039 assert_approx_eq ! ( 1f64 . exp( ) , f64 :: consts:: E ) ;
1040+ assert_eq ! ( 0f32 . exp( ) , 1f32 ) ;
1041+ assert_eq ! ( 0f64 . exp( ) , 1f64 ) ;
10111042
10121043 assert_approx_eq ! ( 1f32 . exp_m1( ) , f32 :: consts:: E - 1.0 ) ;
10131044 assert_approx_eq ! ( 1f64 . exp_m1( ) , f64 :: consts:: E - 1.0 ) ;
10141045
10151046 assert_approx_eq ! ( 10f32 . exp2( ) , 1024f32 ) ;
10161047 assert_approx_eq ! ( 50f64 . exp2( ) , 1125899906842624f64 ) ;
1048+ assert_eq ! ( 0f32 . exp2( ) , 1f32 ) ;
1049+ assert_eq ! ( 0f64 . exp2( ) , 1f64 ) ;
10171050
10181051 assert_approx_eq ! ( f32 :: consts:: E . ln( ) , 1f32 ) ;
1019- assert_approx_eq ! ( 1f64 . ln( ) , 0f64 ) ;
1052+ assert_approx_eq ! ( f64 :: consts:: E . ln( ) , 1f64 ) ;
1053+ assert_eq ! ( 1f32 . ln( ) , 0f32 ) ;
1054+ assert_eq ! ( 1f64 . ln( ) , 0f64 ) ;
10201055
10211056 assert_approx_eq ! ( 0f32 . ln_1p( ) , 0f32 ) ;
10221057 assert_approx_eq ! ( 0f64 . ln_1p( ) , 0f64 ) ;
@@ -1045,7 +1080,8 @@ pub fn libm() {
10451080
10461081 // Trigonometric functions.
10471082
1048- assert_approx_eq ! ( 0f32 . sin( ) , 0f32 ) ;
1083+ assert_eq ! ( 0f32 . sin( ) , 0f32 ) ;
1084+ assert_eq ! ( 0f64 . sin( ) , 0f64 ) ;
10491085 assert_approx_eq ! ( ( f64 :: consts:: PI / 2f64 ) . sin( ) , 1f64 ) ;
10501086 assert_approx_eq ! ( f32 :: consts:: FRAC_PI_6 . sin( ) , 0.5 ) ;
10511087 assert_approx_eq ! ( f64 :: consts:: FRAC_PI_6 . sin( ) , 0.5 ) ;
@@ -1057,7 +1093,23 @@ pub fn libm() {
10571093 assert_approx_eq ! ( 2.0f32 . asinh( ) , 1.443635475178810342493276740273105f32 ) ;
10581094 assert_approx_eq ! ( ( -2.0f64 ) . asinh( ) , -1.443635475178810342493276740273105f64 ) ;
10591095
1060- assert_approx_eq ! ( 0f32 . cos( ) , 1f32 ) ;
1096+ // from #4207
1097+ // TODO: should this be the behaviour? I haven't found anything in the IEEE Standard
1098+ let halve_pi_single = std:: f32:: consts:: FRAC_PI_2 ;
1099+ let halve_pi_double = std:: f64:: consts:: FRAC_PI_2 ;
1100+ let pi_single = std:: f32:: consts:: PI ;
1101+ let pi_double = std:: f64:: consts:: PI ;
1102+ for _ in 0 ..64 {
1103+ // sin() should be clamped to [-1, 1] so asin() can never return NaN
1104+ assert ! ( !halve_pi_single. sin( ) . asin( ) . is_nan( ) ) ;
1105+ assert ! ( !halve_pi_double. sin( ) . asin( ) . is_nan( ) ) ;
1106+ // sin() should be clamped to [-1, 1] so acos() can never return NaN
1107+ assert ! ( !pi_single. cos( ) . acos( ) . is_nan( ) ) ;
1108+ assert ! ( !pi_double. cos( ) . acos( ) . is_nan( ) ) ;
1109+ }
1110+
1111+ assert_eq ! ( 0f32 . cos( ) , 1f32 ) ;
1112+ assert_eq ! ( 0f64 . cos( ) , 1f64 ) ;
10611113 assert_approx_eq ! ( ( f64 :: consts:: PI * 2f64 ) . cos( ) , 1f64 ) ;
10621114 assert_approx_eq ! ( f32 :: consts:: FRAC_PI_3 . cos( ) , 0.5 ) ;
10631115 assert_approx_eq ! ( f64 :: consts:: FRAC_PI_3 . cos( ) , 0.5 ) ;
@@ -1281,7 +1333,6 @@ fn test_non_determinism() {
12811333 /// Ensure that the operation is non-deterministic
12821334 #[ track_caller]
12831335 fn ensure_nondet < T : PartialEq + std:: fmt:: Debug > ( f : impl Fn ( ) -> T ) {
1284-
12851336 let rounds = 16 ;
12861337 let first = f ( ) ;
12871338 for _ in 1 ..rounds {
@@ -1328,7 +1379,7 @@ fn test_non_determinism() {
13281379 ensure_nondet ( || 27.0f32 . cbrt ( ) ) ;
13291380 ensure_nondet ( || 3.0f32 . hypot ( 4.0f32 ) ) ;
13301381 ensure_nondet ( || 1f32 . sin ( ) ) ;
1331- ensure_nondet ( || 0f32 . cos ( ) ) ;
1382+ ensure_nondet ( || 3.1f32 . cos ( ) ) ;
13321383 // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version,
13331384 // which means the little rounding errors Miri introduces are discard by the cast down to `f32`.
13341385 // Just skip the test for them.
@@ -1362,7 +1413,7 @@ fn test_non_determinism() {
13621413 ensure_nondet ( || 27.0f64 . cbrt ( ) ) ;
13631414 ensure_nondet ( || 3.0f64 . hypot ( 4.0f64 ) ) ;
13641415 ensure_nondet ( || 1f64 . sin ( ) ) ;
1365- ensure_nondet ( || 0f64 . cos ( ) ) ;
1416+ ensure_nondet ( || 3.1f64 . cos ( ) ) ;
13661417 ensure_nondet ( || 1.0f64 . tan ( ) ) ;
13671418 ensure_nondet ( || 1.0f64 . asin ( ) ) ;
13681419 ensure_nondet ( || 5.0f64 . acos ( ) ) ;
0 commit comments