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