1use crate::common::{dyad_fmla, f_fmla};
30use crate::double_double::DoubleDouble;
31use std::hint::black_box;
32
33#[cold]
35fn hypot_overflow() -> f64 {
36 const Z: f64 = f64::from_bits(0x7fefffffffffffff);
37 black_box(Z) + black_box(Z)
38}
39
40#[cold]
41fn hypot_denorm(a: u64, b: u64) -> f64 {
42 let mut a = a;
43 let mut b = b;
44 let af = (a as i64) as f64;
45 let bf = (b as i64) as f64;
46 let mut underflow;
47 a = a.wrapping_shl(1);
49 b = b.wrapping_shl(1);
50 let mut rm = f_fmla(af, af, bf * bf).sqrt() as u64;
51 let mut tm: i64 = rm.wrapping_shl(1) as i64;
52 let mut denom: i64 = a
53 .wrapping_mul(a)
54 .wrapping_add(b.wrapping_mul(b))
55 .wrapping_sub((tm as u64).wrapping_mul(tm as u64)) as i64;
56 while denom > 2 * tm {
58 denom -= 2 * tm + 1; tm = tm.wrapping_add(1);
61 }
62 while denom < 0 {
63 denom += 2 * tm - 1; tm = tm.wrapping_sub(1);
66 }
67 let rb: i32 = (tm & 1) as i32; let rb2: i32 = (denom >= tm) as i32; let sb: i32 = (denom != 0) as i32; rm = (tm >> 1) as u64; underflow = rm < 0x10000000000000u64;
75 if rb != 0 || sb != 0 {
76 let op = 1.0 + f64::from_bits(0x3c90000000000000);
77 let om = 1.0 - f64::from_bits(0x3c90000000000000);
78 if op == om {
79 if sb != 0 {
81 rm = rm.wrapping_add(rb as u64);
82 if rm >> 52 != 0 && rb2 != 0 {
88 underflow = false;
89 }
90 } else {
91 rm += rm & 1; }
94 } else if op > 1.0 {
95 rm = rm.wrapping_add(1);
97 if (rm >> 52) != 0 && (tm & 1) != 0 {
99 underflow = false;
100 }
101 }
102 if underflow {
103 let trig_uf = black_box(f64::from_bits(0x0010000000000000));
105 _ = black_box(black_box(trig_uf) * black_box(trig_uf)); }
107 }
108 f64::from_bits(rm)
110}
111
112#[cold]
117fn hypot_hard(x: f64, y: f64) -> f64 {
118 let op = 1.0 + f64::from_bits(0x3c90000000000000);
119 let om = 1.0 - f64::from_bits(0x3c90000000000000);
120 let mut xi = x.to_bits();
121 let yi = y.to_bits();
122 let mut bm = (xi & 0x000fffffffffffff) | (1u64 << 52);
123 let mut lm = (yi & 0x000fffffffffffff) | (1u64 << 52);
124 let be: i32 = (xi >> 52) as i32;
125 let le: i32 = (yi >> 52) as i32;
126 let ri = f_fmla(x, x, y * y).sqrt().to_bits();
127 const BS: u32 = 2;
128 let mut rm: u64 = ri & 0x000fffffffffffff;
129 let mut re: i32 = ((ri >> 52) as i32).wrapping_sub(0x3ff);
130 rm |= 1u64 << 52;
131 for _ in 0..3 {
132 if rm == (1u64 << 52) {
133 rm = 0x001fffffffffffff;
134 re = re.wrapping_sub(1);
135 } else {
136 rm = rm.wrapping_sub(1);
137 }
138 }
139 bm = bm.wrapping_shl(BS);
140 let mut m2: u64 = bm.wrapping_mul(bm);
141 let de: i32 = be.wrapping_sub(le);
142 let mut ls: i32 = (BS as i32).wrapping_sub(de);
143 if ls >= 0 {
144 lm <<= ls;
145 m2 = m2.wrapping_add(lm.wrapping_mul(lm));
146 } else {
147 let lm2: u128 = (lm as u128).wrapping_mul(lm as u128);
148 ls = ls.wrapping_mul(2);
149 m2 = m2.wrapping_add((lm2 >> -ls) as u64); m2 |= ((lm2.wrapping_shl((128 + ls) as u32)) != 0) as u64;
151 }
152 let k: i32 = (BS as i32).wrapping_add(re);
153 let mut denom: i64;
154 loop {
155 rm += 1 + (rm >= (1u64 << 53)) as u64;
156 let tm: u64 = rm.wrapping_shl(k as u32);
157 let rm2: u64 = tm.wrapping_mul(tm);
158 denom = (m2 as i64).wrapping_sub(rm2 as i64);
159 if denom <= 0 {
160 break;
161 }
162 }
163 if denom != 0 {
164 if op == om {
165 let ssm = if rm <= (1u64 << 53) { 1 } else { 0 };
166 let tm: u64 = (rm << k) - (1 << (k - ssm));
167 denom = (m2 as i64).wrapping_sub(tm.wrapping_mul(tm) as i64);
168 if denom != 0 {
169 rm = rm.wrapping_add((denom >> 63) as u64);
170 } else {
171 rm = rm.wrapping_sub(rm & 1);
172 }
173 } else {
174 let ssm = if rm > (1u64 << 53) { 1u32 } else { 0 };
175 let pdm = if op == 1. { 1u64 } else { 0 };
176 rm = rm.wrapping_sub(pdm.wrapping_shl(ssm));
177 }
178 }
179 if rm >= (1u64 << 53) {
180 rm >>= 1;
181 re = re.wrapping_add(1);
182 }
183
184 let e: i64 = be.wrapping_sub(1).wrapping_add(re) as i64;
185 xi = (e as u64).wrapping_shl(52).wrapping_add(rm);
186 f64::from_bits(xi)
187}
188
189pub fn f_hypot(x: f64, y: f64) -> f64 {
193 let xi = x.to_bits();
194 let yi = y.to_bits();
195 let emsk = 0x7ffu64 << 52;
196 let mut ex = xi & emsk;
197 let mut ey = yi & emsk;
198 let mut x = x.abs();
199 let mut y = y.abs();
200 if ex == emsk || ey == emsk {
201 let wx = xi.wrapping_shl(1);
203 let wy = yi.wrapping_shl(1);
204 let wm = emsk.wrapping_shl(1);
205 let ninf: i32 = ((wx == wm) ^ (wy == wm)) as i32;
206 let nqnn: i32 = (((wx >> 52) == 0xfff) ^ ((wy >> 52) == 0xfff)) as i32;
207 if ninf != 0 && nqnn != 0 {
211 return if wx == wm { x * x } else { y * y };
212 }
213 return x + y; }
215
216 let u = f64::max(x, y);
217 let v = f64::min(x, y);
218 let mut xd = u.to_bits();
219 let mut yd = v.to_bits();
220 ey = yd;
221 if (ey >> 52) == 0 {
222 if (yd) == 0 {
224 return f64::from_bits(xd);
225 }
226 ex = xd;
227 if (ex >> 52) == 0 {
228 if ex == 0 {
230 return 0.;
231 }
232 return hypot_denorm(ex, ey);
233 }
234 let nz = ey.leading_zeros();
235 ey = ey.wrapping_shl(nz - 11);
236 ey &= u64::MAX >> 12;
237 ey = ey.wrapping_sub(((nz as u64).wrapping_sub(12u64)) << 52);
238 let t = ey;
239 yd = t;
240 }
241
242 let de = xd.wrapping_sub(yd);
243 if de > (27u64 << 52) {
244 return dyad_fmla(f64::from_bits(0x3e40000000000000), v, u);
245 }
246 let off: i64 = ((0x3ffu64 << 52) as i64).wrapping_sub((xd & emsk) as i64);
247 xd = xd.wrapping_add(off as u64);
248 yd = yd.wrapping_add(off as u64);
249 x = f64::from_bits(xd);
250 y = f64::from_bits(yd);
251 let x2 = DoubleDouble::from_exact_mult(x, x);
252 let y2 = DoubleDouble::from_exact_mult(y, y);
253 let r2 = x2.hi + y2.hi;
254 let ir2 = 0.5 / r2;
255 let dr2 = ((x2.hi - r2) + y2.hi) + (x2.lo + y2.lo);
256 let mut th = r2.sqrt();
257 let rsqrt = DoubleDouble::from_exact_mult(th, ir2);
258 let dz = dr2 - rsqrt.lo;
259 let mut tl = rsqrt.hi * dz;
260 let p = DoubleDouble::from_exact_add(th, tl);
261 th = p.hi;
262 tl = p.lo;
263 let mut thd = th.to_bits();
264 let tld = tl.abs().to_bits();
265 ex = thd;
266 ey = tld;
267 ex &= 0x7ffu64 << 52;
268 let aidr = ey.wrapping_add(0x3feu64 << 52).wrapping_sub(ex);
269 let mid = (aidr.wrapping_sub(0x3c90000000000000).wrapping_add(16)) >> 5;
270 if mid == 0 || aidr < 0x39b0000000000000u64 || aidr > 0x3c9fffffffffff80u64 {
271 thd = hypot_hard(x, y).to_bits();
272 }
273 thd = thd.wrapping_sub(off as u64);
274 if thd >= (0x7ffu64 << 52) {
275 return hypot_overflow();
276 }
277 f64::from_bits(thd)
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 #[test]
284 fn test_hypot() {
285 assert_eq!(
286 f_hypot(2.8480945070593211E-306, 2.1219950320804403E-314),
287 2.848094507059321e-306
288 );
289 assert_eq!(
290 f_hypot(3.5601181736115222E-307, 1.0609978954826362E-314),
291 3.560118173611524e-307
292 );
293 assert_eq!(f_hypot(2., 4.), 4.47213595499958);
294 }
295}