Spracherkennung für: .rs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrt.c */
/*
* ====================================================
* Copyright (C)
1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* sqrt(x)
* Return correctly rounded sqrt.
* ------------------------------------------
* | Use the hardware sqrt if you have one |
* ------------------------------------------
* Method:
* Bit by bit method using integer arithmetic. (Slow, but portable)
*
1. Normalization
* Scale x to y in [
1,
4) with even powers of
2:
* find an integer k such that
1 <= (y=x*
2^(
2k)) <
4, then
* sqrt(x) =
2^k * sqrt(y)
*
2. Bit by bit computation
* Let q = sqrt(y) truncated to i bit after binary point (q =
1),
* i
0
* i+
1 2
* s =
2*q , and y =
2 * ( y - q ). (
1)
* i i i i
*
* To compute q from q , one checks whether
* i+
1 i
*
* -(i+
1)
2
* (q +
2 ) <= y. (
2)
* i
* -(i+
1)
* If (
2) is false, then q = q ; otherwise q = q +
2 .
* i+
1 i i+
1 i
*
* With some algebraic manipulation, it is not difficult to see
* that (
2) is equivalent to
* -(i+
1)
* s +
2 <= y (
3)
* i i
*
* The advantage of (
3) is that s and y can be computed by
* i i
* the following recurrence formula:
* if (
3) is false
*
* s = s , y = y ; (
4)
* i+
1 i i+
1 i
*
* otherwise,
* -i -(i+
1)
* s = s +
2 , y = y - s -
2 (
5)
* i+
1 i i+
1 i i
*
* One may easily use induction to prove (
4) and (
5).
* Note. Since the left hand side of (
3) contain only i+
2 bits,
* it does not necessary to do a full (
53-bit) comparison
* in (
3).
*
3. Final rounding
* After generating the
53 bits result, we compute one more bit.
* Together with the remainder, we can decide whether the
* result is exact, bigger than
1/
2ulp, or less than
1/
2ulp
* (it will never equal to
1/
2ulp).
* The rounding mode can be detected by checking whether
* huge + tiny is equal to huge, and whether huge - tiny is
* equal to huge for some floating point number "huge" and "tiny".
*
* Special cases:
* sqrt(+-
0) = +-
0 ... exact
* sqrt(inf) = inf
* sqrt(-ve) = NaN ... with invalid signal
* sqrt(NaN) = NaN ... with invalid signal for signaling NaN
*/
use core::f64;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrt(x: f64) -> f64 {
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
// `f64.sqrt` native instruction, so we can leverage this for both code size
// and speed.
llvm_intrinsically_optimized! {
#[cfg(target_arch = "wasm32")] {
return if x <
0.
0 {
f64::NAN
} else {
unsafe { ::core::intrinsics::sqrtf64(x) }
}
}
}
#[cfg(target_feature = "sse2")]
{
// Note: This path is unlikely since LLVM will usually have already
// optimized sqrt calls into hardware instructions if sse2 is available,
// but if someone does end up here they'll apprected the speed increase.
#[cfg(target_arch = "x86")]
use core::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use core::arch::x86_64::*;
unsafe {
let m = _mm_set_sd(x);
let m_sqrt = _mm_sqrt_pd(m);
_mm_cvtsd_f64(m_sqrt)
}
}
#[cfg(not(target_feature = "sse2"))]
{
use core::num::Wrapping;
const TINY: f64 =
1.
0e-
300;
let mut z: f64;
let sign: Wrapping<u32> = Wrapping(
0x80000000);
let mut ix0: i32;
let mut s0: i32;
let mut q: i32;
let mut m: i32;
let mut t: i32;
let mut i: i32;
let mut r: Wrapping<u32>;
let mut t1: Wrapping<u32>;
let mut s1: Wrapping<u32>;
let mut ix1: Wrapping<u32>;
let mut q1: Wrapping<u32>;
ix0 = (x.to_bits() >>
32) as i32;
ix1 = Wrapping(x.to_bits() as u32);
/* take care of Inf and NaN */
if (ix0 &
0x7ff00000) ==
0x7ff00000 {
return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
}
/* take care of zero */
if ix0 <=
0 {
if ((ix0 & !(sign.
0 as i32)) | ix1.
0 as i32) ==
0 {
return x; /* sqrt(+-
0) = +-
0 */
}
if ix0 <
0 {
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
}
}
/* normalize x */
m = ix0 >>
20;
if m ==
0 {
/* subnormal x */
while ix0 ==
0 {
m -=
21;
ix0 |= (ix1 >>
11).
0 as i32;
ix1 <<=
21;
}
i =
0;
while (ix0 &
0x00100000) ==
0 {
i +=
1;
ix0 <<=
1;
}
m -= i -
1;
ix0 |= (ix1 >> (
32 - i) as usize).
0 as i32;
ix1 = ix1 << i as usize;
}
m -=
1023; /* unbias exponent */
ix0 = (ix0 &
0x000fffff) |
0x00100000;
if (m &
1) ==
1 {
/* odd m, double x to make it even */
ix0 += ix0 + ((ix1 & sign) >>
31).
0 as i32;
ix1 += ix1;
}
m >>=
1; /* m = [m/
2] */
/* generate sqrt(x) bit by bit */
ix0 += ix0 + ((ix1 & sign) >>
31).
0 as i32;
ix1 += ix1;
q =
0; /* [q,q1] = sqrt(x) */
q1 = Wrapping(
0);
s0 =
0;
s1 = Wrapping(
0);
r = Wrapping(
0x00200000); /* r = moving bit from right to left */
while r != Wrapping(
0) {
t = s0 + r.
0 as i32;
if t <= ix0 {
s0 = t + r.
0 as i32;
ix0 -= t;
q += r.
0 as i32;
}
ix0 += ix0 + ((ix1 & sign) >>
31).
0 as i32;
ix1 += ix1;
r >>=
1;
}
r = sign;
while r != Wrapping(
0) {
t1 = s1 + r;
t = s0;
if t < ix0 || (t == ix0 && t1 <= ix1) {
s1 = t1 + r;
if (t1 & sign) == sign && (s1 & sign) == Wrapping(
0) {
s0 +=
1;
}
ix0 -= t;
if ix1 < t1 {
ix0 -=
1;
}
ix1 -= t1;
q1 += r;
}
ix0 += ix0 + ((ix1 & sign) >>
31).
0 as i32;
ix1 += ix1;
r >>=
1;
}
/* use floating add to find out rounding direction */
if (ix0 as u32 | ix1.
0) !=
0 {
z =
1.
0 - TINY; /* raise inexact flag */
if z >=
1.
0 {
z =
1.
0 + TINY;
if q1.
0 ==
0xffffffff {
q1 = Wrapping(
0);
q +=
1;
} else if z >
1.
0 {
if q1.
0 ==
0xfffffffe {
q +=
1;
}
q1 += Wrapping(
2);
} else {
q1 += q1 & Wrapping(
1);
}
}
}
ix0 = (q >>
1) +
0x3fe00000;
ix1 = q1 >>
1;
if (q &
1) ==
1 {
ix1 |= sign;
}
ix0 += m <<
20;
f64::from_bits((ix0 as u64) <<
32 | ix1.
0 as u64)
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::f64::*;
#[test]
fn sanity_check() {
assert_eq!(sqrt(
100.
0),
10.
0);
assert_eq!(sqrt(
4.
0),
2.
0);
}
/// The spec:
https://en.cppreference.com/w/cpp/numeric/math/sqrt
#[test]
fn spec_tests() {
// Not Asserted: FE_INVALID exception is raised if argument is negative.
assert!(sqrt(-
1.
0).is_nan());
assert!(sqrt(NAN).is_nan());
for f in [
0.
0, -
0.
0, INFINITY].iter().copied() {
assert_eq!(sqrt(f), f);
}
}
}