Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Add newlib sqrtf #172

Closed
wants to merge 8 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
@@ -344,3 +344,93 @@ fn with_set_low_word(f: f64, lo: u32) -> f64 {
fn combine_words(hi: u32, lo: u32) -> f64 {
f64::from_bits((hi as u64) << 32 | lo as u64)
}

mod fdlibm {
#![allow(dead_code)] // FIXME: remove it after other dependent codes merged
#![allow(non_snake_case)]

/* @(#)fdlibm.h 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/

/* Most routines need to check whether a float is finite, infinite, or not a
number, and many need to know whether the result of an operation will
overflow. These conditions depend on whether the largest exponent is
used for NaNs & infinities, or whether it's used for finite numbers. */

/// True if a positive float with bitmask X is finite.
#[inline]
pub(crate) fn FLT_UWORD_IS_FINITE(x: u32) -> bool {
x < INFINITE
}

/// True if a positive float with bitmask X is not a number.
#[inline]
pub(crate) fn FLT_UWORD_IS_NAN(x: u32) -> bool {
x > INFINITE
}

/// True if a positive float with bitmask X is +infinity.
#[inline]
pub(crate) fn FLT_UWORD_IS_INFINITE(x: u32) -> bool {
x == INFINITE
}

const INFINITE: u32 = 0x7f80_0000;

/// The bitmask of FLT_MAX.
pub(crate) const FLT_UWORD_MAX: u32 = 0x7f7f_ffff;
/// The bitmask of FLT_MAX/2.
pub(crate) const FLT_UWORD_HALF_MAX: u32 = FLT_UWORD_MAX - (1 << 23);
/// The bitmask of the largest finite exponent (129 if the largest
/// exponent is used for finite numbers, 128 otherwise).
pub(crate) const FLT_UWORD_EXP_MAX: u32 = 0x4300_0000;
/// The bitmask of log(FLT_MAX), rounded down. This value is the largest
/// input that can be passed to exp() without producing overflow.
pub(crate) const FLT_UWORD_LOG_MAX: u32 = 0x42b1_7217;
/// The bitmask of log(2*FLT_MAX), rounded down. This value is the
/// largest input than can be passed to cosh() without producing
/// overflow.
pub(crate) const FLT_UWORD_LOG_2MAX: u32 = 0x42b2_d4fc;
/// The largest biased exponent that can be used for finite numbers
/// (255 if the largest exponent is used for finite numbers, 254
/// otherwise)
pub(crate) const FLT_LARGEST_EXP: u32 = FLT_UWORD_MAX >> 23;
pub(crate) const HUGE: f32 = 3.402_823_466_385_288_60e+38;

/* Many routines check for zero and subnormal numbers. Such things depend
on whether the target supports denormals or not */

/// True if a positive float with bitmask X is +0. Without denormals,
/// any float with a zero exponent is a +0 representation. With
/// denormals, the only +0 representation is a 0 bitmask.
#[inline]
pub(crate) fn FLT_UWORD_IS_ZERO(x: u32) -> bool {
x == 0
}

/// True if a non-zero positive float with bitmask X is subnormal.
/// (Routines should check for zeros first.)
#[inline]
pub(crate) fn FLT_UWORD_IS_SUBNORMAL(x: u32) -> bool {
x < 0x0080_0000
}

/// The bitmask of the smallest float above +0. Call this number REAL_FLT_MIN...
pub(crate) const FLT_UWORD_MIN: u32 = 0x0000_0001;
/// The bitmask of the float representation of REAL_FLT_MIN's exponent.
pub(crate) const FLT_UWORD_EXP_MIN: u32 = 0x4316_0000;
/// The bitmask of |log(REAL_FLT_MIN)|, rounding down.
pub(crate) const FLT_UWORD_LOG_MIN: u32 = 0x42cf_f1b5;
/// REAL_FLT_MIN's exponent - EXP_BIAS (1 if denormals are not supported,
/// -22 if they are).
pub(crate) const FLT_SMALLEST_EXP: i32 = -22;
}
61 changes: 32 additions & 29 deletions src/math/sqrtf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* origin: FreeBSD /usr/src/lib/msun/src/e_sqrtf.c */
/*
/* ef_sqrtf.c -- float version of e_sqrt.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected].
*/

/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
@@ -13,74 +13,78 @@
* ====================================================
*/

const ONE: f32 = 1.0;
const TINY: f32 = 1.0e-30;

#[inline]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf(x: f32) -> f32 {
pub extern "C" fn sqrtf(x: f32) -> f32 {
use super::fdlibm::{FLT_UWORD_IS_FINITE, FLT_UWORD_IS_SUBNORMAL, FLT_UWORD_IS_ZERO};
// On wasm32 we know that LLVM's intrinsic will compile to an optimized
// `f32.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 {
::core::f32::NAN
core::f32::NAN
} else {
unsafe { ::core::intrinsics::sqrtf32(x) }
unsafe { core::intrinsics::sqrtf32(x) }
}
}
}

let mut z: f32;
let sign: i32 = 0x80000000u32 as i32;

let mut r: u32;
let hx: u32;

let mut ix: i32;
let mut s: i32;
let mut q: i32;
let mut m: i32;
let mut t: i32;
let mut i: i32;
let mut r: u32;

ix = x.to_bits() as i32;
hx = ix as u32 & 0x7fff_ffff;

/* take care of Inf and NaN */
if (ix as u32 & 0x7f800000) == 0x7f800000 {
if !FLT_UWORD_IS_FINITE(hx) {
return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
}

/* take care of zero */
if ix <= 0 {
if (ix & !sign) == 0 {
return x; /* sqrt(+-0) = +-0 */
}
if ix < 0 {
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
}
/* take care of zero and -ves */
if FLT_UWORD_IS_ZERO(hx) {
return x; /* sqrt(+-0) = +-0 */
}
if ix < 0 {
return (x - x) / (x - x); /* sqrt(-ve) = sNaN */
}

/* normalize x */
m = ix >> 23;
if m == 0 {
if FLT_UWORD_IS_SUBNORMAL(hx) {
/* subnormal x */
i = 0;
while ix & 0x00800000 == 0 {
while ix & 0x0080_0000 == 0 {
ix <<= 1;
i = i + 1;
i += 1;
}
m -= i - 1;
}
m -= 127; /* unbias exponent */
ix = (ix & 0x007fffff) | 0x00800000;
ix = (ix & 0x007f_ffff) | 0x0080_0000;
/* odd m, double x to make it even */
if m & 1 == 1 {
/* odd m, double x to make it even */
ix += ix;
}
m >>= 1; /* m = [m/2] */

/* generate sqrt(x) bit by bit */
ix += ix;
q = 0;
s = 0;
r = 0x01000000; /* r = moving bit from right to left */
s = 0; /* q = sqrt(x) */
r = 0x0100_0000; /* r = moving bit from right to left */

while r != 0 {
t = s + r as i32;
@@ -95,18 +99,17 @@ pub fn sqrtf(x: f32) -> f32 {

/* use floating add to find out rounding direction */
if ix != 0 {
z = 1.0 - TINY; /* raise inexact flag */
if z >= 1.0 {
z = 1.0 + TINY;
if z > 1.0 {
z = ONE - TINY; /* trigger inexact flag */
if z >= ONE {
z = ONE + TINY;
if z > ONE {
q += 2;
} else {
q += q & 1;
}
}
}

ix = (q >> 1) + 0x3f000000;
ix = (q >> 1) + 0x3f00_0000;
ix += m << 23;
f32::from_bits(ix as u32)
}