m00am
m00am

Reputation: 6298

Check if a float can be converted to integer without loss

I wanted to check whether an integer was a power of 2. My standard approach would have been to see if log₂(x) was an integer value, however I found no elegant way to do this. My approaches were the following:

let x = 65;

let y = (x as f64).log(2.0);

// Compute the difference between y and the result of
// of truncating y by casting to int and back
let difference = y - (y as i64 as f64);

// This looks nice but matches on float values will be phased out
match difference {
    0.0 => println!("{} is a power of 2", x),
    _ => println!("{} is NO power of 2", x),
}

// This seems kind of clunky
if difference == 0.0 {
    println!("{} is a power of 2", x);
} else {
    println!("{} is NO power of 2", x);
}

Is there a builtin option in Rust to check if a float can be converted to an integer without truncation?

Something that behaves like:

42.0f64.is_int() // True/ Ok()
42.23f64.is_int() // False/ Err()

In other words, a method/ macro/ etc. that allows me to check if I will lose information (decimals) by casting to int.


I already found that checking whether an integer is a power of 2 can be done efficiently with x.count_ones() == 1.

Upvotes: 18

Views: 12867

Answers (1)

Jmb
Jmb

Reputation: 23264

You can use fract to check if there is a non-zero fractional part:

42.0f64.fract() == 0.0;
42.23f64.fract() != 0.0;

Note that this only works if you already know that the number is in range. If you need an extra check to test that the floating-point number is between 0 and u32::MAX (or between i32::MIN and i32::MAX), then you might as well do the conversion and check that it didn't lose precision:

x == (x as u32) as f64

Upvotes: 25

Related Questions