github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/cmd/compile/internal/gc/mpfloat.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"math/big"
    11  )
    12  
    13  // implements float arithmetic
    14  
    15  const (
    16  	// Maximum size in bits for Mpints before signalling
    17  	// overflow and also mantissa precision for Mpflts.
    18  	Mpprec = 512
    19  	// Turn on for constant arithmetic debugging output.
    20  	Mpdebug = false
    21  )
    22  
    23  // Mpflt represents a floating-point constant.
    24  type Mpflt struct {
    25  	Val big.Float
    26  }
    27  
    28  // Mpcplx represents a complex constant.
    29  type Mpcplx struct {
    30  	Real Mpflt
    31  	Imag Mpflt
    32  }
    33  
    34  func newMpflt() *Mpflt {
    35  	var a Mpflt
    36  	a.Val.SetPrec(Mpprec)
    37  	return &a
    38  }
    39  
    40  func newMpcmplx() *Mpcplx {
    41  	var a Mpcplx
    42  	a.Real = *newMpflt()
    43  	a.Imag = *newMpflt()
    44  	return &a
    45  }
    46  
    47  func (a *Mpflt) SetInt(b *Mpint) {
    48  	if b.checkOverflow(0) {
    49  		// sign doesn't really matter but copy anyway
    50  		a.Val.SetInf(b.Val.Sign() < 0)
    51  		return
    52  	}
    53  	a.Val.SetInt(&b.Val)
    54  }
    55  
    56  func (a *Mpflt) Set(b *Mpflt) {
    57  	a.Val.Set(&b.Val)
    58  }
    59  
    60  func (a *Mpflt) Add(b *Mpflt) {
    61  	if Mpdebug {
    62  		fmt.Printf("\n%v + %v", a, b)
    63  	}
    64  
    65  	a.Val.Add(&a.Val, &b.Val)
    66  
    67  	if Mpdebug {
    68  		fmt.Printf(" = %v\n\n", a)
    69  	}
    70  }
    71  
    72  func (a *Mpflt) AddFloat64(c float64) {
    73  	var b Mpflt
    74  
    75  	b.SetFloat64(c)
    76  	a.Add(&b)
    77  }
    78  
    79  func (a *Mpflt) Sub(b *Mpflt) {
    80  	if Mpdebug {
    81  		fmt.Printf("\n%v - %v", a, b)
    82  	}
    83  
    84  	a.Val.Sub(&a.Val, &b.Val)
    85  
    86  	if Mpdebug {
    87  		fmt.Printf(" = %v\n\n", a)
    88  	}
    89  }
    90  
    91  func (a *Mpflt) Mul(b *Mpflt) {
    92  	if Mpdebug {
    93  		fmt.Printf("%v\n * %v\n", a, b)
    94  	}
    95  
    96  	a.Val.Mul(&a.Val, &b.Val)
    97  
    98  	if Mpdebug {
    99  		fmt.Printf(" = %v\n\n", a)
   100  	}
   101  }
   102  
   103  func (a *Mpflt) MulFloat64(c float64) {
   104  	var b Mpflt
   105  
   106  	b.SetFloat64(c)
   107  	a.Mul(&b)
   108  }
   109  
   110  func (a *Mpflt) Quo(b *Mpflt) {
   111  	if Mpdebug {
   112  		fmt.Printf("%v\n / %v\n", a, b)
   113  	}
   114  
   115  	a.Val.Quo(&a.Val, &b.Val)
   116  
   117  	if Mpdebug {
   118  		fmt.Printf(" = %v\n\n", a)
   119  	}
   120  }
   121  
   122  func (a *Mpflt) Cmp(b *Mpflt) int {
   123  	return a.Val.Cmp(&b.Val)
   124  }
   125  
   126  func (a *Mpflt) CmpFloat64(c float64) int {
   127  	if c == 0 {
   128  		return a.Val.Sign() // common case shortcut
   129  	}
   130  	return a.Val.Cmp(big.NewFloat(c))
   131  }
   132  
   133  func (a *Mpflt) Float64() float64 {
   134  	x, _ := a.Val.Float64()
   135  
   136  	// check for overflow
   137  	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
   138  		Fatalf("ovf in Mpflt Float64")
   139  	}
   140  
   141  	return x + 0 // avoid -0 (should not be needed, but be conservative)
   142  }
   143  
   144  func (a *Mpflt) Float32() float64 {
   145  	x32, _ := a.Val.Float32()
   146  	x := float64(x32)
   147  
   148  	// check for overflow
   149  	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
   150  		Fatalf("ovf in Mpflt Float32")
   151  	}
   152  
   153  	return x + 0 // avoid -0 (should not be needed, but be conservative)
   154  }
   155  
   156  func (a *Mpflt) SetFloat64(c float64) {
   157  	if Mpdebug {
   158  		fmt.Printf("\nconst %g", c)
   159  	}
   160  
   161  	// convert -0 to 0
   162  	if c == 0 {
   163  		c = 0
   164  	}
   165  	a.Val.SetFloat64(c)
   166  
   167  	if Mpdebug {
   168  		fmt.Printf(" = %v\n", a)
   169  	}
   170  }
   171  
   172  func (a *Mpflt) Neg() {
   173  	// avoid -0
   174  	if a.Val.Sign() != 0 {
   175  		a.Val.Neg(&a.Val)
   176  	}
   177  }
   178  
   179  func (a *Mpflt) SetString(as string) {
   180  	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
   181  		as = as[1:]
   182  	}
   183  
   184  	f, _, err := a.Val.Parse(as, 10)
   185  	if err != nil {
   186  		yyerror("malformed constant: %s (%v)", as, err)
   187  		a.Val.SetFloat64(0)
   188  		return
   189  	}
   190  
   191  	if f.IsInf() {
   192  		yyerror("constant too large: %s", as)
   193  		a.Val.SetFloat64(0)
   194  		return
   195  	}
   196  
   197  	// -0 becomes 0
   198  	if f.Sign() == 0 && f.Signbit() {
   199  		a.Val.SetFloat64(0)
   200  	}
   201  }
   202  
   203  func (f *Mpflt) String() string {
   204  	return fconv(f, 0)
   205  }
   206  
   207  func fconv(fvp *Mpflt, flag FmtFlag) string {
   208  	if flag&FmtSharp == 0 {
   209  		return fvp.Val.Text('b', 0)
   210  	}
   211  
   212  	// use decimal format for error messages
   213  
   214  	// determine sign
   215  	f := &fvp.Val
   216  	var sign string
   217  	if f.Sign() < 0 {
   218  		sign = "-"
   219  		f = new(big.Float).Abs(f)
   220  	} else if flag&FmtSign != 0 {
   221  		sign = "+"
   222  	}
   223  
   224  	// Don't try to convert infinities (will not terminate).
   225  	if f.IsInf() {
   226  		return sign + "Inf"
   227  	}
   228  
   229  	// Use exact fmt formatting if in float64 range (common case):
   230  	// proceed if f doesn't underflow to 0 or overflow to inf.
   231  	if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
   232  		return fmt.Sprintf("%s%.6g", sign, x)
   233  	}
   234  
   235  	// Out of float64 range. Do approximate manual to decimal
   236  	// conversion to avoid precise but possibly slow Float
   237  	// formatting.
   238  	// f = mant * 2**exp
   239  	var mant big.Float
   240  	exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
   241  
   242  	// approximate float64 mantissa m and decimal exponent d
   243  	// f ~ m * 10**d
   244  	m, _ := mant.Float64()                     // 0.5 <= m < 1.0
   245  	d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
   246  
   247  	// adjust m for truncated (integer) decimal exponent e
   248  	e := int64(d)
   249  	m *= math.Pow(10, d-float64(e))
   250  
   251  	// ensure 1 <= m < 10
   252  	switch {
   253  	case m < 1-0.5e-6:
   254  		// The %.6g format below rounds m to 5 digits after the
   255  		// decimal point. Make sure that m*10 < 10 even after
   256  		// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
   257  		m *= 10
   258  		e--
   259  	case m >= 10:
   260  		m /= 10
   261  		e++
   262  	}
   263  
   264  	return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
   265  }