1. # XXX: should be Rational[Int, uint]
  2. my class Rat is Cool does Rational[Int, Int] {
  3. method Rat (Rat:D: Real $?) { self }
  4. method FatRat(Rat:D: Real $?) { FatRat.new($!numerator, $!denominator); }
  5. multi method perl(Rat:D:) {
  6. if $!denominator == 1 {
  7. $!numerator ~ '.0'
  8. }
  9. else {
  10. my $d = $!denominator;
  11. unless $d == 0 {
  12. $d = $d div 5 while $d %% 5;
  13. $d = $d div 2 while $d %% 2;
  14. self.REDUCE-ME;
  15. }
  16. if $d == 1 and (my $b := self.base(10,*)).Numeric === self {
  17. $b;
  18. }
  19. else {
  20. '<' ~ $!numerator ~ '/' ~ $!denominator ~ '>'
  21. }
  22. }
  23. }
  24. }
  25. my constant UINT64_UPPER = nqp::pow_I(2, 64, Num, Int);
  26. my class FatRat is Cool does Rational[Int, Int] {
  27. method FatRat(FatRat:D: Real $?) { self }
  28. method Rat (FatRat:D: Real $?) {
  29. $!denominator < UINT64_UPPER
  30. ?? Rat.new($!numerator, $!denominator)
  31. !! Failure.new("Cannot convert from FatRat to Rat because denominator is too big")
  32. }
  33. multi method perl(FatRat:D:) {
  34. "FatRat.new($!numerator, $!denominator)";
  35. }
  36. }
  37. sub DIVIDE_NUMBERS(Int:D \nu, Int:D \de, \t1, \t2) {
  38. nqp::stmts(
  39. (my Int $gcd := de == 0 ?? 1 !! nu gcd de),
  40. (my Int $numerator := nu div $gcd),
  41. (my Int $denominator := de div $gcd),
  42. nqp::if(
  43. $denominator < 0,
  44. nqp::stmts(
  45. ($numerator := -$numerator),
  46. ($denominator := -$denominator))),
  47. nqp::if(
  48. nqp::istype(t1, FatRat) || nqp::istype(t2, FatRat),
  49. nqp::p6bindattrinvres(
  50. nqp::p6bindattrinvres(nqp::create(FatRat),FatRat,'$!numerator',$numerator),
  51. FatRat,'$!denominator',$denominator),
  52. nqp::if(
  53. $denominator < UINT64_UPPER,
  54. nqp::p6bindattrinvres(
  55. nqp::p6bindattrinvres(nqp::create(Rat),Rat,'$!numerator',$numerator),
  56. Rat,'$!denominator',$denominator),
  57. nqp::p6box_n(nqp::div_In($numerator, $denominator)))))
  58. }
  59. sub DON'T_DIVIDE_NUMBERS(Int:D \nu, Int:D \de, $t1, $t2) {
  60. nqp::istype($t1, FatRat) || nqp::istype($t2, FatRat)
  61. ?? nqp::p6bindattrinvres(
  62. nqp::p6bindattrinvres(
  63. nqp::create(FatRat),
  64. FatRat, '$!numerator', nqp::decont(nu)),
  65. FatRat, '$!denominator', nqp::decont(de))
  66. !! nqp::p6bindattrinvres(
  67. nqp::p6bindattrinvres(
  68. nqp::create(Rat),
  69. Rat, '$!numerator', nqp::decont(nu)),
  70. Rat, '$!denominator', nqp::decont(de))
  71. }
  72. multi sub prefix:<->(Rat:D \a) {
  73. Rat.new(-a.numerator, a.denominator);
  74. }
  75. multi sub prefix:<->(FatRat:D \a) {
  76. FatRat.new(-a.numerator, a.denominator);
  77. }
  78. multi sub infix:<+>(Rational:D \a, Rational:D \b) {
  79. a.denominator == b.denominator
  80. ?? DON'T_DIVIDE_NUMBERS(a.numerator + b.numerator, a.denominator, a, b)
  81. !! DIVIDE_NUMBERS
  82. a.numerator*b.denominator + b.numerator*a.denominator,
  83. a.denominator*b.denominator,
  84. a,
  85. b
  86. }
  87. multi sub infix:<+>(Rational:D \a, Int:D \b) {
  88. DON'T_DIVIDE_NUMBERS(
  89. (a.numerator + b * a.denominator),
  90. a.denominator,
  91. a,
  92. b,
  93. );
  94. }
  95. multi sub infix:<+>(Int:D \a, Rational:D \b) {
  96. DON'T_DIVIDE_NUMBERS(
  97. (a * b.denominator + b.numerator),
  98. b.denominator,
  99. a,
  100. b,
  101. );
  102. }
  103. multi sub infix:<->(Rational:D \a, Rational:D \b) {
  104. a.denominator == b.denominator
  105. ?? DON'T_DIVIDE_NUMBERS(a.numerator - b.numerator, a.denominator, a, b)
  106. !! DIVIDE_NUMBERS
  107. a.numerator*b.denominator - b.numerator*a.denominator,
  108. a.denominator*b.denominator,
  109. a,
  110. b
  111. }
  112. multi sub infix:<->(Rational:D \a, Int:D \b) {
  113. DON'T_DIVIDE_NUMBERS
  114. a.numerator - b * a.denominator,
  115. a.denominator,
  116. a,
  117. b;
  118. }
  119. multi sub infix:<->(Int:D \a, Rational:D \b) {
  120. DON'T_DIVIDE_NUMBERS
  121. a * b.denominator - b.numerator,
  122. b.denominator,
  123. a,
  124. b;
  125. }
  126. multi sub infix:<*>(Rational:D \a, Rational:D \b) {
  127. DIVIDE_NUMBERS
  128. a.numerator * b.numerator,
  129. a.denominator * b.denominator,
  130. a,
  131. b;
  132. }
  133. multi sub infix:<*>(Rational:D \a, Int:D \b) {
  134. DIVIDE_NUMBERS
  135. a.numerator * b,
  136. a.denominator,
  137. a,
  138. b;
  139. }
  140. multi sub infix:<*>(Int:D \a, Rational:D \b) {
  141. DIVIDE_NUMBERS
  142. a * b.numerator,
  143. b.denominator,
  144. a,
  145. b;
  146. }
  147. multi sub infix:</>(Rational:D \a, Rational:D \b) {
  148. DIVIDE_NUMBERS
  149. a.numerator * b.denominator,
  150. a.denominator * b.numerator,
  151. a,
  152. b;
  153. }
  154. multi sub infix:</>(Rational:D \a, Int:D \b) {
  155. DIVIDE_NUMBERS
  156. a.numerator,
  157. a.denominator * b,
  158. a,
  159. b;
  160. }
  161. multi sub infix:</>(Int:D \a, Rational:D \b) {
  162. b.REDUCE-ME; # RT #126391: [BUG] Bad "divide by 0" error message
  163. DIVIDE_NUMBERS
  164. b.denominator * a,
  165. b.numerator,
  166. a,
  167. b;
  168. }
  169. multi sub infix:</>(Int:D \a, Int:D \b) {
  170. DIVIDE_NUMBERS a, b, a, b
  171. }
  172. multi sub infix:<%>(Rational:D \a, Int:D \b) {
  173. a - floor(a / b) * b
  174. }
  175. multi sub infix:<%>(Int:D \a, Rational:D \b) {
  176. a - floor(a / b) * b
  177. }
  178. multi sub infix:<%>(Rational:D \a, Rational:D \b) {
  179. a - floor(a / b) * b
  180. }
  181. multi sub infix:<**>(Rational:D \a, Int:D \b) {
  182. b >= 0
  183. ?? DIVIDE_NUMBERS
  184. (a.numerator ** b // fail (a.numerator.abs > a.denominator ?? X::Numeric::Overflow !! X::Numeric::Underflow).new),
  185. a.denominator ** b, # we presume it likely already blew up on the numerator
  186. a,
  187. b
  188. !! DIVIDE_NUMBERS
  189. (a.denominator ** -b // fail (a.numerator.abs < a.denominator ?? X::Numeric::Overflow !! X::Numeric::Underflow).new),
  190. a.numerator ** -b,
  191. a,
  192. b
  193. }
  194. multi sub infix:<==>(Rational:D \a, Rational:D \b) {
  195. nqp::isfalse(a.denominator) || nqp::isfalse(b.denominator)
  196. ?? a.Num == b.Num
  197. !! a.numerator * b.denominator == b.numerator * a.denominator
  198. }
  199. multi sub infix:<==>(Rational:D \a, Int:D \b) {
  200. a.REDUCE-ME;
  201. a.numerator == b && a.denominator == 1
  202. }
  203. multi sub infix:<==>(Int:D \a, Rational:D \b) {
  204. b.REDUCE-ME;
  205. a == b.numerator && b.denominator == 1;
  206. }
  207. multi sub infix:<===>(Rational:D \a, Rational:D \b --> Bool:D) {
  208. # Check whether we have 0-denominator rationals as well. Those can
  209. # be `==` but have different numerator values and so should not `===` True.
  210. # Since we're already checking equality first, we only need to check the
  211. # zeroeness of the denominator of just one parameter
  212. a.WHAT =:= b.WHAT
  213. && (a == b || (a.isNaN && b.isNaN))
  214. && (a.denominator.Bool || a.numerator == b.numerator)
  215. }
  216. multi sub infix:«<»(Rational:D \a, Rational:D \b) {
  217. a.numerator * b.denominator < b.numerator * a.denominator
  218. }
  219. multi sub infix:«<»(Rational:D \a, Int:D \b) {
  220. a.numerator < b * a.denominator
  221. }
  222. multi sub infix:«<»(Int:D \a, Rational:D \b) {
  223. a * b.denominator < b.numerator
  224. }
  225. multi sub infix:«<=»(Rational:D \a, Rational:D \b) {
  226. a.numerator * b.denominator <= b.numerator * a.denominator
  227. }
  228. multi sub infix:«<=»(Rational:D \a, Int:D \b) {
  229. a.numerator <= b * a.denominator
  230. }
  231. multi sub infix:«<=»(Int:D \a, Rational:D \b) {
  232. a * b.denominator <= b.numerator
  233. }
  234. multi sub infix:«>»(Rational:D \a, Rational:D \b) {
  235. a.numerator * b.denominator > b.numerator * a.denominator
  236. }
  237. multi sub infix:«>»(Rational:D \a, Int:D \b) {
  238. a.numerator > b * a.denominator
  239. }
  240. multi sub infix:«>»(Int:D \a, Rational:D \b) {
  241. a * b.denominator > b.numerator
  242. }
  243. multi sub infix:«>=»(Rational:D \a, Rational:D \b) {
  244. a.numerator * b.denominator >= b.numerator * a.denominator
  245. }
  246. multi sub infix:«>=»(Rational:D \a, Int:D \b) {
  247. a.numerator >= b * a.denominator
  248. }
  249. multi sub infix:«>=»(Int:D \a, Rational:D \b) {
  250. a * b.denominator >= b.numerator
  251. }
  252. multi sub infix:«<=>»(Rational:D \a, Rational:D \b) {
  253. a.numerator * b.denominator <=> b.numerator * a.denominator
  254. }
  255. multi sub infix:«<=>»(Rational:D \a, Int:D \b) {
  256. a.numerator <=> b * a.denominator
  257. }
  258. multi sub infix:«<=>»(Int:D \a, Rational:D \b) {
  259. a * b.denominator <=> b.numerator
  260. }