1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package apd
16
17
18
19
20 func (c *Context) Round(d, x *Decimal) (Condition, error) {
21 return c.goError(c.round(d, x))
22 }
23
24
25 func (c *Context) round(d, x *Decimal) Condition {
26 return c.Rounding.Round(c, d, x, true )
27 }
28
29
30 type Rounder string
31
32
33
34
35
36 func (r Rounder) ShouldAddOne(result *BigInt, neg bool, half int) bool {
37
38
39 switch r {
40 case RoundDown:
41 return roundDown(result, neg, half)
42 case RoundHalfUp:
43 return roundHalfUp(result, neg, half)
44 case RoundHalfEven:
45 return roundHalfEven(result, neg, half)
46 case RoundCeiling:
47 return roundCeiling(result, neg, half)
48 case RoundFloor:
49 return roundFloor(result, neg, half)
50 case RoundHalfDown:
51 return roundHalfDown(result, neg, half)
52 case RoundUp:
53 return roundUp(result, neg, half)
54 case Round05Up:
55 return round05Up(result, neg, half)
56 default:
57 return roundHalfUp(result, neg, half)
58 }
59 }
60
61
62 func (r Rounder) Round(c *Context, d, x *Decimal, disableIfPrecisionZero bool) Condition {
63 d.Set(x)
64 nd := x.NumDigits()
65 xs := x.Sign()
66 var res Condition
67
68 if disableIfPrecisionZero && c.Precision == 0 {
69
70 return d.setExponent(c, nd, res, int64(d.Exponent))
71 }
72
73
74 if adj := int64(x.Exponent) + nd - 1; xs != 0 && adj < int64(c.MinExponent) {
75
76 res |= Subnormal
77
78 res |= d.setExponent(c, nd, res, int64(d.Exponent))
79 return res
80 }
81
82 diff := nd - int64(c.Precision)
83 if diff > 0 {
84 if diff > MaxExponent {
85 return SystemOverflow | Overflow
86 }
87 if diff < MinExponent {
88 return SystemUnderflow | Underflow
89 }
90 res |= Rounded
91 var y, m BigInt
92 e := tableExp10(diff, &y)
93 y.QuoRem(&d.Coeff, e, &m)
94 if m.Sign() != 0 {
95 res |= Inexact
96 var discard Decimal
97 discard.Coeff.Set(&m)
98 discard.Exponent = int32(-diff)
99 if r.ShouldAddOne(&y, x.Negative, discard.Cmp(decimalHalf)) {
100 roundAddOne(&y, &diff)
101 }
102 }
103 d.Coeff.Set(&y)
104
105 nd = unknownNumDigits
106 } else {
107 diff = 0
108 }
109 res |= d.setExponent(c, nd, res, int64(d.Exponent), diff)
110 return res
111 }
112
113
114 func roundAddOne(b *BigInt, diff *int64) {
115 if b.Sign() < 0 {
116 panic("unexpected negative")
117 }
118 nd := NumDigits(b)
119 b.Add(b, bigOne)
120 nd2 := NumDigits(b)
121 if nd2 > nd {
122 b.Quo(b, bigTen)
123 *diff++
124 }
125 }
126
127
128 var roundings = map[Rounder]struct{}{
129 RoundDown: {},
130 RoundHalfUp: {},
131 RoundHalfEven: {},
132 RoundCeiling: {},
133 RoundFloor: {},
134 RoundHalfDown: {},
135 RoundUp: {},
136 Round05Up: {},
137 }
138
139 const (
140
141 RoundDown Rounder = "down"
142
143 RoundHalfUp Rounder = "half_up"
144
145
146
147 RoundHalfEven Rounder = "half_even"
148
149
150 RoundCeiling Rounder = "ceiling"
151
152
153 RoundFloor Rounder = "floor"
154
155 RoundHalfDown Rounder = "half_down"
156
157 RoundUp Rounder = "up"
158
159
160 Round05Up Rounder = "05up"
161 )
162
163 func roundDown(result *BigInt, neg bool, half int) bool {
164 return false
165 }
166
167 func roundUp(result *BigInt, neg bool, half int) bool {
168 return true
169 }
170
171 func round05Up(result *BigInt, neg bool, half int) bool {
172 var z BigInt
173 z.Rem(result, bigFive)
174 if z.Sign() == 0 {
175 return true
176 }
177 z.Rem(result, bigTen)
178 return z.Sign() == 0
179 }
180
181 func roundHalfUp(result *BigInt, neg bool, half int) bool {
182 return half >= 0
183 }
184
185 func roundHalfEven(result *BigInt, neg bool, half int) bool {
186 if half > 0 {
187 return true
188 }
189 if half < 0 {
190 return false
191 }
192 return result.Bit(0) == 1
193 }
194
195 func roundHalfDown(result *BigInt, neg bool, half int) bool {
196 return half > 0
197 }
198
199 func roundFloor(result *BigInt, neg bool, half int) bool {
200 return neg
201 }
202
203 func roundCeiling(result *BigInt, neg bool, half int) bool {
204 return !neg
205 }
206
View as plain text