B_old
B_old

Reputation: 1301

Where is the frexp function for f32 in Rust?

I am looking for the frexp() function in Rust.I found some references to an unstable feature of std::f32 in previous releases, but that doesn't seem work with my standard Rust installation.

I also found references to std::num::Float, but I cannot get the examples to work either.

Do I have to download a crate to access those functions?

Upvotes: 2

Views: 920

Answers (3)

B_old
B_old

Reputation: 1301

I found a Rust implementation of frexp() in the glm-rs lib.

fn frexp(self) -> ($t, isize) {
    // CHECK: use impl in `libstd` after it's stable.
    if self.is_zero() || self.is_infinite() || self.is_nan() {
        (self, 0)
    } else {
        let lg = self.abs().log2();
        let x = (lg.fract() - 1.).exp2();
        let exp = lg.floor() + 1.;
        (self.signum() * x, exp as isize)
    }
}

Interestingly it doesn't give me the same results as C frexpf(), because f32.fract() returns negative numbers for negative input. I solved it by replacing lg.fract() with lg - lg.floor().

My version:

fn frexp(s : f32) -> (f32, i32) {
    if 0.0 == s {
        return (s, 0);
    } else {
        let lg = s.abs().log2();
        let x = (lg - lg.floor() - 1.0).exp2();
        let exp = lg.floor() + 1.0;
        (s.signum() * x, exp as i32)
    }
}

Example:

let x = 0.3f32;
println!("{:?}", (x).frexp()); // (0.6, -1)
println!("{:?}", glmfrexp(x)); // (0.3, -1)
println!("{:?}", myfrexp(x));  // (0.6, -1)

Upvotes: 3

hellow
hellow

Reputation: 13440

I found some references to an unstable feature of std::f32 in previous releases

If you follow your link you can see, that that feature was unstable (as you said) and that the corresponding issue (#27752) was closed. Therefore the feature and the function is no longer available (remove in PR #41437).

I also found references to std::num::Float

If you look at that URL you will notice, that that is a documentation from 2015, so it's also deprecated.


Unfortunately I was not able to find any crate that offers a Rust implementation for you, but since Rust has full FFI support, you can call the corresponding c-function.

use std::os::raw::{c_float, c_double, c_int};

extern "C" {
    fn frexp(x: c_double, exp: *mut c_int) -> c_double;
    fn frexpf(x: c_float, exp: *mut c_int) -> c_float;
}

pub trait FloatExp: Sized {
    fn frexp(self) -> (Self, i32);
}

impl FloatExp for f64 {
    fn frexp(self) -> (Self, i32) {
        let mut exp: c_int = 0;
        let res = unsafe { frexp(self, &mut exp) };
        (res, exp)
    }
}

impl FloatExp for f32 {
    fn frexp(self) -> (Self, i32) {
        let mut exp: c_int = 0;
        let res = unsafe { frexpf(self, &mut exp) };
        (res, exp)
    }
}

fn main() {
    println!("{:?}", (1.3f64).frexp());
    println!("{:?}", (0.3f32).frexp());
}

(Playground)

Upvotes: 3

kabanus
kabanus

Reputation: 25895

This function has been deprecated for a very long time. This is the commit that completely removed it: https://github.com/rust-lang/rust/pull/41437.

Likely you have a new version. If you are interested, the full implementation is available here https://github.com/rust-lang/rust/blob/9ebf47851a357faa4cd97f4b1dc7835f6376e639/src/librustc_apfloat/tests/ieee.rs, but you should likely move to something else.

Checkout for example the Float trait integer_decode that returns the mantissa, exponent and sign instead.

Straight from the docs I linked to:

use num_traits::Float;    
let num = 2.0f32;    
// (8388608, -22, 1)
let (mantissa, exponent, sign) = Float::integer_decode(num);

Upvotes: 4

Related Questions