1
2
3
4
5
6
7
8
9
10
11
12
13
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 }
124
View as plain text