99// except according to those terms.
1010
1111use 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 } ;
1418
1519use super :: err:: * ;
1620
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 ) ]
1826pub enum ConstFloat {
19- F32 ( f32 ) ,
20- F64 ( f64 )
27+ F32 ( u32 ) ,
28+ F64 ( u64 )
2129}
22- pub use self :: ConstFloat :: * ;
30+ use self :: ConstFloat :: * ;
2331
2432impl ConstFloat {
2533 /// Description of the type, not the value
@@ -32,68 +40,119 @@ impl ConstFloat {
3240
3341 pub fn is_nan ( & self ) -> bool {
3442 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 ( ) ,
3745 }
3846 }
3947
4048 /// Compares the values if they are of the same type
4149 pub fn try_cmp ( self , rhs : Self ) -> Result < Ordering , ConstMathErr > {
4250 match ( self , rhs) {
4351 ( F64 ( a) , F64 ( b) ) => {
52+ let a = Double :: from_bits ( a as u128 ) ;
53+ let b = Double :: from_bits ( b as u128 ) ;
4454 // 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 ) )
5256 }
5357
5458 ( 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 ) )
6262 }
6363
6464 _ => Err ( CmpBetweenUnequalTypes ) ,
6565 }
6666 }
67- }
6867
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 )
7872 }
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 )
8175 }
82- _ => false
8376 }
8477 }
85- }
8678
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+ }
8889
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 )
94152 }
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 )
97156 }
98157 }
99158 }
@@ -102,8 +161,8 @@ impl hash::Hash for ConstFloat {
102161impl :: std:: fmt:: Display for ConstFloat {
103162 fn fmt ( & self , fmt : & mut :: std:: fmt:: Formatter ) -> Result < ( ) , :: std:: fmt:: Error > {
104163 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 ) ) ,
107166 }
108167 }
109168}
@@ -114,8 +173,16 @@ macro_rules! derive_binop {
114173 type Output = Result <Self , ConstMathErr >;
115174 fn $func( self , rhs: Self ) -> Result <Self , ConstMathErr > {
116175 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+ }
119186 _ => Err ( UnequalTypes ( Op :: $op) ) ,
120187 }
121188 }
@@ -133,8 +200,8 @@ impl ::std::ops::Neg for ConstFloat {
133200 type Output = Self ;
134201 fn neg ( self ) -> Self {
135202 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 ) ,
138205 }
139206 }
140207}
0 commit comments