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