// Copyright 2016 The Cockroach Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. package apd import ( "errors" "fmt" "strconv" "strings" "unsafe" "database/sql/driver" ) // Decimal is an arbitrary-precision decimal. Its value is: // // Negative × Coeff × 10**Exponent // // Coeff must be positive. If it is negative results may be incorrect and // apd may panic. type Decimal struct { Form Form Negative bool Exponent int32 Coeff BigInt } // Form specifies the form of a Decimal. type Form int8 const ( // These constants must be in the following order. CmpTotal assumes that // the order of these constants reflects the total order on decimals. // Finite is the finite form. Finite Form = iota // Infinite is the infinite form. Infinite // NaNSignaling is the signaling NaN form. It will always raise the // InvalidOperation condition during an operation. NaNSignaling // NaN is the NaN form. NaN ) var ( decimalNaN = &Decimal{Form: NaN} decimalInfinity = &Decimal{Form: Infinite} ) //go:generate stringer -type=Form const ( // TODO(mjibson): MaxExponent is set because both upscale and Round // perform a calculation of 10^x, where x is an exponent. This is done by // big.Int.Exp. This restriction could be lifted if better algorithms were // determined during upscale and Round that don't need to perform Exp. // MaxExponent is the highest exponent supported. Exponents near this range will // perform very slowly (many seconds per operation). MaxExponent = 100000 // MinExponent is the lowest exponent supported with the same limitations as // MaxExponent. MinExponent = -MaxExponent ) // New creates a new decimal with the given coefficient and exponent. func New(coeff int64, exponent int32) *Decimal { d := new(Decimal) d.SetFinite(coeff, exponent) return d } // NewWithBigInt creates a new decimal with the given coefficient and exponent. func NewWithBigInt(coeff *BigInt, exponent int32) *Decimal { d := new(Decimal) d.Coeff.Set(coeff) if d.Coeff.Sign() < 0 { d.Negative = true d.Coeff.Abs(&d.Coeff) } d.Exponent = exponent return d } func consumePrefix(s, prefix string) (string, bool) { if strings.HasPrefix(s, prefix) { return s[len(prefix):], true } return s, false } func (d *Decimal) setString(c *Context, s string) (Condition, error) { orig := s s, d.Negative = consumePrefix(s, "-") if !d.Negative { s, _ = consumePrefix(s, "+") } s = strings.ToLower(s) d.Exponent = 0 d.Coeff.SetInt64(0) // Until there are no parse errors, leave as NaN. d.Form = NaN if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "+") { return 0, fmt.Errorf("could not parse: %s", orig) } switch s { case "infinity", "inf": d.Form = Infinite return 0, nil } isNaN := false s, consumed := consumePrefix(s, "nan") if consumed { isNaN = true } s, consumed = consumePrefix(s, "snan") if consumed { isNaN = true d.Form = NaNSignaling } if isNaN { if s != "" { // We ignore these digits, but must verify them. _, err := strconv.ParseUint(s, 10, 64) if err != nil { return 0, fmt.Errorf("parse payload: %s: %w", s, err) } } return 0, nil } exps := make([]int64, 0, 2) if i := strings.IndexByte(s, 'e'); i >= 0 { exp, err := strconv.ParseInt(s[i+1:], 10, 32) if err != nil { return 0, fmt.Errorf("parse exponent: %s: %w", s[i+1:], err) } exps = append(exps, exp) s = s[:i] } if i := strings.IndexByte(s, '.'); i >= 0 { exp := int64(len(s) - i - 1) exps = append(exps, -exp) s = s[:i] + s[i+1:] } if _, ok := d.Coeff.SetString(s, 10); !ok { return 0, fmt.Errorf("parse mantissa: %s", s) } // No parse errors, can now flag as finite. d.Form = Finite return c.goError(d.setExponent(c, unknownNumDigits, 0, exps...)) } // NewFromString creates a new decimal from s. It has no restrictions on // exponents or precision. func NewFromString(s string) (*Decimal, Condition, error) { return BaseContext.NewFromString(s) } // SetString sets d to s and returns d. It has no restrictions on exponents // or precision. func (d *Decimal) SetString(s string) (*Decimal, Condition, error) { return BaseContext.SetString(d, s) } // NewFromString creates a new decimal from s. The returned Decimal has its // exponents restricted by the context and its value rounded if it contains more // digits than the context's precision. func (c *Context) NewFromString(s string) (*Decimal, Condition, error) { d := new(Decimal) return c.SetString(d, s) } // SetString sets d to s and returns d. The returned Decimal has its exponents // restricted by the context and its value rounded if it contains more digits // than the context's precision. func (c *Context) SetString(d *Decimal, s string) (*Decimal, Condition, error) { res, err := d.setString(c, s) if err != nil { return nil, 0, err } res |= c.round(d, d) _, err = c.goError(res) return d, res, err } // Set sets d's fields to the values of x and returns d. // //gcassert:inline func (d *Decimal) Set(x *Decimal) *Decimal { if d == x { return d } return d.setSlow(x) } // setSlow is split from Set to allow the aliasing fast-path to be // inlined in callers. func (d *Decimal) setSlow(x *Decimal) *Decimal { d.Form = x.Form d.Negative = x.Negative d.Exponent = x.Exponent d.Coeff.Set(&x.Coeff) return d } // SetInt64 sets d to x and returns d. func (d *Decimal) SetInt64(x int64) *Decimal { return d.SetFinite(x, 0) } // SetFinite sets d to x with exponent e and returns d. func (d *Decimal) SetFinite(x int64, e int32) *Decimal { d.setCoefficient(x) d.Exponent = e return d } // setCoefficient sets d's coefficient and negative value to x and its Form // to Finite The exponent is not changed. Since the exponent is not changed // (and this is thus easy to misuse), this is unexported for internal use only. func (d *Decimal) setCoefficient(x int64) { d.Negative = x < 0 d.Coeff.SetInt64(x) d.Coeff.Abs(&d.Coeff) d.Form = Finite } // SetFloat64 sets d's Coefficient and Exponent to x and returns d. d will // hold the exact value of f. func (d *Decimal) SetFloat64(f float64) (*Decimal, error) { var buf [32]byte // Avoid most of the allocations in strconv. _, _, err := d.SetString(string(strconv.AppendFloat(buf[:0], f, 'E', -1, 64))) return d, err } // Int64 returns the int64 representation of x. If x cannot be represented in an // int64, an error is returned. func (d *Decimal) Int64() (int64, error) { if d.Form != Finite { return 0, fmt.Errorf("%s is not finite", d.String()) } var integ, frac Decimal d.Modf(&integ, &frac) if !frac.IsZero() { return 0, fmt.Errorf("%s: has fractional part", d.String()) } var ed ErrDecimal if integ.Cmp(decimalMaxInt64) > 0 { return 0, fmt.Errorf("%s: greater than max int64", d.String()) } if integ.Cmp(decimalMinInt64) < 0 { return 0, fmt.Errorf("%s: less than min int64", d.String()) } if err := ed.Err(); err != nil { return 0, err } v := integ.Coeff.Int64() for i := int32(0); i < integ.Exponent; i++ { v *= 10 } if d.Negative { v = -v } return v, nil } // Float64 returns the float64 representation of x. This conversion may lose // data (see strconv.ParseFloat for caveats). func (d *Decimal) Float64() (float64, error) { return strconv.ParseFloat(d.String(), 64) } const ( errExponentOutOfRangeStr = "exponent out of range" unknownNumDigits = int64(-1) ) // setExponent sets d's Exponent to the sum of xs. Each value and the sum // of xs must fit within an int32. An error occurs if the sum is outside of // the MaxExponent or MinExponent range. nd is the number of digits in d, as // computed by NumDigits. Callers can pass unknownNumDigits to indicate that // they have not yet computed this digit count, in which case setExponent will // do so. res is any Condition previously set for this operation, which can // cause Underflow to be set if, for example, Inexact is already set. func (d *Decimal) setExponent(c *Context, nd int64, res Condition, xs ...int64) Condition { var sum int64 for _, x := range xs { if x > MaxExponent { return SystemOverflow | Overflow } if x < MinExponent { return SystemUnderflow | Underflow } sum += x } r := int32(sum) if nd == unknownNumDigits { nd = d.NumDigits() } // adj is the adjusted exponent: exponent + clength - 1 adj := sum + nd - 1 // Make sure it is less than the system limits. if adj > MaxExponent { return SystemOverflow | Overflow } if adj < MinExponent { return SystemUnderflow | Underflow } v := int32(adj) // d is subnormal. if v < c.MinExponent { if !d.IsZero() { res |= Subnormal } Etiny := c.MinExponent - (int32(c.Precision) - 1) // Only need to round if exponent < Etiny. if r < Etiny { // We need to take off (r - Etiny) digits. Split up d.Coeff into integer and // fractional parts and do operations similar Round. We avoid calling Round // directly because it calls setExponent and modifies the result's exponent // and coeff in ways that would be wrong here. var tmp Decimal tmp.Coeff.Set(&d.Coeff) tmp.Exponent = r - Etiny var integ, frac Decimal tmp.Modf(&integ, &frac) frac.Abs(&frac) if !frac.IsZero() { res |= Inexact if c.Rounding.ShouldAddOne(&integ.Coeff, integ.Negative, frac.Cmp(decimalHalf)) { integ.Coeff.Add(&integ.Coeff, bigOne) } } if integ.IsZero() { res |= Clamped } r = Etiny d.Coeff.Set(&integ.Coeff) res |= Rounded } } else if v > c.MaxExponent { if d.IsZero() { res |= Clamped r = c.MaxExponent } else { res |= Overflow | Inexact d.Form = Infinite } } if res.Inexact() && res.Subnormal() { res |= Underflow } d.Exponent = r return res } // upscale converts a and b to BigInts with the same scaling. It returns // them with this scaling, along with the scaling. An error can be produced // if the resulting scale factor is out of range. The tmp argument must be // provided and can be (but won't always be) one of the return values. func upscale(a, b *Decimal, tmp *BigInt) (*BigInt, *BigInt, int32, error) { if a.Exponent == b.Exponent { return &a.Coeff, &b.Coeff, a.Exponent, nil } swapped := false if a.Exponent < b.Exponent { swapped = true b, a = a, b } s := int64(a.Exponent) - int64(b.Exponent) // TODO(mjibson): figure out a better way to upscale numbers with highly // differing exponents. if s > MaxExponent { return nil, nil, 0, errors.New(errExponentOutOfRangeStr) } x := tmp e := tableExp10(s, x) x.Mul(&a.Coeff, e) y := &b.Coeff if swapped { x, y = y, x } return x, y, b.Exponent, nil } // setBig sets b to d's coefficient with negative. func (d *Decimal) setBig(b *BigInt) *BigInt { b.Set(&d.Coeff) if d.Negative { b.Neg(b) } return b } // CmpTotal compares d and x using their abstract representation rather // than their numerical value. A total ordering is defined for all possible // abstract representations, as described below. If the first operand is // lower in the total order than the second operand then the result is -1, // if the operands have the same abstract representation then the result is // 0, and if the first operand is higher in the total order than the second // operand then the result is 1. // // Numbers (representations which are not NaNs) are ordered such that a // larger numerical value is higher in the ordering. If two representations // have the same numerical value then the exponent is taken into account; // larger (more positive) exponents are higher in the ordering. // // For example, the following values are ordered from lowest to highest. Note // the difference in ordering between 1.2300 and 1.23. // // -NaN // -NaNSignaling // -Infinity // -127 // -1.00 // -1 // -0.000 // -0 // 0 // 1.2300 // 1.23 // 1E+9 // Infinity // NaNSignaling // NaN func (d *Decimal) CmpTotal(x *Decimal) int { do := d.cmpOrder() xo := x.cmpOrder() if do < xo { return -1 } if do > xo { return 1 } switch d.Form { case Finite: // d and x have the same sign and form, compare their value. if c := d.Cmp(x); c != 0 { return c } lt := -1 gt := 1 if d.Negative { lt = 1 gt = -1 } // Values are equal, compare exponents. if d.Exponent < x.Exponent { return lt } if d.Exponent > x.Exponent { return gt } return 0 case Infinite: return 0 default: return d.Coeff.Cmp(&x.Coeff) } } func (d *Decimal) cmpOrder() int { v := int(d.Form) + 1 if d.Negative { v = -v } return v } // Cmp compares x and y and sets d to: // // -1 if x < y // 0 if x == y // +1 if x > y // // This comparison respects the normal rules of special values (like NaN), // and does not compare them. func (c *Context) Cmp(d, x, y *Decimal) (Condition, error) { if c.shouldSetAsNaN(x, y) { return c.setAsNaN(d, x, y) } v := x.Cmp(y) d.SetInt64(int64(v)) return 0, nil } // Cmp compares d and x and returns: // // -1 if d < x // 0 if d == x // +1 if d > x // undefined if d or x are NaN func (d *Decimal) Cmp(x *Decimal) int { ds := d.Sign() xs := x.Sign() // First compare signs. if ds < xs { return -1 } else if ds > xs { return 1 } else if ds == 0 && xs == 0 { return 0 } // Use gt and lt here with flipped signs if d is negative. gt and lt then // allow for simpler comparisons since we can ignore the sign of the decimals // and only worry about the form and value. gt := 1 lt := -1 if ds == -1 { gt = -1 lt = 1 } if d.Form == Infinite { if x.Form == Infinite { return 0 } return gt } else if x.Form == Infinite { return lt } if d.Exponent == x.Exponent { cmp := d.Coeff.Cmp(&x.Coeff) if ds < 0 { cmp = -cmp } return cmp } // Next compare adjusted exponents. dn := d.NumDigits() + int64(d.Exponent) xn := x.NumDigits() + int64(x.Exponent) if dn < xn { return lt } else if dn > xn { return gt } // Now have to use aligned BigInts. This function previously used upscale to // align in all cases, but that requires an error in the return value. upscale // does that so that it can fail if it needs to take the Exp of too-large a // number, which is very slow. The only way for that to happen here is for d // and x's coefficients to be of hugely differing values. That is practically // more difficult, so we are assuming the user is already comfortable with // slowness in those operations. var cmp int if d.Exponent < x.Exponent { var xScaled, tmpE BigInt xScaled.Set(&x.Coeff) xScaled.Mul(&xScaled, tableExp10(int64(x.Exponent)-int64(d.Exponent), &tmpE)) cmp = d.Coeff.Cmp(&xScaled) } else { var dScaled, tmpE BigInt dScaled.Set(&d.Coeff) dScaled.Mul(&dScaled, tableExp10(int64(d.Exponent)-int64(x.Exponent), &tmpE)) cmp = dScaled.Cmp(&x.Coeff) } if ds < 0 { cmp = -cmp } return cmp } // Sign returns, if d is Finite: // // -1 if d < 0 // 0 if d == 0 or -0 // +1 if d > 0 // // Otherwise (if d is Infinite or NaN): // // -1 if d.Negative == true // +1 if d.Negative == false func (d *Decimal) Sign() int { if d.Form == Finite && d.Coeff.Sign() == 0 { return 0 } if d.Negative { return -1 } return 1 } // IsZero returns true if d == 0 or -0. func (d *Decimal) IsZero() bool { return d.Sign() == 0 } // Modf sets integ to the integral part of d and frac to the fractional part // such that d = integ+frac. If d is negative, both integ or frac will be either // 0 or negative. integ.Exponent will be >= 0; frac.Exponent will be <= 0. // Either argument can be nil, preventing it from being set. func (d *Decimal) Modf(integ, frac *Decimal) { if integ == nil && frac == nil { return } neg := d.Negative // No fractional part. if d.Exponent > 0 { if frac != nil { frac.Negative = neg frac.Exponent = 0 frac.Coeff.SetInt64(0) } if integ != nil { integ.Set(d) } return } nd := d.NumDigits() exp := -int64(d.Exponent) // d < 0 because exponent is larger than number of digits. if exp > nd { if integ != nil { integ.Negative = neg integ.Exponent = 0 integ.Coeff.SetInt64(0) } if frac != nil { frac.Set(d) } return } var tmpE BigInt e := tableExp10(exp, &tmpE) var icoeff *BigInt if integ != nil { icoeff = &integ.Coeff integ.Exponent = 0 integ.Negative = neg } else { // This is the integ == nil branch, and we already checked if both integ and // frac were nil above, so frac can never be nil in this branch. icoeff = new(BigInt) } if frac != nil { icoeff.QuoRem(&d.Coeff, e, &frac.Coeff) frac.Exponent = d.Exponent frac.Negative = neg } else { // This is the frac == nil, which means integ must not be nil since they both // can't be due to the check above. icoeff.Quo(&d.Coeff, e) } } // Neg sets d to -x and returns d. func (d *Decimal) Neg(x *Decimal) *Decimal { d.Set(x) if d.IsZero() { d.Negative = false } else { d.Negative = !d.Negative } return d } // Abs sets d to |x| and returns d. func (d *Decimal) Abs(x *Decimal) *Decimal { d.Set(x) d.Negative = false return d } // Reduce sets d to x with all trailing zeros removed and returns d and the // number of zeros removed. func (d *Decimal) Reduce(x *Decimal) (*Decimal, int) { if x.Form != Finite { d.Set(x) return d, 0 } var nd int neg := false switch x.Sign() { case 0: nd = int(d.NumDigits()) d.SetInt64(0) return d, nd - 1 case -1: neg = true } d.Set(x) // Use a uint64 for the division if possible. if d.Coeff.IsUint64() { i := d.Coeff.Uint64() for i >= 10000 && i%10000 == 0 { i /= 10000 nd += 4 } for i%10 == 0 { i /= 10 nd++ } if nd != 0 { d.Exponent += int32(nd) d.Coeff.SetUint64(i) d.Negative = neg } return d, nd } // Divide by 10 in a loop. In benchmarks of reduce0.decTest, this is 20% // faster than converting to a string and trimming the 0s from the end. var z, r BigInt d.setBig(&z) for { z.QuoRem(&d.Coeff, bigTen, &r) if r.Sign() == 0 { d.Coeff.Set(&z) nd++ } else { break } } d.Exponent += int32(nd) return d, nd } const decimalSize = unsafe.Sizeof(Decimal{}) // Size returns the total memory footprint of d in bytes. func (d *Decimal) Size() uintptr { return decimalSize - bigIntSize + d.Coeff.Size() } // Value implements the database/sql/driver.Valuer interface. It converts d to a // string. func (d Decimal) Value() (driver.Value, error) { return d.String(), nil } // Scan implements the database/sql.Scanner interface. It supports string, // []byte, int64, float64. func (d *Decimal) Scan(src interface{}) error { switch src := src.(type) { case []byte: _, _, err := d.SetString(string(src)) return err case string: _, _, err := d.SetString(src) return err case int64: d.SetInt64(src) return nil case float64: _, err := d.SetFloat64(src) return err default: return fmt.Errorf("could not convert %T to Decimal", src) } } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (d *Decimal) UnmarshalText(b []byte) error { _, _, err := d.SetString(string(b)) return err } // MarshalText implements the encoding.TextMarshaler interface. func (d *Decimal) MarshalText() ([]byte, error) { if d == nil { return []byte(""), nil } return []byte(d.String()), nil } // NullDecimal represents a string that may be null. NullDecimal implements // the database/sql.Scanner interface so it can be used as a scan destination: // // var d NullDecimal // err := db.QueryRow("SELECT num FROM foo WHERE id=?", id).Scan(&d) // ... // if d.Valid { // // use d.Decimal // } else { // // NULL value // } type NullDecimal struct { Decimal Decimal Valid bool // Valid is true if Decimal is not NULL } // Scan implements the database/sql.Scanner interface. func (nd *NullDecimal) Scan(value interface{}) error { if value == nil { nd.Valid = false return nil } nd.Valid = true return nd.Decimal.Scan(value) } // Value implements the database/sql/driver.Valuer interface. func (nd NullDecimal) Value() (driver.Value, error) { if !nd.Valid { return nil, nil } return nd.Decimal.Value() }