Rust: from zero to your own organizer Lesson 10 of 10
Numbers and arithmetic
Check calculations and the limits of numeric types.
This text was translated with AI.
Prerequisite: lessons 1–9. Work in organizer unless stated otherwise.
Why this matters
Our organizer now has numbers. Integers have no fractional part. Floating-point numbers approximately represent a wide range of numbers. A bit is a binary unit; a byte consists of eight bits. The available bits limit the values a type can represent, like the capacity of a measuring cup.
The whole picture
Replace src/main.rs and run cargo run from organizer:
fn main() {
let total: u32 = 7;
let done: u32 = 2;
let remaining = total - done;
println!("Remaining: {remaining}");
println!("Complete pairs: {}", remaining / 2);
println!("Unpaired: {}", remaining % 2);
}
Output:
Remaining: 5
Complete pairs: 2
Unpaired: 1
- subtracts, / divides, and % gives the remainder. Empty {} in println! inserts the following argument after the comma. This lets us print a calculation without naming an extra variable.
Seven tasks minus two completed leaves five. Integer division 5 / 2 gives 2, with remainder 5 % 2 equal to 1. Integer division truncates towards zero. Integer division by zero is invalid.
Choosing a type
u8 stores values from 0 through 255; i8 stores −128 through 127. u32 stores 0 through 4,294,967,295; i32 stores −2,147,483,648 through 2,147,483,647. The u prefix means unsigned, i means signed, and the number is the bit count. There are also 16-, 64- and 128-bit integers. usize depends on the platform and is used for sizes and indices, which we will meet with collections. The type has a limit even when today’s value is small.
f32 and f64 are 32- and 64-bit floating-point types; f64 generally offers greater precision and range. An unconstrained floating-point literal defaults to f64. Not every decimal fraction has an exact binary representation. Task counts need integers; exact monetary accounting should not casually use floating-point numbers. Money is outside this project.
+, -, *, / and % mean addition, subtraction, multiplication, division and remainder. Multiplication and division precede addition; parentheses specify the intended order explicitly.
Compare floating-point division and operation order. We specify f64 explicitly; a decimal point is used in code. These particular numbers have exact binary representations. average is our chosen name for a division result, not a task count. Predict all three lines first.
fn main() {
let average: f64 = 5.0 / 2.0;
println!("{average}");
println!("{}", 2 + 3 * 4);
println!("{}", (2 + 3) * 4);
}
2.5
14
20
Overflow and conversions
Overflow occurs when a result cannot fit its type. In our fixed example, done never exceeds total. If that condition is broken, unsigned subtraction does not produce an ordinary negative value. A checked build can stop; do not rely on wrapping when checks are disabled. Conditions and input-validation lessons will enforce this rule explicitly.
Applying a minus sign to an unsigned u32 is invalid. This deliberately wrong example should produce E0600:
fn main() {
let count: u32 = -1;
println!("{count}");
}
A type conversion is an operation, not merely changing how you spell a number. Later we will study checked conversions that can fail. Do not treat as as a universal repair: narrowing may lose data. Here our types agree and our fixed inputs satisfy the task’s conditions.
Recall map
Meaning → type → range → operation → expected answer → check. Compiling does not prove that total and done make sense.
Warm-up
- Predict 6 / 2 and 6 % 2 before running.
- Complete remaining = total ___ done.
- Before changing the type to accept a negative task count, decide whether that value makes sense.
Exercise
Required. With total = 10 and done = 4, produce “Remaining: 6”, “Complete pairs: 3” and “Unpaired: 0”. Calculate the results rather than printing fixed answers.
Your own data. Use total = done. All three results should be zero.
Hint and reference answer
Only the inputs change; the formulas remain the same. Warm-up answers: 3 and 0; subtraction; negative counts are invalid for our task. The zero case helps detect a mistaken addition.
fn main() {
let total: u32 = 10;
let done: u32 = 4;
let remaining = total - done;
println!("Remaining: {remaining}");
println!("Complete pairs: {}", remaining / 2);
println!("Unpaired: {}", remaining % 2);
}
Expected output:
Remaining: 6
Complete pairs: 3
Unpaired: 0
Continue when you can declare a variable, explain its type, change its value and calculate remaining tasks independently. Lessons 11–15 will cover logic, branches, loops, functions and arrays; they are still being prepared.
If you have found a mistake or a typo in this article, tell us about it
Comments (0)
Log in to leave a comment →
No comments yet. Be the first.