How to multiply / divide / add / subtract numbers of different types?

I'm working on the second edition of the Rust reference and decided to try the classic Celsius-to-Fahrenheit converter:

fn c_to_f(c: f32) -> f32 {
    return ( c * ( 9/5 ) ) + 32;
}

      

Compiling with cargo build

will result in a compile-time error:

error[E0277]: the trait bound `f32: std::ops::Mul<{integer}>` is not satisfied
 --> src/main.rs:2:12
  |
2 |     return (c * (9 / 5)) + 32;
  |            ^^^^^^^^^^^^^ the trait `std::ops::Mul<{integer}>` is not implemented for `f32`
  |
  = note: no implementation for `f32 * {integer}`

      

As a new Rust programmer, my interpretation is that I cannot multiply float and integer types together. I solved it by making all my constant floats:

fn c_to_f(c: f32) -> f32 {
    return ( c * ( 9.0/5.0 ) ) + 32.0;
}

      

This leaves me with reservations. Coming from C / C ++ / Java / Python, it was surprising to know that you can't just do arithmetic on different types of numbers. Is it correct to just convert them to the same type as I am here?

+3


source to share


1 answer


TL; DR : as

is the most common way to convert between primitive numeric types, but using it takes some thought.

fn c_to_f(c: f32) -> f32 {
    (c * (9 as f32 / 5 as f32)) + 32 as f32
}

      

In this example, however, it makes more sense to just use floating point literals to start with:

fn c_to_f(c: f32) -> f32 {
    (c * (9. / 5.)) + 32.
}

      


The real problem is that doing mixed type arithmetic is a little trickier.

If you are multiplying 1 a T

by T

, you usually expect to get a type result T

with at least basic types.

However, there are some difficulties when mixing types:



  • signature,
  • mixing precision.

So, for example, what is the ideal result i8 * u32

? The smallest type that can span the full set of all values โ€‹โ€‹of i8

and u32

is i64

. Should this be the result?

As another example, what is the ideal result f32 * i32

? The smallest type that can span the full set of all values โ€‹โ€‹of f32

and i32

is f64

. Should this be the result?

I find the idea that such an extension gets pretty confusing. It also has a performance impact (operations on f32

can be much faster than operations on f64

, once vectorized).

Because of these issues, Rust currently requires you to be explicit: what type do you want the computation to wrap? Which type makes sense for your particular situation?

And then apply the appropriate way, using as

, and think about how to apply the rounding mode ( .round()

, .ceil()

, .floor()

or .trunc()

when switching from floating point to the integral).

1 Addition, subtraction and division work in a similar way.

+7


source







All Articles