github.com/solo-io/cue@v0.4.7/internal/core/adt/decimal.go (about) 1 // Copyright 2020 CUE Authors 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 adt 16 17 import ( 18 "math/big" 19 20 "github.com/cockroachdb/apd/v2" 21 ) 22 23 var apdCtx apd.Context 24 25 func init() { 26 apdCtx = apd.BaseContext 27 apdCtx.Precision = 24 28 } 29 30 func (n *Num) Impl() *apd.Decimal { 31 return &n.X 32 } 33 34 func (n *Num) Negative() bool { 35 return n.X.Negative 36 } 37 38 func (a *Num) Cmp(b *Num) int { 39 return a.X.Cmp(&b.X) 40 } 41 42 func (c *OpContext) Add(a, b *Num) Value { 43 return numOp(c, apdCtx.Add, a, b) 44 } 45 46 func (c *OpContext) Sub(a, b *Num) Value { 47 return numOp(c, apdCtx.Sub, a, b) 48 } 49 50 func (c *OpContext) Mul(a, b *Num) Value { 51 return numOp(c, apdCtx.Mul, a, b) 52 } 53 54 func (c *OpContext) Quo(a, b *Num) Value { 55 v := numOp(c, apdCtx.Quo, a, b) 56 if n, ok := v.(*Num); ok { 57 n.K = FloatKind 58 } 59 return v 60 } 61 62 func (c *OpContext) Pow(a, b *Num) Value { 63 return numOp(c, apdCtx.Pow, a, b) 64 } 65 66 type numFunc func(z, x, y *apd.Decimal) (apd.Condition, error) 67 68 func numOp(c *OpContext, fn numFunc, x, y *Num) Value { 69 var d apd.Decimal 70 71 cond, err := fn(&d, &x.X, &y.X) 72 73 if err != nil { 74 return c.NewErrf("failed arithmetic: %v", err) 75 } 76 77 if cond.DivisionByZero() { 78 return c.NewErrf("division by zero") 79 } 80 81 k := x.Kind() & y.Kind() 82 if k == 0 { 83 k = FloatKind 84 } 85 return c.newNum(&d, k) 86 } 87 88 func (c *OpContext) IntDiv(a, b *Num) Value { 89 return intDivOp(c, (*big.Int).Div, a, b) 90 } 91 92 func (c *OpContext) IntMod(a, b *Num) Value { 93 return intDivOp(c, (*big.Int).Mod, a, b) 94 } 95 96 func (c *OpContext) IntQuo(a, b *Num) Value { 97 return intDivOp(c, (*big.Int).Quo, a, b) 98 } 99 100 func (c *OpContext) IntRem(a, b *Num) Value { 101 return intDivOp(c, (*big.Int).Rem, a, b) 102 } 103 104 type intFunc func(z, x, y *big.Int) *big.Int 105 106 func intDivOp(c *OpContext, fn intFunc, a, b *Num) Value { 107 if b.X.IsZero() { 108 return c.NewErrf("division by zero") 109 } 110 111 var x, y apd.Decimal 112 _, _ = apdCtx.RoundToIntegralValue(&x, &a.X) 113 if x.Negative { 114 x.Coeff.Neg(&x.Coeff) 115 } 116 _, _ = apdCtx.RoundToIntegralValue(&y, &b.X) 117 if y.Negative { 118 y.Coeff.Neg(&y.Coeff) 119 } 120 121 var d apd.Decimal 122 123 fn(&d.Coeff, &x.Coeff, &y.Coeff) 124 125 if d.Coeff.Sign() < 0 { 126 d.Coeff.Neg(&d.Coeff) 127 d.Negative = true 128 } 129 130 return c.newNum(&d, IntKind) 131 }