github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/float.go (about)

     1  // Copyright 2016 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package grumpy
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  	"math/big"
    21  	"reflect"
    22  	"strconv"
    23  	"strings"
    24  	"sync/atomic"
    25  	"unicode"
    26  	"unsafe"
    27  )
    28  
    29  // FloatType is the object representing the Python 'float' type.
    30  var FloatType = newBasisType("float", reflect.TypeOf(Float{}), toFloatUnsafe, ObjectType)
    31  
    32  // Float represents Python 'float' objects.
    33  type Float struct {
    34  	Object
    35  	value float64
    36  	hash  int
    37  }
    38  
    39  // NewFloat returns a new Float holding the given floating point value.
    40  func NewFloat(value float64) *Float {
    41  	return &Float{Object: Object{typ: FloatType}, value: value}
    42  }
    43  
    44  func toFloatUnsafe(o *Object) *Float {
    45  	return (*Float)(o.toPointer())
    46  }
    47  
    48  // ToObject upcasts f to an Object.
    49  func (f *Float) ToObject() *Object {
    50  	return &f.Object
    51  }
    52  
    53  // Value returns the underlying floating point value held by f.
    54  func (f *Float) Value() float64 {
    55  	return f.value
    56  }
    57  
    58  func floatAbs(f *Frame, o *Object) (*Object, *BaseException) {
    59  	z := toFloatUnsafe(o).Value()
    60  	return NewFloat(math.Abs(z)).ToObject(), nil
    61  }
    62  
    63  func floatAdd(f *Frame, v, w *Object) (*Object, *BaseException) {
    64  	return floatArithmeticOp(f, "__add__", v, w, func(v, w float64) float64 { return v + w })
    65  }
    66  
    67  func floatDiv(f *Frame, v, w *Object) (*Object, *BaseException) {
    68  	return floatDivModOp(f, "__div__", v, w, func(v, w float64) (float64, bool) {
    69  		if w == 0.0 {
    70  			return 0, false
    71  		}
    72  		return v / w, true
    73  	})
    74  }
    75  
    76  func floatDivMod(f *Frame, v, w *Object) (*Object, *BaseException) {
    77  	return floatDivAndModOp(f, "__divmod__", v, w, func(v, w float64) (float64, float64, bool) {
    78  		m, r := floatModFunc(v, w)
    79  		if !r {
    80  			return 0, 0, false
    81  		}
    82  		return math.Floor(v / w), m, true
    83  	})
    84  }
    85  
    86  func floatEq(f *Frame, v, w *Object) (*Object, *BaseException) {
    87  	return floatCompare(toFloatUnsafe(v), w, False, True, False), nil
    88  }
    89  
    90  func floatFloat(f *Frame, o *Object) (*Object, *BaseException) {
    91  	return o, nil
    92  }
    93  
    94  func floatFloorDiv(f *Frame, v, w *Object) (*Object, *BaseException) {
    95  	return floatDivModOp(f, "__floordiv__", v, w, func(v, w float64) (float64, bool) {
    96  		if w == 0.0 {
    97  			return 0, false
    98  		}
    99  		return math.Floor(v / w), true
   100  	})
   101  }
   102  
   103  func floatGE(f *Frame, v, w *Object) (*Object, *BaseException) {
   104  	return floatCompare(toFloatUnsafe(v), w, False, True, True), nil
   105  }
   106  
   107  func floatGetNewArgs(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
   108  	if raised := checkMethodArgs(f, "__getnewargs__", args, FloatType); raised != nil {
   109  		return nil, raised
   110  	}
   111  	return NewTuple1(args[0]).ToObject(), nil
   112  }
   113  
   114  func floatGT(f *Frame, v, w *Object) (*Object, *BaseException) {
   115  	return floatCompare(toFloatUnsafe(v), w, False, False, True), nil
   116  }
   117  
   118  func floatHash(f *Frame, o *Object) (*Object, *BaseException) {
   119  	v := toFloatUnsafe(o)
   120  	p := (*unsafe.Pointer)(unsafe.Pointer(&v.hash))
   121  	if lp := atomic.LoadPointer(p); lp != unsafe.Pointer(nil) {
   122  		return (*Int)(lp).ToObject(), nil
   123  	}
   124  	hash := hashFloat(v.Value())
   125  	if hash == -1 {
   126  		hash--
   127  	}
   128  	h := NewInt(hash)
   129  	atomic.StorePointer(p, unsafe.Pointer(h))
   130  
   131  	return h.ToObject(), nil
   132  }
   133  
   134  func floatInt(f *Frame, o *Object) (*Object, *BaseException) {
   135  	val := toFloatUnsafe(o).Value()
   136  	if math.IsInf(val, 0) {
   137  		return nil, f.RaiseType(OverflowErrorType, "cannot convert float infinity to integer")
   138  	}
   139  	if math.IsNaN(val) {
   140  		return nil, f.RaiseType(OverflowErrorType, "cannot convert float NaN to integer")
   141  	}
   142  	i := big.Int{}
   143  	big.NewFloat(val).Int(&i)
   144  	if !numInIntRange(&i) {
   145  		return NewLong(&i).ToObject(), nil
   146  	}
   147  	return NewInt(int(i.Int64())).ToObject(), nil
   148  }
   149  
   150  func floatLong(f *Frame, o *Object) (*Object, *BaseException) {
   151  	val := toFloatUnsafe(o).Value()
   152  	if math.IsInf(val, 0) {
   153  		return nil, f.RaiseType(OverflowErrorType, "cannot convert float infinity to integer")
   154  	}
   155  	if math.IsNaN(val) {
   156  		return nil, f.RaiseType(OverflowErrorType, "cannot convert float NaN to integer")
   157  	}
   158  	i, _ := big.NewFloat(val).Int(nil)
   159  	return NewLong(i).ToObject(), nil
   160  }
   161  
   162  func floatLE(f *Frame, v, w *Object) (*Object, *BaseException) {
   163  	return floatCompare(toFloatUnsafe(v), w, True, True, False), nil
   164  }
   165  
   166  func floatLT(f *Frame, v, w *Object) (*Object, *BaseException) {
   167  	return floatCompare(toFloatUnsafe(v), w, True, False, False), nil
   168  }
   169  
   170  func floatMod(f *Frame, v, w *Object) (*Object, *BaseException) {
   171  	return floatDivModOp(f, "__mod__", v, w, floatModFunc)
   172  }
   173  
   174  func floatMul(f *Frame, v, w *Object) (*Object, *BaseException) {
   175  	return floatArithmeticOp(f, "__mul__", v, w, func(v, w float64) float64 { return v * w })
   176  }
   177  
   178  func floatNative(f *Frame, o *Object) (reflect.Value, *BaseException) {
   179  	return reflect.ValueOf(toFloatUnsafe(o).Value()), nil
   180  }
   181  
   182  func floatNE(f *Frame, v, w *Object) (*Object, *BaseException) {
   183  	return floatCompare(toFloatUnsafe(v), w, True, False, True), nil
   184  }
   185  
   186  func floatNeg(f *Frame, o *Object) (*Object, *BaseException) {
   187  	z := toFloatUnsafe(o).Value()
   188  	return NewFloat(-z).ToObject(), nil
   189  }
   190  
   191  func floatNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) {
   192  	argc := len(args)
   193  	if argc == 0 {
   194  		return newObject(t), nil
   195  	}
   196  	if argc != 1 {
   197  		return nil, f.RaiseType(TypeErrorType, "'__new__' of 'float' requires 0 or 1 arguments")
   198  	}
   199  	if t != FloatType {
   200  		// Allocate a plain float then copy it's value into an object
   201  		// of the float subtype.
   202  		x, raised := floatNew(f, FloatType, args, nil)
   203  		if raised != nil {
   204  			return nil, raised
   205  		}
   206  		result := toFloatUnsafe(newObject(t))
   207  		result.value = toFloatUnsafe(x).Value()
   208  		return result.ToObject(), nil
   209  	}
   210  	o := args[0]
   211  	if floatSlot := o.typ.slots.Float; floatSlot != nil {
   212  		fl, raised := floatConvert(floatSlot, f, o)
   213  		if raised != nil {
   214  			return nil, raised
   215  		}
   216  		return fl.ToObject(), nil
   217  	}
   218  	if !o.isInstance(StrType) {
   219  		return nil, f.RaiseType(TypeErrorType, "float() argument must be a string or a number")
   220  	}
   221  	s := toStrUnsafe(o).Value()
   222  	result, err := strconv.ParseFloat(s, 64)
   223  	if err != nil {
   224  		return nil, f.RaiseType(ValueErrorType, fmt.Sprintf("could not convert string to float: %s", s))
   225  	}
   226  	return NewFloat(result).ToObject(), nil
   227  }
   228  
   229  func floatNonZero(f *Frame, o *Object) (*Object, *BaseException) {
   230  	return GetBool(toFloatUnsafe(o).Value() != 0).ToObject(), nil
   231  }
   232  
   233  func floatPos(f *Frame, o *Object) (*Object, *BaseException) {
   234  	return o, nil
   235  }
   236  
   237  func floatPow(f *Frame, v, w *Object) (*Object, *BaseException) {
   238  	return floatArithmeticOp(f, "__pow__", v, w, func(v, w float64) float64 { return math.Pow(v, w) })
   239  }
   240  
   241  func floatRAdd(f *Frame, v, w *Object) (*Object, *BaseException) {
   242  	return floatArithmeticOp(f, "__radd__", v, w, func(v, w float64) float64 { return w + v })
   243  }
   244  
   245  func floatRDiv(f *Frame, v, w *Object) (*Object, *BaseException) {
   246  	return floatDivModOp(f, "__rdiv__", v, w, func(v, w float64) (float64, bool) {
   247  		if v == 0.0 {
   248  			return 0, false
   249  		}
   250  		return w / v, true
   251  	})
   252  }
   253  
   254  func floatRDivMod(f *Frame, v, w *Object) (*Object, *BaseException) {
   255  	return floatDivAndModOp(f, "__rdivmod__", v, w, func(v, w float64) (float64, float64, bool) {
   256  		m, r := floatModFunc(w, v)
   257  		if !r {
   258  			return 0, 0, false
   259  		}
   260  		return w / v, m, true
   261  	})
   262  }
   263  
   264  const (
   265  	floatReprPrecision = 16
   266  	floatStrPrecision  = 12
   267  )
   268  
   269  func floatRepr(f *Frame, o *Object) (*Object, *BaseException) {
   270  	return NewStr(floatToString(toFloatUnsafe(o).Value(), floatReprPrecision)).ToObject(), nil
   271  }
   272  
   273  func floatRFloorDiv(f *Frame, v, w *Object) (*Object, *BaseException) {
   274  	return floatDivModOp(f, "__rfloordiv__", v, w, func(v, w float64) (float64, bool) {
   275  		if v == 0.0 {
   276  			return 0, false
   277  		}
   278  		return math.Floor(w / v), true
   279  	})
   280  }
   281  
   282  func floatRMod(f *Frame, v, w *Object) (*Object, *BaseException) {
   283  	return floatDivModOp(f, "__rmod__", v, w, func(v, w float64) (float64, bool) {
   284  		return floatModFunc(w, v)
   285  	})
   286  }
   287  
   288  func floatRMul(f *Frame, v, w *Object) (*Object, *BaseException) {
   289  	return floatArithmeticOp(f, "__rmul__", v, w, func(v, w float64) float64 { return w * v })
   290  }
   291  
   292  func floatRPow(f *Frame, v, w *Object) (*Object, *BaseException) {
   293  	return floatArithmeticOp(f, "__rpow", v, w, func(v, w float64) float64 { return math.Pow(w, v) })
   294  }
   295  
   296  func floatRSub(f *Frame, v, w *Object) (*Object, *BaseException) {
   297  	return floatArithmeticOp(f, "__rsub__", v, w, func(v, w float64) float64 { return w - v })
   298  }
   299  
   300  func floatStr(f *Frame, o *Object) (*Object, *BaseException) {
   301  	return NewStr(floatToString(toFloatUnsafe(o).Value(), floatStrPrecision)).ToObject(), nil
   302  }
   303  
   304  func floatSub(f *Frame, v, w *Object) (*Object, *BaseException) {
   305  	return floatArithmeticOp(f, "__sub__", v, w, func(v, w float64) float64 { return v - w })
   306  }
   307  
   308  func initFloatType(dict map[string]*Object) {
   309  	dict["__getnewargs__"] = newBuiltinFunction("__getnewargs__", floatGetNewArgs).ToObject()
   310  	FloatType.slots.Abs = &unaryOpSlot{floatAbs}
   311  	FloatType.slots.Add = &binaryOpSlot{floatAdd}
   312  	FloatType.slots.Div = &binaryOpSlot{floatDiv}
   313  	FloatType.slots.DivMod = &binaryOpSlot{floatDivMod}
   314  	FloatType.slots.Eq = &binaryOpSlot{floatEq}
   315  	FloatType.slots.Float = &unaryOpSlot{floatFloat}
   316  	FloatType.slots.FloorDiv = &binaryOpSlot{floatFloorDiv}
   317  	FloatType.slots.GE = &binaryOpSlot{floatGE}
   318  	FloatType.slots.GT = &binaryOpSlot{floatGT}
   319  	FloatType.slots.Hash = &unaryOpSlot{floatHash}
   320  	FloatType.slots.Int = &unaryOpSlot{floatInt}
   321  	FloatType.slots.Long = &unaryOpSlot{floatLong}
   322  	FloatType.slots.LE = &binaryOpSlot{floatLE}
   323  	FloatType.slots.LT = &binaryOpSlot{floatLT}
   324  	FloatType.slots.Mod = &binaryOpSlot{floatMod}
   325  	FloatType.slots.Mul = &binaryOpSlot{floatMul}
   326  	FloatType.slots.Native = &nativeSlot{floatNative}
   327  	FloatType.slots.NE = &binaryOpSlot{floatNE}
   328  	FloatType.slots.Neg = &unaryOpSlot{floatNeg}
   329  	FloatType.slots.New = &newSlot{floatNew}
   330  	FloatType.slots.NonZero = &unaryOpSlot{floatNonZero}
   331  	FloatType.slots.Pos = &unaryOpSlot{floatPos}
   332  	FloatType.slots.Pow = &binaryOpSlot{floatPow}
   333  	FloatType.slots.RAdd = &binaryOpSlot{floatRAdd}
   334  	FloatType.slots.RDiv = &binaryOpSlot{floatRDiv}
   335  	FloatType.slots.RDivMod = &binaryOpSlot{floatRDivMod}
   336  	FloatType.slots.Repr = &unaryOpSlot{floatRepr}
   337  	FloatType.slots.RFloorDiv = &binaryOpSlot{floatRFloorDiv}
   338  	FloatType.slots.RMod = &binaryOpSlot{floatRMod}
   339  	FloatType.slots.RMul = &binaryOpSlot{floatRMul}
   340  	FloatType.slots.RPow = &binaryOpSlot{floatRPow}
   341  	FloatType.slots.RSub = &binaryOpSlot{floatRSub}
   342  	FloatType.slots.Str = &unaryOpSlot{floatStr}
   343  	FloatType.slots.Sub = &binaryOpSlot{floatSub}
   344  }
   345  
   346  func floatArithmeticOp(f *Frame, method string, v, w *Object, fun func(v, w float64) float64) (*Object, *BaseException) {
   347  	floatW, ok := floatCoerce(w)
   348  	if !ok {
   349  		if math.IsInf(floatW, 0) {
   350  			return nil, f.RaiseType(OverflowErrorType, "long int too large to convert to float")
   351  		}
   352  		return NotImplemented, nil
   353  	}
   354  	return NewFloat(fun(toFloatUnsafe(v).Value(), floatW)).ToObject(), nil
   355  }
   356  
   357  func floatCompare(v *Float, w *Object, ltResult, eqResult, gtResult *Int) *Object {
   358  	lhs := v.Value()
   359  	rhs, ok := floatCoerce(w)
   360  	if !ok {
   361  		if !math.IsInf(rhs, 0) {
   362  			return NotImplemented
   363  		}
   364  		// When floatCoerce returns (Inf, false) it indicates an
   365  		// overflow - abs(rhs) is between MaxFloat64 and Inf.
   366  		// When comparing with infinite floats, rhs might as well be 0.
   367  		// Otherwise, let the compare proceed normally as |rhs| might
   368  		// as well be infinite, since it's outside the range of finite
   369  		// floats.
   370  		if math.IsInf(lhs, 0) {
   371  			rhs = 0
   372  		}
   373  	}
   374  	if lhs < rhs {
   375  		return ltResult.ToObject()
   376  	}
   377  	if lhs == rhs {
   378  		return eqResult.ToObject()
   379  	}
   380  	if lhs > rhs {
   381  		return gtResult.ToObject()
   382  	}
   383  	// There must be a NaN involved, which always compares false, even to other NaNs.
   384  	// This is true both in Go and in Python.
   385  	return False.ToObject()
   386  }
   387  
   388  // floatCoerce will coerce any numeric type to a float. If all is
   389  // well, it will return the float64 value, and true (OK). If an overflow
   390  // occurs, it will return either (+Inf, false) or (-Inf, false) depending
   391  // on whether the source value was too large or too small. Note that if the
   392  // source number is an infinite float, the result will be infinite without
   393  // overflow, (+-Inf, true).
   394  // If the input is not a number, it will return (0, false).
   395  func floatCoerce(o *Object) (float64, bool) {
   396  	switch {
   397  	case o.isInstance(IntType):
   398  		return float64(toIntUnsafe(o).Value()), true
   399  	case o.isInstance(LongType):
   400  		f, _ := new(big.Float).SetInt(toLongUnsafe(o).Value()).Float64()
   401  		// If f is infinite, that indicates the big.Int was too large
   402  		// or too small to be represented as a float64. In that case,
   403  		// indicate the overflow by returning (f, false).
   404  		overflow := math.IsInf(f, 0)
   405  		return f, !overflow
   406  	case o.isInstance(FloatType):
   407  		return toFloatUnsafe(o).Value(), true
   408  	default:
   409  		return 0, false
   410  	}
   411  }
   412  
   413  func floatConvert(floatSlot *unaryOpSlot, f *Frame, o *Object) (*Float, *BaseException) {
   414  	result, raised := floatSlot.Fn(f, o)
   415  	if raised != nil {
   416  		return nil, raised
   417  	}
   418  	if !result.isInstance(FloatType) {
   419  		exc := fmt.Sprintf("__float__ returned non-float (type %s)", result.typ.Name())
   420  		return nil, f.RaiseType(TypeErrorType, exc)
   421  	}
   422  	return toFloatUnsafe(result), nil
   423  }
   424  
   425  func floatDivModOp(f *Frame, method string, v, w *Object, fun func(v, w float64) (float64, bool)) (*Object, *BaseException) {
   426  	floatW, ok := floatCoerce(w)
   427  	if !ok {
   428  		if math.IsInf(floatW, 0) {
   429  			return nil, f.RaiseType(OverflowErrorType, "long int too large to convert to float")
   430  		}
   431  		return NotImplemented, nil
   432  	}
   433  	x, ok := fun(toFloatUnsafe(v).Value(), floatW)
   434  	if !ok {
   435  		return nil, f.RaiseType(ZeroDivisionErrorType, "float division or modulo by zero")
   436  	}
   437  	return NewFloat(x).ToObject(), nil
   438  }
   439  
   440  func floatDivAndModOp(f *Frame, method string, v, w *Object, fun func(v, w float64) (float64, float64, bool)) (*Object, *BaseException) {
   441  	floatW, ok := floatCoerce(w)
   442  	if !ok {
   443  		if math.IsInf(floatW, 0) {
   444  			return nil, f.RaiseType(OverflowErrorType, "long int too large to convert to float")
   445  		}
   446  		return NotImplemented, nil
   447  	}
   448  	q, m, ok := fun(toFloatUnsafe(v).Value(), floatW)
   449  	if !ok {
   450  		return nil, f.RaiseType(ZeroDivisionErrorType, "float division or modulo by zero")
   451  	}
   452  	return NewTuple2(NewFloat(q).ToObject(), NewFloat(m).ToObject()).ToObject(), nil
   453  }
   454  
   455  func hashFloat(v float64) int {
   456  	if math.IsNaN(v) {
   457  		return 0
   458  	}
   459  
   460  	if math.IsInf(v, 0) {
   461  		if math.IsInf(v, 1) {
   462  			return 314159
   463  		}
   464  		if math.IsInf(v, -1) {
   465  			return -271828
   466  		}
   467  		return 0
   468  	}
   469  
   470  	_, fracPart := math.Modf(v)
   471  	if fracPart == 0.0 {
   472  		i := big.Int{}
   473  		big.NewFloat(v).Int(&i)
   474  		if numInIntRange(&i) {
   475  			return int(i.Int64())
   476  		}
   477  		// TODO: hashBigInt() is not yet matched that of cpython or pypy.
   478  		return hashBigInt(&i)
   479  	}
   480  
   481  	v, expo := math.Frexp(v)
   482  	v *= 2147483648.0
   483  	hiPart := int(v)
   484  	v = (v - float64(hiPart)) * 2147483648.0
   485  	x := int(hiPart + int(v) + (expo << 15))
   486  	return x
   487  }
   488  
   489  func floatModFunc(v, w float64) (float64, bool) {
   490  	if w == 0.0 {
   491  		return 0, false
   492  	}
   493  	x := math.Mod(v, w)
   494  	if x != 0 && math.Signbit(x) != math.Signbit(w) {
   495  		// In Python the result of the modulo operator is
   496  		// always the same sign as the divisor, whereas in Go,
   497  		// the result is always the same sign as the dividend.
   498  		// Therefore we need to do an adjustment when the sign
   499  		// of the modulo result differs from that of the
   500  		// divisor.
   501  		x += w
   502  	}
   503  	return x, true
   504  }
   505  
   506  func floatToString(f float64, p int) string {
   507  	s := unsignPositiveInf(strings.ToLower(strconv.FormatFloat(f, 'g', p, 64)))
   508  	fun := func(r rune) bool {
   509  		return !unicode.IsDigit(r)
   510  	}
   511  	if i := strings.IndexFunc(s, fun); i == -1 {
   512  		s += ".0"
   513  	}
   514  	return s
   515  }
   516  
   517  func unsignPositiveInf(s string) string {
   518  	if s == "+inf" {
   519  		return "inf"
   520  	}
   521  	return s
   522  }