The task
A student has three grades, stored in math_grade, english_grade and science_grade. The program computes their average and prints whether the student passed. A grade of 5 or more is a pass.
This exercise combines the previous lessons: variables, arithmetic, a comparison and an if-else. The one new difficulty is the type of the average.
Why the average is tricky
The three grades are integers: let math_grade = 7; and so on, so Rust makes them i32 values. Their sum is an integer, and dividing an integer by an integer in Rust gives an integer, with the fractional part discarded:
let sum = 7 + 4 + 9;
println!("{}", sum / 3);
6
The true average of 7, 4 and 9 is 6.666..., so the integer result loses information. For the pass mark of 5 the verdict would happen to be the same, but the average itself would be wrong the moment you print it or compare it with a mark such as 5.5. To keep the fraction, the division has to be done on floating-point numbers.
Rust never converts between number types on its own. The integer sum can't be divided by 3.0 directly, and the compiler reports "cannot divide {integer} by {float}". You convert explicitly with as.
Step by step
- Compute
gradeas a float. Add the three grades in parentheses, cast the sum withas f64, and divide by3.0. The cast applies to the parenthesised sum, so the addition itself still happens on integers, and the division happens onf64values. - Write the
if. Checkgrade >= 5.0. A pass is 5 or more, so the comparison is "greater than or equal to". The literal must be5.0, becausegradeis anf64, and Rust doesn't compare a float with the integer5. - Print the pass message inside the block:
"Passed the test". - Add the
elseand print"Failed the test". It runs whenever the average is below 5.
let math_grade = 7;
let english_grade = 4;
let science_grade = 9;
let grade = (math_grade + english_grade + science_grade) as f64 / 3.0;
if grade >= 5.0 {
println!("Passed the test");
} else {
println!("Failed the test");
}
The sum is 20, the average is 6.666..., which is at least 5.0, so the program prints Passed the test.
The cast and the precedence
The expression (a + b + c) as f64 / 3.0 reads left to right with as binding tighter than /. It means ((a + b + c) as f64) / 3.0. Casting only one grade, as in a + b + c as f64, would be a type error, since the integers and the float would be added together. Casting the grades individually works too, but the cast on the sum is shorter.
The cast from an integer to f64 is lossless for any i32. Casts in the other direction, from float to integer, cut off the fractional part, and that is not what we want here.
Common mistakes
- Dividing by
3instead of3.0. After the cast tof64, dividing by the integer3is a type error. The divisor must be a float too. - Casting too late.
(sum / 3) as f64divides as integers first and only then converts, so the fraction is already lost. - Comparing with
5.grade >= 5doesn't compile whengradeis a float. - Using
>instead of>=. An average of exactly 5.0 should pass. For example grades 5, 5 and 5, or 3, 5 and 7. - Floating-point surprises. Floats can't store every decimal exactly (
0.1 + 0.2 == 0.3is false), so comparisons with a boundary can be off in other computations. Here the sums are whole numbers divided by 3, and exact boundary cases like 15 / 3 = 5.0 work correctly.
Key takeaways
- Integer division discards the fraction, so use
f64for averages. - Rust converts numbers only when you ask, with
as. - Compare floats with float literals such as
5.0. - The
if-elsechooses exactly one message.
