Photo by Chris Liverani on Unsplash
At work today I read a piece of code in Golang that got me curious:
maxQuerySize := 500
// metricDataQueries is user provided
sliceLength := len(metricDataQueries)/maxQuerySize + 1
// what's the value of sliceLength?
for i := 0; i < sliceLength; i++ {
whatever
}
This is a simple integer division, but the result is then used as a parameter to the for loop.
Integer division has a drawback, that can create a bug in this case: the remainder, as float
in for loop declarations are supported only if no truncation happens when converting to int
(i.e. 10.0
works, 10.1
don't).
How does Go handle this? The answer is as simple as it gets: remainder is ignore and the result is the quotient. The reason why this happens is explained in Go specs, under Constant expressions:
Any other operation on untyped constants results in an untyped constant of the same kind; that is, a boolean, integer, floating-point, complex, or string constant. If the untyped operands of a binary operation (other than a shift) are of different kinds, the result is of the operand's kind that appears later in this list: integer, rune, floating-point, complex.
Which means that to have "true" division you need to convert at least one argument to float
:
a := 10.0 / 2
b := 10 / 2.0
c := 10.0 / 2.0
d := 10 / 2
fmt.Println(reflect.TypeOf(a)) // float
fmt.Println(reflect.TypeOf(b)) // float
fmt.Println(reflect.TypeOf(c)) // float
fmt.Println(reflect.TypeOf(d)) // int
Doing integer division effectively "floors" the result of the operation. What if we want the ceil of it?
Go math
package has Ceil(x float64) float64
for this, which implies doing a "true" division and applying Ceil
on the result.
All of this was not really surprising, but it's cool to see this being implemented in a very ergonomic way.
Just a note: if you want to get a float value you must convert to float
division arguments before the division.
Do this: float64(2) / float64(10) // 0.2
and not this: a := float64(2 / 10) // 0
.
Top comments (0)