rounder.go 10.0 KB

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