@@ -16,17 +16,14 @@ pub trait Float: Sized + Copy {
16
16
/// Returns the bitwidth of the significand
17
17
fn significand_bits ( ) -> u32 ;
18
18
19
- /// Returns `self` transmuted to `Self::Int `
20
- fn repr ( self ) -> Self :: Int ;
19
+ /// Returns a mask for the sign bit of `self `
20
+ fn sign_mask ( ) -> Self :: Int ;
21
21
22
- #[ cfg( test) ]
23
- /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
24
- /// represented in multiple different ways. This methods returns `true` if two NaNs are
25
- /// compared.
26
- fn eq_repr ( self , rhs : Self ) -> bool ;
22
+ /// Returns a mask for the exponent portion of `self`
23
+ fn exponent_mask ( ) -> Self :: Int ;
27
24
28
- /// Returns a `Self::Int` transmuted back to `Self `
29
- fn from_repr ( a : Self :: Int ) -> Self ;
25
+ /// Returns a mask for the significand portion of `self `
26
+ fn significand_mask ( ) -> Self :: Int ;
30
27
31
28
/// Returns the sign bit of `self`
32
29
fn sign ( self ) -> bool ;
@@ -37,6 +34,21 @@ pub trait Float: Sized + Copy {
37
34
/// Returns the significand portion of `self`
38
35
fn significand ( self ) -> Self :: Int ;
39
36
37
+ /// Returns `self` transmuted to `Self::Int`
38
+ fn repr ( self ) -> Self :: Int ;
39
+
40
+ #[ cfg( test) ]
41
+ /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
42
+ /// represented in multiple different ways. This method returns `true` if two NaNs are
43
+ /// compared.
44
+ fn eq_repr ( self , rhs : Self ) -> bool ;
45
+
46
+ /// Returns a `Self::Int` transmuted back to `Self`
47
+ fn from_repr ( a : Self :: Int ) -> Self ;
48
+
49
+ /// Constructs a `Self` from its parts
50
+ fn from_parts ( sign : bool , exponent : Self :: Int , significand : Self :: Int ) -> Self ;
51
+
40
52
/// Returns (normalized exponent, normalized significand)
41
53
fn normalize ( significand : Self :: Int ) -> ( i32 , Self :: Int ) ;
42
54
}
@@ -52,12 +64,26 @@ impl Float for f32 {
52
64
fn significand_bits ( ) -> u32 {
53
65
23
54
66
}
67
+ fn sign_mask ( ) -> Self :: Int {
68
+ 1 << ( Self :: bits ( ) - 1 )
69
+ }
70
+ fn exponent_mask ( ) -> Self :: Int {
71
+ ( ( 1 << Self :: exponent_bits ( ) ) - 1 ) << Self :: significand_bits ( )
72
+ }
73
+ fn significand_mask ( ) -> Self :: Int {
74
+ ( 1 << Self :: significand_bits ( ) ) - 1
75
+ }
55
76
fn repr ( self ) -> Self :: Int {
56
77
unsafe { mem:: transmute ( self ) }
57
78
}
58
79
#[ cfg( test) ]
59
80
fn eq_repr ( self , rhs : Self ) -> bool {
60
- if self . is_nan ( ) && rhs. is_nan ( ) {
81
+ // NOTE(cfg) for some reason, on hard float targets, our implementation doesn't
82
+ // match the output of its gcc_s counterpart. Until we investigate further, we'll
83
+ // just avoid testing against gcc_s on those targets. Do note that our
84
+ // implementation matches the output of the FPU instruction on *hard* float targets
85
+ // and matches its gcc_s counterpart on *soft* float targets.
86
+ if cfg ! ( gnueabihf) || self . is_nan ( ) && rhs. is_nan ( ) {
61
87
true
62
88
} else {
63
89
self . repr ( ) == rhs. repr ( )
@@ -66,15 +92,20 @@ impl Float for f32 {
66
92
fn from_repr ( a : Self :: Int ) -> Self {
67
93
unsafe { mem:: transmute ( a) }
68
94
}
95
+
96
+ fn from_parts ( sign : bool , exponent : Self :: Int , significand : Self :: Int ) -> Self {
97
+ Self :: from_repr ( ( ( sign as Self :: Int ) << ( Self :: bits ( ) - 1 ) ) |
98
+ exponent & Self :: exponent_mask ( ) |
99
+ significand & Self :: significand_mask ( ) )
100
+ }
69
101
fn sign ( self ) -> bool {
70
- ( self . repr ( ) & 1 << Self :: bits ( ) ) != 0
102
+ ( self . repr ( ) & Self :: sign_mask ( ) ) != 0
71
103
}
72
104
fn exponent ( self ) -> Self :: Int {
73
- self . repr ( ) >> Self :: significand_bits ( )
74
- & ( ( 1 << Self :: exponent_bits ( ) ) - 1 )
105
+ self . repr ( ) >> Self :: significand_bits ( ) & Self :: exponent_mask ( )
75
106
}
76
107
fn significand ( self ) -> Self :: Int {
77
- self . repr ( ) & ( ( 1 << Self :: significand_bits ( ) ) - 1 )
108
+ self . repr ( ) & Self :: significand_mask ( )
78
109
}
79
110
fn normalize ( significand : Self :: Int ) -> ( i32 , Self :: Int ) {
80
111
let shift = significand. leading_zeros ( )
@@ -93,12 +124,22 @@ impl Float for f64 {
93
124
fn significand_bits ( ) -> u32 {
94
125
52
95
126
}
127
+ fn sign_mask ( ) -> Self :: Int {
128
+ 1 << ( Self :: bits ( ) - 1 )
129
+ }
130
+ fn exponent_mask ( ) -> Self :: Int {
131
+ ( ( 1 << Self :: exponent_bits ( ) ) - 1 ) << Self :: significand_bits ( )
132
+ }
133
+ fn significand_mask ( ) -> Self :: Int {
134
+ ( 1 << Self :: significand_bits ( ) ) - 1
135
+ }
96
136
fn repr ( self ) -> Self :: Int {
97
137
unsafe { mem:: transmute ( self ) }
98
138
}
99
139
#[ cfg( test) ]
100
140
fn eq_repr ( self , rhs : Self ) -> bool {
101
- if self . is_nan ( ) && rhs. is_nan ( ) {
141
+ // Note(cfg) see above
142
+ if cfg ! ( gnueabihf) || self . is_nan ( ) && rhs. is_nan ( ) {
102
143
true
103
144
} else {
104
145
self . repr ( ) == rhs. repr ( )
@@ -107,15 +148,19 @@ impl Float for f64 {
107
148
fn from_repr ( a : Self :: Int ) -> Self {
108
149
unsafe { mem:: transmute ( a) }
109
150
}
151
+ fn from_parts ( sign : bool , exponent : Self :: Int , significand : Self :: Int ) -> Self {
152
+ Self :: from_repr ( ( ( sign as Self :: Int ) << ( Self :: bits ( ) - 1 ) ) |
153
+ exponent & Self :: exponent_mask ( ) |
154
+ significand & Self :: significand_mask ( ) )
155
+ }
110
156
fn sign ( self ) -> bool {
111
- ( self . repr ( ) & 1 << Self :: bits ( ) ) != 0
157
+ ( self . repr ( ) & Self :: sign_mask ( ) ) != 0
112
158
}
113
159
fn exponent ( self ) -> Self :: Int {
114
- self . repr ( ) >> Self :: significand_bits ( )
115
- & ( ( 1 << Self :: exponent_bits ( ) ) - 1 )
160
+ self . repr ( ) >> Self :: significand_bits ( ) & Self :: exponent_mask ( )
116
161
}
117
162
fn significand ( self ) -> Self :: Int {
118
- self . repr ( ) & ( ( 1 << Self :: significand_bits ( ) ) - 1 )
163
+ self . repr ( ) & Self :: significand_mask ( )
119
164
}
120
165
fn normalize ( significand : Self :: Int ) -> ( i32 , Self :: Int ) {
121
166
let shift = significand. leading_zeros ( )
0 commit comments