2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
2015-05-21 13:28:10 -04:00
|
|
|
"cmd/compile/internal/big"
|
2015-03-26 18:07:19 -07:00
|
|
|
"cmd/internal/obj"
|
2015-02-13 14:40:36 -05:00
|
|
|
"fmt"
|
|
|
|
|
"math"
|
|
|
|
|
)
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
/// implements float arihmetic
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
func newMpflt() *Mpflt {
|
|
|
|
|
var a Mpflt
|
2015-03-26 18:07:19 -07:00
|
|
|
a.Val.SetPrec(Mpprec)
|
2015-03-20 16:59:08 -07:00
|
|
|
return &a
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
func Mpmovefixflt(a *Mpflt, b *Mpint) {
|
|
|
|
|
if b.Ovf {
|
|
|
|
|
// sign doesn't really matter but copy anyway
|
|
|
|
|
a.Val.SetInf(b.Val.Sign() < 0)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
a.Val.SetInt(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mpmovefltflt(a *Mpflt, b *Mpflt) {
|
|
|
|
|
a.Val.Set(&b.Val)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
func mpaddfltflt(a *Mpflt, b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\n%v + %v", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Add(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
func mpaddcflt(a *Mpflt, c float64) {
|
|
|
|
|
var b Mpflt
|
|
|
|
|
|
|
|
|
|
Mpmovecflt(&b, c)
|
|
|
|
|
mpaddfltflt(a, &b)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mpsubfltflt(a *Mpflt, b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("\n%v - %v", a, b)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Sub(&a.Val, &b.Val)
|
|
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func mpmulfltflt(a *Mpflt, b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("%v\n * %v\n", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Mul(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
func mpmulcflt(a *Mpflt, c float64) {
|
|
|
|
|
var b Mpflt
|
|
|
|
|
|
|
|
|
|
Mpmovecflt(&b, c)
|
|
|
|
|
mpmulfltflt(a, &b)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func mpdivfltflt(a *Mpflt, b *Mpflt) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("%v\n / %v\n", a, b)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.Quo(&a.Val, &b.Val)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
|
|
|
|
|
return a.Val.Cmp(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mpcmpfltc(b *Mpflt, c float64) int {
|
|
|
|
|
var a Mpflt
|
|
|
|
|
|
|
|
|
|
Mpmovecflt(&a, c)
|
|
|
|
|
return mpcmpfltflt(b, &a)
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-22 11:31:47 -07:00
|
|
|
func mpgetflt(a *Mpflt) float64 {
|
|
|
|
|
x, _ := a.Val.Float64()
|
2015-03-20 16:59:08 -07:00
|
|
|
|
|
|
|
|
// check for overflow
|
|
|
|
|
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("mpgetflt ovf")
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
return x + 0 // avoid -0 (should not be needed, but be conservative)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mpgetflt32(a *Mpflt) float64 {
|
2015-05-22 11:31:47 -07:00
|
|
|
x32, _ := a.Val.Float32()
|
|
|
|
|
x := float64(x32)
|
|
|
|
|
|
|
|
|
|
// check for overflow
|
|
|
|
|
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
|
|
|
|
|
Yyerror("mpgetflt32 ovf")
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
return x + 0 // avoid -0 (should not be needed, but be conservative)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Mpmovecflt(a *Mpflt, c float64) {
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-02-13 14:40:36 -05:00
|
|
|
fmt.Printf("\nconst %g", c)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-20 14:45:36 -07:00
|
|
|
// convert -0 to 0
|
|
|
|
|
if c == 0 {
|
|
|
|
|
c = 0
|
|
|
|
|
}
|
2015-03-20 16:59:08 -07:00
|
|
|
a.Val.SetFloat64(c)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
if Mpdebug {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf(" = %v\n", a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mpnegflt(a *Mpflt) {
|
2015-10-20 14:45:36 -07:00
|
|
|
// avoid -0
|
|
|
|
|
if a.Val.Sign() != 0 {
|
|
|
|
|
a.Val.Neg(&a.Val)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-26 18:07:19 -07:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// floating point input
|
|
|
|
|
// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
|
|
|
|
|
//
|
|
|
|
|
func mpatoflt(a *Mpflt, as string) {
|
|
|
|
|
for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
|
|
|
|
|
as = as[1:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f, ok := a.Val.SetString(as)
|
|
|
|
|
if !ok {
|
|
|
|
|
// At the moment we lose precise error cause;
|
|
|
|
|
// the old code additionally distinguished between:
|
|
|
|
|
// - malformed hex constant
|
|
|
|
|
// - decimal point in hex constant
|
|
|
|
|
// - constant exponent out of range
|
|
|
|
|
// - decimal point and binary point in constant
|
|
|
|
|
// TODO(gri) use different conversion function or check separately
|
|
|
|
|
Yyerror("malformed constant: %s", as)
|
2015-10-20 14:45:36 -07:00
|
|
|
a.Val.SetFloat64(0)
|
2015-06-28 23:25:38 -04:00
|
|
|
return
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if f.IsInf() {
|
|
|
|
|
Yyerror("constant too large: %s", as)
|
2015-10-20 14:45:36 -07:00
|
|
|
a.Val.SetFloat64(0)
|
2015-06-28 23:25:38 -04:00
|
|
|
return
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2015-10-20 14:45:36 -07:00
|
|
|
|
|
|
|
|
// -0 becomes 0
|
|
|
|
|
if f.Sign() == 0 && f.Signbit() {
|
|
|
|
|
a.Val.SetFloat64(0)
|
|
|
|
|
}
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (f *Mpflt) String() string {
|
|
|
|
|
return Fconv(f, 0)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
func Fconv(fvp *Mpflt, flag int) string {
|
2015-04-03 17:50:37 -07:00
|
|
|
if flag&obj.FmtSharp == 0 {
|
2015-06-03 15:11:05 -07:00
|
|
|
return fvp.Val.Text('b', 0)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2015-04-03 17:50:37 -07:00
|
|
|
|
|
|
|
|
// use decimal format for error messages
|
|
|
|
|
|
|
|
|
|
// determine sign
|
|
|
|
|
f := &fvp.Val
|
|
|
|
|
var sign string
|
2015-10-20 14:45:36 -07:00
|
|
|
if f.Sign() < 0 {
|
2015-04-03 17:50:37 -07:00
|
|
|
sign = "-"
|
|
|
|
|
f = new(big.Float).Abs(f)
|
|
|
|
|
} else if flag&obj.FmtSign != 0 {
|
|
|
|
|
sign = "+"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use fmt formatting if in float64 range (common case).
|
|
|
|
|
if x, _ := f.Float64(); !math.IsInf(x, 0) {
|
|
|
|
|
return fmt.Sprintf("%s%.6g", sign, x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Out of float64 range. Do approximate manual to decimal
|
|
|
|
|
// conversion to avoid precise but possibly slow Float
|
|
|
|
|
// formatting. The exponent is > 0 since a negative out-
|
|
|
|
|
// of-range exponent would have underflowed and led to 0.
|
|
|
|
|
// f = mant * 2**exp
|
|
|
|
|
var mant big.Float
|
|
|
|
|
exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
|
|
|
|
|
|
|
|
|
|
// approximate float64 mantissa m and decimal exponent d
|
|
|
|
|
// f ~ m * 10**d
|
|
|
|
|
m, _ := mant.Float64() // 0.5 <= m < 1.0
|
|
|
|
|
d := exp * (math.Ln2 / math.Ln10) // log_10(2)
|
|
|
|
|
|
|
|
|
|
// adjust m for truncated (integer) decimal exponent e
|
|
|
|
|
e := int64(d)
|
|
|
|
|
m *= math.Pow(10, d-float64(e))
|
|
|
|
|
for m >= 10 {
|
|
|
|
|
m /= 10
|
|
|
|
|
e++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|