liveBook · Manning

Off-by-one error

As explained in Go in Practice, Second Edition

An off-by-one error is a boundary mistake in which a loop or index begins, ends, or counts one position incorrectly.

An off-by-one error is a boundary mistake in which a loop or index begins, ends, or counts one position incorrectly. In Go, table-driven tests expose these errors quickly by comparing generated output with an exact expected result. section 6.3.1

Check both boundaries when reviewing a loop:

  • Verify the initial index matches the domain being modeled; starting at 0 produces a different sequence from one beginning at 1. section 6.3.1
  • Verify whether the target value is included; a condition such as i < n excludes n. section 6.3.1
  • Add representative boundary cases to a table-driven test and rerun go test after correcting the implementation. section 6.3.1

Fizz Buzz boundary failure

A Fizz Buzz loop using `for i := int64(0); i < n; i++` starts with 0 and stops before n. For an expected sequence from 1 through 37, the test fails immediately; correcting the start, endpoint, and formatting produces a passing `go test` result. section 6.3.1

Listing 6.12 Basic Fizz Buzz
package main

import (
    "fmt"
    "strings"
    "strconv"
)

func main() {
    var input string
    fmt.Println("Enter a number for fizzbuzz")
    fmt.Scanln(&input)                            #1

    numInput, err := strconv.ParseInt(input, 10, 16)
    if err != nil {
        panic("that's not a number!")
    }

    result := fizzbuzz(numInput)     #2
    fmt.Println("result:", result)
}

func fizzbuzz(n int64) string {
    var fizzbuzzes []string
    for i := int64(0); i < n; i++ {   #3
        v := ""
        isThree := i % 3 == 0
        isFive := i % 5 == 0
        if isThree && isFive {
            v = "Fizz Buzz"
        } else if isThree {
            v = "Fizz"
        } else if isFive {
            v = "Buzz "
        } else {
            v = fmt.Sprintf("%d", i)
        }
        fizzbuzzes = append(fizzbuzzes, v)
    }


    return strings.Join(fizzbuzzes, " ")
}

Inspect the complete Fizz Buzz implementation to see the loop boundaries that create the error. section 6.3.1

How Go in Practice, Second Edition covers it

How deep it goes
Explains two boundary mistakes and demonstrates diagnosis through failing and passing Go test output.
Examples
Uses a Fizz Buzz loop, exact expected strings, table cases, and go test output.
What it assumes
Assumes basic Go loops and testing while clarifying index starts, endpoint inclusion, and test-table expansion.
What you can do after
Diagnose boundary mistakes with table-driven tests and correct loop starts, endpoints, and expected output.
How it connects
Connects loop indexing, boundary conditions, Fizz Buzz, and table-driven testing.

Also explained in

Compare how 4 books explain off-by-one error →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.