-2

Below code compiles:

package main

import "fmt"

const (
    // Max integer value on 64 bit architecture.
    maxInt = 9223372036854775807

    // Much larger value than int64.
    bigger = 9223372036854775808543522345

    // Will NOT compile
    // biggerInt int64 = 9223372036854775808543522345
)

func main() {
    fmt.Println("Will Compile")
    //fmt.Println(bigger) // error
}

Type is size in memory + representation of bits in that memory

What is the implicit type assigned to bigger at compile time? Because error constant 9223372036854775808543522345 overflows int for line fmt.Println(bigger)

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
overexchange
  • 15,768
  • 30
  • 152
  • 347
  • Nothing. It's an untyped constant. A type will be chosen when it's assigned to a variable. [See The Go Blog: Constants](https://blog.golang.org/constants). See related questions: [How does Go perform arithmetic on constants?](https://stackoverflow.com/questions/38982278/how-does-go-perform-arithmetic-on-constants/38982889#38982889) and [What is the purpose of arbitrary precision constants in Go?](https://stackoverflow.com/questions/57511935/what-is-the-purpose-of-arbitrary-precision-constants-in-go/57512022#57512022) – icza Mar 28 '20 at 01:44
  • @icza `fmt.Println(bigger)` gives error `constant 9223372036854775808543522345 overflows int` – overexchange Mar 28 '20 at 01:49
  • @overexchange: sure: `fmt.Println(bigger)` tries to assign the untyped constant to a variable—an *unnamed* variable, but one of type `int`, that can then be passed to `fmt.Println`. It doesn't fit, and you get the complaint. – torek Mar 28 '20 at 01:52
  • @torek `go run myfile.go` compiles and execute machine code to give this error. How to compile-only this file `myfile.go` to `myfile.o`? – overexchange Mar 28 '20 at 01:54
  • It *doesn't* compile. It fails to compile. It does not execute. The *compiler* prints the error. `go run` only runs the program if it compiles. – torek Mar 28 '20 at 01:55
  • @torek What is the command to compile-only? to verify this... – overexchange Mar 28 '20 at 01:57
  • Generally, to build without running we use `go build`. – torek Mar 28 '20 at 01:57
  • @torek Am unable to use this tool https://golang.org/cmd/compile/ – overexchange Mar 28 '20 at 01:58
  • Running `go tool compile main.go` produces the same error as `go build` on my system: `main.go:18:16: constant 9223372036854775808543522345 overflows int` – torek Mar 28 '20 at 01:59
  • @torek It compiles for me after commenting line 18 – overexchange Mar 28 '20 at 02:01
  • Well, sure: if you take out your erroneous lines, you can compile, but you're no longer using the value as an `int`. Line 18 is the line that tries to assign the overly-large constant into an `int`. Remove the line, and you've removed the error. – torek Mar 28 '20 at 02:03
  • @torek How do you refer(term) `bigger`? do I need to say constant identifier? – overexchange Mar 28 '20 at 02:20
  • You would have to define what you want to *do* with this constant. For instance, you might want to convert it to a 128-bit integer stored as two 64-bit integers. In that case you'd take the actual constant and divide it by 18446744073709551616 to get the upper 64 bit word, and reduce it mod 18446744073709551616 to get the lower 64 bit word. – torek Mar 28 '20 at 05:59
  • Or, maybe you want to hold an approximation to it as a `float64`, in which case you'd simply assign it to a `float64` variable: https://play.golang.org/p/AZXObXh3v9_J Here's a variant using two 64-bit words to hold a 128-bit value: https://play.golang.org/p/opLxE3_Sa5Z – torek Mar 28 '20 at 06:01
  • Just do three things: Read the language spec, read the blog post about constants and learn and understand how Go code is compiled, linked and executed. – Volker Mar 28 '20 at 07:24
  • @torek my goal is to convertf `bigger = 9223372036854775808543522345` to binary form – overexchange Mar 28 '20 at 13:02
  • Well, since that's `111011100110101100101000000000000000000000000000000000000000000100000011001010111111000101001` (93 bits long) you'll need a 93+ bit storage unit to hold it. See my example where I store the value into two 64-bit words, which provides 128 bits of storage. It is easy to convert two base-(2sup64) numbers `{500000000 543522345}` to binary and concatenate them. – torek Mar 28 '20 at 17:45
  • Of course, since `9223372036854775808543522345` is a constant, you can also do this at compile time, though it's then hard (but maybe unnecessary) to suppress leading zero bits: just pick the number of bits you want to use to express the number, and compute (value / big-constant-power-of-two) for the first bit, (value % big-constant)/(one-bit-less-big-constant), ..., (value%4)/2, (value%2), and you have N single-bit constants. – torek Mar 28 '20 at 17:48
  • There isn't a lot more to add there after Grzegorz Żur's answer. The Go scheduler changes from one release to the next and there are not a lot of promises made; it's not wise to depend on anything that is not explicitly mentioned in the documentation. – torek Mar 30 '20 at 20:20
  • It's just a data-type that the Go runtime uses to keep track of information. There are struct types for `g`, `m`, and `p` data structures. Their content depends on the Go version. – torek Mar 30 '20 at 22:50

3 Answers3

2

Those are untyped constants. They have larger limits than typed constants:

https://golang.org/ref/spec#Constants

In particular:

Represent integer constants with at least 256 bits.

Burak Serdar
  • 46,455
  • 3
  • 40
  • 59
  • Yes.. but how do I use those larger limits in my program, if those large values cannot be asigned to a variable? – overexchange Mar 28 '20 at 02:29
  • You can use them to define other untyped constants that can be assigned to variables. – Burak Serdar Mar 28 '20 at 02:43
  • What was the point for GoLang compiler to allow 256 bits integer value and 256 bits for floating point precision, when it is not usable in the program? – overexchange Mar 28 '20 at 02:45
  • Only language designers can answer that. But I suppose the point was to prevent overflows during constant computations. You may run into situations where very large intermediate constant results can be used to arrive at usable constant values. You can define a constant `bigger/maxInt` in your program, and use that. – Burak Serdar Mar 28 '20 at 02:48
2

None, it's an untyped constant. Because you haven't assigned it to any variable or used it in any expression, it doesn't "need" to be given a representation as any concrete type yet. Numeric constants in Go have effectively unlimited precision (required by the language spec to be at least 256 bits for integers, and at least 256 mantissa bits for floating-point numbers, but I believe that the golang/go compiler uses the Go arbitrary-precision types internally which are only limited by memory). See the section about Constants in the language spec.

What is the use of a constant if you can't assign it to a variable of any type? Well, it can be part of a constant expression. Constant expressions are evaluated at arbitrary precision, and their results may be able to be assigned to a variable. In other words, it's allowed to use values that are too big to represent to reach an answer that is representable, as long as all of that computation happens at compile time.

hobbs
  • 223,387
  • 19
  • 210
  • 288
2

From this comment:

my goal is to convertf bigger = 9223372036854775808543522345 to binary form

we find that your question is an XY problem.

Since we do know that the constant exceeds 64 bits, we'll need to take it apart into multiple 64-bit words, or store it in some sort of bigger-integer storage.

Go provides math/big for general purpose large-number operations, or in this case we can take advantage of the fact that it's easy to store up to 127-bit signed values (or 128-bit unsigned values) in a struct holding two 64-bit integers (at least one of which is unsigned).

This rather trivial program prints the result of converting to binary:

500000000 x 2-sup-64 + 543522345 as binary:
111011100110101100101000000000000000000000000000000000000000000100000011001010111111000101001
package main

import "fmt"

const (
    // Much larger value than int64.
    bigger = 9223372036854775808543522345
    d64    = 1 << 64
)

type i128 struct {
    Upper int64
    Lower uint64
}

func main() {
    x := i128{Upper: bigger / d64, Lower: bigger % d64}
    fmt.Printf("%d x 2-sup-64 + %d as binary:\n%b%.64b\n", x.Upper, x.Lower, x.Upper, x.Lower)
}
torek
  • 448,244
  • 59
  • 642
  • 775
  • Is this(`10000000000000000000000000000000000000000000000000000000000000000`) the binary representation of `d64`? which is 65 bits size – overexchange Mar 28 '20 at 19:18
  • If that's a 1 followed by 64 zeros, then yes. 2-sup-k (for nonnegative integer k) is always a single bit, and when expressed as a binary number, is a 1 followed by k zeros. – torek Mar 28 '20 at 19:20