Constant 1 truncated to integer?
Why won't this code compile?
package main
const a = 1.000001
const base = 0
const b = a+base
func main() {
f(b)
}
func f(int) {}
$ go run a.go
# command-line-arguments
./a.go:4: constant 1 truncated to integer
They say that 1 is truncated? Or that 1 can't be trimmed? Which one is he talking about?
Someone answered that the specified code does not compile because b
- it is float64
. But then why does this compile:
package main
import "fmt"
const a = 1.000001
const b = a-0.000001
func main() {
fmt.Printf("%T %v\n",a,a)
fmt.Printf("%T %v\n",b,b)
f(b)
}
func f(int) {}
$ go run a.go
float64 1.000001
float64 1
? b
here float64
, but it can be passed to f
.
source to share
The go team made a blog post about this which I invite you to read.
From the introduction
Go is a statically typed language that doesn't allow operations that mix numeric types. You cannot add float64 to int, or even int32 to int. However, it is legal to write 1e6 * time.Second or math.Exp (1) or even 1 <('\ t' + 2.0). In Go, constants, unlike variables, behave quite like regular numbers. This article explains why this is the case and what it means.
TL; DR - constants are untyped in Go. Their type crystallizes only at the last moment.
This explains your problem above. Considering,
func f(int) {}
Then
f(1) // ok
f(1.000) // OK
f(1.0E6) // OK
f(1.0001) // BAD
source to share
Go has very strict conversion rules for constants:
The constant value x can be converted to type T in any of these cases:
x
is represented by a value of the typeT
.x
is a floating point constant, T is a floating point type, and x represents a value of the typeT
after rounding using the IEEE 754 round-even rules. A constantT(x)
is a rounded value.x
is an integer constant, andT
is a string type. In this case, the same rule applies as for the non-permanent onex
.
The golang blog post on constants might be helpful to understand this further. Because of the severity, any transformation that violates the quoted rules is considered an error. The reason for this is that Go tries to represent constants as accurately as possible. It also means that the final type is determined in the context of the expression used. The overshoot will exceed this and is a sign of a possible programming error.
If you really want to round the value to an integer, convert it to a variable ( Play example ):
const b = 1.01
c := b
f(int(c))
This works because the compiler does not trace the origin of values and constant rules that do not apply to variables.
But then why does it work when I change it to this? const a = 1.000001;const b = a-0.000001
In this example, the b
value is 1. 1 can be represented as an integer, so there is no rounding or loss of information. Therefore, this is not a bug as it follows the conversion rules for float values (as stated earlier).
source to share
Your first program can be rewritten like this:
package main
func main() {
f(1.000001)
}
func f(int) {}
This does not explicitly pass the integer value to the integer function.
Your second program can also be rewritten like this:
package main
import "fmt"
func main() {
fmt.Printf("%T %v\n",1.000001,1.000001)
fmt.Printf("%T %v\n",1,1)
f(1)
}
func f(int) {}
Which looks good.
Everything I did was manually replaced with constants a
and b
. It all goes.
source to share
Disclaimer . I have no experience with Go, but below answer is based on general principles related to data types.
Your function f
takes an input parameter of type int
, but the actual value you pass to it, i.e. b
, has a floating point value based on your code. This will truncate the floating point value to an integer value, as indicated in the error message.
I believe you can fix this problem by changing your function signature to accept a float value as an input parameter ie
func f(float64) {}
To compare this with the language I'm familiar with (C #), you can look at the code below:
public static void Main(string[] args)
{
var a = 1.3;
var b = 1.3 + 9;
f(b);
Console.WriteLine("Hello, world!");
}
public static void f(int a)
{
}
By using the keyword var
, we are not explicitly making variables a
and b
data types double
. However, since they are assigned floating point values, their type is defined as double
. Now if you define a method f
to take a datatype input parameter int
and then pass a
or b
. this will give you an error message. However, if you change the method to accept a value double
instead int
, your code will compile without issue.
source to share