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 ;
1413
14+ use syntax:: ast;
15+
16+ use super :: apfloat:: { Float , IeeeSingle , IeeeDouble , OpStatus , Round } ;
1517use super :: err:: * ;
1618
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 ) ]
1824pub enum ConstFloat {
19- F32 ( f32 ) ,
20- F64 ( f64 )
25+ F32 ( u32 ) ,
26+ F64 ( u64 )
2127}
22- pub use self :: ConstFloat :: * ;
28+ use self :: ConstFloat :: * ;
2329
2430impl ConstFloat {
2531 /// Description of the type, not the value
@@ -32,68 +38,133 @@ impl ConstFloat {
3238
3339 pub fn is_nan ( & self ) -> bool {
3440 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 ( ) ,
3743 }
3844 }
3945
4046 /// Compares the values if they are of the same type
4147 pub fn try_cmp ( self , rhs : Self ) -> Result < Ordering , ConstMathErr > {
4248 match ( self , rhs) {
4349 ( F64 ( a) , F64 ( b) ) => {
50+ let a = IeeeDouble :: from_bits ( a as u128 ) ;
51+ let b = IeeeDouble :: from_bits ( b as u128 ) ;
4452 // 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 ) )
5254 }
5355
5456 ( 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 ) )
6260 }
6361
6462 _ => Err ( CmpBetweenUnequalTypes ) ,
6563 }
6664 }
67- }
6865
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 )
7871 }
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 )
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+ 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+ }
8891
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 )
94163 }
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 )
97168 }
98169 }
99170 }
@@ -102,8 +173,8 @@ impl hash::Hash for ConstFloat {
102173impl :: std:: fmt:: Display for ConstFloat {
103174 fn fmt ( & self , fmt : & mut :: std:: fmt:: Formatter ) -> Result < ( ) , :: std:: fmt:: Error > {
104175 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 ) ) ,
107178 }
108179 }
109180}
@@ -114,8 +185,16 @@ macro_rules! derive_binop {
114185 type Output = Result <Self , ConstMathErr >;
115186 fn $func( self , rhs: Self ) -> Result <Self , ConstMathErr > {
116187 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+ }
119198 _ => Err ( UnequalTypes ( Op :: $op) ) ,
120199 }
121200 }
@@ -133,8 +212,8 @@ impl ::std::ops::Neg for ConstFloat {
133212 type Output = Self ;
134213 fn neg ( self ) -> Self {
135214 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 ) ,
138217 }
139218 }
140219}
0 commit comments