PageRenderTime 74ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/math.c

https://github.com/wanabe/ruby
C | 1030 lines | 451 code | 109 blank | 470 comment | 55 complexity | 59ae56c1863ed75523424f8e927b2ea1 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, 0BSD, Unlicense, GPL-2.0, BSD-3-Clause
  1. /**********************************************************************
  2. math.c -
  3. $Author$
  4. created at: Tue Jan 25 14:12:56 JST 1994
  5. Copyright (C) 1993-2007 Yukihiro Matsumoto
  6. **********************************************************************/
  7. #include "ruby/internal/config.h"
  8. #ifdef _MSC_VER
  9. # define _USE_MATH_DEFINES 1
  10. #endif
  11. #include <errno.h>
  12. #include <float.h>
  13. #include <math.h>
  14. #include "internal.h"
  15. #include "internal/bignum.h"
  16. #include "internal/complex.h"
  17. #include "internal/math.h"
  18. #include "internal/object.h"
  19. #include "internal/vm.h"
  20. VALUE rb_mMath;
  21. VALUE rb_eMathDomainError;
  22. #define Get_Double(x) rb_num_to_dbl(x)
  23. #define domain_error(msg) \
  24. rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " msg)
  25. #define domain_check_min(val, min, msg) \
  26. ((val) < (min) ? domain_error(msg) : (void)0)
  27. #define domain_check_range(val, min, max, msg) \
  28. ((val) < (min) || (max) < (val) ? domain_error(msg) : (void)0)
  29. /*
  30. * call-seq:
  31. * Math.atan2(y, x) -> Float
  32. *
  33. * Computes the arc tangent given +y+ and +x+.
  34. * Returns a Float in the range -PI..PI. Return value is a angle
  35. * in radians between the positive x-axis of cartesian plane
  36. * and the point given by the coordinates (+x+, +y+) on it.
  37. *
  38. * Domain: (-INFINITY, INFINITY)
  39. *
  40. * Codomain: [-PI, PI]
  41. *
  42. * Math.atan2(-0.0, -1.0) #=> -3.141592653589793
  43. * Math.atan2(-1.0, -1.0) #=> -2.356194490192345
  44. * Math.atan2(-1.0, 0.0) #=> -1.5707963267948966
  45. * Math.atan2(-1.0, 1.0) #=> -0.7853981633974483
  46. * Math.atan2(-0.0, 1.0) #=> -0.0
  47. * Math.atan2(0.0, 1.0) #=> 0.0
  48. * Math.atan2(1.0, 1.0) #=> 0.7853981633974483
  49. * Math.atan2(1.0, 0.0) #=> 1.5707963267948966
  50. * Math.atan2(1.0, -1.0) #=> 2.356194490192345
  51. * Math.atan2(0.0, -1.0) #=> 3.141592653589793
  52. * Math.atan2(INFINITY, INFINITY) #=> 0.7853981633974483
  53. * Math.atan2(INFINITY, -INFINITY) #=> 2.356194490192345
  54. * Math.atan2(-INFINITY, INFINITY) #=> -0.7853981633974483
  55. * Math.atan2(-INFINITY, -INFINITY) #=> -2.356194490192345
  56. *
  57. */
  58. static VALUE
  59. math_atan2(VALUE unused_obj, VALUE y, VALUE x)
  60. {
  61. double dx, dy;
  62. dx = Get_Double(x);
  63. dy = Get_Double(y);
  64. if (dx == 0.0 && dy == 0.0) {
  65. if (!signbit(dx))
  66. return DBL2NUM(dy);
  67. if (!signbit(dy))
  68. return DBL2NUM(M_PI);
  69. return DBL2NUM(-M_PI);
  70. }
  71. #ifndef ATAN2_INF_C99
  72. if (isinf(dx) && isinf(dy)) {
  73. /* optimization for FLONUM */
  74. if (dx < 0.0) {
  75. const double dz = (3.0 * M_PI / 4.0);
  76. return (dy < 0.0) ? DBL2NUM(-dz) : DBL2NUM(dz);
  77. }
  78. else {
  79. const double dz = (M_PI / 4.0);
  80. return (dy < 0.0) ? DBL2NUM(-dz) : DBL2NUM(dz);
  81. }
  82. }
  83. #endif
  84. return DBL2NUM(atan2(dy, dx));
  85. }
  86. /*
  87. * call-seq:
  88. * Math.cos(x) -> Float
  89. *
  90. * Computes the cosine of +x+ (expressed in radians).
  91. * Returns a Float in the range -1.0..1.0.
  92. *
  93. * Domain: (-INFINITY, INFINITY)
  94. *
  95. * Codomain: [-1, 1]
  96. *
  97. * Math.cos(Math::PI) #=> -1.0
  98. *
  99. */
  100. static VALUE
  101. math_cos(VALUE unused_obj, VALUE x)
  102. {
  103. return DBL2NUM(cos(Get_Double(x)));
  104. }
  105. /*
  106. * call-seq:
  107. * Math.sin(x) -> Float
  108. *
  109. * Computes the sine of +x+ (expressed in radians).
  110. * Returns a Float in the range -1.0..1.0.
  111. *
  112. * Domain: (-INFINITY, INFINITY)
  113. *
  114. * Codomain: [-1, 1]
  115. *
  116. * Math.sin(Math::PI/2) #=> 1.0
  117. *
  118. */
  119. static VALUE
  120. math_sin(VALUE unused_obj, VALUE x)
  121. {
  122. return DBL2NUM(sin(Get_Double(x)));
  123. }
  124. /*
  125. * call-seq:
  126. * Math.tan(x) -> Float
  127. *
  128. * Computes the tangent of +x+ (expressed in radians).
  129. *
  130. * Domain: (-INFINITY, INFINITY)
  131. *
  132. * Codomain: (-INFINITY, INFINITY)
  133. *
  134. * Math.tan(0) #=> 0.0
  135. *
  136. */
  137. static VALUE
  138. math_tan(VALUE unused_obj, VALUE x)
  139. {
  140. return DBL2NUM(tan(Get_Double(x)));
  141. }
  142. /*
  143. * call-seq:
  144. * Math.acos(x) -> Float
  145. *
  146. * Computes the arc cosine of +x+. Returns 0..PI.
  147. *
  148. * Domain: [-1, 1]
  149. *
  150. * Codomain: [0, PI]
  151. *
  152. * Math.acos(0) == Math::PI/2 #=> true
  153. *
  154. */
  155. static VALUE
  156. math_acos(VALUE unused_obj, VALUE x)
  157. {
  158. double d;
  159. d = Get_Double(x);
  160. domain_check_range(d, -1.0, 1.0, "acos");
  161. return DBL2NUM(acos(d));
  162. }
  163. /*
  164. * call-seq:
  165. * Math.asin(x) -> Float
  166. *
  167. * Computes the arc sine of +x+. Returns -PI/2..PI/2.
  168. *
  169. * Domain: [-1, -1]
  170. *
  171. * Codomain: [-PI/2, PI/2]
  172. *
  173. * Math.asin(1) == Math::PI/2 #=> true
  174. */
  175. static VALUE
  176. math_asin(VALUE unused_obj, VALUE x)
  177. {
  178. double d;
  179. d = Get_Double(x);
  180. domain_check_range(d, -1.0, 1.0, "asin");
  181. return DBL2NUM(asin(d));
  182. }
  183. /*
  184. * call-seq:
  185. * Math.atan(x) -> Float
  186. *
  187. * Computes the arc tangent of +x+. Returns -PI/2..PI/2.
  188. *
  189. * Domain: (-INFINITY, INFINITY)
  190. *
  191. * Codomain: (-PI/2, PI/2)
  192. *
  193. * Math.atan(0) #=> 0.0
  194. */
  195. static VALUE
  196. math_atan(VALUE unused_obj, VALUE x)
  197. {
  198. return DBL2NUM(atan(Get_Double(x)));
  199. }
  200. #ifndef HAVE_COSH
  201. double
  202. cosh(double x)
  203. {
  204. return (exp(x) + exp(-x)) / 2;
  205. }
  206. #endif
  207. /*
  208. * call-seq:
  209. * Math.cosh(x) -> Float
  210. *
  211. * Computes the hyperbolic cosine of +x+ (expressed in radians).
  212. *
  213. * Domain: (-INFINITY, INFINITY)
  214. *
  215. * Codomain: [1, INFINITY)
  216. *
  217. * Math.cosh(0) #=> 1.0
  218. *
  219. */
  220. static VALUE
  221. math_cosh(VALUE unused_obj, VALUE x)
  222. {
  223. return DBL2NUM(cosh(Get_Double(x)));
  224. }
  225. #ifndef HAVE_SINH
  226. double
  227. sinh(double x)
  228. {
  229. return (exp(x) - exp(-x)) / 2;
  230. }
  231. #endif
  232. /*
  233. * call-seq:
  234. * Math.sinh(x) -> Float
  235. *
  236. * Computes the hyperbolic sine of +x+ (expressed in radians).
  237. *
  238. * Domain: (-INFINITY, INFINITY)
  239. *
  240. * Codomain: (-INFINITY, INFINITY)
  241. *
  242. * Math.sinh(0) #=> 0.0
  243. *
  244. */
  245. static VALUE
  246. math_sinh(VALUE unused_obj, VALUE x)
  247. {
  248. return DBL2NUM(sinh(Get_Double(x)));
  249. }
  250. #ifndef HAVE_TANH
  251. double
  252. tanh(double x)
  253. {
  254. # if defined(HAVE_SINH) && defined(HAVE_COSH)
  255. const double c = cosh(x);
  256. if (!isinf(c)) return sinh(x) / c;
  257. # else
  258. const double e = exp(x+x);
  259. if (!isinf(e)) return (e - 1) / (e + 1);
  260. # endif
  261. return x > 0 ? 1.0 : -1.0;
  262. }
  263. #endif
  264. /*
  265. * call-seq:
  266. * Math.tanh(x) -> Float
  267. *
  268. * Computes the hyperbolic tangent of +x+ (expressed in radians).
  269. *
  270. * Domain: (-INFINITY, INFINITY)
  271. *
  272. * Codomain: (-1, 1)
  273. *
  274. * Math.tanh(0) #=> 0.0
  275. *
  276. */
  277. static VALUE
  278. math_tanh(VALUE unused_obj, VALUE x)
  279. {
  280. return DBL2NUM(tanh(Get_Double(x)));
  281. }
  282. /*
  283. * call-seq:
  284. * Math.acosh(x) -> Float
  285. *
  286. * Computes the inverse hyperbolic cosine of +x+.
  287. *
  288. * Domain: [1, INFINITY)
  289. *
  290. * Codomain: [0, INFINITY)
  291. *
  292. * Math.acosh(1) #=> 0.0
  293. *
  294. */
  295. static VALUE
  296. math_acosh(VALUE unused_obj, VALUE x)
  297. {
  298. double d;
  299. d = Get_Double(x);
  300. domain_check_min(d, 1.0, "acosh");
  301. return DBL2NUM(acosh(d));
  302. }
  303. /*
  304. * call-seq:
  305. * Math.asinh(x) -> Float
  306. *
  307. * Computes the inverse hyperbolic sine of +x+.
  308. *
  309. * Domain: (-INFINITY, INFINITY)
  310. *
  311. * Codomain: (-INFINITY, INFINITY)
  312. *
  313. * Math.asinh(1) #=> 0.881373587019543
  314. *
  315. */
  316. static VALUE
  317. math_asinh(VALUE unused_obj, VALUE x)
  318. {
  319. return DBL2NUM(asinh(Get_Double(x)));
  320. }
  321. /*
  322. * call-seq:
  323. * Math.atanh(x) -> Float
  324. *
  325. * Computes the inverse hyperbolic tangent of +x+.
  326. *
  327. * Domain: (-1, 1)
  328. *
  329. * Codomain: (-INFINITY, INFINITY)
  330. *
  331. * Math.atanh(1) #=> Infinity
  332. *
  333. */
  334. static VALUE
  335. math_atanh(VALUE unused_obj, VALUE x)
  336. {
  337. double d;
  338. d = Get_Double(x);
  339. domain_check_range(d, -1.0, +1.0, "atanh");
  340. /* check for pole error */
  341. if (d == -1.0) return DBL2NUM(-HUGE_VAL);
  342. if (d == +1.0) return DBL2NUM(+HUGE_VAL);
  343. return DBL2NUM(atanh(d));
  344. }
  345. /*
  346. * call-seq:
  347. * Math.exp(x) -> Float
  348. *
  349. * Returns e**x.
  350. *
  351. * Domain: (-INFINITY, INFINITY)
  352. *
  353. * Codomain: (0, INFINITY)
  354. *
  355. * Math.exp(0) #=> 1.0
  356. * Math.exp(1) #=> 2.718281828459045
  357. * Math.exp(1.5) #=> 4.4816890703380645
  358. *
  359. */
  360. static VALUE
  361. math_exp(VALUE unused_obj, VALUE x)
  362. {
  363. return DBL2NUM(exp(Get_Double(x)));
  364. }
  365. #if defined __CYGWIN__
  366. # include <cygwin/version.h>
  367. # if CYGWIN_VERSION_DLL_MAJOR < 1005
  368. # define nan(x) nan()
  369. # endif
  370. # define log(x) ((x) < 0.0 ? nan("") : log(x))
  371. # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
  372. #endif
  373. #ifndef M_LN2
  374. # define M_LN2 0.693147180559945309417232121458176568
  375. #endif
  376. #ifndef M_LN10
  377. # define M_LN10 2.30258509299404568401799145468436421
  378. #endif
  379. static double math_log1(VALUE x);
  380. FUNC_MINIMIZED(static VALUE math_log(int, const VALUE *, VALUE));
  381. /*
  382. * call-seq:
  383. * Math.log(x) -> Float
  384. * Math.log(x, base) -> Float
  385. *
  386. * Returns the logarithm of +x+.
  387. * If additional second argument is given, it will be the base
  388. * of logarithm. Otherwise it is +e+ (for the natural logarithm).
  389. *
  390. * Domain: (0, INFINITY)
  391. *
  392. * Codomain: (-INFINITY, INFINITY)
  393. *
  394. * Math.log(0) #=> -Infinity
  395. * Math.log(1) #=> 0.0
  396. * Math.log(Math::E) #=> 1.0
  397. * Math.log(Math::E**3) #=> 3.0
  398. * Math.log(12, 3) #=> 2.2618595071429146
  399. *
  400. */
  401. static VALUE
  402. math_log(int argc, const VALUE *argv, VALUE unused_obj)
  403. {
  404. return rb_math_log(argc, argv);
  405. }
  406. VALUE
  407. rb_math_log(int argc, const VALUE *argv)
  408. {
  409. VALUE x, base;
  410. double d;
  411. rb_scan_args(argc, argv, "11", &x, &base);
  412. d = math_log1(x);
  413. if (argc == 2) {
  414. d /= math_log1(base);
  415. }
  416. return DBL2NUM(d);
  417. }
  418. static double
  419. get_double_rshift(VALUE x, size_t *pnumbits)
  420. {
  421. size_t numbits;
  422. if (RB_BIGNUM_TYPE_P(x) && BIGNUM_POSITIVE_P(x) &&
  423. DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
  424. numbits -= DBL_MANT_DIG;
  425. x = rb_big_rshift(x, SIZET2NUM(numbits));
  426. }
  427. else {
  428. numbits = 0;
  429. }
  430. *pnumbits = numbits;
  431. return Get_Double(x);
  432. }
  433. static double
  434. math_log1(VALUE x)
  435. {
  436. size_t numbits;
  437. double d = get_double_rshift(x, &numbits);
  438. domain_check_min(d, 0.0, "log");
  439. /* check for pole error */
  440. if (d == 0.0) return -HUGE_VAL;
  441. return log(d) + numbits * M_LN2; /* log(d * 2 ** numbits) */
  442. }
  443. #ifndef log2
  444. #ifndef HAVE_LOG2
  445. double
  446. log2(double x)
  447. {
  448. return log10(x)/log10(2.0);
  449. }
  450. #else
  451. extern double log2(double);
  452. #endif
  453. #endif
  454. /*
  455. * call-seq:
  456. * Math.log2(x) -> Float
  457. *
  458. * Returns the base 2 logarithm of +x+.
  459. *
  460. * Domain: (0, INFINITY)
  461. *
  462. * Codomain: (-INFINITY, INFINITY)
  463. *
  464. * Math.log2(1) #=> 0.0
  465. * Math.log2(2) #=> 1.0
  466. * Math.log2(32768) #=> 15.0
  467. * Math.log2(65536) #=> 16.0
  468. *
  469. */
  470. static VALUE
  471. math_log2(VALUE unused_obj, VALUE x)
  472. {
  473. size_t numbits;
  474. double d = get_double_rshift(x, &numbits);
  475. domain_check_min(d, 0.0, "log2");
  476. /* check for pole error */
  477. if (d == 0.0) return DBL2NUM(-HUGE_VAL);
  478. return DBL2NUM(log2(d) + numbits); /* log2(d * 2 ** numbits) */
  479. }
  480. /*
  481. * call-seq:
  482. * Math.log10(x) -> Float
  483. *
  484. * Returns the base 10 logarithm of +x+.
  485. *
  486. * Domain: (0, INFINITY)
  487. *
  488. * Codomain: (-INFINITY, INFINITY)
  489. *
  490. * Math.log10(1) #=> 0.0
  491. * Math.log10(10) #=> 1.0
  492. * Math.log10(10**100) #=> 100.0
  493. *
  494. */
  495. static VALUE
  496. math_log10(VALUE unused_obj, VALUE x)
  497. {
  498. size_t numbits;
  499. double d = get_double_rshift(x, &numbits);
  500. domain_check_min(d, 0.0, "log10");
  501. /* check for pole error */
  502. if (d == 0.0) return DBL2NUM(-HUGE_VAL);
  503. return DBL2NUM(log10(d) + numbits * log10(2)); /* log10(d * 2 ** numbits) */
  504. }
  505. static VALUE rb_math_sqrt(VALUE x);
  506. /*
  507. * call-seq:
  508. * Math.sqrt(x) -> Float
  509. *
  510. * Returns the non-negative square root of +x+.
  511. *
  512. * Domain: [0, INFINITY)
  513. *
  514. * Codomain:[0, INFINITY)
  515. *
  516. * 0.upto(10) {|x|
  517. * p [x, Math.sqrt(x), Math.sqrt(x)**2]
  518. * }
  519. * #=> [0, 0.0, 0.0]
  520. * # [1, 1.0, 1.0]
  521. * # [2, 1.4142135623731, 2.0]
  522. * # [3, 1.73205080756888, 3.0]
  523. * # [4, 2.0, 4.0]
  524. * # [5, 2.23606797749979, 5.0]
  525. * # [6, 2.44948974278318, 6.0]
  526. * # [7, 2.64575131106459, 7.0]
  527. * # [8, 2.82842712474619, 8.0]
  528. * # [9, 3.0, 9.0]
  529. * # [10, 3.16227766016838, 10.0]
  530. *
  531. * Note that the limited precision of floating point arithmetic
  532. * might lead to surprising results:
  533. *
  534. * Math.sqrt(10**46).to_i #=> 99999999999999991611392 (!)
  535. *
  536. * See also BigDecimal#sqrt and Integer.sqrt.
  537. */
  538. static VALUE
  539. math_sqrt(VALUE unused_obj, VALUE x)
  540. {
  541. return rb_math_sqrt(x);
  542. }
  543. inline static VALUE
  544. f_negative_p(VALUE x)
  545. {
  546. if (FIXNUM_P(x))
  547. return RBOOL(FIX2LONG(x) < 0);
  548. return rb_funcall(x, '<', 1, INT2FIX(0));
  549. }
  550. inline static VALUE
  551. f_signbit(VALUE x)
  552. {
  553. if (RB_FLOAT_TYPE_P(x)) {
  554. double f = RFLOAT_VALUE(x);
  555. return RBOOL(!isnan(f) && signbit(f));
  556. }
  557. return f_negative_p(x);
  558. }
  559. static VALUE
  560. rb_math_sqrt(VALUE x)
  561. {
  562. double d;
  563. if (RB_TYPE_P(x, T_COMPLEX)) {
  564. VALUE neg = f_signbit(RCOMPLEX(x)->imag);
  565. double re = Get_Double(RCOMPLEX(x)->real), im;
  566. d = Get_Double(rb_complex_abs(x));
  567. im = sqrt((d - re) / 2.0);
  568. re = sqrt((d + re) / 2.0);
  569. if (neg) im = -im;
  570. return rb_complex_new(DBL2NUM(re), DBL2NUM(im));
  571. }
  572. d = Get_Double(x);
  573. domain_check_min(d, 0.0, "sqrt");
  574. if (d == 0.0) return DBL2NUM(0.0);
  575. return DBL2NUM(sqrt(d));
  576. }
  577. /*
  578. * call-seq:
  579. * Math.cbrt(x) -> Float
  580. *
  581. * Returns the cube root of +x+.
  582. *
  583. * Domain: (-INFINITY, INFINITY)
  584. *
  585. * Codomain: (-INFINITY, INFINITY)
  586. *
  587. * -9.upto(9) {|x|
  588. * p [x, Math.cbrt(x), Math.cbrt(x)**3]
  589. * }
  590. * #=> [-9, -2.0800838230519, -9.0]
  591. * # [-8, -2.0, -8.0]
  592. * # [-7, -1.91293118277239, -7.0]
  593. * # [-6, -1.81712059283214, -6.0]
  594. * # [-5, -1.7099759466767, -5.0]
  595. * # [-4, -1.5874010519682, -4.0]
  596. * # [-3, -1.44224957030741, -3.0]
  597. * # [-2, -1.25992104989487, -2.0]
  598. * # [-1, -1.0, -1.0]
  599. * # [0, 0.0, 0.0]
  600. * # [1, 1.0, 1.0]
  601. * # [2, 1.25992104989487, 2.0]
  602. * # [3, 1.44224957030741, 3.0]
  603. * # [4, 1.5874010519682, 4.0]
  604. * # [5, 1.7099759466767, 5.0]
  605. * # [6, 1.81712059283214, 6.0]
  606. * # [7, 1.91293118277239, 7.0]
  607. * # [8, 2.0, 8.0]
  608. * # [9, 2.0800838230519, 9.0]
  609. *
  610. */
  611. static VALUE
  612. math_cbrt(VALUE unused_obj, VALUE x)
  613. {
  614. double f = Get_Double(x);
  615. double r = cbrt(f);
  616. #if defined __GLIBC__
  617. if (isfinite(r) && !(f == 0.0 && r == 0.0)) {
  618. r = (2.0 * r + (f / r / r)) / 3.0;
  619. }
  620. #endif
  621. return DBL2NUM(r);
  622. }
  623. /*
  624. * call-seq:
  625. * Math.frexp(x) -> [fraction, exponent]
  626. *
  627. * Returns a two-element array containing the normalized fraction (a Float)
  628. * and exponent (an Integer) of +x+.
  629. *
  630. * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
  631. * fraction * 2**exponent #=> 1234.0
  632. */
  633. static VALUE
  634. math_frexp(VALUE unused_obj, VALUE x)
  635. {
  636. double d;
  637. int exp;
  638. d = frexp(Get_Double(x), &exp);
  639. return rb_assoc_new(DBL2NUM(d), INT2NUM(exp));
  640. }
  641. /*
  642. * call-seq:
  643. * Math.ldexp(fraction, exponent) -> float
  644. *
  645. * Returns the value of +fraction+*(2**+exponent+).
  646. *
  647. * fraction, exponent = Math.frexp(1234)
  648. * Math.ldexp(fraction, exponent) #=> 1234.0
  649. */
  650. static VALUE
  651. math_ldexp(VALUE unused_obj, VALUE x, VALUE n)
  652. {
  653. return DBL2NUM(ldexp(Get_Double(x), NUM2INT(n)));
  654. }
  655. /*
  656. * call-seq:
  657. * Math.hypot(x, y) -> Float
  658. *
  659. * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle with
  660. * sides +x+ and +y+.
  661. *
  662. * Math.hypot(3, 4) #=> 5.0
  663. */
  664. static VALUE
  665. math_hypot(VALUE unused_obj, VALUE x, VALUE y)
  666. {
  667. return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
  668. }
  669. /*
  670. * call-seq:
  671. * Math.erf(x) -> Float
  672. *
  673. * Calculates the error function of +x+.
  674. *
  675. * Domain: (-INFINITY, INFINITY)
  676. *
  677. * Codomain: (-1, 1)
  678. *
  679. * Math.erf(0) #=> 0.0
  680. *
  681. */
  682. static VALUE
  683. math_erf(VALUE unused_obj, VALUE x)
  684. {
  685. return DBL2NUM(erf(Get_Double(x)));
  686. }
  687. /*
  688. * call-seq:
  689. * Math.erfc(x) -> Float
  690. *
  691. * Calculates the complementary error function of x.
  692. *
  693. * Domain: (-INFINITY, INFINITY)
  694. *
  695. * Codomain: (0, 2)
  696. *
  697. * Math.erfc(0) #=> 1.0
  698. *
  699. */
  700. static VALUE
  701. math_erfc(VALUE unused_obj, VALUE x)
  702. {
  703. return DBL2NUM(erfc(Get_Double(x)));
  704. }
  705. /*
  706. * call-seq:
  707. * Math.gamma(x) -> Float
  708. *
  709. * Calculates the gamma function of x.
  710. *
  711. * Note that gamma(n) is the same as fact(n-1) for integer n > 0.
  712. * However gamma(n) returns float and can be an approximation.
  713. *
  714. * def fact(n) (1..n).inject(1) {|r,i| r*i } end
  715. * 1.upto(26) {|i| p [i, Math.gamma(i), fact(i-1)] }
  716. * #=> [1, 1.0, 1]
  717. * # [2, 1.0, 1]
  718. * # [3, 2.0, 2]
  719. * # [4, 6.0, 6]
  720. * # [5, 24.0, 24]
  721. * # [6, 120.0, 120]
  722. * # [7, 720.0, 720]
  723. * # [8, 5040.0, 5040]
  724. * # [9, 40320.0, 40320]
  725. * # [10, 362880.0, 362880]
  726. * # [11, 3628800.0, 3628800]
  727. * # [12, 39916800.0, 39916800]
  728. * # [13, 479001600.0, 479001600]
  729. * # [14, 6227020800.0, 6227020800]
  730. * # [15, 87178291200.0, 87178291200]
  731. * # [16, 1307674368000.0, 1307674368000]
  732. * # [17, 20922789888000.0, 20922789888000]
  733. * # [18, 355687428096000.0, 355687428096000]
  734. * # [19, 6.402373705728e+15, 6402373705728000]
  735. * # [20, 1.21645100408832e+17, 121645100408832000]
  736. * # [21, 2.43290200817664e+18, 2432902008176640000]
  737. * # [22, 5.109094217170944e+19, 51090942171709440000]
  738. * # [23, 1.1240007277776077e+21, 1124000727777607680000]
  739. * # [24, 2.5852016738885062e+22, 25852016738884976640000]
  740. * # [25, 6.204484017332391e+23, 620448401733239439360000]
  741. * # [26, 1.5511210043330954e+25, 15511210043330985984000000]
  742. *
  743. */
  744. static VALUE
  745. math_gamma(VALUE unused_obj, VALUE x)
  746. {
  747. static const double fact_table[] = {
  748. /* fact(0) */ 1.0,
  749. /* fact(1) */ 1.0,
  750. /* fact(2) */ 2.0,
  751. /* fact(3) */ 6.0,
  752. /* fact(4) */ 24.0,
  753. /* fact(5) */ 120.0,
  754. /* fact(6) */ 720.0,
  755. /* fact(7) */ 5040.0,
  756. /* fact(8) */ 40320.0,
  757. /* fact(9) */ 362880.0,
  758. /* fact(10) */ 3628800.0,
  759. /* fact(11) */ 39916800.0,
  760. /* fact(12) */ 479001600.0,
  761. /* fact(13) */ 6227020800.0,
  762. /* fact(14) */ 87178291200.0,
  763. /* fact(15) */ 1307674368000.0,
  764. /* fact(16) */ 20922789888000.0,
  765. /* fact(17) */ 355687428096000.0,
  766. /* fact(18) */ 6402373705728000.0,
  767. /* fact(19) */ 121645100408832000.0,
  768. /* fact(20) */ 2432902008176640000.0,
  769. /* fact(21) */ 51090942171709440000.0,
  770. /* fact(22) */ 1124000727777607680000.0,
  771. /* fact(23)=25852016738884976640000 needs 56bit mantissa which is
  772. * impossible to represent exactly in IEEE 754 double which have
  773. * 53bit mantissa. */
  774. };
  775. enum {NFACT_TABLE = numberof(fact_table)};
  776. double d;
  777. d = Get_Double(x);
  778. /* check for domain error */
  779. if (isinf(d)) {
  780. if (signbit(d)) domain_error("gamma");
  781. return DBL2NUM(HUGE_VAL);
  782. }
  783. if (d == 0.0) {
  784. return signbit(d) ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
  785. }
  786. if (d == floor(d)) {
  787. domain_check_min(d, 0.0, "gamma");
  788. if (1.0 <= d && d <= (double)NFACT_TABLE) {
  789. return DBL2NUM(fact_table[(int)d - 1]);
  790. }
  791. }
  792. return DBL2NUM(tgamma(d));
  793. }
  794. /*
  795. * call-seq:
  796. * Math.lgamma(x) -> [float, -1 or 1]
  797. *
  798. * Calculates the logarithmic gamma of +x+ and the sign of gamma of +x+.
  799. *
  800. * Math.lgamma(x) is the same as
  801. * [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
  802. * but avoids overflow by Math.gamma(x) for large x.
  803. *
  804. * Math.lgamma(0) #=> [Infinity, 1]
  805. *
  806. */
  807. static VALUE
  808. math_lgamma(VALUE unused_obj, VALUE x)
  809. {
  810. double d;
  811. int sign=1;
  812. VALUE v;
  813. d = Get_Double(x);
  814. /* check for domain error */
  815. if (isinf(d)) {
  816. if (signbit(d)) domain_error("lgamma");
  817. return rb_assoc_new(DBL2NUM(HUGE_VAL), INT2FIX(1));
  818. }
  819. if (d == 0.0) {
  820. VALUE vsign = signbit(d) ? INT2FIX(-1) : INT2FIX(+1);
  821. return rb_assoc_new(DBL2NUM(HUGE_VAL), vsign);
  822. }
  823. v = DBL2NUM(lgamma_r(d, &sign));
  824. return rb_assoc_new(v, INT2FIX(sign));
  825. }
  826. #define exp1(n) \
  827. VALUE \
  828. rb_math_##n(VALUE x)\
  829. {\
  830. return math_##n(0, x);\
  831. }
  832. #define exp2(n) \
  833. VALUE \
  834. rb_math_##n(VALUE x, VALUE y)\
  835. {\
  836. return math_##n(0, x, y);\
  837. }
  838. exp2(atan2)
  839. exp1(cos)
  840. exp1(cosh)
  841. exp1(exp)
  842. exp2(hypot)
  843. exp1(sin)
  844. exp1(sinh)
  845. #if 0
  846. exp1(sqrt)
  847. #endif
  848. /*
  849. * Document-class: Math::DomainError
  850. *
  851. * Raised when a mathematical function is evaluated outside of its
  852. * domain of definition.
  853. *
  854. * For example, since +cos+ returns values in the range -1..1,
  855. * its inverse function +acos+ is only defined on that interval:
  856. *
  857. * Math.acos(42)
  858. *
  859. * <em>produces:</em>
  860. *
  861. * Math::DomainError: Numerical argument is out of domain - "acos"
  862. */
  863. /*
  864. * Document-class: Math
  865. *
  866. * The Math module contains module functions for basic
  867. * trigonometric and transcendental functions. See class
  868. * Float for a list of constants that
  869. * define Ruby's floating point accuracy.
  870. *
  871. * Domains and codomains are given only for real (not complex) numbers.
  872. */
  873. void
  874. InitVM_Math(void)
  875. {
  876. rb_mMath = rb_define_module("Math");
  877. rb_eMathDomainError = rb_define_class_under(rb_mMath, "DomainError", rb_eStandardError);
  878. /* Definition of the mathematical constant PI as a Float number. */
  879. rb_define_const(rb_mMath, "PI", DBL2NUM(M_PI));
  880. #ifdef M_E
  881. /* Definition of the mathematical constant E for Euler's number (e) as a Float number. */
  882. rb_define_const(rb_mMath, "E", DBL2NUM(M_E));
  883. #else
  884. rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));
  885. #endif
  886. rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
  887. rb_define_module_function(rb_mMath, "cos", math_cos, 1);
  888. rb_define_module_function(rb_mMath, "sin", math_sin, 1);
  889. rb_define_module_function(rb_mMath, "tan", math_tan, 1);
  890. rb_define_module_function(rb_mMath, "acos", math_acos, 1);
  891. rb_define_module_function(rb_mMath, "asin", math_asin, 1);
  892. rb_define_module_function(rb_mMath, "atan", math_atan, 1);
  893. rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
  894. rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
  895. rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
  896. rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
  897. rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
  898. rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
  899. rb_define_module_function(rb_mMath, "exp", math_exp, 1);
  900. rb_define_module_function(rb_mMath, "log", math_log, -1);
  901. rb_define_module_function(rb_mMath, "log2", math_log2, 1);
  902. rb_define_module_function(rb_mMath, "log10", math_log10, 1);
  903. rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
  904. rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
  905. rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
  906. rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
  907. rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
  908. rb_define_module_function(rb_mMath, "erf", math_erf, 1);
  909. rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
  910. rb_define_module_function(rb_mMath, "gamma", math_gamma, 1);
  911. rb_define_module_function(rb_mMath, "lgamma", math_lgamma, 1);
  912. }
  913. void
  914. Init_Math(void)
  915. {
  916. InitVM(Math);
  917. }