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?
source to share
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.
source to share