Step 1 of 5 · Reading · ~3 min
Learn
Getting Started
Numbers and Math
By the end of this lesson you can do integer arithmetic in Rust without the three classic surprises: silent truncation, a mixed-type compile error, and overflow.
Types never mix silently
Every value has one numeric type, and arithmetic needs both sides to match. Rust never converts for you:
let apples: i32 = 3;
let weight: f64 = 1.5;
// apples + weight -> compile error: cannot add `f64` to `i32`
let total = apples as f64 + weight; // 4.5
as is the explicit cast. Widening (i32 to i64 or f64) is safe. Narrowing is lossy on purpose: 300_i32 as u8 is 44, because only the low 8 bits survive. The _i32 suffix pins a literal's type, and underscores are digit separators: 1_000_000.
Integer division truncates; % is the remainder
When both operands are integers, / throws away the fraction (toward zero) and % gives what was thrown away:
| expression | result |
|---|---|
17 / 5 | 3 |
17 % 5 | 2 |
4 / 9 | 0 |
4 % 9 | 4 |
17.0 / 5.0 | 3.4 |
The two always fit back together: (a / b) * b + a % b == a. That makes them the tool for splitting a quantity into whole units plus a rest. A worked trace, turning 135 minutes into hours and minutes:
let minutes: i64 = 135;
let hours = minutes / 60; // 135 / 60 = 2
let rest = minutes % 60; // 135 % 60 = 15
println!("{}h {}m", hours, rest); // 2h 15m
Order matters as soon as a division sits inside a longer formula, because every / truncates at the moment it runs. Take 7 boxes of 3 eggs split between 4 cooks:
let boxes: i64 = 7;
let per_box: i64 = 3;
let cooks: i64 = 4;
println!("{}", boxes * per_box / cooks); // 21 / 4 = 5 (correct)
println!("{}", boxes / cooks * per_box); // 1 * 3 = 3 (fraction lost early)
Multiply first, divide last.
Overflow is a bug, and Rust treats it like one
An i32 holds up to 2,147,483,647. A debug build panics with attempt to multiply with overflow the moment a result goes past that; a release build wraps around silently. So pick a type that is wide enough: i64 reaches about 9.2 * 10^18. Two numbers near 10^9 multiplied give a product near 10^18, which needs i64. When wrapping is really what you want, say so with a method: wrapping_add, checked_add (gives None on overflow), saturating_add (stops at the maximum).
Floats have their own rules
f64 is IEEE-754: 0.1 + 0.2 is not exactly 0.3, so never compare floats with ==. Math lives in methods: 2.0_f64.sqrt() is 1.4142135623730951, 3_i32.pow(4) is 81. Converting to float just to divide changes the answer's shape: 17 as f64 / 5 as f64 prints 3.4, not 3.
Common mistakes
- Dividing before multiplying.
a / c * btruncates early; with 7, 3 and 4 you get3instead of5. - Swapping
/and%, so the whole-unit count and the rest come out in the wrong order. - Converting to
f64to divide. You print0.99or3.4where the task wants the whole-number quotient0or3. - Doing the arithmetic in
i32. Anything past 2,147,483,647 panics or wraps; keep it ini64.
Your exercise
A rectangular plot of land is shared between people in whole square metres. The starter reads the three numbers as i64 and prints placeholder zeros; replace them with the area, each person's whole share, and what is left over. The usual slip is dividing one side by the number of people before multiplying.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…