1 package inf
2
3 import (
4 "math/big"
5 )
6
7
8
9
10
11
12
13 type Rounder rounder
14
15
16
17 var (
18 RoundDown Rounder
19 RoundUp Rounder
20 RoundFloor Rounder
21 RoundCeil Rounder
22 RoundHalfDown Rounder
23 RoundHalfUp Rounder
24 RoundHalfEven Rounder
25 )
26
27
28
29
30
31 var RoundExact Rounder
32
33 type rounder interface {
34
35
36
37
38 UseRemainder() bool
39
40
41
42
43
44
45
46
47
48
49
50
51 Round(z, quo *Dec, remNum, remDen *big.Int) *Dec
52 }
53
54 type rndr struct {
55 useRem bool
56 round func(z, quo *Dec, remNum, remDen *big.Int) *Dec
57 }
58
59 func (r rndr) UseRemainder() bool {
60 return r.useRem
61 }
62
63 func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec {
64 return r.round(z, quo, remNum, remDen)
65 }
66
67 var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)}
68
69 func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec {
70 return func(z, q *Dec, rA, rB *big.Int) *Dec {
71 z.Set(q)
72 brA, brB := rA.BitLen(), rB.BitLen()
73 if brA < brB-1 {
74
75 return z
76 }
77 roundUp := false
78 srA, srB := rA.Sign(), rB.Sign()
79 s := srA * srB
80 if brA == brB-1 {
81 rA2 := new(big.Int).Lsh(rA, 1)
82 if s < 0 {
83 rA2.Neg(rA2)
84 }
85 roundUp = f(rA2.Cmp(rB)*srB, z.UnscaledBig().Bit(0))
86 } else {
87
88 roundUp = true
89 }
90 if roundUp {
91 z.UnscaledBig().Add(z.UnscaledBig(), intSign[s+1])
92 }
93 return z
94 }
95 }
96
97 func init() {
98 RoundExact = rndr{true,
99 func(z, q *Dec, rA, rB *big.Int) *Dec {
100 if rA.Sign() != 0 {
101 return nil
102 }
103 return z.Set(q)
104 }}
105 RoundDown = rndr{false,
106 func(z, q *Dec, rA, rB *big.Int) *Dec {
107 return z.Set(q)
108 }}
109 RoundUp = rndr{true,
110 func(z, q *Dec, rA, rB *big.Int) *Dec {
111 z.Set(q)
112 if rA.Sign() != 0 {
113 z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1])
114 }
115 return z
116 }}
117 RoundFloor = rndr{true,
118 func(z, q *Dec, rA, rB *big.Int) *Dec {
119 z.Set(q)
120 if rA.Sign()*rB.Sign() < 0 {
121 z.UnscaledBig().Add(z.UnscaledBig(), intSign[0])
122 }
123 return z
124 }}
125 RoundCeil = rndr{true,
126 func(z, q *Dec, rA, rB *big.Int) *Dec {
127 z.Set(q)
128 if rA.Sign()*rB.Sign() > 0 {
129 z.UnscaledBig().Add(z.UnscaledBig(), intSign[2])
130 }
131 return z
132 }}
133 RoundHalfDown = rndr{true, roundHalf(
134 func(c int, odd uint) bool {
135 return c > 0
136 })}
137 RoundHalfUp = rndr{true, roundHalf(
138 func(c int, odd uint) bool {
139 return c >= 0
140 })}
141 RoundHalfEven = rndr{true, roundHalf(
142 func(c int, odd uint) bool {
143 return c > 0 || c == 0 && odd == 1
144 })}
145 }
146
View as plain text