liveBook · Manning

Numerical overflow

As explained in Rust in Action: Systems programming concepts and techniques

Integer overflow occurs when an integer computation exceeds the finite range representable by its fixed-width representation.

An integer type has a fixed number of bits, so it can represent only a fixed range of values. Overflow occurs when a calculation goes above that range. A `u16`, for example, holds values from 0 through 65,535; it cannot hold 65,536. Unlike a floating-point number, an integer cannot give up precision to extend its range. section 5.2

Listing 5.4 How u16 bit patterns translate to a fixed number of integers
fn main() {
  let zero: u16 = 0b0000_0000_0000_0000;
  let one:  u16 = 0b0000_0000_0000_0001;
  let two:  u16 = 0b0000_0000_0000_0010;
  // ...
  let sixtyfivethousand_533: u16 = 0b1111_1111_1111_1101;
  let sixtyfivethousand_534: u16 = 0b1111_1111_1111_1110;
  let sixtyfivethousand_535: u16 = 0b1111_1111_1111_1111;
 
  print!("{}, {}, {}, ..., ", zero, one, two);
  println!("{}, {}, {}", sixty5_533, sixty5_534, sixty5_535);
}

Compare the first and last `u16` bit patterns. Once all 16 bits are 1, there is no next pattern available for a larger `u16` value. section 5.2

Listing 5.3 Exploring the effect of incrementing an integer past its range
 fn main() {
   let mut i: u16 = 0;
   print!("{}..", i);
 
   loop {
       i += 1000;
       print!("{}..", i);
       if i % 10000 == 0 {
           print!{"\n"}
       }
   }
 }

This loop adds 1,000 to a `u16` on every pass. With default compilation, it eventually panics with an “attempt to add with overflow” message. section 5.2

When the answer will not fit

Try to store `200 + 200` in a `u8`. The answer, 400, exceeds that type’s maximum of 255. The supplied example panics with default compilation; with optimizations enabled, its unchecked result is 144. Do not assume that a successful optimized build means the arithmetic stayed in range. section 5.2 section 5.8

This makes overflow a safety issue that depends on how the program is built: Rust checks for it in debug builds, while optimized builds can disable those runtime checks. Going below an integer type’s lowest value is the related problem called underflow. section 1.6.1 section 5.8

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains bit-pattern limits and compares default and optimized execution, but does not develop an overflow-handling API.
Examples
Demonstrates a repeatedly incremented `u16` and an out-of-range `200 + 200` calculation stored in a `u8`.
What it assumes
Introduces fixed-width representation for readers who may not have systems-programming background.
What you can do after
Diagnose/debug with it when integer arithmetic panics or gives an unexpected result in an optimized build.
How it connects
Connects overflow to fixed-width integer types, bit patterns, integer underflow, and runtime checks.

Also explained in

Compare how 7 books explain numerical overflow →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.