Source File
num.go
Belonging Package
src.elv.sh/pkg/eval/vals
package valsimport ()// Design notes://// The choice and relationship of number types in Elvish is closely modelled// after R6RS's numerical tower (with the omission of complex types for now). In// fact, there is a 1:1 correspondence between number types in Elvish and a// typical R6RS implementation (the list below uses Chez Scheme's terminology;// see https://www.scheme.com/csug8/numeric.html)://// int : fixnum// *big.Int : bignum// *big.Rat : ratnum// float64 : flonum//// Similar to Chez Scheme, *big.Int is only used for representing integers// outside the range of int, and *big.Rat is only used for representing// non-integer rationals. Furthermore, *big.Rat values are always in simplest// form (this is guaranteed by the math/big library). As a consequence, each// number in Elvish only has a single unique representation.//// Note that the only machine-native integer type included in the system is int.// This is done primarily for the uniqueness of representation for each number,// but also for simplicity - the vast majority of Go functions that take// machine-native integers take int. When there is a genuine need to work with// other machine-native integer types, you may have to manually convert from and// to *big.Int and check for the relevant range of integers.// Num is a stand-in type for int, *big.Int, *big.Rat or float64. This type// doesn't offer type safety, but is useful as a marker; for example, it is// respected when parsing function arguments.type Num interface{}// NumSlice is a stand-in type for []int, []*big.Int, []*big.Rat or []float64.// This type doesn't offer type safety, but is useful as a marker.type NumSlice interface{}// ParseNum parses a string into a suitable number type. If the string does not// represent a valid number, it returns nil.func ( string) Num {if strings.ContainsRune(, '/') {// Parse as big.Ratif , := new(big.Rat).SetString(); {return NormalizeBigRat()}return nil}// Try parsing as big.Intif , := new(big.Int).SetString(, 0); {return NormalizeBigInt()}// Try parsing as float64if , := strconv.ParseFloat(, 64); == nil {return}return nil}// NumType represents a number type.type NumType uint8// Possible values for NumType, sorted in the order of implicit conversion// (lower types can be implicitly converted to higher types).const (Int NumType = iotaBigIntBigRatFloat64)// UnifyNums unifies the given slice of numbers into the same type, converting// those with lower NumType to the higest NumType present in the slice. The typ// argument can be used to force the minimum NumType.func ( []Num, NumType) NumSlice {for , := range {if := getNumType(); > {=}}switch {case Int::= make([]int, len())for , := range {[] = .(int)}returncase BigInt::= make([]*big.Int, len())for , := range {switch num := .(type) {case int:[] = big.NewInt(int64())case *big.Int:[] =default:panic("unreachable")}}returncase BigRat::= make([]*big.Rat, len())for , := range {switch num := .(type) {case int:[] = big.NewRat(int64(), 1)case *big.Int:var big.Rat.SetInt()[] = &case *big.Rat:[] =default:panic("unreachable")}}returncase Float64::= make([]float64, len())for , := range {switch num := .(type) {case int:[] = float64()case *big.Int:if .IsInt64() {// Might fit in float64[] = float64(.Int64())} else {// Definitely won't fit in float64[] = math.Inf(.Sign())}case *big.Rat:[], _ = .Float64()case float64:[] =default:panic("unreachable")}}returndefault:panic("unreachable")}}func ( Num) NumType {switch .(type) {case int:return Intcase *big.Int:return BigIntcase *big.Rat:return BigRatcase float64:return Float64default:panic("invalid num type " + fmt.Sprintf("%T", ))}}// NormalizeBigInt converts a big.Int to an int if it is within the range of// int. Otherwise it returns n as is.func ( *big.Int) Num {if , := getInt(); {return}return}// NormalizeBigRat converts a big.Rat to a big.Int (or an int if within the// range) if its denominator is 1.func ( *big.Rat) Num {if .IsInt() {:= .Num()if , := getInt(); {return}return}return}func ( *big.Int) (int, bool) {// TODO: Use a more efficient implementation by examining z.Bitsif .IsInt64() {:= .Int64():= int()if int64() == {return , true}}return -1, false}
The pages are generated with Golds v0.2.8-preview. (GOOS=darwin GOARCH=arm64)