1. my class Rat { ... }
  2. my class X::Numeric::DivideByZero { ... }
  3. my class X::NYI::BigInt { ... }
  4. my class Int { ... }
  5. my subset UInt of Int where {not .defined or $_ >= 0};
  6. my class Int does Real { # declared in BOOTSTRAP
  7. # class Int is Cool
  8. # has bigint $!value is box_target;
  9. multi method WHICH(Int:D:) {
  10. nqp::box_s(
  11. nqp::concat(
  12. nqp::if(
  13. nqp::eqaddr(self.WHAT,Int),
  14. 'Int|',
  15. nqp::concat(nqp::unbox_s(self.^name), '|')
  16. ),
  17. nqp::tostr_I(self)
  18. ),
  19. ObjAt
  20. )
  21. }
  22. multi method new($value) {
  23. # clone to ensure we return a new object for any cached
  24. # numeric constants
  25. $value.Int.clone;
  26. }
  27. multi method perl(Int:D:) {
  28. self.Str;
  29. }
  30. multi method Bool(Int:D:) {
  31. nqp::p6bool(nqp::bool_I(self));
  32. }
  33. method Int() { self }
  34. multi method Str(Int:D:) {
  35. nqp::p6box_s(nqp::tostr_I(self));
  36. }
  37. method Num(Int:D:) {
  38. nqp::p6box_n(nqp::tonum_I(self));
  39. }
  40. method Rat(Int:D: $?) {
  41. Rat.new(self, 1);
  42. }
  43. method FatRat(Int:D: $?) {
  44. FatRat.new(self, 1);
  45. }
  46. method abs(Int:D:) {
  47. nqp::abs_I(self, Int)
  48. }
  49. method Bridge(Int:D:) {
  50. nqp::p6box_n(nqp::tonum_I(self));
  51. }
  52. method chr(Int:D:) {
  53. nqp::if(
  54. nqp::isbig_I(self),
  55. (die "chr codepoint too large: {self}"),
  56. nqp::p6box_s(nqp::chr(nqp::unbox_i(self)))
  57. )
  58. }
  59. method sqrt(Int:D:) { nqp::p6box_n(nqp::sqrt_n(nqp::tonum_I(self))) }
  60. proto method base(|) { * }
  61. multi method base(Int:D: Int:D $base) {
  62. 2 <= $base <= 36
  63. ?? nqp::p6box_s(nqp::base_I(self,nqp::unbox_i($base)))
  64. !! Failure.new(X::OutOfRange.new(
  65. what => "base argument to base", :got($base), :range<2..36>))
  66. }
  67. multi method base(Int:D: Int(Cool) $base, $digits?) {
  68. 2 <= $base <= 36
  69. ?? $digits && ! nqp::istype($digits, Whatever)
  70. ?? $digits < 0
  71. ?? Failure.new(X::OutOfRange.new(
  72. :what('digits argument to base'),:got($digits),:range<0..1073741824>))
  73. !! nqp::p6box_s(nqp::base_I(self,nqp::unbox_i($base)))
  74. ~ '.'
  75. ~ '0' x $digits
  76. !! nqp::p6box_s(nqp::base_I(self,nqp::unbox_i($base)))
  77. !! Failure.new(X::OutOfRange.new(
  78. :what('base argument to base'),:got($base),:range<2..36>))
  79. }
  80. # If self is Int, we assume mods are Ints also. (div fails otherwise.)
  81. # If do-not-want, user should cast invocant to proper domain.
  82. method polymod(Int:D: +@mods) {
  83. fail X::OutOfRange.new(
  84. :what('invocant to polymod'), :got(self), :range<0..^Inf>
  85. ) if self < 0;
  86. gather {
  87. my $more = self;
  88. if @mods.is-lazy {
  89. for @mods -> $mod {
  90. $more
  91. ?? $mod
  92. ?? take $more mod $mod
  93. !! Failure.new(X::Numeric::DivideByZero.new:
  94. using => 'polymod', numerator => $more)
  95. !! last;
  96. $more = $more div $mod;
  97. }
  98. take $more if $more;
  99. }
  100. else {
  101. for @mods -> $mod {
  102. $mod
  103. ?? take $more mod $mod
  104. !! Failure.new(X::Numeric::DivideByZero.new:
  105. using => 'polymod', numerator => $more);
  106. $more = $more div $mod;
  107. }
  108. take $more;
  109. }
  110. }
  111. }
  112. method expmod(Int:D: Int:D \base, Int:D \mod) {
  113. nqp::expmod_I(self, nqp::decont(base), nqp::decont(mod), Int);
  114. }
  115. method is-prime(Int:D: --> Bool:D) {
  116. nqp::p6bool(nqp::isprime_I(self, nqp::unbox_i(100)));
  117. }
  118. method floor(Int:D:) { self }
  119. method ceiling(Int:D:) { self }
  120. proto method round(|) {*}
  121. multi method round(Int:D:) { self }
  122. multi method round(Int:D: Real(Cool) $scale) { (self / $scale + 1/2).floor * $scale }
  123. method lsb(Int:D:) {
  124. return Nil if self == 0;
  125. my $lsb = 0;
  126. my $x = self.abs;
  127. while $x +& 0xff == 0 { $lsb += 8; $x +>= 8; }
  128. while $x +& 0x01 == 0 { $lsb++; $x +>= 1; }
  129. $lsb;
  130. }
  131. method msb(Int:D:) {
  132. return Nil if self == 0;
  133. return 0 if self == -1;
  134. my $msb = 0;
  135. my $x = self;
  136. $x = ($x + 1) * -2 if $x < 0; # handle negative conversions
  137. while $x > 0xff { $msb += 8; $x +>= 8; }
  138. if $x > 0x0f { $msb += 4; $x +>= 4; }
  139. if $x +& 0x8 { $msb += 3; }
  140. elsif $x +& 0x4 { $msb += 2; }
  141. elsif $x +& 0x2 { $msb += 1; }
  142. $msb;
  143. }
  144. method narrow(Int:D:) { self }
  145. method Range(Int:U:) {
  146. given self {
  147. when int { $?BITS == 64 ?? int64.Range !! int32.Range }
  148. when uint { $?BITS == 64 ?? uint64.Range !! uint32.Range }
  149. when int64 { Range.new(-9223372036854775808, 9223372036854775807) }
  150. when int32 { Range.new( -2147483648, 2147483647 ) }
  151. when int16 { Range.new( -32768, 32767 ) }
  152. when int8 { Range.new( -128, 127 ) }
  153. # Bring back in a future Perl 6 version, or just put on the type object
  154. #when int4 { Range.new( -8, 7 ) }
  155. #when int2 { Range.new( -2, 1 ) }
  156. #when int1 { Range.new( -1, 0 ) }
  157. when uint64 { Range.new( 0, 18446744073709551615 ) }
  158. when uint32 { Range.new( 0, 4294967295 ) }
  159. when uint16 { Range.new( 0, 65535 ) }
  160. when uint8 { Range.new( 0, 255 ) }
  161. # Bring back in a future Perl 6 version, or just put on the type object
  162. #when uint4 { Range.new( 0, 15 ) }
  163. #when uint2 { Range.new( 0, 3 ) }
  164. #when uint1 { Range.new( 0, 1 ) }
  165. when Int { # smartmatch matches both UInt and Int
  166. .^name eq 'UInt'
  167. ?? Range.new( 0, Inf, :excludes-max )
  168. !! Range.new( -Inf, Inf, :excludes-min, :excludes-max )
  169. }
  170. default {
  171. fail "Unknown integer type: {self.^name}";
  172. }
  173. }
  174. }
  175. }
  176. multi sub prefix:<++>(Int:D $a is rw) {
  177. $a = nqp::add_I(nqp::decont($a), 1, Int);
  178. }
  179. multi sub prefix:<++>(int $a is rw) {
  180. $a = nqp::add_i($a, 1);
  181. }
  182. multi sub prefix:<-->(Int:D $a is rw) {
  183. $a = nqp::sub_I(nqp::decont($a), 1, Int);
  184. }
  185. multi sub prefix:<-->(int $a is rw) {
  186. $a = nqp::sub_i($a, 1);
  187. }
  188. multi sub postfix:<++>(Int:D $a is rw) {
  189. my \b := nqp::decont($a);
  190. $a = nqp::add_I(b, 1, Int);
  191. b
  192. }
  193. multi sub postfix:<++>(int $a is rw) {
  194. my int $b = $a;
  195. $a = nqp::add_i($b, 1);
  196. $b
  197. }
  198. multi sub postfix:<-->(Int:D $a is rw) {
  199. my \b := nqp::decont($a);
  200. $a = nqp::sub_I(b, 1, Int);
  201. b
  202. }
  203. multi sub postfix:<-->(int $a is rw) {
  204. my int $b = $a;
  205. $a = nqp::sub_i($b, 1);
  206. $b
  207. }
  208. multi sub prefix:<->(Int:D \a --> Int:D) {
  209. nqp::neg_I(nqp::decont(a), Int);
  210. }
  211. multi sub prefix:<->(int $a --> int) {
  212. nqp::neg_i($a)
  213. }
  214. multi sub abs(Int:D \a --> Int:D) {
  215. nqp::abs_I(nqp::decont(a), Int);
  216. }
  217. multi sub abs(int $a --> int) {
  218. nqp::abs_i($a)
  219. }
  220. multi sub infix:<+>(Int:D \a, Int:D \b --> Int:D) {
  221. nqp::add_I(nqp::decont(a), nqp::decont(b), Int);
  222. }
  223. multi sub infix:<+>(int $a, int $b --> int) {
  224. nqp::add_i($a, $b)
  225. }
  226. multi sub infix:<->(Int:D \a, Int:D \b --> Int:D) {
  227. nqp::sub_I(nqp::decont(a), nqp::decont(b), Int);
  228. }
  229. multi sub infix:<->(int $a, int $b --> int) {
  230. nqp::sub_i($a, $b)
  231. }
  232. multi sub infix:<*>(Int:D \a, Int:D \b --> Int:D) {
  233. nqp::mul_I(nqp::decont(a), nqp::decont(b), Int);
  234. }
  235. multi sub infix:<*>(int $a, int $b --> int) {
  236. nqp::mul_i($a, $b);
  237. }
  238. multi sub infix:<div>(Int:D \a, Int:D \b) {
  239. b
  240. ?? nqp::div_I(nqp::decont(a), nqp::decont(b), Int)
  241. !! Failure.new(X::Numeric::DivideByZero.new(:using<div>, :numerator(a)))
  242. }
  243. multi sub infix:<div>(int $a, int $b --> int) {
  244. # relies on opcode or hardware to detect division by 0
  245. nqp::div_i($a, $b)
  246. }
  247. multi sub infix:<%>(Int:D \a, Int:D \b --> Int:D) {
  248. nqp::if(
  249. nqp::isbig_I(nqp::decont(a)) || nqp::isbig_I(nqp::decont(b)),
  250. nqp::if(
  251. b,
  252. nqp::mod_I(nqp::decont(a),nqp::decont(b),Int),
  253. Failure.new(X::Numeric::DivideByZero.new(:using<%>, :numerator(a)))
  254. ),
  255. nqp::if(
  256. nqp::isne_i(b,0),
  257. nqp::mod_i( # quick fix RT #128318
  258. nqp::add_i(nqp::mod_i(nqp::decont(a),nqp::decont(b)),b),
  259. nqp::decont(b)
  260. ),
  261. Failure.new(X::Numeric::DivideByZero.new(:using<%>, :numerator(a)))
  262. )
  263. )
  264. }
  265. multi sub infix:<%>(int $a, int $b --> int) {
  266. # relies on opcode or hardware to detect division by 0
  267. nqp::mod_i(nqp::add_i(nqp::mod_i($a,$b),$b),$b) # quick fix RT #128318
  268. }
  269. multi sub infix:<**>(Int:D \a, Int:D \b) {
  270. my $power := nqp::pow_I(nqp::decont(a), nqp::decont(b >= 0 ?? b !! -b), Num, Int);
  271. # when a**b is too big nqp::pow_I returns Inf
  272. nqp::istype($power, Num)
  273. ?? Failure.new(
  274. b >= 0 ?? X::Numeric::Overflow.new !! X::Numeric::Underflow.new
  275. ) !! b >= 0 ?? $power
  276. !! ($power := 1 / $power) == 0 && a != 0
  277. ?? Failure.new(X::Numeric::Underflow.new)
  278. !! $power;
  279. }
  280. multi sub infix:<**>(int $a, int $b --> int) {
  281. nqp::pow_i($a, $b);
  282. }
  283. multi sub infix:<lcm>(Int:D \a, Int:D \b --> Int:D) {
  284. nqp::lcm_I(nqp::decont(a), nqp::decont(b), Int);
  285. }
  286. multi sub infix:<lcm>(int $a, int $b --> int) {
  287. nqp::lcm_i($a, $b)
  288. }
  289. multi sub infix:<gcd>(Int:D \a, Int:D \b --> Int:D) {
  290. nqp::gcd_I(nqp::decont(a), nqp::decont(b), Int);
  291. }
  292. multi sub infix:<gcd>(int $a, int $b --> int) {
  293. nqp::gcd_i($a, $b)
  294. }
  295. multi sub infix:<===>(Int:D \a, Int:D \b) {
  296. nqp::p6bool(
  297. nqp::eqaddr(a.WHAT,b.WHAT)
  298. && nqp::iseq_I(nqp::decont(a), nqp::decont(b))
  299. )
  300. }
  301. multi sub infix:<===>(int $a, int $b) {
  302. # hey, the optimizer is smart enough to figure that one out for us, no?
  303. $a == $b
  304. }
  305. multi sub infix:<==>(Int:D \a, Int:D \b) {
  306. nqp::p6bool(nqp::iseq_I(nqp::decont(a), nqp::decont(b)))
  307. }
  308. multi sub infix:<==>(int $a, int $b) {
  309. nqp::p6bool(nqp::iseq_i($a, $b))
  310. }
  311. multi sub infix:<!=>(int $a, int $b) {
  312. nqp::p6bool(nqp::isne_i($a, $b))
  313. }
  314. multi sub infix:«<»(Int:D \a, Int:D \b) {
  315. nqp::p6bool(nqp::islt_I(nqp::decont(a), nqp::decont(b)))
  316. }
  317. multi sub infix:«<»(int $a, int $b) {
  318. nqp::p6bool(nqp::islt_i($a, $b))
  319. }
  320. multi sub infix:«<=»(Int:D \a, Int:D \b) {
  321. nqp::p6bool(nqp::isle_I(nqp::decont(a), nqp::decont(b)))
  322. }
  323. multi sub infix:«<=»(int $a, int $b) {
  324. nqp::p6bool(nqp::isle_i($a, $b))
  325. }
  326. multi sub infix:«>»(Int:D \a, Int:D \b) {
  327. nqp::p6bool(nqp::isgt_I(nqp::decont(a), nqp::decont(b)))
  328. }
  329. multi sub infix:«>»(int $a, int $b) {
  330. nqp::p6bool(nqp::isgt_i($a, $b))
  331. }
  332. multi sub infix:«>=»(Int:D \a, Int:D \b) {
  333. nqp::p6bool(nqp::isge_I(nqp::decont(a), nqp::decont(b)))
  334. }
  335. multi sub infix:«>=»(int $a, int $b) {
  336. nqp::p6bool(nqp::isge_i($a, $b))
  337. }
  338. multi sub infix:<+|>(Int:D \a, Int:D \b) {
  339. nqp::bitor_I(nqp::decont(a), nqp::decont(b), Int)
  340. }
  341. #multi sub infix:<+|>(int $a, int $b) { RT#128655
  342. # nqp::bitor_i($a, $b)
  343. #}
  344. multi sub infix:<+&>(Int:D \a, Int:D \b) {
  345. nqp::bitand_I(nqp::decont(a), nqp::decont(b), Int)
  346. }
  347. #multi sub infix:<+&>(int $a, int $b) { RT#128655
  348. # nqp::bitand_i($a, $b)
  349. #}
  350. multi sub infix:<+^>(Int:D \a, Int:D \b) {
  351. nqp::bitxor_I(nqp::decont(a), nqp::decont(b), Int)
  352. }
  353. #multi sub infix:<+^>(int $a, int $b) { RT#128655
  354. # nqp::bitxor_i($a, $b);
  355. #}
  356. multi sub infix:«+<»(Int:D \a, Int:D \b --> Int:D) {
  357. my $ignore = nqp::ctx(); # <-- kludge for RT#131306
  358. nqp::bitshiftl_I(nqp::decont(a), nqp::unbox_i(b), Int)
  359. }
  360. #multi sub infix:«+<»(int $a, int $b) { RT#128655
  361. # nqp::bitshiftl_i($a, $b);
  362. #}
  363. multi sub infix:«+>»(Int:D \a, Int:D \b --> Int:D) {
  364. my $ignore = nqp::ctx(); # <-- kludge for RT#131306
  365. nqp::bitshiftr_I(nqp::decont(a), nqp::unbox_i(b), Int)
  366. }
  367. #multi sub infix:«+>»(int $a, int $b) { RT#128655
  368. # nqp::bitshiftr_i($a, $b)
  369. #}
  370. multi sub prefix:<+^>(Int:D \a) {
  371. nqp::bitneg_I(nqp::decont(a), Int);
  372. }
  373. #multi sub prefix:<+^>(int $a) { RT#128655
  374. # nqp::bitneg_i($a);
  375. #}
  376. proto sub chr($) is pure {*}
  377. multi sub chr(Int:D \x --> Str:D) { x.chr }
  378. multi sub chr(Cool \x --> Str:D) { x.Int.chr }
  379. multi sub chr(int $x --> str) {
  380. nqp::chr($x);
  381. }
  382. proto sub is-prime($) is pure {*}
  383. multi sub is-prime(Int:D \i) {
  384. nqp::p6bool(nqp::isprime_I(nqp::decont(i), nqp::unbox_i(100)));
  385. }
  386. multi sub is-prime(\i) {
  387. i == i.floor
  388. && nqp::p6bool(nqp::isprime_I(nqp::decont(i.Int), nqp::unbox_i(100)));
  389. }
  390. proto sub expmod($, $, $) is pure {*}
  391. multi sub expmod(Int:D \base, Int:D \exp, Int:D \mod) {
  392. nqp::expmod_I(nqp::decont(base), nqp::decont(exp), nqp::decont(mod), Int);
  393. }
  394. multi sub expmod(\base, \exp, \mod) {
  395. nqp::expmod_I(nqp::decont(base.Int), nqp::decont(exp.Int), nqp::decont(mod.Int), Int);
  396. }
  397. proto sub lsb($) {*}
  398. multi sub lsb(Int:D \i) { i.lsb }
  399. proto sub msb($) {*}
  400. multi sub msb(Int:D \i) { i.msb }