Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / gopkg.in / inf.v0 / rounder.go
1 package inf
2
3 import (
4         "math/big"
5 )
6
7 // Rounder represents a method for rounding the (possibly infinite decimal)
8 // result of a division to a finite Dec. It is used by Dec.Round() and
9 // Dec.Quo().
10 //
11 // See the Example for results of using each Rounder with some sample values.
12 //
13 type Rounder rounder
14
15 // See http://speleotrove.com/decimal/damodel.html#refround for more detailed
16 // definitions of these rounding modes.
17 var (
18         RoundDown     Rounder // towards 0
19         RoundUp       Rounder // away from 0
20         RoundFloor    Rounder // towards -infinity
21         RoundCeil     Rounder // towards +infinity
22         RoundHalfDown Rounder // to nearest; towards 0 if same distance
23         RoundHalfUp   Rounder // to nearest; away from 0 if same distance
24         RoundHalfEven Rounder // to nearest; even last digit if same distance
25 )
26
27 // RoundExact is to be used in the case when rounding is not necessary.
28 // When used with Quo or Round, it returns the result verbatim when it can be
29 // expressed exactly with the given precision, and it returns nil otherwise.
30 // QuoExact is a shorthand for using Quo with RoundExact.
31 var RoundExact Rounder
32
33 type rounder interface {
34
35         // When UseRemainder() returns true, the Round() method is passed the
36         // remainder of the division, expressed as the numerator and denominator of
37         // a rational.
38         UseRemainder() bool
39
40         // Round sets the rounded value of a quotient to z, and returns z.
41         // quo is rounded down (truncated towards zero) to the scale obtained from
42         // the Scaler in Quo().
43         //
44         // When the remainder is not used, remNum and remDen are nil.
45         // When used, the remainder is normalized between -1 and 1; that is:
46         //
47         //  -|remDen| < remNum < |remDen|
48         //
49         // remDen has the same sign as y, and remNum is zero or has the same sign
50         // as x.
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                         // brA < brB-1 => |rA| < |rB/2|
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                         // brA > brB-1 => |rA| > |rB/2|
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 }