rounder.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. type Rounder interface {
  10. // When UseRemainder() returns true, the Round() method is passed the
  11. // remainder of the division, expressed as the numerator and denominator of
  12. // a rational.
  13. UseRemainder() bool
  14. // Round sets the rounded value of a quotient to z, and returns z.
  15. // quo is rounded down (truncated towards zero) to the scale obtained from
  16. // the Scaler in Quo().
  17. //
  18. // When the remainder is not used, remNum and remDen are nil.
  19. // When used, the remainder is normalized between -1 and 1; that is:
  20. //
  21. // -|remDen| < remNum < |remDen|
  22. //
  23. // remDen has the same sign as y, and remNum is zero or has the same sign
  24. // as x.
  25. Round(z, quo *Dec, remNum, remDen *big.Int) *Dec
  26. }
  27. type rounder struct {
  28. useRem bool
  29. round func(z, quo *Dec, remNum, remDen *big.Int) *Dec
  30. }
  31. func (r rounder) UseRemainder() bool {
  32. return r.useRem
  33. }
  34. func (r rounder) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec {
  35. return r.round(z, quo, remNum, remDen)
  36. }
  37. // RoundExact returns quo if rem is zero, or nil otherwise. It is intended to
  38. // be used with ScaleQuoExact when it is guaranteed that the result can be
  39. // obtained without rounding. QuoExact is a shorthand for such a quotient
  40. // operation.
  41. //
  42. var RoundExact Rounder = roundExact
  43. // RoundDown rounds towards 0; that is, returns the Dec with the greatest
  44. // absolute value not exceeding that of the result represented by quo and rem.
  45. //
  46. // The following table shows examples of the results for
  47. // Quo(x, y, Scale(scale), RoundDown).
  48. //
  49. // x y scale result
  50. // ------------------------------
  51. // -1.8 10 1 -0.1
  52. // -1.5 10 1 -0.1
  53. // -1.2 10 1 -0.1
  54. // -1.0 10 1 -0.1
  55. // -0.8 10 1 -0.0
  56. // -0.5 10 1 -0.0
  57. // -0.2 10 1 -0.0
  58. // 0.0 10 1 0.0
  59. // 0.2 10 1 0.0
  60. // 0.5 10 1 0.0
  61. // 0.8 10 1 0.0
  62. // 1.0 10 1 0.1
  63. // 1.2 10 1 0.1
  64. // 1.5 10 1 0.1
  65. // 1.8 10 1 0.1
  66. //
  67. var RoundDown Rounder = roundDown
  68. // RoundUp rounds away from 0; that is, returns the Dec with the smallest
  69. // absolute value not smaller than that of the result represented by quo and
  70. // rem.
  71. //
  72. // The following table shows examples of the results for
  73. // Quo(x, y, Scale(scale), RoundUp).
  74. //
  75. // x y scale result
  76. // ------------------------------
  77. // -1.8 10 1 -0.2
  78. // -1.5 10 1 -0.2
  79. // -1.2 10 1 -0.2
  80. // -1.0 10 1 -0.1
  81. // -0.8 10 1 -0.1
  82. // -0.5 10 1 -0.1
  83. // -0.2 10 1 -0.1
  84. // 0.0 10 1 0.0
  85. // 0.2 10 1 0.1
  86. // 0.5 10 1 0.1
  87. // 0.8 10 1 0.1
  88. // 1.0 10 1 0.1
  89. // 1.2 10 1 0.2
  90. // 1.5 10 1 0.2
  91. // 1.8 10 1 0.2
  92. //
  93. var RoundUp Rounder = roundUp
  94. // RoundHalfDown rounds to the nearest Dec, and when the remainder is 1/2, it
  95. // rounds to the Dec with the lower absolute value.
  96. //
  97. // The following table shows examples of the results for
  98. // Quo(x, y, Scale(scale), RoundHalfDown).
  99. //
  100. // x y scale result
  101. // ------------------------------
  102. // -1.8 10 1 -0.2
  103. // -1.5 10 1 -0.1
  104. // -1.2 10 1 -0.1
  105. // -1.0 10 1 -0.1
  106. // -0.8 10 1 -0.1
  107. // -0.5 10 1 -0.0
  108. // -0.2 10 1 -0.0
  109. // 0.0 10 1 0.0
  110. // 0.2 10 1 0.0
  111. // 0.5 10 1 0.0
  112. // 0.8 10 1 0.1
  113. // 1.0 10 1 0.1
  114. // 1.2 10 1 0.1
  115. // 1.5 10 1 0.1
  116. // 1.8 10 1 0.2
  117. //
  118. var RoundHalfDown Rounder = roundHalfDown
  119. // RoundHalfUp rounds to the nearest Dec, and when the remainder is 1/2, it
  120. // rounds to the Dec with the greater absolute value.
  121. //
  122. // The following table shows examples of the results for
  123. // Quo(x, y, Scale(scale), RoundHalfUp).
  124. //
  125. // x y scale result
  126. // ------------------------------
  127. // -1.8 10 1 -0.2
  128. // -1.5 10 1 -0.2
  129. // -1.2 10 1 -0.1
  130. // -1.0 10 1 -0.1
  131. // -0.8 10 1 -0.1
  132. // -0.5 10 1 -0.1
  133. // -0.2 10 1 -0.0
  134. // 0.0 10 1 0.0
  135. // 0.2 10 1 0.0
  136. // 0.5 10 1 0.1
  137. // 0.8 10 1 0.1
  138. // 1.0 10 1 0.1
  139. // 1.2 10 1 0.1
  140. // 1.5 10 1 0.2
  141. // 1.8 10 1 0.2
  142. //
  143. var RoundHalfUp Rounder = roundHalfUp
  144. // RoundHalfEven rounds to the nearest Dec, and when the remainder is 1/2, it
  145. // rounds to the Dec with even last digit.
  146. //
  147. // The following table shows examples of the results for
  148. // Quo(x, y, Scale(scale), RoundHalfEven).
  149. //
  150. // x y scale result
  151. // ------------------------------
  152. // -1.8 10 1 -0.2
  153. // -1.5 10 1 -0.2
  154. // -1.2 10 1 -0.1
  155. // -1.0 10 1 -0.1
  156. // -0.8 10 1 -0.1
  157. // -0.5 10 1 -0.0
  158. // -0.2 10 1 -0.0
  159. // 0.0 10 1 0.0
  160. // 0.2 10 1 0.0
  161. // 0.5 10 1 0.0
  162. // 0.8 10 1 0.1
  163. // 1.0 10 1 0.1
  164. // 1.2 10 1 0.1
  165. // 1.5 10 1 0.2
  166. // 1.8 10 1 0.2
  167. //
  168. var RoundHalfEven Rounder = roundHalfEven
  169. // RoundFloor rounds towards negative infinity; that is, returns the greatest
  170. // Dec not exceeding the result represented by quo and rem.
  171. //
  172. // The following table shows examples of the results for
  173. // Quo(x, y, Scale(scale), RoundFloor).
  174. //
  175. // x y scale result
  176. // ------------------------------
  177. // -1.8 10 1 -0.2
  178. // -1.5 10 1 -0.2
  179. // -1.2 10 1 -0.2
  180. // -1.0 10 1 -0.1
  181. // -0.8 10 1 -0.1
  182. // -0.5 10 1 -0.1
  183. // -0.2 10 1 -0.1
  184. // 0.0 10 1 0.0
  185. // 0.2 10 1 0.0
  186. // 0.5 10 1 0.0
  187. // 0.8 10 1 0.0
  188. // 1.0 10 1 0.1
  189. // 1.2 10 1 0.1
  190. // 1.5 10 1 0.1
  191. // 1.8 10 1 0.1
  192. //
  193. var RoundFloor Rounder = roundFloor
  194. // RoundCeil rounds towards positive infinity; that is, returns the
  195. // smallest Dec not smaller than the result represented by quo and rem.
  196. //
  197. // The following table shows examples of the results for
  198. // Quo(x, y, Scale(scale), RoundCeil).
  199. //
  200. // x y scale result
  201. // ------------------------------
  202. // -1.8 10 1 -0.1
  203. // -1.5 10 1 -0.1
  204. // -1.2 10 1 -0.1
  205. // -1.0 10 1 -0.1
  206. // -0.8 10 1 -0.0
  207. // -0.5 10 1 -0.0
  208. // -0.2 10 1 -0.0
  209. // 0.0 10 1 0.0
  210. // 0.2 10 1 0.1
  211. // 0.5 10 1 0.1
  212. // 0.8 10 1 0.1
  213. // 1.0 10 1 0.1
  214. // 1.2 10 1 0.2
  215. // 1.5 10 1 0.2
  216. // 1.8 10 1 0.2
  217. //
  218. var RoundCeil Rounder = roundCeil
  219. var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)}
  220. var roundExact = rounder{true,
  221. func(z, q *Dec, rA, rB *big.Int) *Dec {
  222. if rA.Sign() != 0 {
  223. return nil
  224. }
  225. return z.move(q)
  226. }}
  227. var roundDown = rounder{false,
  228. func(z, q *Dec, rA, rB *big.Int) *Dec {
  229. return z.move(q)
  230. }}
  231. var roundUp = rounder{true,
  232. func(z, q *Dec, rA, rB *big.Int) *Dec {
  233. z.move(q)
  234. if rA.Sign() != 0 {
  235. z.Unscaled().Add(z.Unscaled(), intSign[rA.Sign()*rB.Sign()+1])
  236. }
  237. return z
  238. }}
  239. func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec {
  240. return func(z, q *Dec, rA, rB *big.Int) *Dec {
  241. z.move(q)
  242. brA, brB := rA.BitLen(), rB.BitLen()
  243. if brA < brB-1 {
  244. // brA < brB-1 => |rA| < |rB/2|
  245. return z
  246. }
  247. roundUp := false
  248. srA, srB := rA.Sign(), rB.Sign()
  249. s := srA * srB
  250. if brA == brB-1 {
  251. rA2 := new(big.Int).Lsh(rA, 1)
  252. if s < 0 {
  253. rA2.Neg(rA2)
  254. }
  255. roundUp = f(rA2.Cmp(rB)*srB, z.Unscaled().Bit(0))
  256. } else {
  257. // brA > brB-1 => |rA| > |rB/2|
  258. roundUp = true
  259. }
  260. if roundUp {
  261. z.Unscaled().Add(z.Unscaled(), intSign[s+1])
  262. }
  263. return z
  264. }
  265. }
  266. var roundHalfDown = rounder{true, roundHalf(
  267. func(c int, odd uint) bool {
  268. return c > 0
  269. })}
  270. var roundHalfUp = rounder{true, roundHalf(
  271. func(c int, odd uint) bool {
  272. return c >= 0
  273. })}
  274. var roundHalfEven = rounder{true, roundHalf(
  275. func(c int, odd uint) bool {
  276. return c > 0 || c == 0 && odd == 1
  277. })}
  278. var roundFloor = rounder{true,
  279. func(z, q *Dec, rA, rB *big.Int) *Dec {
  280. z.move(q)
  281. if rA.Sign()*rB.Sign() < 0 {
  282. z.Unscaled().Add(z.Unscaled(), intSign[0])
  283. }
  284. return z
  285. }}
  286. var roundCeil = rounder{true,
  287. func(z, q *Dec, rA, rB *big.Int) *Dec {
  288. z.move(q)
  289. if rA.Sign()*rB.Sign() > 0 {
  290. z.Unscaled().Add(z.Unscaled(), intSign[2])
  291. }
  292. return z
  293. }}