2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"math"
|
2016-10-13 15:13:41 -04:00
|
|
|
"math/big"
|
2015-02-13 14:40:36 -05:00
|
|
|
)
|
|
|
|
|
|
2016-02-24 11:55:20 +01:00
|
|
|
// implements float arithmetic
|
2015-03-26 18:07:19 -07:00
|
|
|
|
2016-02-29 20:20:13 -08:00
|
|
|
const (
|
|
|
|
|
// Maximum size in bits for Mpints before signalling
|
|
|
|
|
// overflow and also mantissa precision for Mpflts.
|
|
|
|
|
Mpprec = 512
|
|
|
|
|
// Turn on for constant arithmetic debugging output.
|
|
|
|
|
Mpdebug = false
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Mpflt represents a floating-point constant.
|
|
|
|
|
type Mpflt struct {
|
|
|
|
|
Val big.Float
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mpcplx represents a complex constant.
|
|
|
|
|
type Mpcplx struct {
|
|
|
|
|
Real Mpflt
|
|
|
|
|
Imag Mpflt
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
func newMpflt() *Mpflt {
|
|
|
|
|
var a Mpflt
|
2015-03-26 18:07:19 -07:00
|
|
|
a.Val.SetPrec(Mpprec)
|
2015-03-20 16:59:08 -07:00
|
|
|
return &a
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-07 11:54:29 +01:00
|
|
|
func newMpcmplx() *Mpcplx {
|
|
|
|
|
var a Mpcplx
|
|
|
|
|
a.Real = *newMpflt()
|
|
|
|
|
a.Imag = *newMpflt()
|
|
|
|
|
return &a
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) SetInt(b *Mpint) {
|
2017-04-07 09:09:17 +02:00
|
|
|
if b.checkOverflow(0) {
|
2015-03-26 18:07:19 -07:00
|
|
|
// sign doesn't really matter but copy anyway
|
|
|
|
|
a.Val.SetInf(b.Val.Sign() < 0)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
a.Val.SetInt(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Set(b *Mpflt) {
|
2015-03-26 18:07:19 -07:00
|
|
|
a.Val.Set(&b.Val)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Add(b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\n%v + %v", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Add(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) AddFloat64(c float64) {
|
2015-03-26 18:07:19 -07:00
|
|
|
var b Mpflt
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
b.SetFloat64(c)
|
|
|
|
|
a.Add(&b)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Sub(b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\n%v - %v", a, b)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Sub(&a.Val, &b.Val)
|
|
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Mul(b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("%v\n * %v\n", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Mul(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) MulFloat64(c float64) {
|
2015-03-26 18:07:19 -07:00
|
|
|
var b Mpflt
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
b.SetFloat64(c)
|
|
|
|
|
a.Mul(&b)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Quo(b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("%v\n / %v\n", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Quo(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Cmp(b *Mpflt) int {
|
2015-03-26 18:07:19 -07:00
|
|
|
return a.Val.Cmp(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 10:52:03 -07:00
|
|
|
func (a *Mpflt) CmpFloat64(c float64) int {
|
|
|
|
|
if c == 0 {
|
|
|
|
|
return a.Val.Sign() // common case shortcut
|
|
|
|
|
}
|
|
|
|
|
return a.Val.Cmp(big.NewFloat(c))
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Float64() float64 {
|
2015-05-22 11:31:47 -07:00
|
|
|
x, _ := a.Val.Float64()
|
2015-03-20 16:59:08 -07:00
|
|
|
|
|
|
|
|
// check for overflow
|
|
|
|
|
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
2017-03-14 09:46:45 -07:00
|
|
|
Fatalf("ovf in Mpflt Float64")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
return x + 0 // avoid -0 (should not be needed, but be conservative)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Float32() float64 {
|
2015-05-22 11:31:47 -07:00
|
|
|
x32, _ := a.Val.Float32()
|
|
|
|
|
x := float64(x32)
|
|
|
|
|
|
|
|
|
|
// check for overflow
|
|
|
|
|
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
2017-03-14 09:46:45 -07:00
|
|
|
Fatalf("ovf in Mpflt Float32")
|
2015-05-22 11:31:47 -07:00
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
return x + 0 // avoid -0 (should not be needed, but be conservative)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) SetFloat64(c float64) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmt.Printf("\nconst %g", c)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
// convert -0 to 0
|
|
|
|
|
if c == 0 {
|
|
|
|
|
c = 0
|
|
|
|
|
}
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.SetFloat64(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) Neg() {
|
2015-10-20 14:45:36 -07:00
|
|
|
// avoid -0
|
|
|
|
|
if a.Val.Sign() != 0 {
|
|
|
|
|
a.Val.Neg(&a.Val)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-26 18:07:19 -07:00
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpflt) SetString(as string) {
|
2015-03-26 18:07:19 -07:00
|
|
|
for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
|
|
|
|
|
as = as[1:]
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-08 13:32:18 -07:00
|
|
|
f, _, err := a.Val.Parse(as, 10)
|
|
|
|
|
if err != nil {
|
|
|
|
|
yyerror("malformed constant: %s (%v)", as, err)
|
2015-10-20 14:45:36 -07:00
|
|
|
a.Val.SetFloat64(0)
|
2015-06-28 23:25:38 -04:00
|
|
|
return
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f.IsInf() {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant too large: %s", as)
|
2015-10-20 14:45:36 -07:00
|
|
|
a.Val.SetFloat64(0)
|
2015-06-28 23:25:38 -04:00
|
|
|
return
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2015-10-20 14:45:36 -07:00
|
|
|
|
|
|
|
|
// -0 becomes 0
|
|
|
|
|
if f.Sign() == 0 && f.Signbit() {
|
|
|
|
|
a.Val.SetFloat64(0)
|
|
|
|
|
}
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (f *Mpflt) String() string {
|
cmd/compile/internal/gc: unexport {J,S,F,H,B,V}conv
Updates #15462
Unexport Jconv, Sconv, Fconv, Hconv, Bconv, and VConv as they are
not referenced outside internal/gc.
Econv was only called by EType.String, so merge it into that method.
Change-Id: Iad9b06078eb513b85a03a43cd9eb9366477643d1
Reviewed-on: https://go-review.googlesource.com/22531
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dave Cheney <dave@cheney.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-27 15:15:47 +10:00
|
|
|
return fconv(f, 0)
|
2015-04-17 11:56:29 -04:00
|
|
|
}
|
|
|
|
|
|
cmd/compile/internal/gc: unexport {J,S,F,H,B,V}conv
Updates #15462
Unexport Jconv, Sconv, Fconv, Hconv, Bconv, and VConv as they are
not referenced outside internal/gc.
Econv was only called by EType.String, so merge it into that method.
Change-Id: Iad9b06078eb513b85a03a43cd9eb9366477643d1
Reviewed-on: https://go-review.googlesource.com/22531
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dave Cheney <dave@cheney.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-27 15:15:47 +10:00
|
|
|
func fconv(fvp *Mpflt, flag FmtFlag) string {
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtSharp == 0 {
|
2015-06-03 15:11:05 -07:00
|
|
|
return fvp.Val.Text('b', 0)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2015-04-03 17:50:37 -07:00
|
|
|
|
|
|
|
|
// use decimal format for error messages
|
|
|
|
|
|
|
|
|
|
// determine sign
|
|
|
|
|
f := &fvp.Val
|
|
|
|
|
var sign string
|
2015-10-20 14:45:36 -07:00
|
|
|
if f.Sign() < 0 {
|
2015-04-03 17:50:37 -07:00
|
|
|
sign = "-"
|
|
|
|
|
f = new(big.Float).Abs(f)
|
2016-03-15 13:06:58 -07:00
|
|
|
} else if flag&FmtSign != 0 {
|
2015-04-03 17:50:37 -07:00
|
|
|
sign = "+"
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-10 11:32:26 -08:00
|
|
|
// Don't try to convert infinities (will not terminate).
|
|
|
|
|
if f.IsInf() {
|
|
|
|
|
return sign + "Inf"
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 17:22:48 -08:00
|
|
|
// Use exact fmt formatting if in float64 range (common case):
|
|
|
|
|
// proceed if f doesn't underflow to 0 or overflow to inf.
|
|
|
|
|
if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
|
2015-04-03 17:50:37 -07:00
|
|
|
return fmt.Sprintf("%s%.6g", sign, x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Out of float64 range. Do approximate manual to decimal
|
|
|
|
|
// conversion to avoid precise but possibly slow Float
|
2015-12-09 17:22:48 -08:00
|
|
|
// formatting.
|
2015-04-03 17:50:37 -07:00
|
|
|
// f = mant * 2**exp
|
|
|
|
|
var mant big.Float
|
2015-12-09 17:22:48 -08:00
|
|
|
exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
|
2015-04-03 17:50:37 -07:00
|
|
|
|
|
|
|
|
// approximate float64 mantissa m and decimal exponent d
|
|
|
|
|
// f ~ m * 10**d
|
2015-12-09 17:22:48 -08:00
|
|
|
m, _ := mant.Float64() // 0.5 <= m < 1.0
|
|
|
|
|
d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
|
2015-04-03 17:50:37 -07:00
|
|
|
|
|
|
|
|
// adjust m for truncated (integer) decimal exponent e
|
|
|
|
|
e := int64(d)
|
|
|
|
|
m *= math.Pow(10, d-float64(e))
|
2015-12-09 17:22:48 -08:00
|
|
|
|
|
|
|
|
// ensure 1 <= m < 10
|
|
|
|
|
switch {
|
|
|
|
|
case m < 1-0.5e-6:
|
|
|
|
|
// The %.6g format below rounds m to 5 digits after the
|
|
|
|
|
// decimal point. Make sure that m*10 < 10 even after
|
|
|
|
|
// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
|
|
|
|
|
m *= 10
|
|
|
|
|
e--
|
|
|
|
|
case m >= 10:
|
2015-04-03 17:50:37 -07:00
|
|
|
m /= 10
|
|
|
|
|
e++
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 17:22:48 -08:00
|
|
|
return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2018-04-06 09:44:29 -07:00
|
|
|
|
|
|
|
|
// complex multiply v *= rv
|
|
|
|
|
// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
|
|
|
|
|
func (v *Mpcplx) Mul(rv *Mpcplx) {
|
|
|
|
|
var ac, ad, bc, bd Mpflt
|
|
|
|
|
|
|
|
|
|
ac.Set(&v.Real)
|
|
|
|
|
ac.Mul(&rv.Real) // ac
|
|
|
|
|
|
|
|
|
|
bd.Set(&v.Imag)
|
|
|
|
|
bd.Mul(&rv.Imag) // bd
|
|
|
|
|
|
|
|
|
|
bc.Set(&v.Imag)
|
|
|
|
|
bc.Mul(&rv.Real) // bc
|
|
|
|
|
|
|
|
|
|
ad.Set(&v.Real)
|
|
|
|
|
ad.Mul(&rv.Imag) // ad
|
|
|
|
|
|
|
|
|
|
v.Real.Set(&ac)
|
|
|
|
|
v.Real.Sub(&bd) // ac-bd
|
|
|
|
|
|
|
|
|
|
v.Imag.Set(&bc)
|
|
|
|
|
v.Imag.Add(&ad) // bc+ad
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// complex divide v /= rv
|
|
|
|
|
// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
|
|
|
|
|
func (v *Mpcplx) Div(rv *Mpcplx) bool {
|
|
|
|
|
if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ac, ad, bc, bd, cc_plus_dd Mpflt
|
|
|
|
|
|
|
|
|
|
cc_plus_dd.Set(&rv.Real)
|
|
|
|
|
cc_plus_dd.Mul(&rv.Real) // cc
|
|
|
|
|
|
|
|
|
|
ac.Set(&rv.Imag)
|
|
|
|
|
ac.Mul(&rv.Imag) // dd
|
|
|
|
|
cc_plus_dd.Add(&ac) // cc+dd
|
|
|
|
|
|
|
|
|
|
// We already checked that c and d are not both zero, but we can't
|
|
|
|
|
// assume that c²+d² != 0 follows, because for tiny values of c
|
|
|
|
|
// and/or d c²+d² can underflow to zero. Check that c²+d² is
|
|
|
|
|
// nonzero, return if it's not.
|
|
|
|
|
if cc_plus_dd.CmpFloat64(0) == 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ac.Set(&v.Real)
|
|
|
|
|
ac.Mul(&rv.Real) // ac
|
|
|
|
|
|
|
|
|
|
bd.Set(&v.Imag)
|
|
|
|
|
bd.Mul(&rv.Imag) // bd
|
|
|
|
|
|
|
|
|
|
bc.Set(&v.Imag)
|
|
|
|
|
bc.Mul(&rv.Real) // bc
|
|
|
|
|
|
|
|
|
|
ad.Set(&v.Real)
|
|
|
|
|
ad.Mul(&rv.Imag) // ad
|
|
|
|
|
|
|
|
|
|
v.Real.Set(&ac)
|
|
|
|
|
v.Real.Add(&bd) // ac+bd
|
|
|
|
|
v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd)
|
|
|
|
|
|
|
|
|
|
v.Imag.Set(&bc)
|
|
|
|
|
v.Imag.Sub(&ad) // bc-ad
|
|
|
|
|
v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|