1. my class X::Numeric::DivideByZero { ... };
  2. my role Rational { ... };
  3. my class Num does Real { # declared in BOOTSTRAP
  4. # class Num is Cool
  5. # has num $!value is box_target;
  6. multi method WHICH(Num:D:) {
  7. nqp::box_s(
  8. nqp::concat(
  9. nqp::if(
  10. nqp::eqaddr(self.WHAT,Num),
  11. 'Num|',
  12. nqp::concat(nqp::unbox_s(self.^name), '|')
  13. ),
  14. nqp::unbox_n(self)
  15. ),
  16. ObjAt
  17. )
  18. }
  19. method Num() { self }
  20. method Bridge(Num:D:) { self }
  21. method Range(Num:U:) { Range.new(-Inf,Inf) }
  22. method Int(Num:D:) {
  23. nqp::isnanorinf(nqp::unbox_n(self))
  24. ?? Failure.new("Cannot coerce {self} to an Int")
  25. !! nqp::fromnum_I(nqp::unbox_n(self),Int)
  26. }
  27. multi method new() { nqp::box_n(0e0, self) }
  28. multi method new($n) { nqp::box_n($n.Num, self) }
  29. multi method perl(Num:D:) {
  30. my str $res = self.Str;
  31. nqp::isnanorinf(nqp::unbox_n(self))
  32. || nqp::isge_i(nqp::index($res,'e'),0)
  33. || nqp::isge_i(nqp::index($res,'E'),0)
  34. ?? $res
  35. !! nqp::concat($res,'e0')
  36. }
  37. method Rat(Num:D: Real $epsilon = 1.0e-6, :$fat) {
  38. return Rational[Num,Int].new(self,0)
  39. if nqp::isnanorinf(nqp::unbox_n(self));
  40. my Num $num = self;
  41. $num = -$num if (my int $signum = $num < 0);
  42. my num $r = $num - floor($num);
  43. # basically have an Int
  44. if nqp::iseq_n($r,0e0) {
  45. $fat
  46. ?? FatRat.new(nqp::fromnum_I(self,Int),1)
  47. !! Rat.new(nqp::fromnum_I(self,Int),1)
  48. }
  49. # find convergents of the continued fraction.
  50. else {
  51. my Int $q = nqp::fromnum_I($num, Int);
  52. my Int $a = 1;
  53. my Int $b = $q;
  54. my Int $c = 0;
  55. my Int $d = 1;
  56. while nqp::isne_n($r,0e0) && abs($num - ($b / $d)) > $epsilon {
  57. my num $modf_arg = 1e0 / $r;
  58. $q = nqp::fromnum_I($modf_arg, Int);
  59. $r = $modf_arg - floor($modf_arg);
  60. my $orig_b = $b;
  61. $b = $q * $b + $a;
  62. $a = $orig_b;
  63. my $orig_d = $d;
  64. $d = $q * $d + $c;
  65. $c = $orig_d;
  66. }
  67. # Note that this result has less error than any Rational with a
  68. # smaller denominator but it is not (necessarily) the Rational
  69. # with the smallest denominator that has less than $epsilon error.
  70. # However, to find that Rational would take more processing.
  71. $fat
  72. ?? FatRat.new($signum ?? -$b !! $b, $d)
  73. !! Rat.new($signum ?? -$b !! $b, $d)
  74. }
  75. }
  76. method FatRat(Num:D: Real $epsilon = 1.0e-6) {
  77. self.Rat($epsilon, :fat);
  78. }
  79. multi method atan2(Num:D: Num:D $x = 1e0) {
  80. nqp::p6box_n(nqp::atan2_n(nqp::unbox_n(self), nqp::unbox_n($x)));
  81. }
  82. multi method Str(Num:D:) {
  83. nqp::p6box_s(nqp::unbox_n(self));
  84. }
  85. method succ(Num:D:) { self + 1e0 }
  86. method pred(Num:D:) { self - 1e0 }
  87. method isNaN(Num:D: ) {
  88. self != self;
  89. }
  90. method abs(Num:D: ) {
  91. nqp::p6box_n(nqp::abs_n(nqp::unbox_n(self)));
  92. }
  93. multi method exp(Num:D: ) {
  94. nqp::p6box_n(nqp::exp_n(nqp::unbox_n(self)));
  95. }
  96. proto method log(|) {*}
  97. multi method log(Num:D: ) {
  98. nqp::p6box_n(nqp::log_n(nqp::unbox_n(self)));
  99. }
  100. multi method log(Num:D: Num \base) {
  101. self.log() / base.log();
  102. }
  103. proto method sqrt(|) {*}
  104. multi method sqrt(Num:D: ) {
  105. nqp::p6box_n(nqp::sqrt_n(nqp::unbox_n(self)));
  106. }
  107. method rand(Num:D: ) {
  108. nqp::p6box_n(nqp::rand_n(nqp::unbox_n(self)));
  109. }
  110. method ceiling(Num:D: ) {
  111. nqp::isnanorinf(nqp::unbox_n(self))
  112. ?? self
  113. !! nqp::fromnum_I(nqp::ceil_n(nqp::unbox_n(self)), Int);
  114. }
  115. method floor(Num:D: ) {
  116. nqp::isnanorinf(nqp::unbox_n(self))
  117. ?? self
  118. !! nqp::fromnum_I(nqp::floor_n(nqp::unbox_n(self)), Int);
  119. }
  120. proto method sin(|) {*}
  121. multi method sin(Num:D: ) {
  122. nqp::p6box_n(nqp::sin_n(nqp::unbox_n(self)));
  123. }
  124. proto method asin(|) {*}
  125. multi method asin(Num:D: ) {
  126. nqp::p6box_n(nqp::asin_n(nqp::unbox_n(self)));
  127. }
  128. proto method cos(|) {*}
  129. multi method cos(Num:D: ) {
  130. nqp::p6box_n(nqp::cos_n(nqp::unbox_n(self)));
  131. }
  132. proto method acos(|) {*}
  133. multi method acos(Num:D: ) {
  134. nqp::p6box_n(nqp::acos_n(nqp::unbox_n(self)));
  135. }
  136. proto method tan(|) {*}
  137. multi method tan(Num:D: ) {
  138. nqp::p6box_n(nqp::tan_n(nqp::unbox_n(self)));
  139. }
  140. proto method atan(|) {*}
  141. multi method atan(Num:D: ) {
  142. nqp::p6box_n(nqp::atan_n(nqp::unbox_n(self)));
  143. }
  144. proto method sec(|) {*}
  145. multi method sec(Num:D: ) {
  146. nqp::p6box_n(nqp::sec_n(nqp::unbox_n(self)));
  147. }
  148. proto method asec(|) {*}
  149. multi method asec(Num:D: ) {
  150. nqp::p6box_n(nqp::asec_n(nqp::unbox_n(self)));
  151. }
  152. method cosec(Num:D:) {
  153. nqp::p6box_n(nqp::div_n(1e0, nqp::sin_n(nqp::unbox_n(self))));
  154. }
  155. method acosec(Num:D:) {
  156. nqp::p6box_n(nqp::asin_n(nqp::div_n(1e0, nqp::unbox_n(self))));
  157. }
  158. method cotan(Num:D:) {
  159. nqp::p6box_n(nqp::div_n(1e0, nqp::tan_n(nqp::unbox_n(self))));
  160. }
  161. method acotan(Num:D:) {
  162. nqp::p6box_n(nqp::atan_n(nqp::div_n(1e0, nqp::unbox_n(self))));
  163. }
  164. proto method sinh(|) {*}
  165. multi method sinh(Num:D: ) {
  166. nqp::p6box_n(nqp::sinh_n(nqp::unbox_n(self)));
  167. }
  168. proto method asinh(|) {*}
  169. multi method asinh(Num:D: ) {
  170. nqp::isnanorinf(self)
  171. ?? self
  172. !! (self + (self * self + 1e0).sqrt).log;
  173. }
  174. proto method cosh(|) {*}
  175. multi method cosh(Num:D: ) {
  176. nqp::p6box_n(nqp::cosh_n(nqp::unbox_n(self)));
  177. }
  178. proto method acosh(|) {*}
  179. multi method acosh(Num:D: ) {
  180. self < 1e0
  181. ?? NaN
  182. !! (self + (self * self - 1e0).sqrt).log;
  183. }
  184. proto method tanh(|) {*}
  185. multi method tanh(Num:D: ) {
  186. nqp::p6box_n(nqp::tanh_n(nqp::unbox_n(self)));
  187. }
  188. proto method atanh(|) {*}
  189. multi method atanh(1e0:) { ∞ }
  190. multi method atanh(Num:D: ) {
  191. ((1e0 + self) / (1e0 - self)).log / 2e0;
  192. }
  193. proto method sech(|) {*}
  194. multi method sech(Num:D: ) {
  195. nqp::p6box_n(nqp::sech_n(nqp::unbox_n(self)));
  196. }
  197. proto method asech(|) {*}
  198. multi method asech(Num:D: ) {
  199. (1e0 / self).acosh;
  200. }
  201. proto method cosech(|) {*}
  202. multi method cosech(Num:D: ) {
  203. nqp::p6box_n(nqp::div_n(1e0, nqp::sinh_n(nqp::unbox_n(self))));
  204. }
  205. proto method acosech(|) {*}
  206. multi method acosech(Num:D: ) {
  207. (1e0 / self).asinh;
  208. }
  209. proto method cotanh(|) {*}
  210. multi method cotanh(Num:D: ) {
  211. nqp::p6box_n(nqp::div_n(1e0, nqp::tanh_n(nqp::unbox_n(self))));
  212. }
  213. proto method acotanh(|) {*}
  214. multi method acotanh(Num:D: ) {
  215. (1e0 / self).atanh;
  216. }
  217. method narrow(Num:D:) {
  218. my $i := self.Int;
  219. $i.defined && $i.Num ≅ self
  220. ?? $i
  221. !! self
  222. }
  223. }
  224. my constant tau = 6.28318_53071_79586_476e0;
  225. my constant pi = 3.14159_26535_89793_238e0;
  226. my constant e = 2.71828_18284_59045_235e0;
  227. my constant π := pi;
  228. my constant τ := tau;
  229. my constant 𝑒 := e;
  230. multi sub prefix:<++>(Num:D $a is rw) {
  231. $a = nqp::p6box_n(nqp::add_n(nqp::unbox_n($a), 1e0))
  232. }
  233. multi sub prefix:<++>(Num:U $a is rw) {
  234. $a = 1e0;
  235. }
  236. multi sub prefix:<++>(num $a is rw --> num) {
  237. $a = nqp::add_n($a, 1e0)
  238. }
  239. multi sub prefix:<-->(Num:D $a is rw) {
  240. $a = nqp::p6box_n(nqp::sub_n(nqp::unbox_n($a), 1e0))
  241. }
  242. multi sub prefix:<-->(Num:U $a is rw) {
  243. $a = -1e0;
  244. }
  245. multi sub prefix:<-->(num $a is rw --> num) {
  246. $a = nqp::sub_n($a, 1e0)
  247. }
  248. multi sub postfix:<++>(Num:D $a is rw) {
  249. my $b = $a;
  250. $a = nqp::p6box_n(nqp::add_n(nqp::unbox_n($a), 1e0));
  251. $b
  252. }
  253. multi sub postfix:<++>(Num:U $a is rw) {
  254. $a = 1e0;
  255. 0e0
  256. }
  257. multi sub postfix:<++>(num $a is rw --> num) {
  258. my num $b = $a;
  259. $a = nqp::add_n($a, 1e0);
  260. $b
  261. }
  262. multi sub postfix:<-->(Num:D $a is rw) {
  263. my $b = $a;
  264. $a = nqp::p6box_n(nqp::sub_n(nqp::unbox_n($a), 1e0));
  265. $b
  266. }
  267. multi sub postfix:<-->(Num:U $a is rw) {
  268. $a = -1e0;
  269. 0e0
  270. }
  271. multi sub postfix:<-->(num $a is rw --> num) {
  272. my num $b = $a;
  273. $a = nqp::sub_n($a, 1e0);
  274. $b
  275. }
  276. multi sub prefix:<->(Num:D \a) {
  277. nqp::p6box_n(nqp::neg_n(nqp::unbox_n(a)))
  278. }
  279. multi sub prefix:<->(num $a --> num) {
  280. nqp::neg_n($a);
  281. }
  282. multi sub abs(Num:D \a) {
  283. nqp::p6box_n(nqp::abs_n(nqp::unbox_n(a)))
  284. }
  285. multi sub abs(num $a --> num) {
  286. nqp::abs_n($a)
  287. }
  288. multi sub infix:<+>(Num:D \a, Num:D \b) {
  289. nqp::p6box_n(nqp::add_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  290. }
  291. multi sub infix:<+>(num $a, num $b --> num) {
  292. nqp::add_n($a, $b)
  293. }
  294. multi sub infix:<->(Num:D \a, Num:D \b) {
  295. nqp::p6box_n(nqp::sub_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  296. }
  297. multi sub infix:<->(num $a, num $b --> num) {
  298. nqp::sub_n($a, $b)
  299. }
  300. multi sub infix:<*>(Num:D \a, Num:D \b) {
  301. nqp::p6box_n(nqp::mul_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  302. }
  303. multi sub infix:<*>(num $a, num $b --> num) {
  304. nqp::mul_n($a, $b)
  305. }
  306. multi sub infix:</>(Num:D \a, Num:D \b) {
  307. b
  308. ?? nqp::p6box_n(nqp::div_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  309. !! Failure.new(X::Numeric::DivideByZero.new(:using</>, :numerator(a)))
  310. }
  311. multi sub infix:</>(num $a, num $b --> num) {
  312. $b
  313. ?? nqp::div_n($a, $b)
  314. !! Failure.new(X::Numeric::DivideByZero.new(:using</>, :numerator($a)))
  315. }
  316. multi sub infix:<%>(Num:D \a, Num:D \b) {
  317. b
  318. ?? nqp::p6box_n(nqp::mod_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  319. !! Failure.new(X::Numeric::DivideByZero.new(:using<%>, :numerator(a)))
  320. }
  321. multi sub infix:<%>(num $a, num $b --> num) {
  322. $b
  323. ?? nqp::mod_n($a, $b)
  324. !! Failure.new(X::Numeric::DivideByZero.new(:using<%>, :numerator($a)))
  325. }
  326. # (If we get 0 here, must be underflow, since floating overflow provides Inf.)
  327. multi sub infix:<**>(Num:D \a, Num:D \b) {
  328. nqp::p6box_n(nqp::pow_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  329. or a == 0e0 || b.abs == Inf
  330. ?? 0e0
  331. !! Failure.new(X::Numeric::Underflow.new)
  332. }
  333. multi sub infix:<**>(num $a, num $b --> num) {
  334. nqp::pow_n($a, $b)
  335. or $a == 0e0 || $b.abs == Inf
  336. ?? 0e0
  337. !! Failure.new(X::Numeric::Underflow.new)
  338. }
  339. # Here we sort NaN in with string "NaN"
  340. multi sub infix:<cmp>(Num:D \a, Num:D \b) {
  341. ORDER(nqp::cmp_n(nqp::unbox_n(a), nqp::unbox_n(b))) or
  342. a === b ?? Same # === cares about signed zeros, we don't, so:
  343. !! nqp::iseq_n(a, 0e0) && nqp::iseq_n(b, 0e0)
  344. ?? Same !! a.Stringy cmp b.Stringy;
  345. }
  346. multi sub infix:<cmp>(num $a, num $b) {
  347. ORDER(nqp::cmp_n($a, $b)) or
  348. $a === $b ?? Same # === cares about signed zeros, we don't, so:
  349. !! nqp::iseq_n($a, 0e0) && nqp::iseq_n($b, 0e0)
  350. ?? Same !! $a.Stringy cmp $b.Stringy;
  351. }
  352. # Here we treat NaN as undefined
  353. multi sub infix:«<=>»(Num:D \a, Num:D \b) {
  354. ORDER(nqp::cmp_n(nqp::unbox_n(a), nqp::unbox_n(b))) or
  355. a == b ?? Same !! Nil;
  356. }
  357. multi sub infix:«<=>»(num $a, num $b) {
  358. ORDER(nqp::cmp_n($a, $b)) or
  359. $a == $b ?? Same !! Nil;
  360. }
  361. multi sub infix:<===>(Num:D \a, Num:D \b) {
  362. nqp::p6bool(
  363. nqp::eqaddr(a.WHAT,b.WHAT)
  364. && (
  365. ( # Both are NaNs
  366. nqp::not_i(nqp::isle_n(a, nqp::inf))
  367. && nqp::not_i(nqp::isle_n(b, nqp::inf))
  368. )
  369. || (
  370. nqp::iseq_n(a, b)
  371. && ( # if we're dealing with zeros, ensure the signs match
  372. nqp::isne_n(a, 0e0)
  373. || nqp::if( # 1/-0 = -Inf; 1/0 = +Inf
  374. nqp::islt_n(nqp::div_n(1e0,a), 0e0), # a is -0, if true:
  375. nqp::islt_n(nqp::div_n(1e0,b), 0e0), # check b is -0 too
  376. nqp::isgt_n(nqp::div_n(1e0,b), 0e0), # check b is +0 too
  377. )
  378. )
  379. )
  380. )
  381. )
  382. }
  383. multi sub infix:<===>(num \a, num \b --> Bool:D) {
  384. nqp::p6bool(
  385. nqp::eqaddr(a.WHAT,b.WHAT)
  386. && (
  387. ( # Both are NaNs
  388. nqp::not_i(nqp::isle_n(a, nqp::inf))
  389. && nqp::not_i(nqp::isle_n(b, nqp::inf))
  390. )
  391. || (
  392. nqp::iseq_n(a, b)
  393. && ( # if we're dealing with zeros, ensure the signs match
  394. nqp::isne_n(a, 0e0)
  395. || nqp::if( # 1/-0 = -Inf; 1/0 = +Inf
  396. nqp::islt_n(nqp::div_n(1e0,a), 0e0), # a is -0, if true:
  397. nqp::islt_n(nqp::div_n(1e0,b), 0e0), # check b is -0 too
  398. nqp::isgt_n(nqp::div_n(1e0,b), 0e0), # check b is +0 too
  399. )
  400. )
  401. )
  402. )
  403. )
  404. }
  405. multi sub infix:<≅>( Inf, Inf) { Bool::True }
  406. multi sub infix:<≅>(-Inf, -Inf) { Bool::True }
  407. multi sub infix:<==>(Num:D \a, Num:D \b --> Bool:D) {
  408. nqp::p6bool(nqp::iseq_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  409. }
  410. multi sub infix:<==>(num $a, num $b --> Bool:D) {
  411. nqp::p6bool(nqp::iseq_n($a, $b))
  412. }
  413. multi sub infix:<!=>(num $a, num $b --> Bool:D) {
  414. nqp::p6bool(nqp::isne_n($a, $b))
  415. }
  416. multi sub infix:«<»(Num:D \a, Num:D \b --> Bool:D) {
  417. nqp::p6bool(nqp::islt_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  418. }
  419. multi sub infix:«<»(num $a, num $b --> Bool:D) {
  420. nqp::p6bool(nqp::islt_n($a, $b))
  421. }
  422. multi sub infix:«<=»(Num:D \a, Num:D \b --> Bool:D) {
  423. nqp::p6bool(nqp::isle_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  424. }
  425. multi sub infix:«<=»(num $a, num $b --> Bool:D) {
  426. nqp::p6bool(nqp::isle_n($a, $b))
  427. }
  428. multi sub infix:«>»(Num:D \a, Num:D \b --> Bool:D) {
  429. nqp::p6bool(nqp::isgt_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  430. }
  431. multi sub infix:«>»(num $a, num $b --> Bool:D) {
  432. nqp::p6bool(nqp::isgt_n($a, $b))
  433. }
  434. multi sub infix:«>=»(Num:D \a, Num:D \b --> Bool:D) {
  435. nqp::p6bool(nqp::isge_n(nqp::unbox_n(a), nqp::unbox_n(b)))
  436. }
  437. multi sub infix:«>=»(num $a, num $b --> Bool:D) {
  438. nqp::p6bool(nqp::isge_n($a, $b))
  439. }
  440. sub rand(--> Num:D) {
  441. nqp::p6box_n(nqp::rand_n(1e0));
  442. }
  443. # TODO: default seed of 'time'
  444. sub srand(Int $seed --> Int:D) {
  445. nqp::p6box_i(nqp::srand($seed))
  446. }
  447. multi sub atan2(Num:D $a, Num:D $b = 1e0) {
  448. nqp::p6box_n(nqp::atan2_n(nqp::unbox_n($a), nqp::unbox_n($b)));
  449. }
  450. multi sub cosec(Num:D \x) {
  451. nqp::p6box_n(nqp::div_n(1e0, nqp::sin_n(nqp::unbox_n(x))));
  452. }
  453. multi sub acosec(Num:D \x) {
  454. nqp::p6box_n(nqp::asin_n(nqp::div_n(1e0, nqp::unbox_n(x))));
  455. }
  456. multi sub log(num $x --> num) {
  457. nqp::log_n($x);
  458. }
  459. multi sub sin(num $x --> num) {
  460. nqp::sin_n($x);
  461. }
  462. multi sub asin(num $x --> num) {
  463. nqp::asin_n($x);
  464. }
  465. multi sub cos(num $x --> num) {
  466. nqp::cos_n($x);
  467. }
  468. multi sub acos(num $x --> num) {
  469. nqp::acos_n($x);
  470. }
  471. multi sub tan(num $x --> num) {
  472. nqp::tan_n($x);
  473. }
  474. multi sub atan(num $x --> num) {
  475. nqp::atan_n($x);
  476. }
  477. multi sub sec(num $x --> num) {
  478. nqp::sec_n($x);
  479. }
  480. multi sub asec(num $x --> num) {
  481. nqp::asec_n($x);
  482. }
  483. multi sub cotan(num $x --> num) {
  484. nqp::div_n(1e0, nqp::tan_n($x));
  485. }
  486. multi sub acotan(num $x --> num) {
  487. nqp::atan_n(nqp::div_n(1e0, $x));
  488. }
  489. multi sub sinh(num $x --> num) {
  490. nqp::sinh_n($x);
  491. }
  492. multi sub asinh(num $x --> num) {
  493. # ln(x + √(x²+1))
  494. nqp::isnanorinf($x)
  495. ?? $x
  496. !! nqp::log_n(
  497. nqp::add_n(
  498. $x,
  499. nqp::pow_n( nqp::add_n(nqp::mul_n($x,$x), 1e0), .5e0 )
  500. )
  501. )
  502. }
  503. multi sub cosh(num $x --> num) {
  504. nqp::cosh_n($x);
  505. }
  506. multi sub acosh(num $x --> num) {
  507. # ln(x + √(x²-1))
  508. $x < 1e0
  509. ?? NaN
  510. !! nqp::log_n(
  511. nqp::add_n(
  512. $x,
  513. nqp::pow_n( nqp::sub_n(nqp::mul_n($x,$x), 1e0), .5e0 )
  514. )
  515. )
  516. }
  517. multi sub tanh(num $x --> num) {
  518. nqp::tanh_n($x);
  519. }
  520. multi sub atanh(num $x --> num) {
  521. $x == 1e0 ?? Inf !! log((1e0 + $x) / (1e0 - $x)) / 2e0;
  522. }
  523. multi sub sech(num $x --> num) {
  524. nqp::sech_n($x);
  525. }
  526. multi sub asech(num $x --> num) {
  527. acosh(1e0 / $x);
  528. }
  529. multi sub cosech(num $x --> num) {
  530. 1e0 / sinh($x)
  531. }
  532. multi sub acosech(num $x --> num) {
  533. asinh(1e0 / $x);
  534. }
  535. multi sub cotanh(num $x --> num) {
  536. 1e0 / tanh($x);
  537. }
  538. multi sub acotanh(num $x --> num) {
  539. atanh(1e0 / $x)
  540. }
  541. multi sub floor(num $a --> num) {
  542. nqp::floor_n($a)
  543. }
  544. multi sub ceiling(num $a --> num) {
  545. nqp::ceil_n($a)
  546. }
  547. multi sub sqrt(num $a --> num) {
  548. nqp::sqrt_n($a)
  549. }