@@ -5,11 +5,15 @@ use super::super::{CastFrom, Float, Int, MinInt};
5
5
6
6
const ZEROINFNAN : i32 = 0x7ff - 0x3ff - 52 - 1 ;
7
7
8
- type F = f64 ;
9
-
10
8
/// Fused multiply-add.
11
9
#[ cfg_attr( all( test, assert_no_panic) , no_panic:: no_panic) ]
12
- pub fn fma ( x : f64 , y : f64 , z : f64 ) -> f64 {
10
+ pub fn fma < F > ( x : F , y : F , z : F ) -> F
11
+ where
12
+ F : Float + Helper ,
13
+ F : CastFrom < F :: SignedInt > ,
14
+ F : CastFrom < i8 > ,
15
+ F :: Int : HInt ,
16
+ {
13
17
// let x1p63: f64 = f64::from_bits(0x43e0000000000000); // 0x1p63 === 2 ^ 63
14
18
let one = IntTy :: < F > :: ONE ;
15
19
let zero = IntTy :: < F > :: ZERO ;
@@ -32,8 +36,8 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
32
36
}
33
37
34
38
/* mul: r = x*y */
35
- let zhi: u64 ;
36
- let zlo: u64 ;
39
+ let zhi: F :: Int ;
40
+ let zlo: F :: Int ;
37
41
let ( mut rlo, mut rhi) = nx. m . widen_mul ( ny. m ) . lo_hi ( ) ;
38
42
39
43
/* either top 20 or 21 bits of rhi and last 2 bits of rlo are 0 */
@@ -55,8 +59,9 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
55
59
d -= sbits;
56
60
if d == 0 {
57
61
} else if d < sbits {
58
- rlo =
59
- ( rhi << ( sbits - d) ) | ( rlo >> d) | IntTy :: < F > :: from ( ( rlo << ( sbits - d) ) != 0 ) ;
62
+ rlo = ( rhi << ( sbits - d) )
63
+ | ( rlo >> d)
64
+ | IntTy :: < F > :: from ( ( rlo << ( sbits - d) ) != zero) ;
60
65
rhi = rhi >> d;
61
66
} else {
62
67
rlo = one;
@@ -69,7 +74,7 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
69
74
if d == 0 {
70
75
zlo = nz. m ;
71
76
} else if d < sbits {
72
- zlo = ( nz. m >> d) | IntTy :: < F > :: from ( ( nz. m << ( sbits - d) ) != 0 ) ;
77
+ zlo = ( nz. m >> d) | IntTy :: < F > :: from ( ( nz. m << ( sbits - d) ) != zero ) ;
73
78
} else {
74
79
zlo = one;
75
80
}
@@ -88,25 +93,24 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
88
93
let ( res, borrow) = rlo. overflowing_sub ( zlo) ;
89
94
rlo = res;
90
95
rhi = rhi. wrapping_sub ( zhi. wrapping_add ( IntTy :: < F > :: from ( borrow) ) ) ;
91
- if ( rhi >> ( F :: BITS - 1 ) ) != 0 {
96
+ if ( rhi >> ( F :: BITS - 1 ) ) != zero {
92
97
rlo = rlo. signed ( ) . wrapping_neg ( ) . unsigned ( ) ;
93
- rhi = rhi. signed ( ) . wrapping_neg ( ) . unsigned ( ) - IntTy :: < F > :: from ( rlo != 0 ) ;
98
+ rhi = rhi. signed ( ) . wrapping_neg ( ) . unsigned ( ) - IntTy :: < F > :: from ( rlo != zero ) ;
94
99
neg = !neg;
95
- // sign = (sign == 0) as i32;
96
100
}
97
- nonzero = ( rhi != 0 ) as i32 ;
101
+ nonzero = ( rhi != zero ) as i32 ;
98
102
}
99
103
100
104
/* set rhi to top 63bit of the result (last bit is sticky) */
101
105
if nonzero != 0 {
102
106
e += sbits;
103
107
d = rhi. leading_zeros ( ) as i32 - 1 ;
104
108
/* note: d > 0 */
105
- rhi = ( rhi << d) | ( rlo >> ( sbits - d) ) | IntTy :: < F > :: from ( ( rlo << d) != 0 ) ;
106
- } else if rlo != 0 {
109
+ rhi = ( rhi << d) | ( rlo >> ( sbits - d) ) | IntTy :: < F > :: from ( ( rlo << d) != zero ) ;
110
+ } else if rlo != zero {
107
111
d = rlo. leading_zeros ( ) as i32 - 1 ;
108
112
if d < 0 {
109
- rhi = ( rlo >> 1 ) | ( rlo & 1 ) ;
113
+ rhi = ( rlo >> 1 ) | ( rlo & one ) ;
110
114
} else {
111
115
rhi = rlo << d;
112
116
}
@@ -117,17 +121,17 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
117
121
e -= d;
118
122
119
123
/* convert to double */
120
- let mut i: i64 = rhi. signed ( ) ; /* i is in [1<<62,(1<<63)-1] */
124
+ let mut i: F :: SignedInt = rhi. signed ( ) ; /* i is in [1<<62,(1<<63)-1] */
121
125
if neg {
122
126
i = -i;
123
127
}
124
128
125
- let mut r: f64 = f64 :: cast_from_lossy ( i) ; /* |r| is in [0x1p62,0x1p63] */
129
+ let mut r: F = F :: cast_from_lossy ( i) ; /* |r| is in [0x1p62,0x1p63] */
126
130
127
131
if e < -( F :: EXP_BIAS as i32 - 1 ) - ( sbits - 2 ) {
128
132
/* result is subnormal before rounding */
129
133
if e == -( F :: EXP_BIAS as i32 - 1 ) - ( sbits - 1 ) {
130
- let mut c: f64 = magic;
134
+ let mut c: F = magic;
131
135
if neg {
132
136
c = -c;
133
137
}
@@ -139,13 +143,14 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
139
143
}
140
144
/* one bit is lost when scaled, add another top bit to
141
145
* only round once at conversion if it is inexact */
142
- if ( rhi << F :: SIG_BITS ) != 0 {
143
- i = ( ( rhi >> 1 ) | ( rhi & 1 ) | ( 1 << 62 ) ) . signed ( ) ;
146
+ if ( rhi << F :: SIG_BITS ) != zero {
147
+ let iu: F :: Int = ( rhi >> 1 ) | ( rhi & one) | ( one << 62 ) ;
148
+ i = iu. signed ( ) ;
144
149
if neg {
145
150
i = -i;
146
151
}
147
152
r = F :: cast_from ( i) ;
148
- r = 2.0 * r - c; /* remove top bit */
153
+ r = F :: cast_from ( 2i8 ) * r - c; /* remove top bit */
149
154
150
155
/* raise underflow portably, such that it
151
156
* cannot be optimized away */
@@ -154,11 +159,12 @@ pub fn fma(x: f64, y: f64, z: f64) -> f64 {
154
159
} else {
155
160
/* only round once when scaled */
156
161
d = 10 ;
157
- i = ( ( ( rhi >> d) | IntTy :: < F > :: from ( rhi << ( F :: BITS as i32 - d) != 0 ) ) << d) . signed ( ) ;
162
+ i = ( ( ( rhi >> d) | IntTy :: < F > :: from ( rhi << ( F :: BITS as i32 - d) != zero) ) << d)
163
+ . signed ( ) ;
158
164
if neg {
159
165
i = -i;
160
166
}
161
- r = f64 :: cast_from ( i) ;
167
+ r = F :: cast_from ( i) ;
162
168
}
163
169
}
164
170
@@ -197,13 +203,13 @@ impl<F: Float> Norm<F> {
197
203
}
198
204
199
205
// Need to figure out how to do this better.
200
- trait RaiseUnderflow {
206
+ pub trait Helper {
201
207
fn raise_underflow ( self ) -> Self ;
202
208
fn raise_underflow2 ( self ) -> Self ;
203
209
fn scalbn ( self , n : i32 ) -> Self ;
204
210
}
205
211
206
- impl RaiseUnderflow for f64 {
212
+ impl Helper for f64 {
207
213
fn raise_underflow ( self ) -> Self {
208
214
let x0_ffffff8p_63 = f64:: from_bits ( 0x3bfffffff0000000 ) ; // 0x0.ffffff8p-63
209
215
let fltmin: f32 = ( x0_ffffff8p_63 * f32:: MIN_POSITIVE as f64 * self ) as f32 ;
0 commit comments