github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/src/cmd/compile/internal/gc/mparith3.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  	"cmd/compile/internal/big"
     9  	"cmd/internal/obj"
    10  	"fmt"
    11  	"math"
    12  	"strings"
    13  )
    14  
    15  /// implements float arihmetic
    16  
    17  func newMpflt() *Mpflt {
    18  	var a Mpflt
    19  	a.Val.SetPrec(Mpprec)
    20  	return &a
    21  }
    22  
    23  func Mpmovefixflt(a *Mpflt, b *Mpint) {
    24  	if b.Ovf {
    25  		// sign doesn't really matter but copy anyway
    26  		a.Val.SetInf(b.Val.Sign() < 0)
    27  		return
    28  	}
    29  	a.Val.SetInt(&b.Val)
    30  }
    31  
    32  func mpmovefltflt(a *Mpflt, b *Mpflt) {
    33  	a.Val.Set(&b.Val)
    34  }
    35  
    36  func mpaddfltflt(a *Mpflt, b *Mpflt) {
    37  	if Mpdebug {
    38  		fmt.Printf("\n%v + %v", a, b)
    39  	}
    40  
    41  	a.Val.Add(&a.Val, &b.Val)
    42  
    43  	if Mpdebug {
    44  		fmt.Printf(" = %v\n\n", a)
    45  	}
    46  }
    47  
    48  func mpaddcflt(a *Mpflt, c float64) {
    49  	var b Mpflt
    50  
    51  	Mpmovecflt(&b, c)
    52  	mpaddfltflt(a, &b)
    53  }
    54  
    55  func mpsubfltflt(a *Mpflt, b *Mpflt) {
    56  	if Mpdebug {
    57  		fmt.Printf("\n%v - %v", a, b)
    58  	}
    59  
    60  	a.Val.Sub(&a.Val, &b.Val)
    61  
    62  	if Mpdebug {
    63  		fmt.Printf(" = %v\n\n", a)
    64  	}
    65  }
    66  
    67  func mpmulfltflt(a *Mpflt, b *Mpflt) {
    68  	if Mpdebug {
    69  		fmt.Printf("%v\n * %v\n", a, b)
    70  	}
    71  
    72  	a.Val.Mul(&a.Val, &b.Val)
    73  
    74  	if Mpdebug {
    75  		fmt.Printf(" = %v\n\n", a)
    76  	}
    77  }
    78  
    79  func mpmulcflt(a *Mpflt, c float64) {
    80  	var b Mpflt
    81  
    82  	Mpmovecflt(&b, c)
    83  	mpmulfltflt(a, &b)
    84  }
    85  
    86  func mpdivfltflt(a *Mpflt, b *Mpflt) {
    87  	if Mpdebug {
    88  		fmt.Printf("%v\n / %v\n", a, b)
    89  	}
    90  
    91  	a.Val.Quo(&a.Val, &b.Val)
    92  
    93  	if Mpdebug {
    94  		fmt.Printf(" = %v\n\n", a)
    95  	}
    96  }
    97  
    98  func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
    99  	return a.Val.Cmp(&b.Val)
   100  }
   101  
   102  func mpcmpfltc(b *Mpflt, c float64) int {
   103  	var a Mpflt
   104  
   105  	Mpmovecflt(&a, c)
   106  	return mpcmpfltflt(b, &a)
   107  }
   108  
   109  func mpgetflt(a *Mpflt) float64 {
   110  	x, _ := a.Val.Float64()
   111  
   112  	// check for overflow
   113  	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
   114  		Yyerror("mpgetflt ovf")
   115  	}
   116  
   117  	return x
   118  }
   119  
   120  func mpgetflt32(a *Mpflt) float64 {
   121  	x32, _ := a.Val.Float32()
   122  	x := float64(x32)
   123  
   124  	// check for overflow
   125  	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
   126  		Yyerror("mpgetflt32 ovf")
   127  	}
   128  
   129  	return x
   130  }
   131  
   132  func Mpmovecflt(a *Mpflt, c float64) {
   133  	if Mpdebug {
   134  		fmt.Printf("\nconst %g", c)
   135  	}
   136  
   137  	a.Val.SetFloat64(c)
   138  
   139  	if Mpdebug {
   140  		fmt.Printf(" = %v\n", a)
   141  	}
   142  }
   143  
   144  func mpnegflt(a *Mpflt) {
   145  	a.Val.Neg(&a.Val)
   146  }
   147  
   148  //
   149  // floating point input
   150  // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
   151  //
   152  func mpatoflt(a *Mpflt, as string) {
   153  	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
   154  		as = as[1:]
   155  	}
   156  
   157  	// The spec requires accepting exponents that fit in int32.
   158  	// Don't accept much more than that.
   159  	// Count digits in exponent and stop early if there are too many.
   160  	if i := strings.Index(as, "e"); i >= 0 {
   161  		i++
   162  		if i < len(as) && (as[i] == '-' || as[i] == '+') {
   163  			i++
   164  		}
   165  		for i < len(as) && as[i] == '0' {
   166  			i++
   167  		}
   168  		// TODO(rsc): This should be > 10, because we're supposed
   169  		// to accept any signed 32-bit int as an exponent.
   170  		// But that's not working terribly well, so we deviate from the
   171  		// spec in order to make sure that what we accept works.
   172  		// We can remove this restriction once those larger exponents work.
   173  		// See golang.org/issue/11326 and test/fixedbugs/issue11326*.go.
   174  		if len(as)-i > 8 {
   175  			Yyerror("malformed constant: %s (exponent too large)", as)
   176  			a.Val.SetUint64(0)
   177  			return
   178  		}
   179  	}
   180  
   181  	f, ok := a.Val.SetString(as)
   182  	if !ok {
   183  		// At the moment we lose precise error cause;
   184  		// the old code additionally distinguished between:
   185  		// - malformed hex constant
   186  		// - decimal point in hex constant
   187  		// - constant exponent out of range
   188  		// - decimal point and binary point in constant
   189  		// TODO(gri) use different conversion function or check separately
   190  		Yyerror("malformed constant: %s", as)
   191  		a.Val.SetUint64(0)
   192  		return
   193  	}
   194  
   195  	if f.IsInf() {
   196  		Yyerror("constant too large: %s", as)
   197  		a.Val.SetUint64(0)
   198  		return
   199  	}
   200  }
   201  
   202  func (f *Mpflt) String() string {
   203  	return Fconv(f, 0)
   204  }
   205  
   206  func Fconv(fvp *Mpflt, flag int) string {
   207  	if flag&obj.FmtSharp == 0 {
   208  		return fvp.Val.Text('b', 0)
   209  	}
   210  
   211  	// use decimal format for error messages
   212  
   213  	// determine sign
   214  	f := &fvp.Val
   215  	var sign string
   216  	if fvp.Val.Signbit() {
   217  		sign = "-"
   218  		f = new(big.Float).Abs(f)
   219  	} else if flag&obj.FmtSign != 0 {
   220  		sign = "+"
   221  	}
   222  
   223  	// Use fmt formatting if in float64 range (common case).
   224  	if x, _ := f.Float64(); !math.IsInf(x, 0) {
   225  		return fmt.Sprintf("%s%.6g", sign, x)
   226  	}
   227  
   228  	// Out of float64 range. Do approximate manual to decimal
   229  	// conversion to avoid precise but possibly slow Float
   230  	// formatting. The exponent is > 0 since a negative out-
   231  	// of-range exponent would have underflowed and led to 0.
   232  	// f = mant * 2**exp
   233  	var mant big.Float
   234  	exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
   235  
   236  	// approximate float64 mantissa m and decimal exponent d
   237  	// f ~ m * 10**d
   238  	m, _ := mant.Float64()            // 0.5 <= m < 1.0
   239  	d := exp * (math.Ln2 / math.Ln10) // log_10(2)
   240  
   241  	// adjust m for truncated (integer) decimal exponent e
   242  	e := int64(d)
   243  	m *= math.Pow(10, d-float64(e))
   244  	for m >= 10 {
   245  		m /= 10
   246  		e++
   247  	}
   248  
   249  	return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
   250  }