Why does 3*(1/3) not equal 3*1/3

Hello, may I introduce myself quickly, I am teacher at a Berlin Gymnasium doing some excercises in golang for my Informatiklessons. My first subjects are Music and German Language. This is my first post here.

The following code:

VAR result float64
result=3*(1/3)
fmt.Printf(“Result is %.2f”, result)

Prints out 0

When I change the calculation to 3*1/3 (without the round brackets) it prints out 1 correctly,

Can someone explain that behaviour to me? Does it have s,th to do with the way the go Compiler works or is it a data type issue?

Best regards!
Ganymed

Basically, the issue is:

  • In Go (and every other C-like language I know), numbers have types.
  • Go (and every other C-like language I know) evaluates every expression.

Number types in Go:

In Go, numbers can be integers, floating points or complex numbers. The 3, 1, and 3 that make up your 3*(1/3) expression are all integers, so integer math applies:

When you write 3*(1/3), Go understands operator precedence and knows that 1/3 has to be evaluated first. When you’re dealing with integers, 1 / 3 = 0 with a remainder of 1. Go doesn’t preserve remainders, so you’re left with just 0. 3 * 0 = 0.

When you remove the parentheses, because division and multiplication have the same precedence and associativity, Go evaluates first 3 * 1 = 3 and then does 3 / 3 = 1 with a remainder of 0, so the result is 1.

Expression evaluation

When we see an expression like 1/3, we often have an intuitive sense that we probably should leave that number a fraction. Most people who program in Go live in a society where base-10 is the norm. We know that 1/3 doesn’t translate to a decimal nicely. If you round every expression to tenths, then 1 / 3 = 0.3 and then 0.3 * 3 gets you 0.9, not 1.0. When we mentally evaluate the expression, 3 * (1/3), we conceptually leave the 1/3 as a fraction, instead of evaluating it, and multiply it by 3 to yield 3/3 = 1. Go (and again, every other C-like language I know) doesn’t “know” this and so expressions that don’t fit nicely into the computer’s base-2 system are still evaluated.

A workaround is to use the math/big package. That package defines a big.Rat type (as in “big rational number”) that can represent ratios like 1/3. Its API is clunky compared to just writing operators out, but it’s designed to be both accurate and fast when dealing with arbitrary precision rational numbers.

EDIT: @j-forster made a good point that if you change the 1 or the 3 in 1/3 to 1.0 or 3.0, the evaluation of 1/3 will become a float64 and you’ll get the right answer again.

1 Like

The short answer is:
3*(1/3) is made of integers numbers only, so the evaluation will be done with integers too. With that in mind, 1/3 is 0, which makes the result zero.
You can do 3*(1.0/3) which will be ok.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.