rounder.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package inf
  2. import (
  3. "math/big"
  4. )
  5. // Rounder represents a method for rounding the (possibly infinite decimal)
  6. // result of a division to a finite Dec. It is used by Dec.Round() and
  7. // Dec.Quo().
  8. //
  9. // See the Example for results of using each Rounder with some sample values.
  10. //
  11. type Rounder rounder
  12. type rounder interface {
  13. // When UseRemainder() returns true, the Round() method is passed the
  14. // remainder of the division, expressed as the numerator and denominator of
  15. // a rational.
  16. UseRemainder() bool
  17. // Round sets the rounded value of a quotient to z, and returns z.
  18. // quo is rounded down (truncated towards zero) to the scale obtained from
  19. // the Scaler in Quo().
  20. //
  21. // When the remainder is not used, remNum and remDen are nil.
  22. // When used, the remainder is normalized between -1 and 1; that is:
  23. //
  24. // -|remDen| < remNum < |remDen|
  25. //
  26. // remDen has the same sign as y, and remNum is zero or has the same sign
  27. // as x.
  28. Round(z, quo *Dec, remNum, remDen *big.Int) *Dec
  29. }
  30. type rndr struct {
  31. useRem bool
  32. round func(z, quo *Dec, remNum, remDen *big.Int) *Dec
  33. }
  34. func (r rndr) UseRemainder() bool {
  35. return r.useRem
  36. }
  37. func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec {
  38. return r.round(z, quo, remNum, remDen)
  39. }
  40. // RoundExact returns quo if rem is zero, or nil otherwise. It is intended to
  41. // be used with ScaleQuoExact when it is guaranteed that the result can be
  42. // obtained without rounding. QuoExact is a shorthand for such a quotient
  43. // operation.
  44. //
  45. var RoundExact Rounder = roundExact
  46. // RoundDown rounds towards 0; that is, returns the Dec with the greatest
  47. // absolute value not exceeding that of the result represented by quo and rem.
  48. //
  49. var RoundDown Rounder = roundDown
  50. // RoundUp rounds away from 0; that is, returns the Dec with the smallest
  51. // absolute value not smaller than that of the result represented by quo and
  52. // rem.
  53. //
  54. var RoundUp Rounder = roundUp
  55. // RoundHalfDown rounds to the nearest Dec, and when the remainder is 1/2, it
  56. // rounds to the Dec with the lower absolute value.
  57. //
  58. var RoundHalfDown Rounder = roundHalfDown
  59. // RoundHalfUp rounds to the nearest Dec, and when the remainder is 1/2, it
  60. // rounds to the Dec with the greater absolute value.
  61. //
  62. var RoundHalfUp Rounder = roundHalfUp
  63. // RoundHalfEven rounds to the nearest Dec, and when the remainder is 1/2, it
  64. // rounds to the Dec with even last digit.
  65. //
  66. var RoundHalfEven Rounder = roundHalfEven
  67. // RoundFloor rounds towards negative infinity; that is, returns the greatest
  68. // Dec not exceeding the result represented by quo and rem.
  69. //
  70. var RoundFloor Rounder = roundFloor
  71. // RoundCeil rounds towards positive infinity; that is, returns the
  72. // smallest Dec not smaller than the result represented by quo and rem.
  73. //
  74. var RoundCeil Rounder = roundCeil
  75. var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)}
  76. var roundExact = rndr{true,
  77. func(z, q *Dec, rA, rB *big.Int) *Dec {
  78. if rA.Sign() != 0 {
  79. return nil
  80. }
  81. return z.Set(q)
  82. }}
  83. var roundDown = rndr{false,
  84. func(z, q *Dec, rA, rB *big.Int) *Dec {
  85. return z.Set(q)
  86. }}
  87. var roundUp = rndr{true,
  88. func(z, q *Dec, rA, rB *big.Int) *Dec {
  89. z.Set(q)
  90. if rA.Sign() != 0 {
  91. z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1])
  92. }
  93. return z
  94. }}
  95. func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec {
  96. return func(z, q *Dec, rA, rB *big.Int) *Dec {
  97. z.Set(q)
  98. brA, brB := rA.BitLen(), rB.BitLen()
  99. if brA < brB-1 {
  100. // brA < brB-1 => |rA| < |rB/2|
  101. return z
  102. }
  103. roundUp := false
  104. srA, srB := rA.Sign(), rB.Sign()
  105. s := srA * srB
  106. if brA == brB-1 {
  107. rA2 := new(big.Int).Lsh(rA, 1)
  108. if s < 0 {
  109. rA2.Neg(rA2)
  110. }
  111. roundUp = f(rA2.Cmp(rB)*srB, z.UnscaledBig().Bit(0))
  112. } else {
  113. // brA > brB-1 => |rA| > |rB/2|
  114. roundUp = true
  115. }
  116. if roundUp {
  117. z.UnscaledBig().Add(z.UnscaledBig(), intSign[s+1])
  118. }
  119. return z
  120. }
  121. }
  122. var roundHalfDown = rndr{true, roundHalf(
  123. func(c int, odd uint) bool {
  124. return c > 0
  125. })}
  126. var roundHalfUp = rndr{true, roundHalf(
  127. func(c int, odd uint) bool {
  128. return c >= 0
  129. })}
  130. var roundHalfEven = rndr{true, roundHalf(
  131. func(c int, odd uint) bool {
  132. return c > 0 || c == 0 && odd == 1
  133. })}
  134. var roundFloor = rndr{true,
  135. func(z, q *Dec, rA, rB *big.Int) *Dec {
  136. z.Set(q)
  137. if rA.Sign()*rB.Sign() < 0 {
  138. z.UnscaledBig().Add(z.UnscaledBig(), intSign[0])
  139. }
  140. return z
  141. }}
  142. var roundCeil = rndr{true,
  143. func(z, q *Dec, rA, rB *big.Int) *Dec {
  144. z.Set(q)
  145. if rA.Sign()*rB.Sign() > 0 {
  146. z.UnscaledBig().Add(z.UnscaledBig(), intSign[2])
  147. }
  148. return z
  149. }}