Skip to content
Theory · Operators · lesson 1 of 9

Arithmetic and integer division

What you'll learn

What you'll learn:

  • predict the result of integer division and remainder, negative numbers included;
  • pick an integer type's size and notice the overflow Go keeps quiet about;
  • compare values and combine conditions with &&, || and !;
  • compare fractional numbers with a tolerance instead of ==.
An adult shares 17 apples between five children, three each, and two apples stay in the adult's hand

Go counts like a calculator, but this calculator has rules of its own. It remembers the type of every number: whole or fractional.

The operators +, - and * work on whole numbers the same way school arithmetic does. Division is different: when both numbers have type int, the result is an int too, and an int has no fractional part.

Picture sharing apples among kids. You can't cut the apples, so each kid gets a whole number of them, and the extras stay with you. That is how dividing whole numbers works:

GO
package main

import "fmt"

func main() {
    apples := 17
    kids := 5
    fmt.Println(apples / kids) // 3
    fmt.Println(apples % kids) // 2
}

Let's see what the program printed:

  1. apples / kids prints 3: seventeen apples shared among five kids give three each. The / operator produced the quotient.
  2. apples % kids prints 2: two apples stay with you. The % operator produced the remainder.

An ordinary calculator would show 3.4, but Go showed 3. The apple picture works well for positive numbers, while negative ones follow a rule of their own, covered in the section on the remainder.

A quotient without a fraction

The values an operator works on are called operands. Dividing two integer operands is integer division: the fractional part of the result is discarded, not rounded.

  • 17 / 5 is 3, even though on paper it comes to 3.4.
  • 19 / 5 is also 3, even though 3.8 is closer to four.
  • -17 / 5 is -3, not -4: a negative result drops its fraction too.

So integer division always moves the result toward zero: a positive one down, a negative one up.

Getting a fraction

A fraction comes from dividing numbers of type float64. A number written directly in the code is a literal. Here are two ways to get a fractional result:

GO
a, b := 17, 5
fmt.Println(7.0 / 2)                 // 3.5
fmt.Println(float64(a) / float64(b)) // 3.4

A fractional literal: 7.0 / 2

A literal with a dot, such as 7.0, is already fractional. The literal 2 next to it adapts to the fractional type, and the result is 3.5.

This way fits numbers written directly in the code. It does not work with variables: a variable already has its type and cannot adapt.

Converting variables: float64(a) / float64(b)

The expression float64(a) takes the value of the integer variable a and turns it into a fractional one. The variable a itself stays an int.

  • Convert both variables: then both operands are float64, and the result is 3.4.
  • Converting only one does not compile: in float64(a) / b the operand types differ.

Division by zero

What happens when you divide an integer by zero depends on when the zero becomes known.

Zero known at build time

Dividing by the literal 0 does not compile: invalid operation: division by zero. Dividing by a constant equal to zero, such as z after const z = 0, gives the same message.

The compiler sees that value in advance, so the error is caught before the program runs.

Zero in a variable

If an integer variable turns out to be zero, the compiler does not know it. The program starts and runs the lines before the division. At the division itself, it stops with the message panic: runtime error: integer divide by zero.

Such a crash is called a panic. Before dividing by a variable that may be zero, check it.

Remainder

The % operator follows three rules:

  • it works only on integer operands;
  • it ranks with * and /, left to right;
  • it is linked to the quotient: a / b * b + a % b equals a.

The third rule means the remainder takes the sign of the dividend, the left operand:

GO
fmt.Println(-17/5, -17%5) // -3 -2
fmt.Println(17/-5, 17%-5) // -3 2

Let's check both lines:

  1. fmt.Println(-17/5, -17%5) prints -3 -2. The quotient is -3, and -3 * 5 is -15. To reach -17, -2 is missing, and that is the remainder.
  2. fmt.Println(17/-5, 17%-5) prints -3 2. The dividend 17 is positive, so the remainder 2 is positive too, even though the divisor is negative.

Interviewers like to ask this: what sign does the remainder have when the dividend is negative? In math the remainder is usually taken as non-negative, while in Go it takes the sign of the dividend.

Digits of a number

The remainder helps take a number apart into digits. For 253:

  • n % 10 is the last digit, 3;
  • n / 10 is the number without it, 25.

Common mistake

The result of dividing two int values is converted to float64 in the hope of getting a fraction:

GO
package main

import "fmt"

func main() {
    total := 5
    count := 2
    half := float64(total / count) // ✗
    fmt.Println(half)              // 2
}

The compiler sees no error, and the program prints 2. First total / count runs as integer division, and only its result 2 becomes a float64. Convert the operands, not the result: float64(total) / float64(count) gives 2.5.

Key points

  • Dividing two integers drops the fraction: 17 / 5 is 3, and -17 / 5 is -3.
  • The % operator gives the remainder, and its sign matches the dividend's.
  • To get a fraction, convert the operands to float64, not the result.
  • Dividing by the literal 0 does not compile; dividing by an integer variable equal to zero panics.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way