#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
-#[cfg(stage0)]
-use prelude::v1::*;
-
use core::num;
-#[cfg(not(target_env = "msvc"))]
use intrinsics;
use libc::c_int;
use num::{FpCategory, ParseFloatError};
pub fn fmaxf(a: c_float, b: c_float) -> c_float;
pub fn fminf(a: c_float, b: c_float) -> c_float;
pub fn fmodf(a: c_float, b: c_float) -> c_float;
- pub fn nextafterf(x: c_float, y: c_float) -> c_float;
+ pub fn ilogbf(n: c_float) -> c_int;
pub fn logbf(n: c_float) -> c_float;
pub fn log1pf(n: c_float) -> c_float;
- pub fn ilogbf(n: c_float) -> c_int;
pub fn modff(n: c_float, iptr: &mut c_float) -> c_float;
+ pub fn nextafterf(x: c_float, y: c_float) -> c_float;
pub fn tgammaf(n: c_float) -> c_float;
#[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
#[stable(feature = "rust1", since = "1.0.0")]
impl f32 {
/// Parses a float as with a given radix
- #[unstable(feature = "float_from_str_radix", reason = "recently moved API")]
+ #[unstable(feature = "float_from_str_radix", reason = "recently moved API",
+ issue = "27736")]
+ #[deprecated(since = "1.4.0",
+ reason = "unclear how useful or correct this is")]
pub fn from_str_radix(s: &str, radix: u32) -> Result<f32, ParseFloatError> {
num::Float::from_str_radix(s, radix)
}
/// assert!(abs_difference <= f32::EPSILON);
/// ```
/// [floating-point]: ../../../../../reference.html#machine-types
- #[unstable(feature = "float_extras", reason = "signature is undecided")]
+ #[unstable(feature = "float_extras", reason = "signature is undecided",
+ issue = "27752")]
#[inline]
pub fn integer_decode(self) -> (u64, i16, i8) {
num::Float::integer_decode(self)
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn floor(self) -> f32 { num::Float::floor(self) }
+ pub fn floor(self) -> f32 {
+ return floorf(self);
+
+ // On MSVC LLVM will lower many math intrinsics to a call to the
+ // corresponding function. On MSVC, however, many of these functions
+ // aren't actually available as symbols to call, but rather they are all
+ // `static inline` functions in header files. This means that from a C
+ // perspective it's "compatible", but not so much from an ABI
+ // perspective (which we're worried about).
+ //
+ // The inline header functions always just cast to a f64 and do their
+ // operation, so we do that here as well, but only for MSVC targets.
+ //
+ // Note that there are many MSVC-specific float operations which
+ // redirect to this comment, so `floorf` is just one case of a missing
+ // function on MSVC, but there are many others elsewhere.
+ #[cfg(target_env = "msvc")]
+ fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
+ }
/// Returns the smallest integer greater than or equal to a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn ceil(self) -> f32 { num::Float::ceil(self) }
+ pub fn ceil(self) -> f32 {
+ return ceilf(self);
+
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
+ }
/// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn round(self) -> f32 { num::Float::round(self) }
+ pub fn round(self) -> f32 {
+ unsafe { intrinsics::roundf32(self) }
+ }
/// Returns the integer part of a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn trunc(self) -> f32 { num::Float::trunc(self) }
+ pub fn trunc(self) -> f32 {
+ unsafe { intrinsics::truncf32(self) }
+ }
/// Returns the fractional part of a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn fract(self) -> f32 { num::Float::fract(self) }
+ pub fn fract(self) -> f32 { self - self.trunc() }
/// Computes the absolute value of `self`. Returns `NAN` if the
/// number is `NAN`.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn mul_add(self, a: f32, b: f32) -> f32 { num::Float::mul_add(self, a, b) }
+ pub fn mul_add(self, a: f32, b: f32) -> f32 {
+ unsafe { intrinsics::fmaf32(self, a, b) }
+ }
/// Takes the reciprocal (inverse) of a number, `1/x`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) }
+ pub fn powf(self, n: f32) -> f32 {
+ return powf(self, n);
+
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
+ }
/// Takes the square root of a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn sqrt(self) -> f32 { num::Float::sqrt(self) }
+ pub fn sqrt(self) -> f32 {
+ if self < 0.0 {
+ NAN
+ } else {
+ unsafe { intrinsics::sqrtf32(self) }
+ }
+ }
/// Returns `e^(self)`, (the exponential function).
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn exp(self) -> f32 { num::Float::exp(self) }
+ pub fn exp(self) -> f32 {
+ return expf(self);
+
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
+ }
/// Returns `2^(self)`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn exp2(self) -> f32 { num::Float::exp2(self) }
+ pub fn exp2(self) -> f32 {
+ unsafe { intrinsics::exp2f32(self) }
+ }
/// Returns the natural logarithm of the number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn ln(self) -> f32 { num::Float::ln(self) }
+ pub fn ln(self) -> f32 {
+ return logf(self);
+
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
+ }
/// Returns the logarithm of the number with respect to an arbitrary base.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn log(self, base: f32) -> f32 { num::Float::log(self, base) }
+ pub fn log(self, base: f32) -> f32 { self.ln() / base.ln() }
/// Returns the base 2 logarithm of the number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn log2(self) -> f32 { num::Float::log2(self) }
+ pub fn log2(self) -> f32 {
+ unsafe { intrinsics::log2f32(self) }
+ }
/// Returns the base 10 logarithm of the number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn log10(self) -> f32 { num::Float::log10(self) }
+ pub fn log10(self) -> f32 {
+ return log10f(self);
+
+ // see notes above in `floor`
+ #[cfg(target_env = "msvc")]
+ fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
+ #[cfg(not(target_env = "msvc"))]
+ fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
+ }
/// Converts radians to degrees.
///
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
- #[unstable(feature = "float_extras", reason = "desirability is unclear")]
+ #[unstable(feature = "float_extras", reason = "desirability is unclear",
+ issue = "27752")]
#[inline]
pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
- #[unstable(feature = "float_extras", reason = "desirability is unclear")]
+ #[unstable(feature = "float_extras", reason = "desirability is unclear",
+ issue = "27752")]
#[inline]
pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
/// assert!(abs_difference <= f32::EPSILON);
/// ```
#[unstable(feature = "float_extras",
- reason = "pending integer conventions")]
+ reason = "pending integer conventions",
+ issue = "27752")]
#[inline]
pub fn ldexp(x: f32, exp: isize) -> f32 {
unsafe { cmath::ldexpf(x, exp as c_int) }
/// assert!(abs_difference_1 <= f32::EPSILON);
/// ```
#[unstable(feature = "float_extras",
- reason = "pending integer conventions")]
+ reason = "pending integer conventions",
+ issue = "27752")]
#[inline]
pub fn frexp(self) -> (f32, isize) {
unsafe {
/// assert!(abs_diff <= f32::EPSILON);
/// ```
#[unstable(feature = "float_extras",
- reason = "unsure about its place in the world")]
+ reason = "unsure about its place in the world",
+ issue = "27752")]
#[inline]
pub fn next_after(self, other: f32) -> f32 {
unsafe { cmath::nextafterf(self, other) }
use super::consts;
let pi: f32 = consts::PI;
- let two_pi: f32 = consts::PI_2;
let frac_pi_2: f32 = consts::FRAC_PI_2;
let frac_pi_3: f32 = consts::FRAC_PI_3;
let frac_pi_4: f32 = consts::FRAC_PI_4;
let ln_2: f32 = consts::LN_2;
let ln_10: f32 = consts::LN_10;
- assert_approx_eq!(two_pi, 2f32 * pi);
assert_approx_eq!(frac_pi_2, pi / 2f32);
assert_approx_eq!(frac_pi_3, pi / 3f32);
assert_approx_eq!(frac_pi_4, pi / 4f32);