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