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