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