Shanraq.org Shanraq.org
Numbers and arithmetic
IT

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

  1. Predict 6 / 2 and 6 % 2 before running.
  2. Complete remaining = total ___ done.
  3. 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.

Previous lesson · Contents

If you have found a mistake or a typo in this article, tell us about it

Comments (0)

No comments yet. Be the first.