Why converting the same value in two ways, the results are different? - go

Two kinds of conversion of the same constant to float64 return the same value, but when I try to convert these new values to int, the results are different.
...
const Big = 92233720368547758074444444
func needFloat(x float64) float64 {
return x
}
func main() {
fmt.Println(needFloat(Big))
fmt.Println(float64(Big))
fmt.Println(int(needFloat(Big)))
fmt.Println(int(float64(Big)))
}
I'd expect the two first Println return the same type of value
fmt.Println(needFloat(Big)) // 9.223372036854776e+25
fmt.Println(float64(Big)) // 9.223372036854776e+25
so when I convert them to int, I expect the same output, but:
fmt.Println(int(needFloat(Big))) // -2147483648
fmt.Println(int(float64(Big))) // constant 92233720368547758080000000 overflows int

If your real question is why one attempt to convert to int produces a compile-time error message, but the other produces a very negative integer, it's because one is a compile-time conversion, and the other is a runtime conversion. I think it helps in these cases to be explicit about what you are expecting, and what can be run and what can't. Here's a Go Playground version of your code, where the last conversion is commented out. The reason for commenting it out is of course that it doesn't compile.
As Adrian noted in a comment, Big is a constant, specifically an untyped one. As Uvelichitel answered, a constant x (of any type) can be converted to a new and different type T if and only if
x is representable by a value of type T.
(The quote part is from the section Uvelichitel linked, except that mine adds the inner link for the word "representable".)
The expression float64(Big) is an explicit type conversion, with a constant as its x, so the result is a float64-typed constant with the given value. So far, that's fine: now we have 92233720368547758074444444 as a float64. This chops off some of the digits: the actual internal representation is 92233720368547758080000000 (see variant with %f directives). The low digits, ...74444444, have been rounded to ...80000000. See the link for "representable" for why the rounding occurs.
The expression int(float64(Big)) is an outer explicit type conversion surrounding an inner explicit type conversion. We already know what the inner type conversion does: it produces the float64 constant 92233720368547758080000000.0. The outer conversion tries to represent this new value as int, but it does not fit, producing an error:
./prog.go:18:17: constant 92233720368547758080000000 overflows int
if the commented-out line is uncommented. Note again that the value has been rounded, due to the inner conversion.
On the other hand, needFloat(Big) is a function call. Calling the function assigns the untyped constant to its argument (a float64) and obtains its return value (the same float64, value 92233720368547758080000000.0. Printing that prints what you'd expect, given the default or explicit formatting directive. The returned value is not a constant.
Similarly, int(needFloat(Big)) calls needFloat, which returns the same float64 value—not a constant—as before. The int explicit type conversion tries to convert this value to int at runtime, rather than at compile time. For such conversions between numeric types, there is a list of three explicit rules at https://golang.org/ref/spec#Conversions, plus a final caveat. Here, rule 2 applies: any fractional part is discarded. But the caveat also applies:
In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.
In other words, there is no runtime error, but the int value you get—which in this case was -2147483648, which is the smallest allowed 32-bit integer—is up to the implementation. This particular implementation chose to use this particular negative number as its result. Another implementation might choose some other number. (Interestingly, in the playground, if I convert directly to uint I get zero. If I convert to int, then to uint, I get the 0x80000000 I expected.)
Hence, the key difference in terms of whether you get an error is whether you do the conversion at compile time, via constants, or at runtime, via runtime conversion.

int(float64(Big)) //illegal because
A constant value x can be converted to type T if x is representable by
a value of T
int(needFloat(Big)) //is non-constant expression because of function call
A non-constant value x can be converted to type T in any of these
cases:
- x's type and T are both integer or floating point types.
https://golang.org/ref/spec#Conversions

Related

VHDL : How is this statement resolved: type foo is range -(2**30) to 2**30;?

I am having an issue processing the following type declaration:
type foo is range -(2**30) to 2**30;
For the exponentiation, there are two possible interpretations to consider:
function "**"(universal_integer, integer) return universal_integer;
function "**"(integer, integer) return integer;
(There are interpretations using reals, but we can easily reject those since the first argument is integral.)
Since the second operand of the exponentiation must be integer, use of either alternative requires an implicit conversion. For this reason, we cannot disqualify either choice on the grounds that an implicit conversion is required.
The bounds of a type declaration must be of some integral type, but they need not be the same type. Absent any further constraints, I reject this type declaration as being ambiguous.
This seems to be a quirk with exponentiation. If I had instead:
type foo is range 0 to 2 * 30;
Then again you have two alternatives for "*". However:
function "*"(universal_integer,universal_integer) return universal_integer;
does not require an implicit conversion, so we can use that and reject the other.
Furthermore:
constant K: integer := 2 ** 30;
also works fine due to the additional constraint that the result type must be integer.
But the combination of type definition and exponentiation deprives us of enough information to make a selection.
Since this type definition works in other implementations, what am I missing?
On behalf of my implementor ..
Ken
For
type foo is range -(2**30) to 2**30;
There are two eligible "**" functions implementing the exponentiation operator.
9.2.8 Miscellaneous operators
The exponentiating operator ** is predefined for each integer type and for each floating-point type. In either case the right operand, called the exponent, is of the predefined type INTEGER.
Exponentiation with an integer exponent is equivalent to repeated multiplication of the left operand by itself for a number of times indicated by the absolute value of the exponent and from left to right; if the exponent is negative, then the result is the reciprocal of that obtained with the absolute value of the exponent. Exponentiation with a negative exponent is only allowed for a left operand of a floating-point type. Exponentiation by a zero exponent results in the value one. Exponentiation of a value of a floating-point type is approximate.
Predefined operators for predefined types are shown as comments in package STANDARD. The two applicable here:
16.3 Package STANDARD
-- function "**" (anonymous: universal_integer; anonymous: INTEGER)
-- return universal_integer;
-- function "**" (anonymous: INTEGER; anonymous: INTEGER)
-- return INTEGER;
Note the right operand type is INTEGER. The right operand is subject to implicit type conversion.
The reason there are two is found in 5.2.3 Integer types, 5.2.3.1 General:
Each bound of a range constraint that is used in an integer type definition shall be a locally static expression of some integer type, but the two bounds need not have the same integer type. (Negative bounds are allowed.)
Integer literals are the literals of an anonymous predefined type that is called universal_integer in this standard. Other integer types have no literals. However, for each integer type there exists an implicit conversion that converts a value of type universal_integer into the corresponding value (if any) of the integer type (see 9.3.6).
The bounds are required to be some integer type and that can include universal_integer.
Which of those two are selected by The context of overload resolution is based on semantics found in 9.3.6 Type conversions:
In certain cases, an implicit type conversion will be performed. An implicit conversion of an operand of type universal_integer to another integer type, or of an operand of type universal_real to another floating-point type, can only be applied if the operand is either a numeric literal or an attribute, or if the operand is an expression consisting of the division of a value of a physical type by a value of the same type; such an operand is called a convertible universal operand. An implicit conversion of a convertible universal operand is applied if and only if the innermost complete context determines a unique (numeric) target type for the implicit conversion, and there is no legal interpretation of this context without this conversion.
You only implicitly convert from universal_integer to another integer type if there is no other legal interpretation. This is the mechanism to prevent two possible choices here in the context of overload resolution.
For 2 ** 30 do you have to implicitly convert the left operand? No. Do you have to implicitly convert the right operand? Yes, both choices require the type be INTEGER. Further there's no requirement the result be a different integer type than universal_integer required by the semantics of integer type definition (5.2.3.1).
Looking at 9.5 Universal expressions, there's one additional limitation on the definition of an integer type here:
For the evaluation of an operation of a universal expression, the following rules apply. If the result is of type universal_integer, then the values of the operands and the result shall lie within the range of the integer type with the widest range provided by the implementation, excluding type universal_integer itself. If the result is of type universal_real, then the values of the operands and the result shall lie within the range of the floating-point type with the widest range provided by the implementation, excluding type universal_real itself.
There's no way for you to use literals to describe an integer type with a value range greater than that of type INTEGER, the only predefined integer type (5.2.3.2).
There's also the limitation of integer literals of the anonymous type universal_integer whose value range is unknowable.
12.5 The context of overload resolution
When considering possible interpretations of a complete context, the only rules considered are the syntax rules, the scope and visibility rules, and the rules of the form as follows:
a) ...
e) The rules given for the resolution of overloaded subprogram calls; for the implicit conversions of universal expressions; for the interpretation of discrete ranges with bounds having a universal type; for the interpretation of an expanded name whose prefix denotes a subprogram; and for a subprogram named in a subprogram instantiation declaration to denote an uninstantiated subprogram.
f) ...
Where we can see both the semantics of implicit conversion found in 9.3.6 and the limitations on range found in 9.5 are embraced.
For purposes of knowing how to select between the two candidate functions providing operator overload the key is found in 9.3.6.
Both operands of of the exponentiation operator in
constant K: integer := 2 ** 30;
can be implicitly type converted to another integer type (INTEGER) while the otherwise universal expression 2 ** 30 can't be implicitly converted, not meeting the requirements of 9.3.6 (the operands aren't values of a physical type and operator isn't the multiplying operator /).
The overload for that is also alluded to in package STANDARD:
-- function "**" (anonymous: INTEGER; anonymous: INTEGER)
-- return INTEGER;
Chuck Swart (the last ISAC chair) described this behavior in Issue Report 2073 (IR2073.txt) as forcing implicit type conversion to the leaves of an abstract syntax tree. In his words "This clause implies that implicit conversions occur as far down as possible in the expression tree." Note that 9.3.6 was 7.3.5 before Accellera VHDL -2006 was re-written to conform to the IEEE-SA's format for a standard.
The universal_integer to to another integer type conversion can be forced away from the leaves by using explicit type conversion:
constant K: integer := integer(2 ** 30);
Noting the right operand of "**" the integer literal 30 would still be implicitly type converted to type INTEGER, while the left operand and result are of type universal_integer.

