1
1
#![ feature( stmt_expr_attributes) ]
2
2
#![ feature( float_gamma) ]
3
3
#![ feature( core_intrinsics) ]
4
+ #![ feature( f128) ]
5
+ #![ feature( f16) ]
4
6
#![ allow( arithmetic_overflow) ]
5
7
6
8
use std:: fmt:: Debug ;
@@ -41,104 +43,43 @@ trait FloatToInt<Int>: Copy {
41
43
unsafe fn cast_unchecked ( self ) -> Int ;
42
44
}
43
45
44
- impl FloatToInt < i8 > for f32 {
45
- fn cast ( self ) -> i8 {
46
- self as _
47
- }
48
- unsafe fn cast_unchecked ( self ) -> i8 {
49
- self . to_int_unchecked ( )
50
- }
51
- }
52
- impl FloatToInt < i32 > for f32 {
53
- fn cast ( self ) -> i32 {
54
- self as _
55
- }
56
- unsafe fn cast_unchecked ( self ) -> i32 {
57
- self . to_int_unchecked ( )
58
- }
59
- }
60
- impl FloatToInt < u32 > for f32 {
61
- fn cast ( self ) -> u32 {
62
- self as _
63
- }
64
- unsafe fn cast_unchecked ( self ) -> u32 {
65
- self . to_int_unchecked ( )
66
- }
67
- }
68
- impl FloatToInt < i64 > for f32 {
69
- fn cast ( self ) -> i64 {
70
- self as _
71
- }
72
- unsafe fn cast_unchecked ( self ) -> i64 {
73
- self . to_int_unchecked ( )
74
- }
75
- }
76
- impl FloatToInt < u64 > for f32 {
77
- fn cast ( self ) -> u64 {
78
- self as _
79
- }
80
- unsafe fn cast_unchecked ( self ) -> u64 {
81
- self . to_int_unchecked ( )
82
- }
46
+ macro_rules! float_to_int {
47
+ ( $fty: ty => $( $ity: ty) ,+ $( , ) ?) => {
48
+ $(
49
+ impl FloatToInt <$ity> for $fty {
50
+ fn cast( self ) -> $ity {
51
+ self as _
52
+ }
53
+ unsafe fn cast_unchecked( self ) -> $ity {
54
+ self . to_int_unchecked( )
55
+ }
56
+ }
57
+ ) *
58
+ } ;
83
59
}
84
60
85
- impl FloatToInt < i8 > for f64 {
86
- fn cast ( self ) -> i8 {
87
- self as _
88
- }
89
- unsafe fn cast_unchecked ( self ) -> i8 {
90
- self . to_int_unchecked ( )
91
- }
92
- }
93
- impl FloatToInt < i32 > for f64 {
94
- fn cast ( self ) -> i32 {
95
- self as _
96
- }
97
- unsafe fn cast_unchecked ( self ) -> i32 {
98
- self . to_int_unchecked ( )
99
- }
100
- }
101
- impl FloatToInt < u32 > for f64 {
102
- fn cast ( self ) -> u32 {
103
- self as _
104
- }
105
- unsafe fn cast_unchecked ( self ) -> u32 {
106
- self . to_int_unchecked ( )
107
- }
108
- }
109
- impl FloatToInt < i64 > for f64 {
110
- fn cast ( self ) -> i64 {
111
- self as _
112
- }
113
- unsafe fn cast_unchecked ( self ) -> i64 {
114
- self . to_int_unchecked ( )
115
- }
116
- }
117
- impl FloatToInt < u64 > for f64 {
118
- fn cast ( self ) -> u64 {
119
- self as _
120
- }
121
- unsafe fn cast_unchecked ( self ) -> u64 {
122
- self . to_int_unchecked ( )
123
- }
124
- }
125
- impl FloatToInt < i128 > for f64 {
126
- fn cast ( self ) -> i128 {
127
- self as _
128
- }
129
- unsafe fn cast_unchecked ( self ) -> i128 {
130
- self . to_int_unchecked ( )
131
- }
132
- }
133
- impl FloatToInt < u128 > for f64 {
134
- fn cast ( self ) -> u128 {
135
- self as _
136
- }
137
- unsafe fn cast_unchecked ( self ) -> u128 {
138
- self . to_int_unchecked ( )
139
- }
61
+ // FIXME(f16_f128): this is just used while we don't have `to_int_unchecked` on `f16` and `f128`.
62
+ // Just use `float_to_int` once available.
63
+ macro_rules! float_to_int_fallback {
64
+ ( $fty: ty => $( $ity: ty) ,+ $( , ) ?) => {
65
+ $(
66
+ impl FloatToInt <$ity> for $fty {
67
+ fn cast( self ) -> $ity {
68
+ self as _
69
+ }
70
+ unsafe fn cast_unchecked( self ) -> $ity {
71
+ self as _
72
+ }
73
+ }
74
+ ) *
75
+ } ;
140
76
}
141
77
78
+ float_to_int_fallback ! ( f16 => i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , i128 , u128 ) ;
79
+ float_to_int ! ( f32 => i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , i128 , u128 ) ;
80
+ float_to_int ! ( f64 => i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , i128 , u128 ) ;
81
+ float_to_int_fallback ! ( f128 => i8 , u8 , i16 , u16 , i32 , u32 , i64 , u64 , i128 , u128 ) ;
82
+
142
83
/// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate).
143
84
#[ track_caller]
144
85
#[ inline( never) ]
@@ -153,18 +94,29 @@ where
153
94
154
95
fn basic ( ) {
155
96
// basic arithmetic
97
+ assert_eq ( 6.0_f16 * 6.0_f16 , 36.0_f16 ) ;
156
98
assert_eq ( 6.0_f32 * 6.0_f32 , 36.0_f32 ) ;
157
99
assert_eq ( 6.0_f64 * 6.0_f64 , 36.0_f64 ) ;
100
+ assert_eq ( 6.0_f128 * 6.0_f128 , 36.0_f128 ) ;
101
+ assert_eq ( -{ 5.0_f16 } , -5.0_f16 ) ;
158
102
assert_eq ( -{ 5.0_f32 } , -5.0_f32 ) ;
159
103
assert_eq ( -{ 5.0_f64 } , -5.0_f64 ) ;
104
+ assert_eq ( -{ 5.0_f128 } , -5.0_f128 ) ;
105
+
160
106
// infinities, NaN
107
+ // FIXME(f16_f128): add when constants and `is_infinite` are available
161
108
assert ! ( ( 5.0_f32 / 0.0 ) . is_infinite( ) ) ;
162
109
assert_ne ! ( { 5.0_f32 / 0.0 } , { -5.0_f32 / 0.0 } ) ;
163
110
assert ! ( ( 5.0_f64 / 0.0 ) . is_infinite( ) ) ;
164
111
assert_ne ! ( { 5.0_f64 / 0.0 } , { 5.0_f64 / -0.0 } ) ;
165
112
assert_ne ! ( f32 :: NAN , f32 :: NAN ) ;
166
113
assert_ne ! ( f64 :: NAN , f64 :: NAN ) ;
114
+
167
115
// negative zero
116
+ let posz = 0.0f16 ;
117
+ let negz = -0.0f16 ;
118
+ assert_eq ( posz, negz) ;
119
+ assert_ne ! ( posz. to_bits( ) , negz. to_bits( ) ) ;
168
120
let posz = 0.0f32 ;
169
121
let negz = -0.0f32 ;
170
122
assert_eq ( posz, negz) ;
@@ -173,15 +125,30 @@ fn basic() {
173
125
let negz = -0.0f64 ;
174
126
assert_eq ( posz, negz) ;
175
127
assert_ne ! ( posz. to_bits( ) , negz. to_bits( ) ) ;
128
+ let posz = 0.0f128 ;
129
+ let negz = -0.0f128 ;
130
+ assert_eq ( posz, negz) ;
131
+ assert_ne ! ( posz. to_bits( ) , negz. to_bits( ) ) ;
132
+
176
133
// byte-level transmute
177
- let x: u64 = unsafe { std:: mem:: transmute ( 42.0_f64 ) } ;
178
- let y: f64 = unsafe { std:: mem:: transmute ( x) } ;
179
- assert_eq ( y, 42.0_f64 ) ;
134
+ let x: u16 = unsafe { std:: mem:: transmute ( 42.0_f16 ) } ;
135
+ let y: f16 = unsafe { std:: mem:: transmute ( x) } ;
136
+ assert_eq ( y, 42.0_f16 ) ;
180
137
let x: u32 = unsafe { std:: mem:: transmute ( 42.0_f32 ) } ;
181
138
let y: f32 = unsafe { std:: mem:: transmute ( x) } ;
182
139
assert_eq ( y, 42.0_f32 ) ;
140
+ let x: u64 = unsafe { std:: mem:: transmute ( 42.0_f64 ) } ;
141
+ let y: f64 = unsafe { std:: mem:: transmute ( x) } ;
142
+ assert_eq ( y, 42.0_f64 ) ;
143
+ let x: u128 = unsafe { std:: mem:: transmute ( 42.0_f128 ) } ;
144
+ let y: f128 = unsafe { std:: mem:: transmute ( x) } ;
145
+ assert_eq ( y, 42.0_f128 ) ;
183
146
184
147
// `%` sign behavior, some of this used to be buggy
148
+ assert ! ( ( black_box( 1.0f16 ) % 1.0 ) . is_sign_positive( ) ) ;
149
+ assert ! ( ( black_box( 1.0f16 ) % -1.0 ) . is_sign_positive( ) ) ;
150
+ assert ! ( ( black_box( -1.0f16 ) % 1.0 ) . is_sign_negative( ) ) ;
151
+ assert ! ( ( black_box( -1.0f16 ) % -1.0 ) . is_sign_negative( ) ) ;
185
152
assert ! ( ( black_box( 1.0f32 ) % 1.0 ) . is_sign_positive( ) ) ;
186
153
assert ! ( ( black_box( 1.0f32 ) % -1.0 ) . is_sign_positive( ) ) ;
187
154
assert ! ( ( black_box( -1.0f32 ) % 1.0 ) . is_sign_negative( ) ) ;
@@ -190,7 +157,12 @@ fn basic() {
190
157
assert ! ( ( black_box( 1.0f64 ) % -1.0 ) . is_sign_positive( ) ) ;
191
158
assert ! ( ( black_box( -1.0f64 ) % 1.0 ) . is_sign_negative( ) ) ;
192
159
assert ! ( ( black_box( -1.0f64 ) % -1.0 ) . is_sign_negative( ) ) ;
160
+ assert ! ( ( black_box( 1.0f128 ) % 1.0 ) . is_sign_positive( ) ) ;
161
+ assert ! ( ( black_box( 1.0f128 ) % -1.0 ) . is_sign_positive( ) ) ;
162
+ assert ! ( ( black_box( -1.0f128 ) % 1.0 ) . is_sign_negative( ) ) ;
163
+ assert ! ( ( black_box( -1.0f128 ) % -1.0 ) . is_sign_negative( ) ) ;
193
164
165
+ // FIXME(f16_f128): add when `abs` is available
194
166
assert_eq ! ( ( -1.0f32 ) . abs( ) , 1.0f32 ) ;
195
167
assert_eq ! ( 34.2f64 . abs( ) , 34.2f64 ) ;
196
168
}
0 commit comments