Numbers and Math

Go does arithmetic with the usual operators, but integer division, remainders of negative numbers and division by zero have rules worth knowing. This lesson covers those, the built-in min and max, the math package, random numbers with math/rand/v2, and arbitrary-size numbers with math/big.

Arithmetic

GO
package main

import "fmt"

func main() {
	a, b := 17, 5
	fmt.Println(a+b, a-b, a*b)
	fmt.Println(a/b, a%b) // integer division and remainder

	x, y := 17.0, 5.0
	fmt.Println(x / y)
}
Output
22 12 85
3 2
3.4

When both operands are integers, / gives an integer result and discards the fraction. To get 3.4 from two int variables you must convert them first: float64(a) / float64(b) (lesson 9).

Negative numbers

Integer division truncates toward zero, and the remainder takes the sign of the left operand:

GO
package main

import "fmt"

func main() {
	fmt.Println(-7/2, -7%2)
	fmt.Println(7/-2, 7%-2)

	// a remainder that is never negative, e.g. for wrapping around a clock
	hour := -3
	fmt.Println(((hour % 24) + 24) % 24)
}
Output
-3 -1
-3 1
21

Division by zero

Dividing an integer by a constant zero is a compile error. Dividing by a variable that turns out to be zero crashes the program at run time with a panic (lesson 46). Floating-point division by zero doesn't crash — it produces infinity or "not a number":

GO
package main

import "fmt"

func main() {
	zero := 0.0
	fmt.Println(1/zero, -1/zero, zero/zero)

	items, boxes := 10, 0
	fmt.Println(items / boxes)
}
Output
+Inf -Inf NaN
panic: runtime error: integer divide by zero

goroutine 1 [running]:
…
exit status 2

Check divisors that come from user input or data before you divide.

Increment and compound assignment

GO
package main

import "fmt"

func main() {
	score := 10
	score++
	score += 5
	score *= 2
	score -= 1
	score /= 3
	score %= 7
	fmt.Println(score)
}
Output
3

++ and -- are statements in Go, not expressions: you can write score++ on its own line, but not x := score++ or ++score.

min and max

The built-in functions min and max take any number of arguments of the same ordered type — integers, floats or even strings:

GO
package main

import "fmt"

func main() {
	fmt.Println(min(4, 9, 2), max(4, 9, 2))
	fmt.Println(max(0.5, 1.25))
	fmt.Println(min("pear", "apple", "fig"))

	volume := 130
	volume = min(max(volume, 0), 100) // clamp to 0..100
	fmt.Println(volume)
}
Output
2 9
1.25
apple
100

The math package

GO
package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(math.Sqrt(2), math.Pow(2, 10), math.Cbrt(27))
	fmt.Println(math.Abs(-4.2), math.Hypot(3, 4))
	fmt.Println(math.Floor(2.7), math.Ceil(2.1), math.Trunc(-2.7))
	fmt.Println(math.Round(2.5), math.Round(-2.5), math.RoundToEven(2.5))
	fmt.Println(math.Mod(7.5, 2), math.Log(math.E), math.Log10(1000))
	fmt.Printf("%.4f %.4f\n", math.Pi, math.Sin(math.Pi/2))
	fmt.Println(math.Inf(1), math.IsNaN(math.NaN()))
}
Output
1.4142135623730951 1024 3
4.2 5
2 3 -2
3 -3 2
1.5 1 3
3.1416 1.0000
+Inf true

The math functions work with float64. math.Round rounds halves away from zero; math.RoundToEven uses "banker's rounding". To round to two decimal places for display, format with %.2f rather than rounding the number itself.

Random numbers

Use math/rand/v2 for games, simulations and shuffling. Its top-level functions are automatically seeded, so each run differs. For reproducible results — tests, or this course's examples — create your own generator from a fixed seed:

GO
package main

import (
	"fmt"
	"math/rand/v2"
)

func main() {
	r := rand.New(rand.NewPCG(1, 2)) // fixed seed: same numbers every run

	fmt.Println(r.IntN(6)+1, r.IntN(6)+1, r.IntN(6)+1) // dice rolls, 1..6
	fmt.Printf("%.3f\n", r.Float64())                  // in [0, 1)

	cards := []string{"A", "K", "Q", "J"}
	r.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] })
	fmt.Println(cards)

	fmt.Println(rand.N(100) < 100) // top-level: random seed each run
}
Output
5 4 5
0.430
[Q K J A]
true

For passwords, tokens and keys, use crypto/rand instead — math/rand/v2 is fast but predictable, so it's not safe for security.

Arbitrarily large numbers

When even int64 isn't big enough, math/big provides integers (and rationals and floats) of any size:

GO
package main

import (
	"fmt"
	"math/big"
)

func main() {
	f := big.NewInt(1)
	for i := int64(2); i <= 30; i++ {
		f.Mul(f, big.NewInt(i))
	}
	fmt.Println("30! =", f)
}
Output
30! = 265252859812191058636308480000000

big values are changed by methods (f.Mul(f, x) means "set f to f × x") rather than by operators, and they're much slower than built-in types, so use them only when you need them.

Try it yourself

Split a bill: work out each person's share in cents and the leftover cents that can't be split evenly.

Try it yourself · main.go
Edit the code, copy it into main.go in a new folder and run it with go run main.go (Go 1.27 or later). How to install Go
Output
each pays 33.33, 1 cent(s) left over
Next: converting between types.