Skip to content

Commit 2f3151e

Browse files
71: implement sqrt and hypot r=japaric a=erikdesjardins closes rust-lang#57, closes rust-lang#22 Co-authored-by: Erik <[email protected]>
2 parents 6084dad + 22fb926 commit 2f3151e

File tree

5 files changed

+209
-6
lines changed

5 files changed

+209
-6
lines changed

src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,6 @@ pub trait F64Ext: private::Sealed {
391391
#[cfg(todo)]
392392
fn powf(self, n: Self) -> Self;
393393

394-
#[cfg(todo)]
395394
fn sqrt(self) -> Self;
396395

397396
#[cfg(todo)]
@@ -415,7 +414,6 @@ pub trait F64Ext: private::Sealed {
415414
#[cfg(todo)]
416415
fn cbrt(self) -> Self;
417416

418-
#[cfg(todo)]
419417
fn hypot(self, other: Self) -> Self;
420418

421419
#[cfg(todo)]
@@ -536,7 +534,6 @@ impl F64Ext for f64 {
536534
pow(self, n)
537535
}
538536

539-
#[cfg(todo)]
540537
#[inline]
541538
fn sqrt(self) -> Self {
542539
sqrt(self)
@@ -584,7 +581,6 @@ impl F64Ext for f64 {
584581
cbrt(self)
585582
}
586583

587-
#[cfg(todo)]
588584
#[inline]
589585
fn hypot(self, other: Self) -> Self {
590586
hypot(self, other)

src/math/hypot.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use core::f64;
2+
3+
use super::sqrt;
4+
5+
const SPLIT: f64 = 134217728. + 1.; // 0x1p27 + 1 === (2 ^ 27) + 1
6+
7+
fn sq(x: f64) -> (f64, f64) {
8+
let xh: f64;
9+
let xl: f64;
10+
let xc: f64;
11+
12+
xc = x * SPLIT;
13+
xh = x - xc + xc;
14+
xl = x - xh;
15+
let hi = x*x;
16+
let lo = xh*xh - hi + 2.*xh*xl + xl*xl;
17+
(hi, lo)
18+
}
19+
20+
#[inline]
21+
pub fn hypot(mut x: f64, mut y: f64) -> f64 {
22+
let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700
23+
let x1p_700 = f64::from_bits(0x1430000000000000); // 0x1p-700 === 2 ^ -700
24+
25+
let mut uxi = x.to_bits();
26+
let mut uyi = y.to_bits();
27+
let uti;
28+
let ex: i64;
29+
let ey: i64;
30+
let mut z: f64;
31+
32+
/* arrange |x| >= |y| */
33+
uxi &= -1i64 as u64 >> 1;
34+
uyi &= -1i64 as u64 >> 1;
35+
if uxi < uyi {
36+
uti = uxi;
37+
uxi = uyi;
38+
uyi = uti;
39+
}
40+
41+
/* special cases */
42+
ex = (uxi>>52) as i64;
43+
ey = (uyi>>52) as i64;
44+
x = f64::from_bits(uxi);
45+
y = f64::from_bits(uyi);
46+
/* note: hypot(inf,nan) == inf */
47+
if ey == 0x7ff {
48+
return y;
49+
}
50+
if ex == 0x7ff || uyi == 0 {
51+
return x;
52+
}
53+
/* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */
54+
/* 64 difference is enough for ld80 double_t */
55+
if ex - ey > 64 {
56+
return x + y;
57+
}
58+
59+
/* precise sqrt argument in nearest rounding mode without overflow */
60+
/* xh*xh must not overflow and xl*xl must not underflow in sq */
61+
z = 1.;
62+
if ex > 0x3ff+510 {
63+
z = x1p700;
64+
x *= x1p_700;
65+
y *= x1p_700;
66+
} else if ey < 0x3ff-450 {
67+
z = x1p_700;
68+
x *= x1p700;
69+
y *= x1p700;
70+
}
71+
let (hx, lx) = sq(x);
72+
let (hy, ly) = sq(y);
73+
return z*sqrt(ly+lx+hy+hx);
74+
}

src/math/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ mod powf;
1111
mod round;
1212
mod scalbn;
1313
mod scalbnf;
14+
mod sqrt;
1415
mod sqrtf;
1516
mod logf;
1617
mod expf;
1718
mod floor;
1819
mod trunc;
1920
mod truncf;
21+
mod hypot;
2022
mod hypotf;
2123

2224
//mod service;
@@ -29,12 +31,14 @@ pub use self::{
2931
round::round,
3032
scalbn::scalbn,
3133
scalbnf::scalbnf,
34+
sqrt::sqrt,
3235
sqrtf::sqrtf,
3336
logf::logf,
3437
expf::expf,
3538
floor::floor,
3639
trunc::trunc,
3740
truncf::truncf,
41+
hypot::hypot,
3842
hypotf::hypotf,
3943
};
4044

src/math/sqrt.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
use core::f64;
2+
3+
const TINY: f64 = 1.0e-300;
4+
5+
#[inline]
6+
pub fn sqrt(x: f64) -> f64 {
7+
let mut z: f64;
8+
let sign: u32 = 0x80000000;
9+
let mut ix0: i32;
10+
let mut s0: i32;
11+
let mut q: i32;
12+
let mut m: i32;
13+
let mut t: i32;
14+
let mut i: i32;
15+
let mut r: u32;
16+
let mut t1: u32;
17+
let mut s1: u32;
18+
let mut ix1: u32;
19+
let mut q1: u32;
20+
21+
ix0 = (x.to_bits() >> 32) as i32;
22+
ix1 = x.to_bits() as u32;
23+
24+
/* take care of Inf and NaN */
25+
if (ix0&0x7ff00000) == 0x7ff00000 {
26+
return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
27+
}
28+
/* take care of zero */
29+
if ix0 <= 0 {
30+
if ((ix0&!(sign as i32))|ix1 as i32) == 0 {
31+
return x; /* sqrt(+-0) = +-0 */
32+
}
33+
if ix0 < 0 {
34+
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
35+
}
36+
}
37+
/* normalize x */
38+
m = ix0>>20;
39+
if m == 0 { /* subnormal x */
40+
while ix0 == 0 {
41+
m -= 21;
42+
ix0 |= (ix1>>11) as i32;
43+
ix1 <<= 21;
44+
}
45+
i=0;
46+
while (ix0&0x00100000) == 0 {
47+
i += 1;
48+
ix0 <<= 1;
49+
}
50+
m -= i - 1;
51+
ix0 |= (ix1>>(32-i)) as i32;
52+
ix1 <<= i;
53+
}
54+
m -= 1023; /* unbias exponent */
55+
ix0 = (ix0&0x000fffff)|0x00100000;
56+
if (m & 1) == 1 { /* odd m, double x to make it even */
57+
ix0 += ix0 + ((ix1&sign)>>31) as i32;
58+
ix1 += ix1;
59+
}
60+
m >>= 1; /* m = [m/2] */
61+
62+
/* generate sqrt(x) bit by bit */
63+
ix0 += ix0 + ((ix1&sign)>>31) as i32;
64+
ix1 += ix1;
65+
q = 0; /* [q,q1] = sqrt(x) */
66+
q1 = 0;
67+
s0 = 0;
68+
s1 = 0;
69+
r = 0x00200000; /* r = moving bit from right to left */
70+
71+
while r != 0 {
72+
t = s0 + r as i32;
73+
if t <= ix0 {
74+
s0 = t + r as i32;
75+
ix0 -= t;
76+
q += r as i32;
77+
}
78+
ix0 += ix0 + ((ix1&sign)>>31) as i32;
79+
ix1 += ix1;
80+
r >>= 1;
81+
}
82+
83+
r = sign;
84+
while r != 0 {
85+
t1 = s1 + r;
86+
t = s0;
87+
if t < ix0 || (t == ix0 && t1 <= ix1) {
88+
s1 = t1 + r;
89+
if (t1&sign) == sign && (s1&sign) == 0 {
90+
s0 += 1;
91+
}
92+
ix0 -= t;
93+
if ix1 < t1 {
94+
ix0 -= 1;
95+
}
96+
ix1 -= t1;
97+
q1 += r;
98+
}
99+
ix0 += ix0 + ((ix1&sign)>>31) as i32;
100+
ix1 += ix1;
101+
r >>= 1;
102+
}
103+
104+
/* use floating add to find out rounding direction */
105+
if (ix0 as u32|ix1) != 0 {
106+
z = 1.0 - TINY; /* raise inexact flag */
107+
if z >= 1.0 {
108+
z = 1.0 + TINY;
109+
if q1 == 0xffffffff {
110+
q1 = 0;
111+
q+=1;
112+
} else if z > 1.0 {
113+
if q1 == 0xfffffffe {
114+
q += 1;
115+
}
116+
q1 += 2;
117+
} else {
118+
q1 += q1 & 1;
119+
}
120+
}
121+
}
122+
ix0 = (q>>1) + 0x3fe00000;
123+
ix1 = q1>>1;
124+
if (q&1) == 1 {
125+
ix1 |= sign;
126+
}
127+
ix0 += m << 20;
128+
f64::from_bits((ix0 as u64) << 32 | ix1 as u64)
129+
}

test-generator/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ f64_f64! {
713713
round,
714714
// sin,
715715
// sinh,
716-
// sqrt,
716+
sqrt,
717717
// tan,
718718
// tanh,
719719
trunc,
@@ -725,7 +725,7 @@ f64f64_f64! {
725725
// atan2,
726726
// fdim,
727727
// fmod,
728-
// hypot,
728+
hypot,
729729
// pow,
730730
}
731731

0 commit comments

Comments
 (0)