github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 f.Val.Text('b', 0)
   205  }
   206  
   207  func (fvp *Mpflt) GoString() string {
   208  	// determine sign
   209  	sign := ""
   210  	f := &fvp.Val
   211  	if f.Sign() < 0 {
   212  		sign = "-"
   213  		f = new(big.Float).Abs(f)
   214  	}
   215  
   216  	// Don't try to convert infinities (will not terminate).
   217  	if f.IsInf() {
   218  		return sign + "Inf"
   219  	}
   220  
   221  	// Use exact fmt formatting if in float64 range (common case):
   222  	// proceed if f doesn't underflow to 0 or overflow to inf.
   223  	if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
   224  		return fmt.Sprintf("%s%.6g", sign, x)
   225  	}
   226  
   227  	// Out of float64 range. Do approximate manual to decimal
   228  	// conversion to avoid precise but possibly slow Float
   229  	// formatting.
   230  	// f = mant * 2**exp
   231  	var mant big.Float
   232  	exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
   233  
   234  	// approximate float64 mantissa m and decimal exponent d
   235  	// f ~ m * 10**d
   236  	m, _ := mant.Float64()                     // 0.5 <= m < 1.0
   237  	d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
   238  
   239  	// adjust m for truncated (integer) decimal exponent e
   240  	e := int64(d)
   241  	m *= math.Pow(10, d-float64(e))
   242  
   243  	// ensure 1 <= m < 10
   244  	switch {
   245  	case m < 1-0.5e-6:
   246  		// The %.6g format below rounds m to 5 digits after the
   247  		// decimal point. Make sure that m*10 < 10 even after
   248  		// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
   249  		m *= 10
   250  		e--
   251  	case m >= 10:
   252  		m /= 10
   253  		e++
   254  	}
   255  
   256  	return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
   257  }
   258  
   259  // complex multiply v *= rv
   260  //	(a, b) * (c, d) = (a*c - b*d, b*c + a*d)
   261  func (v *Mpcplx) Mul(rv *Mpcplx) {
   262  	var ac, ad, bc, bd Mpflt
   263  
   264  	ac.Set(&v.Real)
   265  	ac.Mul(&rv.Real) // ac
   266  
   267  	bd.Set(&v.Imag)
   268  	bd.Mul(&rv.Imag) // bd
   269  
   270  	bc.Set(&v.Imag)
   271  	bc.Mul(&rv.Real) // bc
   272  
   273  	ad.Set(&v.Real)
   274  	ad.Mul(&rv.Imag) // ad
   275  
   276  	v.Real.Set(&ac)
   277  	v.Real.Sub(&bd) // ac-bd
   278  
   279  	v.Imag.Set(&bc)
   280  	v.Imag.Add(&ad) // bc+ad
   281  }
   282  
   283  // complex divide v /= rv
   284  //	(a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
   285  func (v *Mpcplx) Div(rv *Mpcplx) bool {
   286  	if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
   287  		return false
   288  	}
   289  
   290  	var ac, ad, bc, bd, cc_plus_dd Mpflt
   291  
   292  	cc_plus_dd.Set(&rv.Real)
   293  	cc_plus_dd.Mul(&rv.Real) // cc
   294  
   295  	ac.Set(&rv.Imag)
   296  	ac.Mul(&rv.Imag)    // dd
   297  	cc_plus_dd.Add(&ac) // cc+dd
   298  
   299  	// We already checked that c and d are not both zero, but we can't
   300  	// assume that c²+d² != 0 follows, because for tiny values of c
   301  	// and/or d c²+d² can underflow to zero.  Check that c²+d² is
   302  	// nonzero, return if it's not.
   303  	if cc_plus_dd.CmpFloat64(0) == 0 {
   304  		return false
   305  	}
   306  
   307  	ac.Set(&v.Real)
   308  	ac.Mul(&rv.Real) // ac
   309  
   310  	bd.Set(&v.Imag)
   311  	bd.Mul(&rv.Imag) // bd
   312  
   313  	bc.Set(&v.Imag)
   314  	bc.Mul(&rv.Real) // bc
   315  
   316  	ad.Set(&v.Real)
   317  	ad.Mul(&rv.Imag) // ad
   318  
   319  	v.Real.Set(&ac)
   320  	v.Real.Add(&bd)         // ac+bd
   321  	v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd)
   322  
   323  	v.Imag.Set(&bc)
   324  	v.Imag.Sub(&ad)         // bc-ad
   325  	v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
   326  
   327  	return true
   328  }
   329  
   330  func (v *Mpcplx) String() string {
   331  	return fmt.Sprintf("(%s+%si)", v.Real.String(), v.Imag.String())
   332  }
   333  
   334  func (v *Mpcplx) GoString() string {
   335  	var re string
   336  	sre := v.Real.CmpFloat64(0)
   337  	if sre != 0 {
   338  		re = v.Real.GoString()
   339  	}
   340  
   341  	var im string
   342  	sim := v.Imag.CmpFloat64(0)
   343  	if sim != 0 {
   344  		im = v.Imag.GoString()
   345  	}
   346  
   347  	switch {
   348  	case sre == 0 && sim == 0:
   349  		return "0"
   350  	case sre == 0:
   351  		return im + "i"
   352  	case sim == 0:
   353  		return re
   354  	case sim < 0:
   355  		return fmt.Sprintf("(%s%si)", re, im)
   356  	default:
   357  		return fmt.Sprintf("(%s+%si)", re, im)
   358  	}
   359  }