1package inf 2 3import ( 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// 13type Rounder rounder 14 15// See http://speleotrove.com/decimal/damodel.html#refround for more detailed 16// definitions of these rounding modes. 17var ( 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. 31var RoundExact Rounder 32 33type 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 54type rndr struct { 55 useRem bool 56 round func(z, quo *Dec, remNum, remDen *big.Int) *Dec 57} 58 59func (r rndr) UseRemainder() bool { 60 return r.useRem 61} 62 63func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec { 64 return r.round(z, quo, remNum, remDen) 65} 66 67var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)} 68 69func 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 97func 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