github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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
   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
   129  }
   130  
   131  func Mpmovecflt(a *Mpflt, c float64) {
   132  	if Mpdebug {
   133  		fmt.Printf("\nconst %g", c)
   134  	}
   135  
   136  	a.Val.SetFloat64(c)
   137  
   138  	if Mpdebug {
   139  		fmt.Printf(" = %v\n", a)
   140  	}
   141  }
   142  
   143  func mpnegflt(a *Mpflt) {
   144  	a.Val.Neg(&a.Val)
   145  }
   146  
   147  //
   148  // floating point input
   149  // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
   150  //
   151  func mpatoflt(a *Mpflt, as string) {
   152  	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
   153  		as = as[1:]
   154  	}
   155  
   156  	f, ok := a.Val.SetString(as)
   157  	if !ok {
   158  		// At the moment we lose precise error cause;
   159  		// the old code additionally distinguished between:
   160  		// - malformed hex constant
   161  		// - decimal point in hex constant
   162  		// - constant exponent out of range
   163  		// - decimal point and binary point in constant
   164  		// TODO(gri) use different conversion function or check separately
   165  		Yyerror("malformed constant: %s", as)
   166  		a.Val.SetUint64(0)
   167  		return
   168  	}
   169  
   170  	if f.IsInf() {
   171  		Yyerror("constant too large: %s", as)
   172  		a.Val.SetUint64(0)
   173  		return
   174  	}
   175  }
   176  
   177  func (f *Mpflt) String() string {
   178  	return Fconv(f, 0)
   179  }
   180  
   181  func Fconv(fvp *Mpflt, flag int) string {
   182  	if flag&obj.FmtSharp == 0 {
   183  		return fvp.Val.Text('b', 0)
   184  	}
   185  
   186  	// use decimal format for error messages
   187  
   188  	// determine sign
   189  	f := &fvp.Val
   190  	var sign string
   191  	if fvp.Val.Signbit() {
   192  		sign = "-"
   193  		f = new(big.Float).Abs(f)
   194  	} else if flag&obj.FmtSign != 0 {
   195  		sign = "+"
   196  	}
   197  
   198  	// Use fmt formatting if in float64 range (common case).
   199  	if x, _ := f.Float64(); !math.IsInf(x, 0) {
   200  		return fmt.Sprintf("%s%.6g", sign, x)
   201  	}
   202  
   203  	// Out of float64 range. Do approximate manual to decimal
   204  	// conversion to avoid precise but possibly slow Float
   205  	// formatting. The exponent is > 0 since a negative out-
   206  	// of-range exponent would have underflowed and led to 0.
   207  	// f = mant * 2**exp
   208  	var mant big.Float
   209  	exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
   210  
   211  	// approximate float64 mantissa m and decimal exponent d
   212  	// f ~ m * 10**d
   213  	m, _ := mant.Float64()            // 0.5 <= m < 1.0
   214  	d := exp * (math.Ln2 / math.Ln10) // log_10(2)
   215  
   216  	// adjust m for truncated (integer) decimal exponent e
   217  	e := int64(d)
   218  	m *= math.Pow(10, d-float64(e))
   219  	for m >= 10 {
   220  		m /= 10
   221  		e++
   222  	}
   223  
   224  	return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
   225  }