Ruby  2.4.2p198(2017-09-14revision59899)
math.c
Go to the documentation of this file.
1 /**********************************************************************
2 
3  math.c -
4 
5  $Author: naruse $
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
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 
595 static VALUE
596 math_sqrt(VALUE unused_obj, VALUE x)
597 {
598  return rb_math_sqrt(x);
599 }
600 
601 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
602 inline static VALUE
604 {
605  if (FIXNUM_P(x))
606  return f_boolcast(FIX2LONG(x) < 0);
607  return rb_funcall(x, '<', 1, INT2FIX(0));
608 }
609 inline static VALUE
611 {
612  if (RB_TYPE_P(x, T_FLOAT)) {
613  double f = RFLOAT_VALUE(x);
614  return f_boolcast(!isnan(f) && signbit(f));
615  }
616  return f_negative_p(x);
617 }
618 
619 VALUE
621 {
622  double d;
623 
624  if (RB_TYPE_P(x, T_COMPLEX)) {
625  VALUE neg = f_signbit(RCOMPLEX(x)->imag);
626  double re = Get_Double(RCOMPLEX(x)->real), im;
627  d = Get_Double(rb_complex_abs(x));
628  im = sqrt((d - re) / 2.0);
629  re = sqrt((d + re) / 2.0);
630  if (neg) im = -im;
631  return rb_complex_new(DBL2NUM(re), DBL2NUM(im));
632  }
633  d = Get_Double(x);
634  /* check for domain error */
635  if (d < 0.0) domain_error("sqrt");
636  if (d == 0.0) return DBL2NUM(0.0);
637  return DBL2NUM(sqrt(d));
638 }
639 
640 /*
641  * call-seq:
642  * Math.cbrt(x) -> Float
643  *
644  * Returns the cube root of +x+.
645  *
646  * Domain: (-INFINITY, INFINITY)
647  *
648  * Codomain: (-INFINITY, INFINITY)
649  *
650  * -9.upto(9) {|x|
651  * p [x, Math.cbrt(x), Math.cbrt(x)**3]
652  * }
653  * #=> [-9, -2.0800838230519, -9.0]
654  * # [-8, -2.0, -8.0]
655  * # [-7, -1.91293118277239, -7.0]
656  * # [-6, -1.81712059283214, -6.0]
657  * # [-5, -1.7099759466767, -5.0]
658  * # [-4, -1.5874010519682, -4.0]
659  * # [-3, -1.44224957030741, -3.0]
660  * # [-2, -1.25992104989487, -2.0]
661  * # [-1, -1.0, -1.0]
662  * # [0, 0.0, 0.0]
663  * # [1, 1.0, 1.0]
664  * # [2, 1.25992104989487, 2.0]
665  * # [3, 1.44224957030741, 3.0]
666  * # [4, 1.5874010519682, 4.0]
667  * # [5, 1.7099759466767, 5.0]
668  * # [6, 1.81712059283214, 6.0]
669  * # [7, 1.91293118277239, 7.0]
670  * # [8, 2.0, 8.0]
671  * # [9, 2.0800838230519, 9.0]
672  *
673  */
674 
675 static VALUE
676 math_cbrt(VALUE unused_obj, VALUE x)
677 {
678  return DBL2NUM(cbrt(Get_Double(x)));
679 }
680 
681 /*
682  * call-seq:
683  * Math.frexp(x) -> [fraction, exponent]
684  *
685  * Returns a two-element array containing the normalized fraction (a Float)
686  * and exponent (an Integer) of +x+.
687  *
688  * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
689  * fraction * 2**exponent #=> 1234.0
690  */
691 
692 static VALUE
693 math_frexp(VALUE unused_obj, VALUE x)
694 {
695  double d;
696  int exp;
697 
698  d = frexp(Get_Double(x), &exp);
699  return rb_assoc_new(DBL2NUM(d), INT2NUM(exp));
700 }
701 
702 /*
703  * call-seq:
704  * Math.ldexp(fraction, exponent) -> float
705  *
706  * Returns the value of +fraction+*(2**+exponent+).
707  *
708  * fraction, exponent = Math.frexp(1234)
709  * Math.ldexp(fraction, exponent) #=> 1234.0
710  */
711 
712 static VALUE
713 math_ldexp(VALUE unused_obj, VALUE x, VALUE n)
714 {
715  return DBL2NUM(ldexp(Get_Double(x), NUM2INT(n)));
716 }
717 
718 /*
719  * call-seq:
720  * Math.hypot(x, y) -> Float
721  *
722  * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle with
723  * sides +x+ and +y+.
724  *
725  * Math.hypot(3, 4) #=> 5.0
726  */
727 
728 static VALUE
729 math_hypot(VALUE unused_obj, VALUE x, VALUE y)
730 {
731  return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
732 }
733 
734 /*
735  * call-seq:
736  * Math.erf(x) -> Float
737  *
738  * Calculates the error function of +x+.
739  *
740  * Domain: (-INFINITY, INFINITY)
741  *
742  * Codomain: (-1, 1)
743  *
744  * Math.erf(0) #=> 0.0
745  *
746  */
747 
748 static VALUE
749 math_erf(VALUE unused_obj, VALUE x)
750 {
751  return DBL2NUM(erf(Get_Double(x)));
752 }
753 
754 /*
755  * call-seq:
756  * Math.erfc(x) -> Float
757  *
758  * Calculates the complementary error function of x.
759  *
760  * Domain: (-INFINITY, INFINITY)
761  *
762  * Codomain: (0, 2)
763  *
764  * Math.erfc(0) #=> 1.0
765  *
766  */
767 
768 static VALUE
769 math_erfc(VALUE unused_obj, VALUE x)
770 {
771  return DBL2NUM(erfc(Get_Double(x)));
772 }
773 
774 #if defined __MINGW32__
775 static inline double
776 ruby_tgamma(const double d)
777 {
778  const double g = tgamma(d);
779  if (isinf(g)) {
780  if (d == 0.0 && signbit(d)) return -INFINITY;
781  }
782  if (isnan(g)) {
783  if (!signbit(d)) return INFINITY;
784  }
785  return g;
786 }
787 #define tgamma(d) ruby_tgamma(d)
788 #endif
789 
790 #if defined LGAMMA_R_PM0_FIX
791 static inline double
792 ruby_lgamma_r(const double d, int *sign)
793 {
794  const double g = lgamma_r(d, sign);
795  if (isinf(g)) {
796  if (d == 0.0 && signbit(d)) {
797  *sign = -1;
798  return INFINITY;
799  } else if (d == 0.0 && !signbit(d)) {
800  *sign = 1;
801  return INFINITY;
802  }
803  }
804  return g;
805 }
806 #define lgamma_r(d, sign) ruby_lgamma_r(d, sign)
807 #endif
808 
809 /*
810  * call-seq:
811  * Math.gamma(x) -> Float
812  *
813  * Calculates the gamma function of x.
814  *
815  * Note that gamma(n) is same as fact(n-1) for integer n > 0.
816  * However gamma(n) returns float and can be an approximation.
817  *
818  * def fact(n) (1..n).inject(1) {|r,i| r*i } end
819  * 1.upto(26) {|i| p [i, Math.gamma(i), fact(i-1)] }
820  * #=> [1, 1.0, 1]
821  * # [2, 1.0, 1]
822  * # [3, 2.0, 2]
823  * # [4, 6.0, 6]
824  * # [5, 24.0, 24]
825  * # [6, 120.0, 120]
826  * # [7, 720.0, 720]
827  * # [8, 5040.0, 5040]
828  * # [9, 40320.0, 40320]
829  * # [10, 362880.0, 362880]
830  * # [11, 3628800.0, 3628800]
831  * # [12, 39916800.0, 39916800]
832  * # [13, 479001600.0, 479001600]
833  * # [14, 6227020800.0, 6227020800]
834  * # [15, 87178291200.0, 87178291200]
835  * # [16, 1307674368000.0, 1307674368000]
836  * # [17, 20922789888000.0, 20922789888000]
837  * # [18, 355687428096000.0, 355687428096000]
838  * # [19, 6.402373705728e+15, 6402373705728000]
839  * # [20, 1.21645100408832e+17, 121645100408832000]
840  * # [21, 2.43290200817664e+18, 2432902008176640000]
841  * # [22, 5.109094217170944e+19, 51090942171709440000]
842  * # [23, 1.1240007277776077e+21, 1124000727777607680000]
843  * # [24, 2.5852016738885062e+22, 25852016738884976640000]
844  * # [25, 6.204484017332391e+23, 620448401733239439360000]
845  * # [26, 1.5511210043330954e+25, 15511210043330985984000000]
846  *
847  */
848 
849 static VALUE
850 math_gamma(VALUE unused_obj, VALUE x)
851 {
852  static const double fact_table[] = {
853  /* fact(0) */ 1.0,
854  /* fact(1) */ 1.0,
855  /* fact(2) */ 2.0,
856  /* fact(3) */ 6.0,
857  /* fact(4) */ 24.0,
858  /* fact(5) */ 120.0,
859  /* fact(6) */ 720.0,
860  /* fact(7) */ 5040.0,
861  /* fact(8) */ 40320.0,
862  /* fact(9) */ 362880.0,
863  /* fact(10) */ 3628800.0,
864  /* fact(11) */ 39916800.0,
865  /* fact(12) */ 479001600.0,
866  /* fact(13) */ 6227020800.0,
867  /* fact(14) */ 87178291200.0,
868  /* fact(15) */ 1307674368000.0,
869  /* fact(16) */ 20922789888000.0,
870  /* fact(17) */ 355687428096000.0,
871  /* fact(18) */ 6402373705728000.0,
872  /* fact(19) */ 121645100408832000.0,
873  /* fact(20) */ 2432902008176640000.0,
874  /* fact(21) */ 51090942171709440000.0,
875  /* fact(22) */ 1124000727777607680000.0,
876  /* fact(23)=25852016738884976640000 needs 56bit mantissa which is
877  * impossible to represent exactly in IEEE 754 double which have
878  * 53bit mantissa. */
879  };
880  enum {NFACT_TABLE = numberof(fact_table)};
881  double d;
882  d = Get_Double(x);
883  /* check for domain error */
884  if (isinf(d) && signbit(d)) domain_error("gamma");
885  if (d == floor(d)) {
886  if (d < 0.0) domain_error("gamma");
887  if (1.0 <= d && d <= (double)NFACT_TABLE) {
888  return DBL2NUM(fact_table[(int)d - 1]);
889  }
890  }
891  return DBL2NUM(tgamma(d));
892 }
893 
894 /*
895  * call-seq:
896  * Math.lgamma(x) -> [float, -1 or 1]
897  *
898  * Calculates the logarithmic gamma of +x+ and the sign of gamma of +x+.
899  *
900  * Math.lgamma(x) is same as
901  * [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
902  * but avoid overflow by Math.gamma(x) for large x.
903  *
904  * Math.lgamma(0) #=> [Infinity, 1]
905  *
906  */
907 
908 static VALUE
909 math_lgamma(VALUE unused_obj, VALUE x)
910 {
911  double d;
912  int sign=1;
913  VALUE v;
914  d = Get_Double(x);
915  /* check for domain error */
916  if (isinf(d)) {
917  if (signbit(d)) domain_error("lgamma");
918  return rb_assoc_new(DBL2NUM(INFINITY), INT2FIX(1));
919  }
920  v = DBL2NUM(lgamma_r(d, &sign));
921  return rb_assoc_new(v, INT2FIX(sign));
922 }
923 
924 
925 #define exp1(n) \
926 VALUE \
927 rb_math_##n(VALUE x)\
928 {\
929  return math_##n(0, x);\
930 }
931 
932 #define exp2(n) \
933 VALUE \
934 rb_math_##n(VALUE x, VALUE y)\
935 {\
936  return math_##n(0, x, y);\
937 }
938 
939 exp2(atan2)
940 exp1(cos)
941 exp1(cosh)
942 exp1(exp)
943 exp2(hypot)
944 
945 VALUE
946 rb_math_log(int argc, const VALUE *argv)
947 {
948  return math_log(argc, argv, 0);
949 }
950 
951 exp1(sin)
952 exp1(sinh)
953 #if 0
954 exp1(sqrt)
955 #endif
956 
957 
958 /*
959  * Document-class: Math::DomainError
960  *
961  * Raised when a mathematical function is evaluated outside of its
962  * domain of definition.
963  *
964  * For example, since +cos+ returns values in the range -1..1,
965  * its inverse function +acos+ is only defined on that interval:
966  *
967  * Math.acos(42)
968  *
969  * <em>produces:</em>
970  *
971  * Math::DomainError: Numerical argument is out of domain - "acos"
972  */
973 
974 /*
975  * Document-class: Math
976  *
977  * The Math module contains module functions for basic
978  * trigonometric and transcendental functions. See class
979  * Float for a list of constants that
980  * define Ruby's floating point accuracy.
981  *
982  * Domains and codomains are given only for real (not complex) numbers.
983  */
984 
985 
986 void
987 InitVM_Math(void)
988 {
989  rb_mMath = rb_define_module("Math");
991 
992  /* Definition of the mathematical constant PI as a Float number. */
994 
995 #ifdef M_E
996  /* Definition of the mathematical constant E (e) as a Float number. */
997  rb_define_const(rb_mMath, "E", DBL2NUM(M_E));
998 #else
999  rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));
1000 #endif
1001 
1006 
1010 
1014 
1018 
1025 
1028 
1030 
1033 
1036 }
1037 
1038 void
1040 {
1041  InitVM(Math);
1042 }
VALUE rb_eStandardError
Definition: error.c:760
RUBY_EXTERN double cbrt(double)
Definition: cbrt.c:4
static VALUE math_gamma(VALUE unused_obj, VALUE x)
Definition: math.c:850
#define exp1(n)
Definition: math.c:925
double sinh(double x)
Definition: math.c:256
#define INT2NUM(x)
Definition: ruby.h:1538
static VALUE math_ldexp(VALUE unused_obj, VALUE x, VALUE n)
Definition: math.c:713
#define NUM2INT(x)
Definition: ruby.h:684
RUBY_EXTERN int signbit(double x)
Definition: signbit.c:5
static VALUE math_sqrt(VALUE unused_obj, VALUE x)
Definition: math.c:596
static VALUE math_cos(VALUE unused_obj, VALUE x)
Definition: math.c:111
#define InitVM(ext)
Definition: ruby.h:2143
double log2(double x)
Definition: math.c:499
static VALUE math_lgamma(VALUE unused_obj, VALUE x)
Definition: math.c:909
static VALUE math_sin(VALUE unused_obj, VALUE x)
Definition: math.c:132
VALUE rb_eMathDomainError
Definition: math.c:28
static VALUE math_log(int argc, const VALUE *argv, VALUE unused_obj)
Definition: math.c:452
static VALUE f_signbit(VALUE x)
Definition: math.c:610
VALUE rb_mMath
Definition: math.c:27
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:821
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
static VALUE math_log10(VALUE unused_obj, VALUE x)
Definition: math.c:556
#define Get_Double(x)
Definition: math.c:30
static VALUE math_cosh(VALUE unused_obj, VALUE x)
Definition: math.c:249
double cosh(double x)
Definition: math.c:228
static VALUE math_atan2(VALUE unused_obj, VALUE y, VALUE x)
Definition: math.c:66
#define RCOMPLEX(obj)
Definition: internal.h:546
static VALUE math_exp(VALUE unused_obj, VALUE x)
Definition: math.c:407
#define FIXNUM_P(f)
Definition: ruby.h:365
RUBY_EXTERN double tgamma(double)
Definition: tgamma.c:72
static double get_double_rshift(VALUE x, size_t *pnumbits)
Definition: math.c:466
static VALUE math_erfc(VALUE unused_obj, VALUE x)
Definition: math.c:769
#define RB_BIGNUM_TYPE_P(x)
Definition: math.c:25
RUBY_EXTERN double lgamma_r(double, int *)
Definition: lgamma_r.c:63
static VALUE math_sinh(VALUE unused_obj, VALUE x)
Definition: math.c:277
#define RB_TYPE_P(obj, type)
Definition: ruby.h:527
#define neg(x)
Definition: time.c:119
static VALUE math_atan(VALUE unused_obj, VALUE x)
Definition: math.c:221
double tanh(double x)
Definition: math.c:284
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2734
static VALUE math_cbrt(VALUE unused_obj, VALUE x)
Definition: math.c:676
RUBY_SYMBOL_EXPORT_BEGIN RUBY_EXTERN double acosh(double)
Definition: acosh.c:36
#define M_PI
Definition: missing.h:41
static VALUE math_tanh(VALUE unused_obj, VALUE x)
Definition: math.c:312
#define T_FLOAT
Definition: ruby.h:495
int argc
Definition: ruby.c:183
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
static VALUE math_erf(VALUE unused_obj, VALUE x)
Definition: math.c:749
#define numberof(array)
Definition: etc.c:616
#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
static VALUE math_atanh(VALUE unused_obj, VALUE x)
Definition: math.c:377
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:1919
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:623
static VALUE math_asin(VALUE unused_obj, VALUE x)
Definition: math.c:197
static VALUE math_tan(VALUE unused_obj, VALUE x)
Definition: math.c:153
#define domain_error(msg)
Definition: math.c:32
unsigned long VALUE
Definition: ruby.h:85
RUBY_EXTERN double asinh(double)
Definition: acosh.c:52
static VALUE math_asinh(VALUE unused_obj, VALUE x)
Definition: math.c:357
#define INFINITY
Definition: missing.h:149
static double math_log1(VALUE x)
Definition: math.c:483
#define isnan(x)
Definition: win32.h:346
VALUE rb_complex_new(VALUE x, VALUE y)
Definition: complex.c:1429
#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:620
#define RFLOAT_VALUE(v)
Definition: ruby.h:940
#define f_boolcast(x)
Definition: math.c:601
#define f
#define INT2FIX(i)
Definition: ruby.h:232
static VALUE f_negative_p(VALUE x)
Definition: math.c:603
static VALUE math_log2(VALUE unused_obj, VALUE x)
Definition: math.c:526
static VALUE math_acosh(VALUE unused_obj, VALUE x)
Definition: math.c:332
#define BIGNUM_POSITIVE_P(b)
Definition: internal.h:502
size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
Definition: bignum.c:3366
static VALUE math_frexp(VALUE unused_obj, VALUE x)
Definition: math.c:693
VALUE rb_complex_abs(VALUE cmp)
Definition: complex.c:1464
VALUE rb_big_rshift(VALUE x, VALUE y)
Definition: bignum.c:6574
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:932
RUBY_EXTERN double erf(double)
Definition: erf.c:71
#define SIZET2NUM(v)
Definition: ruby.h:264
static VALUE math_acos(VALUE unused_obj, VALUE x)
Definition: math.c:173
static VALUE math_hypot(VALUE unused_obj, VALUE x, VALUE y)
Definition: math.c:729
void Init_Math(void)
Definition: math.c:1039
char ** argv
Definition: ruby.c:184
#define DBL2NUM(dbl)
Definition: ruby.h:941