---
title: "6.2 Arithmetic operators"
description: "Integer vs float division, the remainder operator, division by zero, and how Rust does exponents without an exponent operator."
url: "https://learnrust.net/chapter-6/arithmetic-operators/"
last_updated: "2026-06-12"
---

# 6.2 Arithmetic operators

You've done arithmetic since chapter 0. This lesson makes the relationship official: the five binary arithmetic operators, the one unary one, and the three places where "it works like math class" stops being the whole truth.

| Operator | Form | Result |
|---|---|---|
| unary minus | `-x` | `x` negated |
| addition | `x + y` | sum |
| subtraction | `x - y` | difference |
| multiplication | `x * y` | product |
| division | `x / y` | quotient |
| remainder | `x % y` | what's left after integer division |

(C programmers may notice an absence: Rust has no unary `+`. C's did nothing, so Rust didn't keep it.)

All of these require both operands to be the same type. There are no implicit numeric conversions, as lesson [4.2](https://learnrust.net/chapter-4/integer-types/) established, so `i32 + i64` is a type error and `as` (lesson [4.10](https://learnrust.net/chapter-4/numeric-conversions/)) is the explicit bridge. Each operator produces the type it was given: integers in, integers out. That last sentence is where the trouble starts.

## Integer division truncates

Lesson [4.5](https://learnrust.net/chapter-4/floating-point-types/)'s quiz promised the full story here. Watch the same division performed by two different types:

```rust
fn main() {
    println!("{}", 7 / 2);
    println!("{}", 7.0 / 2.0);
}
```

```
3
3.5
```

Float division gives the math-class answer. Integer division answers a different question: *how many whole times does it fit?* The fractional part isn't rounded; it's discarded. This is called **truncation**, and it always moves toward zero:

```rust
fn main() {
    println!("{}", -7 / 2);
    println!("{}", 7 / -2);
}
```

```
-3
-3
```

Mathematically, -7 ÷ 2 is -3.5; truncation drops the .5 and lands on -3, the neighbor *closer to zero*. Note that this is not the same as rounding down (that would give -4). Truncation is the right tool surprisingly often: dollars into quarters, minutes into hours, pixels into tiles. When you actually want 3.5, do the division in float country, converting first if needed: `7 as f64 / 2 as f64`.

> **Warning**
>
> New programmers often write a formula like `celsius * 9 / 5 + 32` with integer literals and then stare at the slightly-wrong answers. One integer division in the middle of a float formula quietly truncates the whole calculation's accuracy. If a formula involves fractions, keep every operand floating-point: `9.0 / 5.0`. (Lesson 5.6's quiz already made you dodge this once.)

## Division by zero

Integer division by zero has no answer to give, and Rust treats it as seriously as anything in the language. If the compiler can *see* the zero coming, the program doesn't even build:

```rust
fn main() {
    let x = 5 / 0;
    println!("{x}");
}
```

```
error: this operation will panic at runtime
 --> src/main.rs:2:13
  |
2 |     let x = 5 / 0;
  |             ^^^^^ attempt to divide `5_i32` by zero
  |
  = note: `#[deny(unconditional_panic)]` on by default
```

Most divisors aren't visible at compile time, though. Here's a divisor that arrives at runtime, via lesson [5.6](https://learnrust.net/chapter-5/parsing-strings-into-numbers/)'s recipe:

```rust
use std::io;

fn main() {
    println!("Divide 10 by what?");

    let mut divisor = String::new();
    io::stdin()
        .read_line(&mut divisor)
        .expect("failed to read input");
    let divisor: i32 = divisor.trim().parse().expect("that wasn't a whole number");

    println!("{}", 10 / divisor);
}
```

Feed it `0` and the program panics, exactly like lesson [3.1](https://learnrust.net/chapter-3/syntax-and-semantic-errors/)'s examples:

```
Divide 10 by what?
0
thread 'main' (2259730) panicked at src/main.rs:12:20:
attempt to divide by zero
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```

A panic, not a wrong answer, in debug *and* release builds alike (unlike the overflow behavior from lesson [4.4](https://learnrust.net/chapter-4/integer-overflow/), this check is never relaxed). Floats, meanwhile, shrug: `10.0 / 0.0` is `inf`, per lesson 4.5. Whether a panic or an infinity is the better failure is situational; what Rust won't give you is garbage.

## The remainder operator

`%` is division's sidekick: `x % y` produces what's left over after `x / y` truncates.

```rust
fn main() {
    println!("{}", 7 % 3);
    println!("{}", 6 % 3);
    println!("{}", 2 % 4);
}
```

```
1
0
2
```

Seven contains two whole threes with `1` left over. Six contains threes exactly, remainder `0`. And two contains *zero* fours, so the whole `2` is left over. That middle case is the famous one: `x % y == 0` means `x` divides evenly by `y`, which is how lesson [4.6](https://learnrust.net/chapter-4/boolean-values/)'s even-number check worked (`n % 2 == 0`).

With negative numbers, the remainder takes its sign from the *left* operand:

```rust
fn main() {
    println!("{}", -7 % 3);
    println!("{}", 7 % -3);
}
```

```
-1
1
```

This makes `%` a true *remainder*, consistent with truncating division (`-7 / 3` is `-2`, and `-2 × 3 + -1` gets you back to `-7`). Mathematicians' "modulo" behaves differently with negatives, always producing a non-negative result. Keep the distinction in mind whenever the left operand might go negative: checking `n % 2 == 1` for oddness fails on negative `n` (where the remainder is `-1`); `n % 2 != 0` works for both signs.

> **For advanced readers**
>
> When you want the mathematician's version, it ships as a method: `(-7_i32).rem_euclid(3)` is `2`. Wrapping a clock, indexing a circular buffer, normalizing an angle: those are `rem_euclid` jobs.

Dividing by zero with `%` panics too, for the same reason and with the message "attempt to calculate the remainder with a divisor of zero".

## Exponents: there is no operator

Rust has no exponent operator. Worse, the symbol you might guess *exists and means something else*:

```rust
fn main() {
    println!("{}", 2 ^ 10);
}
```

```
8
```

> **Warning**
>
> `^` is bitwise XOR (lesson [6.6](https://learnrust.net/chapter-6/bitwise-operators/)), not exponentiation, and `2 ^ 10` compiling quietly to `8` is the classic way to find out. If an exponent calculation is producing absurd numbers, hunt for a `^`.

Exponentiation is done with methods. For integers, `.pow()`, which takes a `u32` exponent (a negative exponent would produce a fraction, which an integer can't hold):

```rust
fn main() {
    let base: i64 = 7;
    println!("{}", base.pow(12));
}
```

```
13841287201
```

Note the `i64`: seven to the twelfth is about 13.8 billion, well past `i32`'s ceiling. Integer exponents overflow with spectacular ease, and `.pow()` plays by lesson 4.4's rules: panic in debug builds, wrap in release. The careful-arithmetic methods from that lesson have a sibling here too (`checked_pow`).

For floats, two methods: `.powi()` for whole-number exponents and `.powf()` for fractional ones.

```rust
fn main() {
    let x: f64 = 3.0;
    println!("{}", x.powi(4));
    println!("{}", x.powf(0.5));
}
```

```
81
1.7320508075688772
```

Raising to `0.5` is a square root, showing why `powf` earns its keep (though `.sqrt()` exists and says it better).

## Quiz time

**Question #1**

Evaluate by hand, using lesson 6.1's table: `6 + 5 * 4 % 3`

<details class="solution">
<summary>Show solution</summary>

`*` and `%` share the rank above `+` and group left-to-right between themselves, so this is `6 + ((5 * 4) % 3)` = `6 + (20 % 3)` = `6 + 2` = `8`.

</details>

**Question #2**

What does this print?

```rust
fn main() {
    println!("{}", -9 / 2);
    println!("{}", -9 % 2);
}
```

<details class="solution">
<summary>Show solution</summary>

```
-4
-1
```

Truncation moves toward zero: -4.5 truncates to -4, not down to -5. The remainder takes the dividend's sign, and the pair stays consistent: `-4 × 2 + -1 = -9`.

</details>

**Question #3**

A teammate wants two to the eighth power and writes `2 ^ 8`. What does their program print, and what should they have written?

<details class="solution">
<summary>Show solution</summary>

It prints `10`: `^` is XOR, and `0b10 ^ 0b1000` is `0b1010`, decimal ten. (The full why is lesson 6.6's; the symptom is enough to diagnose it.) The fix:

```rust
fn main() {
    let base: i32 = 2;
    println!("{}", base.pow(8));
}
```

```
256
```

</details>

Next lesson: the operators that *change* a variable in place, and the story of why Rust shipped without `++`.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
