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