Arithmetic Operators
Go's +, -, *, / and % on numbers, including why 7 / 2 is 3 and what happens when a type runs out of room.
a + b a - b a * b a / b a % b // both operands must be the same typeArithmetic operators do sums. Go has five of them. + adds, - subtracts, * multiplies, / divides, and % gives the remainder that a division leaves behind. They work on numbers. + also joins two strings end to end.
Both sides must be the same type
Go will not mix number types for you. An int, which is a whole number, cannot be added to a float64, which is a number with a fractional part. Convert one side first, as in float64(sum) / float64(count).
Whole numbers divide into whole numbers
If both sides are whole numbers, the answer is a whole number. 7 / 2 is 3, not 3.5. The leftover is what % gives you: 7 % 2 is 1. Division rounds towards zero rather than downwards, so -7 / 2 is -3 and -7 % 2 is -1. % accepts whole numbers only; for fractional numbers use math.Mod.
Shorthand
sum += n means exactly sum = sum + n. Every operator has that form: -=, *=, /=, %=. count++ means count += 1. It is a statement on its own and not a value, so n := count++ does not compile, and Go has no ++count.
Running out of room
Each integer type holds a fixed range. A uint8 holds 0 to 255. Add 1 to 255 and you get 0. Go does not warn and does not stop, so pick a type wide enough for the numbers you expect.
Example
package main
import "fmt"
func main() {
a := 17
b := 5
fmt.Println("sum:", a+b)
// Whole-number division throws the fraction away.
// What it threw away is what % gives you.
fmt.Println("quotient:", a/b)
fmt.Println("remainder:", a%b)
// float64(a) turns the whole number 17 into 17.0, so this
// division keeps its fraction.
fmt.Println("exact:", float64(a)/float64(b))
// Division rounds towards zero, not downwards.
fmt.Println("negative quotient:", -17/5)
fmt.Println("negative remainder:", -17%5)
// A uint8 holds 0 to 255. Going past 255 wraps back round to 0.
var small uint8 = 250
small += 10
fmt.Println("wrapped:", small)
}
// Output:
// sum: 22
// quotient: 3
// remainder: 2
// exact: 3.4
// negative quotient: -3
// negative remainder: -2
// wrapped: 4When to use it
- Work out how many full pages a list of results fills, and how many rows are left for the last page.
- Turn a total number of seconds into minutes and seconds for a log line.
- Keep a running total that grows as you read each record.
- Test whether a number is even by asking whether n % 2 is 0.
More examples
Splitting a total with / and %
The pair / and % always belong together: one gives how many times the divisor fits, the other gives what is left. Reach for it whenever you turn one number into two, such as seconds into minutes and seconds, or a row count into pages plus a short last page.
package main
import "fmt"
func main() {
total := 497
// / gives the whole minutes, % gives the seconds left over.
minutes := total / 60
seconds := total % 60
fmt.Printf("%d minutes %d seconds\n", minutes, seconds)
}
// Output:
// 8 minutes 17 secondsAn average that keeps its fraction
This is the most common arithmetic bug in Go: an average, a percentage or a rate computed from two ints quietly truncates. Convert before dividing, not after, because float64(sum / count) divides first and converts the already-truncated 3.
package main
import "fmt"
func main() {
sum := 7
count := 2
// Both sides are whole numbers, so this answer loses the .5
// without saying anything about it.
fmt.Println("wrong:", sum/count)
// Convert both sides first and the fraction survives.
average := float64(sum) / float64(count)
fmt.Println("right:", average)
}
// Output:
// wrong: 3
// right: 3.5The three ways to add one
You will read all three forms in other people's code, so you need to recognise each. Use ++ when you are counting and the assignment forms when the amount varies; the long form is worth writing out only when the right-hand side is doing something less obvious.
package main
import "fmt"
func main() {
score := 0
// Each of these three lines adds 1 to score. They are the
// same thing written three ways.
score = score + 1
score += 1
score++
// -=, *=, /= and %= work the same way.
score *= 10
fmt.Println("score:", score)
}
// Output:
// score: 30
Discussion