Integer division

#1

Ok, here is another basic question:

let x = 7;
let y = 3

now, x / y gives 2… but this is wrong i want 2.333333

i find this way:

println!("{}", ((x1 as f64) / (x2 as f64)));

it seems to me a very poor way… is there another better?

Thx

#2

You can declare the number type like so:

let x = 7f64;
let y = 3f64;

println!("{} / {} = {}", x, y, x/y);

You could probably also use let x = 7.0 in this case.

1 Like
#3

You did it right. Rust always prefer to be super explicit in the context of type conversion.

In the machine instructions, you can’t produce non-integer value from integer division. So as you want floating point value, you need floating point division instead. And finally, x and y variables you declared are integer types, so they must be converted to floating point types to perform floating point division.

2 Likes
#4

Of course but the problem is another.
My starting point is that i’m working with integer type, because, for any reason my input data are integers. If, at any time in my project i have that kind of problem, that is making a trivial division and i want the real result, i found that workaround but it seems really bad.

thx.

#5

I see. As Hyeonu says, you need to be explicit with types in Rust. You can make it look a bit neater by using an intermediate variable and omitting the brackets

let z = x as f64 / y as f64

If you really don’t like to explicitly cast each time then you could write a simple utility function that takes (for example) two i64's and returns an f64. Or perhaps a trait implemented on i64 that does the same.

2 Likes
#6

Better to try to minimize the number of “as” casts in your Rust programs:

fn main() {
    let x: u32 = 7;
    let y: u32 = 3;
    println!("{}", f64::from(x) / f64::from(y));
}
#7

Why? Is there some performance/data loss reason? What is different about f64::from(x) with regards to x as f64? I would think with Copy fundamental types, there should be no difference.

#8

In general, the benefit of using from instead of as where possible is that it prevents bugs when refactoring - here’s a (somewhat contrived) example:

fn test(input: u8) {
    let x = input as i32;
    let y = i32::from(input);
}

What happens if I later decide to change the type of input to f32?

  • x silently gets truncated, because as can be a lossy operation.
  • y throws a compile error, as the standard library does not implement From for lossy numeric conversions.

So that’s the main difference (and why Clippy nudges you to use the latter) - they don’t behave differently in this case, but it makes sure that the compiler will let you know if you accidentally change the behavior.

3 Likes
#9

The docs state:

Note: this trait must not fail

It doesn’t mention anything about lossy conversions.

See also:

#10

Ah, whoops, I misremembered that part! Have updated my post to take that info into account :slight_smile:

1 Like