What does this code from go sources mean? Like (*(*float32)(v.ptr))

In reflection package I see the code like
return float64(*(*float32)(v.ptr))
What is *(*float32)(v.ptr)? I don't have any ideas
Let's unwrap the expression. We'll take it from innermost to outermost, since that's the order it's evaluated:
(*float32)(v.ptr)
Convert v.ptr to *float32, a pointer to a float32.
*(*float32)(v.ptr)
Dereference that pointer, giving us a float32 value.
float64(*(*float32)(v.ptr))
Convert the float32 value to a float64 value.
So, whatever v.ptr is, it's converted to a float32 pointer, dereferenced, and then converted to float64, and returned.

How to Define a Constant Value of a User-defined Type in Go?

I am implementing a bit-vector in Go:
// A bit vector uses a slice of unsigned integer values or “words,”
// each bit of which represents an element of the set.
// The set contains i if the ith bit is set.
// The following program demonstrates a simple bit vector type with these methods.
type IntSet struct {
words []uint64 //uint64 is important because we need control over number and value of bits
}
I have defined several methods (e.g. membership test, adding or removing elements, set operations like union, intersection etc.) on it which all have a pointer receiver. Here is one such method:
// Has returns true if the given integer is in the set, false otherwise
func (this *IntSet) Has(m int) bool {
// details omitted for brevity
}
Now, I need to return an empty set that is a true constant, so that I can use the same constant every time I need to refer to an IntSet that contains no elements. One way is to return something like &IntSet{}, but I see two disadvantages:
Every time an empty set is to be returned, a new value needs to be allocated.
The returned value is not really constant since it can be modified by the callers.
How do you define a null set that does not have these limitations?
If you read https://golang.org/ref/spec#Constants you see that constants are limited to basic types. A struct or a slice or array will not work as a constant.
I think that the best you can do is to make a function that returns a copy of an internal empty set. If callers modify it, that isn't something you can fix.
Actually modifying it would be difficult for them since the words inside the IntSet are lowercase and therefore private. If you added a value next to words like mut bool you could add a if mut check to every method that changes the IntSet. If it isn't mutable, return an error or panic.
With that, you could keep users from modifying constant, non-mutable IntSet values.

