Commit 041d31b8 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: don't mix internal float/complex constants of different precision

There are several places where a new (internal) complex constant is allocated
via new(Mpcplx) rather than newMpcmplx(). The problem with using new() is that
the Mpcplx data structure's Real and Imag components don't get initialized with
an Mpflt of the correct precision (they have precision 0, which may be adjusted
later).

In all cases but one, the components of those complex constants are set using
a Set operation which "inherits" the correct precision from the value that is
being set.

But when creating a complex value for an imaginary literal, the imaginary
component is set via SetString which assumes 64bits of precision by default.
As a result, the internal representation of 0.01i and complex(0, 0.01) was
not correct.

Replaced all used of new(Mpcplx) with newMpcmplx() and added a new test.

Fixes #30243.

Change-Id: Ife7fd6ccd42bf887a55c6ce91727754657e6cb2d
Reviewed-on: https://go-review.googlesource.com/c/163000
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 165a8d93
......@@ -427,13 +427,13 @@ bad:
func tocplx(v Val) Val {
switch u := v.U.(type) {
case *Mpint:
c := new(Mpcplx)
c := newMpcmplx()
c.Real.SetInt(u)
c.Imag.SetFloat64(0.0)
v.U = c
case *Mpflt:
c := new(Mpcplx)
c := newMpcmplx()
c.Real.Set(u)
c.Imag.SetFloat64(0.0)
v.U = c
......@@ -845,7 +845,7 @@ Outer:
case CTCPLX:
x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
u := new(Mpcplx)
u := newMpcmplx()
u.Real.Set(&x.Real)
u.Imag.Set(&x.Imag)
switch op {
......@@ -900,7 +900,7 @@ func unaryOp(op Op, x Val, t *types.Type) Val {
case CTCPLX:
x := x.U.(*Mpcplx)
u := new(Mpcplx)
u := newMpcmplx()
u.Real.Set(&x.Real)
u.Imag.Set(&x.Imag)
u.Real.Neg()
......
......@@ -32,12 +32,14 @@ type Mpcplx struct {
Imag Mpflt
}
// Use newMpflt (not new(Mpflt)!) to get the correct default precision.
func newMpflt() *Mpflt {
var a Mpflt
a.Val.SetPrec(Mpprec)
return &a
}
// Use newMpcmplx (not new(Mpcplx)!) to get the correct default precision.
func newMpcmplx() *Mpcplx {
var a Mpcplx
a.Real = *newMpflt()
......
......@@ -1327,7 +1327,7 @@ func (p *noder) basicLit(lit *syntax.BasicLit) Val {
return Val{U: x}
case syntax.ImagLit:
x := new(Mpcplx)
x := newMpcmplx()
x.Imag.SetString(strings.TrimSuffix(s, "i"))
return Val{U: x}
......
......@@ -16,7 +16,7 @@ func nodrune(r rune) *Node {
}
func nodflt(f float64) *Node {
v := new(Mpflt)
v := newMpflt()
v.SetFloat64(f)
return nodlit(Val{v})
}
......
......@@ -1589,7 +1589,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if l.Op == OLITERAL && r.Op == OLITERAL {
// make it a complex literal
c := new(Mpcplx)
c := newMpcmplx()
c.Real.Set(toflt(l.Val()).U.(*Mpflt))
c.Imag.Set(toflt(r.Val()).U.(*Mpflt))
setconst(n, Val{c})
......
// run
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Compile-time constants, even if they cannot be represented
// accurately, should remain the same in operations that don't
// affect their values.
package main
import "fmt"
func main() {
const x = 0.01
const xi = 0.01i
const xc = complex(0, x)
if imag(xi) != x {
fmt.Printf("FAILED: %g != %g\n", imag(xi), x)
}
if xi != complex(0, x) {
fmt.Printf("FAILED: %g != %g\n", xi, complex(0, x))
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment