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
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?
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 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.
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.
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.