Initialize const variable

How can I initialize KILO variable with const type?
const KILO = math.Pow10(3)
Because I have an errror
const initializer math.Pow10(3) is not a constant
Constant declarations cannot contain function calls (with some exceptions, see below), they must be evaluated at compile time while a function call is carried out at runtime.
Quoting from Spec: Constants:
A constant value is represented by a rune, integer, floating-point, imaginary, or string literal, an identifier denoting a constant, a constant expression, a conversion with a result that is a constant, or the result value of some built-in functions such as unsafe.Sizeof applied to any value, cap or len applied to some expressions, real and imag applied to a complex constant and complex applied to numeric constants.
And quoting from Spec: Constant expressions:
Constant expressions may contain only constant operands and are evaluated at compile time.
Note that there is a small set of (builtin) functions that may be called in constant declarations such as unsafe.Sizeof(), but generally you can't do that.
So just use
const Kilo = 1000 // Integer literal
Or
const Kilo = 1e3 // Floating-point literal
For an extensive introduction to Go constants, read blog post: Constants
If for some reason you do need to call a function, you cannot store it in a constant, it must be a variable, e.g.:
var Kilo = math.Pow10(3)
Also see related Writing powers of 10 as constants compactly.

Why use the + sign in printfl?

What's the difference between:
var x float64 = 3.141592
fmt.Println("the value is" + x)
and
var x float64 = 3.141592
fmt.Println("the value is", x)
What does the + means?
Why is the first one wrong and the second correct?
fmt.Println is a variadic function whose arguments are generic interfaces. Any type can fulfill this interfere, including strings and floats. The second example works for this reason.
The first example, however, involves the binary operator +. As https://golang.org/ref/spec#Operators says, binary operators work in identical types. This means you can't "add" a float to a string without first explicitly casting to a string.
In general, this is a decision the golang inventors made. If you read the design tenets of go, I think you'll find this aligns well. But for the purposes of your question, it's sufficient to say, that's how it was made to work.

Resources