How does this behaviour sense? wouln't it make mor sense to just print an compiler warning instead of an error?
func main() {
var y float64 = 0.0
var x float64 = 4.0 / y
fmt.Println(x)
}
+Inf
func main() {
var x float64 = 4.0 / 0.0
fmt.Println(x)
}
prog.go:9:22: division by zero
Golang numeric consts are special. They're not directly mapped to any IEEE754 float type, and they're not able to store infinities or -0 for example.
From the documentation:
Numeric constants represent exact values of arbitrary precision and do not overflow. Consequently, there are no constants denoting the IEEE-754 negative zero, infinity, and not-a-number values.
This choice brings some power, as it reduces overflowing in constants:
var x float64 = 1e1000 / 1e999 // yes, this is 10
If you need an infinity value you may do
var x float64 = math.Inf(1)
Related
I have been making 'A Tour of Go' and occurred on some strange behavior inside the Pic function. It concerns int -> uint8 conversion. Values of dx and dy are 256 by default on program execution. So that x+y inside the nested for loop goes up to 510! (255+255)
Nevertheless Golang sees no problem while converting overflowing x+y to uint8, but when I change it into some hard-coded value, lets say uint8(321), I immediately obtain an error of an overflow.
Can someone explain me that strange behavior?
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
canvas := make([][]uint8, dy)
for y := 0; y < dy; y++ {
canvas[y] = make([]uint8, dx)
for x := 0; x < dx; x++ {
canvas[y][x] = uint8(x+y) // <- here it is
}
}
return canvas;
}
func main() {
pic.Show(Pic)
}
Error obtained:
go: finding module for package golang.org/x/tour/pic
go: downloading golang.org/x/tour v0.0.0-20200508155540-0608babe047d
go: found golang.org/x/tour/pic in golang.org/x/tour v0.0.0-20200508155540-0608babe047d
./prog.go:11:24: constant 321 overflows uint8
Go build failed.
This is from the language spec:
The values of typed constants must always be accurately representable by values of the constant type. The following constant expressions are illegal:
uint(-1) // -1 cannot be represented as a unit
int(3.14) // 3.14 cannot be represented as an int
In your case, x and y are int, so x+y is also int, and uint8(x+y) simply truncates the result. However, uint8(321) is not valid according to the language spec. However, this is valid:
i:=321
x:=uint8(i)
Surprisingly I couldn't find anyone else having this same issue; I tried simply initializing a float64 in Go and printing it, then attempting a string conversion and printing that. Neither output was accurate.
I've attempted this with many fractions, including those which don't resolve to repeating decimals, as well as simply writing out the float and printing (e.g. num := 1.5 then fmt.Println(num) gives output 1).
package main
import (
"fmt"
"strconv"
)
func main() {
var num float64
num = 5/3
fmt.Printf("%v\n", num)
numString := strconv.FormatFloat(num, 'f', -1, 64)
fmt.Println(numString)
}
Expected:
// Output:
1.66
1.66
Actual:
// Output:
1
1
The Go Programming Language Specification
Integer literals
An integer literal is a sequence of digits representing an integer
constant.
Floating-point literals
A floating-point literal is a decimal representation of a
floating-point constant. It has an integer part, a decimal point, a
fractional part, and an exponent part. The integer and fractional part
comprise decimal digits; the exponent part is an e or E followed by an
optionally signed decimal exponent. One of the integer part or the
fractional part may be elided; one of the decimal point or the
exponent may be elided.
Arithmetic operators
For two integer values x and y, the integer quotient q = x / y and
remainder r = x % y satisfy the following relationships:
x = q*y + r and |r| < |y|
with x / y truncated towards zero.
You wrote, using integer literals and arithmetic (x / y truncates towards zero):
package main
import (
"fmt"
"strconv"
)
func main() {
var num float64
num = 5 / 3 // float64(int(5)/int(3))
fmt.Printf("%v\n", num)
numString := strconv.FormatFloat(num, 'f', -1, 64)
fmt.Println(numString)
}
Playground: https://play.golang.org/p/PBqSbpHvuSL
Output:
1
1
You should write, using floating-point literals and arithmetic:
package main
import (
"fmt"
"strconv"
)
func main() {
var num float64
num = 5.0 / 3.0 // float64(float64(5.0) / float64 (3.0))
fmt.Printf("%v\n", num)
numString := strconv.FormatFloat(num, 'f', -1, 64)
fmt.Println(numString)
}
Playground: https://play.golang.org/p/Hp1nac358HK
Output:
1.6666666666666667
1.6666666666666667
I recently tried to learn golang. But I got confused with this code from https://tour.golang.org/basics/13.
package main
import (
"fmt"
"math"
)
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
}
That one works well. Then I tried
var f = math.Sqrt(9 + 16)
which also works. But when I change it to var f = math.Sqrt(x*x + y*y) why is it not working? It says cannot use x * x + y * y (type int) as type float64 in argument to math.Sqrt
I have javascript background, and I somehow can't understand the code above.
The math.Sqrt function signature:
func Sqrt(x float64) float64
requires that you pass float64
In this case:
var f float64 = math.Sqrt(float64(x*x + y*y))
You are converting to float64 directly
In this case:
var f = math.Sqrt(x*x + y*y)
you are passing an int, when float64 is required.
In this case:
var f = math.Sqrt(9 + 16)
The compiler is able to infer the type, and pass float64 for you.
But when we pass a number directly, it automatically converted?
No, not really *). Your "direct numbers" are called "constants" in Go and constants are often "untyped" and (almost) of arbitrary precision. There are special rules for constants: A constant 5 and the integer a defined by a := 5 behave differently because 5 is a constant with special rules and not an int.
Constant expressions like 9 + 16 are evaluated at compile time like if you had typed 25. This 25 is still a (constant.
While Go does not have automatic type conversions for types it does have automatic conversions from constants to several types. The constant 25 can be converted to float64 or int, uint8 or even complex128 automatically.
Please read the blog post https://blog.golang.org/constants and the official language spec for a full explanation and all details: https://golang.org/ref/spec#Constants . This explains the strange notion of
"untyped integer" better than I could.
*) "not really" because it is not helpful to think about it that way. The distinction of constants is special in Go: Most other languages tread 3+5 as a sum of two ints resulting in an int while Go sees two untyped integer constants and evaluates this expression into a new arbitrary precision, untyped constant. Only later are constants converted to actual integers.
I have such code:
type Speed float64
type Distance float64
type Time float64
func speed(a Distance, b Time) Speed {
return Speed(float64(a) / float64(b))
}
func main() {
s := Distance(123.0)
t := Time(300)
fmt.Println(speed(s, t))
}
Can I make it more optimal by removing somehow casting to float64 in speed function?
No, you cannot avoid casting your distance and time back into floats because the division is not defined for those types. And as previously said, Go is strongly typed.
So, in your case you'd have to put casts everywhere (not a good idea). Type aliasing is good if you want to write custom methods for your types, but its purpose is not to solely hide the underlying type under a custom one.
However, not all type are working this way. If you make an alias of a map, then you can call the bracket operators without problem.
type Map map[string]string
func main() {
m := Map(make(map[string]string))
m["answer"] = "42"
fmt.Printf("m's type is %T and answer is %s\n", m, m["answer"])
//
// m's type is main.Map and answer is 42
}
Also, when initializing your custom aliases, casting is unnecessary:
type Speed float64
type Distance float64
func main() {
var s Distance = 123.0
var t Time = 300
// ...
}
This compiles and works perfectly. What happens behind the scene is that the literal 123.0 is considered as an untyped float and 300 is considered as an untyped int.
I know this sounds weird but basically those values are not typed so Go tries to fit them into the type at the left. This is why you can write var f float64 = 1 even though 1 is not a float. But you can't write var f float64 = int(1) because 1 becomes a typed int which cannot be translated in a float64.
This is why the following won't work:
func main() {
var distance float64 = 123.0
var time float64 = 300
var s Distance = distance
var t Time = time
// ...
}
You can't make implicit casts between custom types-- Go is strongly typed.
I know this is just a small example, but maybe you really don't need those custom types?
package main
import "fmt"
func speed(distance float64, time float64) float64 {
return distance / time
}
func main() {
s := 123.0
t := 300.0
fmt.Println(speed(s, t))
}
I was playing around with Go and was wondering what the best way is to perform idiomatic type conversions in Go. Basically my problem lays within automatic type conversions between uint8, uint64, and float64. From my experience with other languages a multiplication of a uint8 with a uint64 will yield a uint64 value, but not so in go.
Here is an example that I build and I ask if this is the idiomatic way of writing this code or if I'm missing an important language construct.
package main
import ("math";"fmt")
const(Width=64)
func main() {
var index uint32
var bits uint8
index = 100
bits = 3
var c uint64
// This is the line of interest vvvv
c = uint64(math.Ceil(float64(index * uint32(bits))/float64(Width)))
fmt.Println("Test: %v\n", c)
}
From my point of view the calculation of the ceiling value seems unnecessary complex because of all the explicit type conversions.
Thanks!
There are no implicit type conversions for non-constant values.
You can write
var x float64
x = 1
But you cannot write
var x float64
var y int
y = 1
x = y
See the spec for reference.
There's a good reason, to not allow automatic/implicit type conversions, as they can
become very messy and one has to learn many rules to circumvent the various caveats
that may occur. Take the Integer Conversion Rules in C for example.
For example,
package main
import "fmt"
func CeilUint(a, b uint64) uint64 {
return (a + (b - 1)) / b
}
func main() {
const Width = 64
var index uint32 = 100
var bits uint8 = 3
var c uint64 = CeilUint(uint64(index)*uint64(bits), Width)
fmt.Println("Test:", c)
}
Output:
Test: 5
To add to #nemo terrific answer. The convenience of automatic conversion between numeric types in C is outweighed by the confusion it causes. See https://Golang.org/doc/faq#conversions. Thats why you can't even convert from int to int32 implicitly. See https://stackoverflow.com/a/13852456/12817546.
package main
import (
. "fmt"
. "strconv"
)
func main() {
i := 71
c := []interface{}{byte(i), []byte(string(i)), float64(i), i, rune(i), Itoa(i), i != 0}
checkType(c)
}
func checkType(s []interface{}) {
for k, _ := range s {
Printf("%T %v\n", s[k], s[k])
}
}
byte(i) creates a uint8 with a value of 71, []byte(string(i)) a []uint8 with [71], float64(i) float64 71, i int 71, rune(i) int32 71, Itoa(i) string 71 and i != 0 a bool with a value of true.
Since Go won't convert numeric types automatically for you (See https://stackoverflow.com/a/13851553/12817546) you have to convert between types manually. See https://stackoverflow.com/a/41419962/12817546. Note, Itoa(i) sets an "Integer to an ASCII". See comment in https://stackoverflow.com/a/10105983/12817546.