9
9
// except according to those terms.
10
10
11
11
use std:: cmp:: Ordering ;
12
- use std:: hash;
13
- use std:: mem:: transmute;
12
+ use std:: num:: ParseFloatError ;
14
13
14
+ use syntax:: ast;
15
+
16
+ use super :: apfloat:: { Float , IeeeSingle , IeeeDouble , OpStatus , Round } ;
15
17
use super :: err:: * ;
16
18
17
- #[ derive( Copy , Clone , Debug , RustcEncodable , RustcDecodable ) ]
19
+ // Note that equality for `ConstFloat` means that the it is the same
20
+ // constant, not that the rust values are equal. In particular, `NaN
21
+ // == NaN` (at least if it's the same NaN; distinct encodings for NaN
22
+ // are considering unequal).
23
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug , Hash , RustcEncodable , RustcDecodable ) ]
18
24
pub enum ConstFloat {
19
- F32 ( f32 ) ,
20
- F64 ( f64 )
25
+ F32 ( u32 ) ,
26
+ F64 ( u64 )
21
27
}
22
- pub use self :: ConstFloat :: * ;
28
+ use self :: ConstFloat :: * ;
23
29
24
30
impl ConstFloat {
25
31
/// Description of the type, not the value
@@ -32,68 +38,133 @@ impl ConstFloat {
32
38
33
39
pub fn is_nan ( & self ) -> bool {
34
40
match * self {
35
- F32 ( f) => f . is_nan ( ) ,
36
- F64 ( f) => f . is_nan ( ) ,
41
+ F32 ( f) => IeeeSingle :: from_bits ( f as u128 ) . is_nan ( ) ,
42
+ F64 ( f) => IeeeDouble :: from_bits ( f as u128 ) . is_nan ( ) ,
37
43
}
38
44
}
39
45
40
46
/// Compares the values if they are of the same type
41
47
pub fn try_cmp ( self , rhs : Self ) -> Result < Ordering , ConstMathErr > {
42
48
match ( self , rhs) {
43
49
( F64 ( a) , F64 ( b) ) => {
50
+ let a = IeeeDouble :: from_bits ( a as u128 ) ;
51
+ let b = IeeeDouble :: from_bits ( b as u128 ) ;
44
52
// This is pretty bad but it is the existing behavior.
45
- Ok ( if a == b {
46
- Ordering :: Equal
47
- } else if a < b {
48
- Ordering :: Less
49
- } else {
50
- Ordering :: Greater
51
- } )
53
+ Ok ( a. partial_cmp ( & b) . unwrap_or ( Ordering :: Greater ) )
52
54
}
53
55
54
56
( F32 ( a) , F32 ( b) ) => {
55
- Ok ( if a == b {
56
- Ordering :: Equal
57
- } else if a < b {
58
- Ordering :: Less
59
- } else {
60
- Ordering :: Greater
61
- } )
57
+ let a = IeeeSingle :: from_bits ( a as u128 ) ;
58
+ let b = IeeeSingle :: from_bits ( b as u128 ) ;
59
+ Ok ( a. partial_cmp ( & b) . unwrap_or ( Ordering :: Greater ) )
62
60
}
63
61
64
62
_ => Err ( CmpBetweenUnequalTypes ) ,
65
63
}
66
64
}
67
- }
68
65
69
- /// Note that equality for `ConstFloat` means that the it is the same
70
- /// constant, not that the rust values are equal. In particular, `NaN
71
- /// == NaN` (at least if it's the same NaN; distinct encodings for NaN
72
- /// are considering unequal).
73
- impl PartialEq for ConstFloat {
74
- fn eq ( & self , other : & Self ) -> bool {
75
- match ( * self , * other) {
76
- ( F64 ( a) , F64 ( b) ) => {
77
- unsafe { transmute :: < _ , u64 > ( a) == transmute :: < _ , u64 > ( b) }
66
+ pub fn from_i128 ( input : i128 , fty : ast:: FloatTy ) -> Self {
67
+ match fty {
68
+ ast:: FloatTy :: F32 => {
69
+ let ( r, _) = IeeeSingle :: from_i128 ( input, Round :: NearestTiesToEven ) ;
70
+ F32 ( r. to_bits ( ) as u32 )
78
71
}
79
- ( F32 ( a) , F32 ( b) ) => {
80
- unsafe { transmute :: < _ , u32 > ( a) == transmute :: < _ , u32 > ( b) }
72
+ ast:: FloatTy :: F64 => {
73
+ let ( r, _) = IeeeDouble :: from_i128 ( input, Round :: NearestTiesToEven ) ;
74
+ F64 ( r. to_bits ( ) as u64 )
81
75
}
82
- _ => false
83
76
}
84
77
}
85
- }
86
78
87
- impl Eq for ConstFloat { }
79
+ pub fn from_u128 ( input : u128 , fty : ast:: FloatTy ) -> Self {
80
+ match fty {
81
+ ast:: FloatTy :: F32 => {
82
+ let ( r, _) = IeeeSingle :: from_u128 ( input, Round :: NearestTiesToEven ) ;
83
+ F32 ( r. to_bits ( ) as u32 )
84
+ }
85
+ ast:: FloatTy :: F64 => {
86
+ let ( r, _) = IeeeDouble :: from_u128 ( input, Round :: NearestTiesToEven ) ;
87
+ F64 ( r. to_bits ( ) as u64 )
88
+ }
89
+ }
90
+ }
88
91
89
- impl hash:: Hash for ConstFloat {
90
- fn hash < H : hash:: Hasher > ( & self , state : & mut H ) {
91
- match * self {
92
- F64 ( a) => {
93
- unsafe { transmute :: < _ , u64 > ( a) } . hash ( state)
92
+ pub fn from_str ( num : & str , fty : ast:: FloatTy ) -> Result < Self , ParseFloatError > {
93
+ match fty {
94
+ ast:: FloatTy :: F32 => {
95
+ let rust_bits = num. parse :: < f32 > ( ) ?. to_bits ( ) ;
96
+ let apfloat = num. parse :: < IeeeSingle > ( ) . unwrap_or_else ( |e| {
97
+ panic ! ( "apfloat::IeeeSingle failed to parse `{}`: {:?}" , num, e) ;
98
+ } ) ;
99
+ let apfloat_bits = apfloat. to_bits ( ) as u32 ;
100
+ assert ! ( rust_bits == apfloat_bits,
101
+ "apfloat::IeeeSingle gave different result for `{}`: \
102
+ {}({:#x}) vs Rust's {}({:#x})", num,
103
+ F32 ( apfloat_bits) , apfloat_bits, F32 ( rust_bits) , rust_bits) ;
104
+ Ok ( F32 ( apfloat_bits) )
105
+ }
106
+ ast:: FloatTy :: F64 => {
107
+ let rust_bits = num. parse :: < f64 > ( ) ?. to_bits ( ) ;
108
+ let apfloat = num. parse :: < IeeeDouble > ( ) . unwrap_or_else ( |e| {
109
+ panic ! ( "apfloat::IeeeDouble failed to parse `{}`: {:?}" , num, e) ;
110
+ } ) ;
111
+ let apfloat_bits = apfloat. to_bits ( ) as u64 ;
112
+ assert ! ( rust_bits == apfloat_bits,
113
+ "apfloat::IeeeDouble gave different result for `{}`: \
114
+ {}({:#x}) vs Rust's {}({:#x})", num,
115
+ F64 ( apfloat_bits) , apfloat_bits, F64 ( rust_bits) , rust_bits) ;
116
+ Ok ( F64 ( apfloat_bits) )
117
+ }
118
+ }
119
+ }
120
+
121
+ pub fn to_i128 ( self , width : usize ) -> Option < i128 > {
122
+ assert ! ( width <= 128 ) ;
123
+ let ( r, fs) = match self {
124
+ F32 ( f) => {
125
+ IeeeSingle :: from_bits ( f as u128 ) . to_i128 ( width, Round :: TowardZero , & mut true )
126
+ }
127
+ F64 ( f) => {
128
+ IeeeDouble :: from_bits ( f as u128 ) . to_i128 ( width, Round :: TowardZero , & mut true )
129
+ }
130
+ } ;
131
+ if fs. intersects ( OpStatus :: INVALID_OP ) {
132
+ None
133
+ } else {
134
+ Some ( r)
135
+ }
136
+ }
137
+
138
+ pub fn to_u128 ( self , width : usize ) -> Option < u128 > {
139
+ assert ! ( width <= 128 ) ;
140
+ let ( r, fs) = match self {
141
+ F32 ( f) => {
142
+ IeeeSingle :: from_bits ( f as u128 ) . to_u128 ( width, Round :: TowardZero , & mut true )
143
+ }
144
+ F64 ( f) => {
145
+ IeeeDouble :: from_bits ( f as u128 ) . to_u128 ( width, Round :: TowardZero , & mut true )
146
+ }
147
+ } ;
148
+ if fs. intersects ( OpStatus :: INVALID_OP ) {
149
+ None
150
+ } else {
151
+ Some ( r)
152
+ }
153
+ }
154
+
155
+ pub fn convert ( self , fty : ast:: FloatTy ) -> Self {
156
+ match ( self , fty) {
157
+ ( F32 ( f) , ast:: FloatTy :: F32 ) => F32 ( f) ,
158
+ ( F64 ( f) , ast:: FloatTy :: F64 ) => F64 ( f) ,
159
+ ( F32 ( f) , ast:: FloatTy :: F64 ) => {
160
+ let from = IeeeSingle :: from_bits ( f as u128 ) ;
161
+ let ( to, _) = from. convert ( Round :: NearestTiesToEven , & mut false ) ;
162
+ F64 ( IeeeDouble :: to_bits ( to) as u64 )
94
163
}
95
- F32 ( a) => {
96
- unsafe { transmute :: < _ , u32 > ( a) } . hash ( state)
164
+ ( F64 ( f) , ast:: FloatTy :: F32 ) => {
165
+ let from = IeeeDouble :: from_bits ( f as u128 ) ;
166
+ let ( to, _) = from. convert ( Round :: NearestTiesToEven , & mut false ) ;
167
+ F32 ( IeeeSingle :: to_bits ( to) as u32 )
97
168
}
98
169
}
99
170
}
@@ -102,8 +173,8 @@ impl hash::Hash for ConstFloat {
102
173
impl :: std:: fmt:: Display for ConstFloat {
103
174
fn fmt ( & self , fmt : & mut :: std:: fmt:: Formatter ) -> Result < ( ) , :: std:: fmt:: Error > {
104
175
match * self {
105
- F32 ( f) => write ! ( fmt, "{}f32" , f ) ,
106
- F64 ( f) => write ! ( fmt, "{}f64" , f ) ,
176
+ F32 ( f) => write ! ( fmt, "{}f32" , IeeeSingle :: from_bits ( f as u128 ) ) ,
177
+ F64 ( f) => write ! ( fmt, "{}f64" , IeeeDouble :: from_bits ( f as u128 ) ) ,
107
178
}
108
179
}
109
180
}
@@ -114,8 +185,16 @@ macro_rules! derive_binop {
114
185
type Output = Result <Self , ConstMathErr >;
115
186
fn $func( self , rhs: Self ) -> Result <Self , ConstMathErr > {
116
187
match ( self , rhs) {
117
- ( F32 ( a) , F32 ( b) ) => Ok ( F32 ( a. $func( b) ) ) ,
118
- ( F64 ( a) , F64 ( b) ) => Ok ( F64 ( a. $func( b) ) ) ,
188
+ ( F32 ( a) , F32 ( b) ) =>{
189
+ let a = IeeeSingle :: from_bits( a as u128 ) ;
190
+ let b = IeeeSingle :: from_bits( b as u128 ) ;
191
+ Ok ( F32 ( a. $func( b) . to_bits( ) as u32 ) )
192
+ }
193
+ ( F64 ( a) , F64 ( b) ) => {
194
+ let a = IeeeDouble :: from_bits( a as u128 ) ;
195
+ let b = IeeeDouble :: from_bits( b as u128 ) ;
196
+ Ok ( F64 ( a. $func( b) . to_bits( ) as u64 ) )
197
+ }
119
198
_ => Err ( UnequalTypes ( Op :: $op) ) ,
120
199
}
121
200
}
@@ -133,8 +212,8 @@ impl ::std::ops::Neg for ConstFloat {
133
212
type Output = Self ;
134
213
fn neg ( self ) -> Self {
135
214
match self {
136
- F32 ( f) => F32 ( -f ) ,
137
- F64 ( f) => F64 ( -f ) ,
215
+ F32 ( f) => F32 ( ( - IeeeSingle :: from_bits ( f as u128 ) ) . to_bits ( ) as u32 ) ,
216
+ F64 ( f) => F64 ( ( - IeeeDouble :: from_bits ( f as u128 ) ) . to_bits ( ) as u64 ) ,
138
217
}
139
218
}
140
219
}
0 commit comments