Ruby 3.5.0dev (2025-07-25 revision bd2d6845f1c48a572e202409367a4e756c4bb3c5)
math.c (bd2d6845f1c48a572e202409367a4e756c4bb3c5)
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#include "ruby/internal/config.h"
13
14#ifdef _MSC_VER
15# define _USE_MATH_DEFINES 1
16#endif
17
18#include <float.h>
19#include <math.h>
20
21#include "internal.h"
22#include "internal/bignum.h"
23#include "internal/complex.h"
24#include "internal/math.h"
25#include "internal/object.h"
26#include "internal/vm.h"
27
30
31#define Get_Double(x) rb_num_to_dbl(x)
32
33#define domain_error(msg) \
34 rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " msg)
35#define domain_check_min(val, min, msg) \
36 ((val) < (min) ? domain_error(msg) : (void)0)
37#define domain_check_range(val, min, max, msg) \
38 ((val) < (min) || (max) < (val) ? domain_error(msg) : (void)0)
39
40/*
41 * call-seq:
42 * Math.atan2(y, x) -> float
43 *
44 * Returns the {arc tangent}[https://en.wikipedia.org/wiki/Atan2] of +y+ and +x+
45 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
46 *
47 * - Domain of +y+: <tt>[-INFINITY, INFINITY]</tt>.
48 * - Domain of +x+: <tt>[-INFINITY, INFINITY]</tt>.
49 * - Range: <tt>[-PI, PI]</tt>.
50 *
51 * Examples:
52 *
53 * atan2(-1.0, -1.0) # => -2.356194490192345 # -3*PI/4
54 * atan2(-1.0, 0.0) # => -1.5707963267948966 # -PI/2
55 * atan2(-1.0, 1.0) # => -0.7853981633974483 # -PI/4
56 * atan2(0.0, -1.0) # => 3.141592653589793 # PI
57 *
58 */
59
60static VALUE
61math_atan2(VALUE unused_obj, VALUE y, VALUE x)
62{
63 double dx, dy;
64 dx = Get_Double(x);
65 dy = Get_Double(y);
66 if (dx == 0.0 && dy == 0.0) {
67 if (!signbit(dx))
68 return DBL2NUM(dy);
69 if (!signbit(dy))
70 return DBL2NUM(M_PI);
71 return DBL2NUM(-M_PI);
72 }
73#ifndef ATAN2_INF_C99
74 if (isinf(dx) && isinf(dy)) {
75 /* optimization for FLONUM */
76 if (dx < 0.0) {
77 const double dz = (3.0 * M_PI / 4.0);
78 return (dy < 0.0) ? DBL2NUM(-dz) : DBL2NUM(dz);
79 }
80 else {
81 const double dz = (M_PI / 4.0);
82 return (dy < 0.0) ? DBL2NUM(-dz) : DBL2NUM(dz);
83 }
84 }
85#endif
86 return DBL2NUM(atan2(dy, dx));
87}
88
89
90/*
91 * call-seq:
92 * Math.cos(x) -> float
93 *
94 * Returns the
95 * {cosine}[https://en.wikipedia.org/wiki/Sine_and_cosine] of +x+
96 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
97 *
98 * - Domain: <tt>(-INFINITY, INFINITY)</tt>.
99 * - Range: <tt>[-1.0, 1.0]</tt>.
100 *
101 * Examples:
102 *
103 * cos(-PI) # => -1.0
104 * cos(-PI/2) # => 6.123031769111886e-17 # 0.0000000000000001
105 * cos(0.0) # => 1.0
106 * cos(PI/2) # => 6.123031769111886e-17 # 0.0000000000000001
107 * cos(PI) # => -1.0
108 *
109 */
110
111static VALUE
112math_cos(VALUE unused_obj, VALUE x)
113{
114 return DBL2NUM(cos(Get_Double(x)));
115}
116
117/*
118 * call-seq:
119 * Math.sin(x) -> float
120 *
121 * Returns the
122 * {sine}[https://en.wikipedia.org/wiki/Sine_and_cosine] of +x+
123 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
124 *
125 * - Domain: <tt>(-INFINITY, INFINITY)</tt>.
126 * - Range: <tt>[-1.0, 1.0]</tt>.
127 *
128 * Examples:
129 *
130 * sin(-PI) # => -1.2246063538223773e-16 # -0.0000000000000001
131 * sin(-PI/2) # => -1.0
132 * sin(0.0) # => 0.0
133 * sin(PI/2) # => 1.0
134 * sin(PI) # => 1.2246063538223773e-16 # 0.0000000000000001
135 *
136 */
137
138static VALUE
139math_sin(VALUE unused_obj, VALUE x)
140{
141 return DBL2NUM(sin(Get_Double(x)));
142}
143
144
145/*
146 * call-seq:
147 * Math.tan(x) -> float
148 *
149 * Returns the
150 * {tangent}[https://en.wikipedia.org/wiki/Trigonometric_functions] of +x+
151 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
152 *
153 * - Domain: <tt>(-INFINITY, INFINITY)</tt>.
154 * - Range: <tt>(-INFINITY, INFINITY)</tt>.
155 *
156 * Examples:
157 *
158 * tan(-PI) # => 1.2246467991473532e-16 # -0.0000000000000001
159 * tan(-PI/2) # => -1.633123935319537e+16 # -16331239353195370.0
160 * tan(0.0) # => 0.0
161 * tan(PI/2) # => 1.633123935319537e+16 # 16331239353195370.0
162 * tan(PI) # => -1.2246467991473532e-16 # -0.0000000000000001
163 *
164 */
165
166static VALUE
167math_tan(VALUE unused_obj, VALUE x)
168{
169 return DBL2NUM(tan(Get_Double(x)));
170}
171
172#define math_arc(num, func) \
173 double d; \
174 d = Get_Double((num)); \
175 domain_check_range(d, -1.0, 1.0, #func); \
176 return DBL2NUM(func(d));
177
178/*
179 * call-seq:
180 * Math.acos(x) -> float
181 *
182 * Returns the {arc cosine}[https://en.wikipedia.org/wiki/Inverse_trigonometric_functions] of +x+.
183 *
184 * - Domain: <tt>[-1, 1]</tt>.
185 * - Range: <tt>[0, PI]</tt>.
186 *
187 * Examples:
188 *
189 * acos(-1.0) # => 3.141592653589793 # PI
190 * acos(0.0) # => 1.5707963267948966 # PI/2
191 * acos(1.0) # => 0.0
192 *
193 */
194
195static VALUE
196math_acos(VALUE unused_obj, VALUE x)
197{
198 math_arc(x, acos)
199}
200
201/*
202 * call-seq:
203 * Math.asin(x) -> float
204 *
205 * Returns the {arc sine}[https://en.wikipedia.org/wiki/Inverse_trigonometric_functions] of +x+.
206 *
207 * - Domain: <tt>[-1, -1]</tt>.
208 * - Range: <tt>[-PI/2, PI/2]</tt>.
209 *
210 * Examples:
211 *
212 * asin(-1.0) # => -1.5707963267948966 # -PI/2
213 * asin(0.0) # => 0.0
214 * asin(1.0) # => 1.5707963267948966 # PI/2
215 *
216 */
217
218static VALUE
219math_asin(VALUE unused_obj, VALUE x)
220{
221 math_arc(x, asin)
222}
223
224/*
225 * call-seq:
226 * Math.atan(x) -> Float
227 *
228 * Returns the {arc tangent}[https://en.wikipedia.org/wiki/Inverse_trigonometric_functions] of +x+.
229 *
230 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
231 * - Range: <tt>[-PI/2, PI/2] </tt>.
232 *
233 * Examples:
234 *
235 * atan(-INFINITY) # => -1.5707963267948966 # -PI2
236 * atan(-PI) # => -1.2626272556789115
237 * atan(-PI/2) # => -1.0038848218538872
238 * atan(0.0) # => 0.0
239 * atan(PI/2) # => 1.0038848218538872
240 * atan(PI) # => 1.2626272556789115
241 * atan(INFINITY) # => 1.5707963267948966 # PI/2
242 *
243 */
244
245static VALUE
246math_atan(VALUE unused_obj, VALUE x)
247{
248 return DBL2NUM(atan(Get_Double(x)));
249}
250
251#ifndef HAVE_COSH
252double
253cosh(double x)
254{
255 return (exp(x) + exp(-x)) / 2;
256}
257#endif
258
259/*
260 * call-seq:
261 * Math.cosh(x) -> float
262 *
263 * Returns the {hyperbolic cosine}[https://en.wikipedia.org/wiki/Hyperbolic_functions] of +x+
264 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
265 *
266 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
267 * - Range: <tt>[1, INFINITY]</tt>.
268 *
269 * Examples:
270 *
271 * cosh(-INFINITY) # => Infinity
272 * cosh(0.0) # => 1.0
273 * cosh(INFINITY) # => Infinity
274 *
275 */
276
277static VALUE
278math_cosh(VALUE unused_obj, VALUE x)
279{
280 return DBL2NUM(cosh(Get_Double(x)));
281}
282
283#ifndef HAVE_SINH
284double
285sinh(double x)
286{
287 return (exp(x) - exp(-x)) / 2;
288}
289#endif
290
291/*
292 * call-seq:
293 * Math.sinh(x) -> float
294 *
295 * Returns the {hyperbolic sine}[https://en.wikipedia.org/wiki/Hyperbolic_functions] of +x+
296 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
297 *
298 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
299 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
300 *
301 * Examples:
302 *
303 * sinh(-INFINITY) # => -Infinity
304 * sinh(0.0) # => 0.0
305 * sinh(INFINITY) # => Infinity
306 *
307 */
308
309static VALUE
310math_sinh(VALUE unused_obj, VALUE x)
311{
312 return DBL2NUM(sinh(Get_Double(x)));
313}
314
315#ifndef HAVE_TANH
316double
317tanh(double x)
318{
319# if defined(HAVE_SINH) && defined(HAVE_COSH)
320 const double c = cosh(x);
321 if (!isinf(c)) return sinh(x) / c;
322# else
323 const double e = exp(x+x);
324 if (!isinf(e)) return (e - 1) / (e + 1);
325# endif
326 return x > 0 ? 1.0 : -1.0;
327}
328#endif
329
330/*
331 * call-seq:
332 * Math.tanh(x) -> float
333 *
334 * Returns the {hyperbolic tangent}[https://en.wikipedia.org/wiki/Hyperbolic_functions] of +x+
335 * in {radians}[https://en.wikipedia.org/wiki/Trigonometric_functions#Radians_versus_degrees].
336 *
337 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
338 * - Range: <tt>[-1, 1]</tt>.
339 *
340 * Examples:
341 *
342 * tanh(-INFINITY) # => -1.0
343 * tanh(0.0) # => 0.0
344 * tanh(INFINITY) # => 1.0
345 *
346 */
347
348static VALUE
349math_tanh(VALUE unused_obj, VALUE x)
350{
351 return DBL2NUM(tanh(Get_Double(x)));
352}
353
354/*
355 * call-seq:
356 * Math.acosh(x) -> float
357 *
358 * Returns the {inverse hyperbolic cosine}[https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions] of +x+.
359 *
360 * - Domain: <tt>[1, INFINITY]</tt>.
361 * - Range: <tt>[0, INFINITY]</tt>.
362 *
363 * Examples:
364 *
365 * acosh(1.0) # => 0.0
366 * acosh(INFINITY) # => Infinity
367 *
368 */
369
370static VALUE
371math_acosh(VALUE unused_obj, VALUE x)
372{
373 double d;
374
375 d = Get_Double(x);
376 domain_check_min(d, 1.0, "acosh");
377 return DBL2NUM(acosh(d));
378}
379
380/*
381 * call-seq:
382 * Math.asinh(x) -> float
383 *
384 * Returns the {inverse hyperbolic sine}[https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions] of +x+.
385 *
386 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
387 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
388 *
389 * Examples:
390 *
391 * asinh(-INFINITY) # => -Infinity
392 * asinh(0.0) # => 0.0
393 * asinh(INFINITY) # => Infinity
394 *
395 */
396
397static VALUE
398math_asinh(VALUE unused_obj, VALUE x)
399{
400 return DBL2NUM(asinh(Get_Double(x)));
401}
402
403/*
404 * call-seq:
405 * Math.atanh(x) -> float
406 *
407 * Returns the {inverse hyperbolic tangent}[https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions] of +x+.
408 *
409 * - Domain: <tt>[-1, 1]</tt>.
410 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
411 *
412 * Examples:
413 *
414 * atanh(-1.0) # => -Infinity
415 * atanh(0.0) # => 0.0
416 * atanh(1.0) # => Infinity
417 *
418 */
419
420static VALUE
421math_atanh(VALUE unused_obj, VALUE x)
422{
423 double d;
424
425 d = Get_Double(x);
426 domain_check_range(d, -1.0, +1.0, "atanh");
427 /* check for pole error */
428 if (d == -1.0) return DBL2NUM(-HUGE_VAL);
429 if (d == +1.0) return DBL2NUM(+HUGE_VAL);
430 return DBL2NUM(atanh(d));
431}
432
433/*
434 * call-seq:
435 * Math.exp(x) -> float
436 *
437 * Returns +e+ raised to the +x+ power.
438 *
439 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
440 * - Range: <tt>[0, INFINITY]</tt>.
441 *
442 * Examples:
443 *
444 * exp(-INFINITY) # => 0.0
445 * exp(-1.0) # => 0.36787944117144233 # 1.0/E
446 * exp(0.0) # => 1.0
447 * exp(0.5) # => 1.6487212707001282 # sqrt(E)
448 * exp(1.0) # => 2.718281828459045 # E
449 * exp(2.0) # => 7.38905609893065 # E**2
450 * exp(INFINITY) # => Infinity
451 *
452 */
453
454static VALUE
455math_exp(VALUE unused_obj, VALUE x)
456{
457 return DBL2NUM(exp(Get_Double(x)));
458}
459
460#if defined __CYGWIN__
461# include <cygwin/version.h>
462# if CYGWIN_VERSION_DLL_MAJOR < 1005
463# define nan(x) nan()
464# endif
465# define log(x) ((x) < 0.0 ? nan("") : log(x))
466# define log10(x) ((x) < 0.0 ? nan("") : log10(x))
467#endif
468
469#ifndef M_LN2
470# define M_LN2 0.693147180559945309417232121458176568
471#endif
472#ifndef M_LN10
473# define M_LN10 2.30258509299404568401799145468436421
474#endif
475
476FUNC_MINIMIZED(static VALUE math_log(int, const VALUE *, VALUE));
477
478/*
479 * call-seq:
480 * Math.log(x, base = Math::E) -> Float
481 *
482 * Returns the base +base+ {logarithm}[https://en.wikipedia.org/wiki/Logarithm] of +x+.
483 *
484 * - Domain: <tt>[0, INFINITY]</tt>.
485 * - Range: <tt>[-INFINITY, INFINITY)]</tt>.
486 *
487 * Examples:
488 *
489 * log(0.0) # => -Infinity
490 * log(1.0) # => 0.0
491 * log(E) # => 1.0
492 * log(INFINITY) # => Infinity
493 *
494 * log(0.0, 2.0) # => -Infinity
495 * log(1.0, 2.0) # => 0.0
496 * log(2.0, 2.0) # => 1.0
497 *
498 * log(0.0, 10.0) # => -Infinity
499 * log(1.0, 10.0) # => 0.0
500 * log(10.0, 10.0) # => 1.0
501 *
502 */
503
504static VALUE
505math_log(int argc, const VALUE *argv, VALUE unused_obj)
506{
507 return rb_math_log(argc, argv);
508}
509
510static double
511get_double_rshift(VALUE x, size_t *pnumbits)
512{
513 size_t numbits;
514
515 if (RB_BIGNUM_TYPE_P(x) && BIGNUM_POSITIVE_P(x) &&
516 DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
517 numbits -= DBL_MANT_DIG;
518 x = rb_big_rshift(x, SIZET2NUM(numbits));
519 }
520 else {
521 numbits = 0;
522 }
523 *pnumbits = numbits;
524 return Get_Double(x);
525}
526
527static double
528math_log_split(VALUE x, size_t *numbits)
529{
530 double d = get_double_rshift(x, numbits);
531
532 domain_check_min(d, 0.0, "log");
533 return d;
534}
535
536#if defined(log2) || defined(HAVE_LOG2)
537# define log_intermediate log2
538#else
539# define log_intermediate log10
540double log2(double x);
541#endif
542
543VALUE
544rb_math_log(int argc, const VALUE *argv)
545{
546 VALUE x, base;
547 double d;
548 size_t numbits;
549
550 argc = rb_scan_args(argc, argv, "11", &x, &base);
551 d = math_log_split(x, &numbits);
552 if (argc == 2) {
553 size_t numbits_2;
554 double b = math_log_split(base, &numbits_2);
555 /* check for pole error */
556 if (d == 0.0) {
557 // Already DomainError if b < 0.0
558 return b ? DBL2NUM(-HUGE_VAL) : DBL2NUM(NAN);
559 }
560 else if (b == 0.0) {
561 return DBL2NUM(-0.0);
562 }
563 d = log_intermediate(d) / log_intermediate(b);
564 d += (numbits - numbits_2) / log2(b);
565 }
566 else {
567 /* check for pole error */
568 if (d == 0.0) return DBL2NUM(-HUGE_VAL);
569 d = log(d);
570 d += numbits * M_LN2;
571 }
572 return DBL2NUM(d);
573}
574
575#ifndef log2
576#ifndef HAVE_LOG2
577double
578log2(double x)
579{
580 return log10(x)/log10(2.0);
581}
582#else
583extern double log2(double);
584#endif
585#endif
586
587/*
588 * call-seq:
589 * Math.log2(x) -> float
590 *
591 * Returns the base 2 {logarithm}[https://en.wikipedia.org/wiki/Logarithm] of +x+.
592 *
593 * - Domain: <tt>[0, INFINITY]</tt>.
594 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
595 *
596 * Examples:
597 *
598 * log2(0.0) # => -Infinity
599 * log2(1.0) # => 0.0
600 * log2(2.0) # => 1.0
601 * log2(INFINITY) # => Infinity
602 *
603 */
604
605static VALUE
606math_log2(VALUE unused_obj, VALUE x)
607{
608 size_t numbits;
609 double d = get_double_rshift(x, &numbits);
610
611 domain_check_min(d, 0.0, "log2");
612 /* check for pole error */
613 if (d == 0.0) return DBL2NUM(-HUGE_VAL);
614
615 return DBL2NUM(log2(d) + numbits); /* log2(d * 2 ** numbits) */
616}
617
618/*
619 * call-seq:
620 * Math.log10(x) -> float
621 *
622 * Returns the base 10 {logarithm}[https://en.wikipedia.org/wiki/Logarithm] of +x+.
623 *
624 * - Domain: <tt>[0, INFINITY]</tt>.
625 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
626 *
627 * Examples:
628 *
629 * log10(0.0) # => -Infinity
630 * log10(1.0) # => 0.0
631 * log10(10.0) # => 1.0
632 * log10(INFINITY) # => Infinity
633 *
634 */
635
636static VALUE
637math_log10(VALUE unused_obj, VALUE x)
638{
639 size_t numbits;
640 double d = get_double_rshift(x, &numbits);
641
642 domain_check_min(d, 0.0, "log10");
643 /* check for pole error */
644 if (d == 0.0) return DBL2NUM(-HUGE_VAL);
645
646 return DBL2NUM(log10(d) + numbits * log10(2)); /* log10(d * 2 ** numbits) */
647}
648
649static VALUE rb_math_sqrt(VALUE x);
650
651/*
652 * call-seq:
653 * Math.sqrt(x) -> float
654 *
655 * Returns the principal (non-negative) {square root}[https://en.wikipedia.org/wiki/Square_root] of +x+.
656 *
657 * - Domain: <tt>[0, INFINITY]</tt>.
658 * - Range: <tt>[0, INFINITY]</tt>.
659 *
660 * Examples:
661 *
662 * sqrt(0.0) # => 0.0
663 * sqrt(0.5) # => 0.7071067811865476
664 * sqrt(1.0) # => 1.0
665 * sqrt(2.0) # => 1.4142135623730951
666 * sqrt(4.0) # => 2.0
667 * sqrt(9.0) # => 3.0
668 * sqrt(INFINITY) # => Infinity
669 *
670 */
671
672static VALUE
673math_sqrt(VALUE unused_obj, VALUE x)
674{
675 return rb_math_sqrt(x);
676}
677
678inline static VALUE
679f_negative_p(VALUE x)
680{
681 if (FIXNUM_P(x))
682 return RBOOL(FIX2LONG(x) < 0);
683 return rb_funcall(x, '<', 1, INT2FIX(0));
684}
685inline static VALUE
686f_signbit(VALUE x)
687{
688 if (RB_FLOAT_TYPE_P(x)) {
689 double f = RFLOAT_VALUE(x);
690 return RBOOL(!isnan(f) && signbit(f));
691 }
692 return f_negative_p(x);
693}
694
695static VALUE
696rb_math_sqrt(VALUE x)
697{
698 double d;
699
700 if (RB_TYPE_P(x, T_COMPLEX)) {
701 VALUE neg = f_signbit(RCOMPLEX(x)->imag);
702 double re = Get_Double(RCOMPLEX(x)->real), im;
703 d = Get_Double(rb_complex_abs(x));
704 im = sqrt((d - re) / 2.0);
705 re = sqrt((d + re) / 2.0);
706 if (neg) im = -im;
707 return rb_complex_new(DBL2NUM(re), DBL2NUM(im));
708 }
709 d = Get_Double(x);
710 domain_check_min(d, 0.0, "sqrt");
711 if (d == 0.0) return DBL2NUM(0.0);
712 return DBL2NUM(sqrt(d));
713}
714
715/*
716 * call-seq:
717 * Math.cbrt(x) -> float
718 *
719 * Returns the {cube root}[https://en.wikipedia.org/wiki/Cube_root] of +x+.
720 *
721 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
722 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
723 *
724 * Examples:
725 *
726 * cbrt(-INFINITY) # => -Infinity
727 * cbrt(-27.0) # => -3.0
728 * cbrt(-8.0) # => -2.0
729 * cbrt(-2.0) # => -1.2599210498948732
730 * cbrt(1.0) # => 1.0
731 * cbrt(0.0) # => 0.0
732 * cbrt(1.0) # => 1.0
733 * cbrt(2.0) # => 1.2599210498948732
734 * cbrt(8.0) # => 2.0
735 * cbrt(27.0) # => 3.0
736 * cbrt(INFINITY) # => Infinity
737 *
738 */
739
740static VALUE
741math_cbrt(VALUE unused_obj, VALUE x)
742{
743 double f = Get_Double(x);
744 double r = cbrt(f);
745#if defined __GLIBC__
746 if (isfinite(r) && !(f == 0.0 && r == 0.0)) {
747 r = (2.0 * r + (f / r / r)) / 3.0;
748 }
749#endif
750 return DBL2NUM(r);
751}
752
753/*
754 * call-seq:
755 * Math.frexp(x) -> [fraction, exponent]
756 *
757 * Returns a 2-element array containing the normalized signed float +fraction+
758 * and integer +exponent+ of +x+ such that:
759 *
760 * x = fraction * 2**exponent
761 *
762 * See {IEEE 754 double-precision binary floating-point format: binary64}[https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64].
763 *
764 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
765 * - Range <tt>[-INFINITY, INFINITY]</tt>.
766 *
767 * Examples:
768 *
769 * frexp(-INFINITY) # => [-Infinity, -1]
770 * frexp(-2.0) # => [-0.5, 2]
771 * frexp(-1.0) # => [-0.5, 1]
772 * frexp(0.0) # => [0.0, 0]
773 * frexp(1.0) # => [0.5, 1]
774 * frexp(2.0) # => [0.5, 2]
775 * frexp(INFINITY) # => [Infinity, -1]
776 *
777 * Related: Math.ldexp (inverse of Math.frexp).
778 *
779 */
780
781static VALUE
782math_frexp(VALUE unused_obj, VALUE x)
783{
784 double d;
785 int exp;
786
787 d = frexp(Get_Double(x), &exp);
788 return rb_assoc_new(DBL2NUM(d), INT2NUM(exp));
789}
790
791/*
792 * call-seq:
793 * Math.ldexp(fraction, exponent) -> float
794 *
795 * Returns the value of <tt>fraction * 2**exponent</tt>.
796 *
797 * - Domain of +fraction+: <tt>[0.0, 1.0)</tt>.
798 * - Domain of +exponent+: <tt>[0, 1024]</tt>
799 * (larger values are equivalent to 1024).
800 *
801 * See {IEEE 754 double-precision binary floating-point format: binary64}[https://en.wikipedia.org/wiki/Double-precision_floating-point_format#IEEE_754_double-precision_binary_floating-point_format:_binary64].
802 *
803 * Examples:
804 *
805 * ldexp(-INFINITY, -1) # => -Infinity
806 * ldexp(-0.5, 2) # => -2.0
807 * ldexp(-0.5, 1) # => -1.0
808 * ldexp(0.0, 0) # => 0.0
809 * ldexp(-0.5, 1) # => 1.0
810 * ldexp(-0.5, 2) # => 2.0
811 * ldexp(INFINITY, -1) # => Infinity
812 *
813 * Related: Math.frexp (inverse of Math.ldexp).
814 *
815 */
816
817static VALUE
818math_ldexp(VALUE unused_obj, VALUE x, VALUE n)
819{
820 return DBL2NUM(ldexp(Get_Double(x), NUM2INT(n)));
821}
822
823/*
824 * call-seq:
825 * Math.hypot(a, b) -> float
826 *
827 * Returns <tt>sqrt(a**2 + b**2)</tt>,
828 * which is the length of the longest side +c+ (the hypotenuse)
829 * of the right triangle whose other sides have lengths +a+ and +b+.
830 *
831 * - Domain of +a+: <tt>[-INFINITY, INFINITY]</tt>.
832 * - Domain of +ab: <tt>[-INFINITY, INFINITY]</tt>.
833 * - Range: <tt>[0, INFINITY]</tt>.
834 *
835 * Examples:
836 *
837 * hypot(0.0, 1.0) # => 1.0
838 * hypot(1.0, 1.0) # => 1.4142135623730951 # sqrt(2.0)
839 * hypot(3.0, 4.0) # => 5.0
840 * hypot(5.0, 12.0) # => 13.0
841 * hypot(1.0, sqrt(3.0)) # => 1.9999999999999998 # Near 2.0
842 *
843 * Note that if either argument is +INFINITY+ or <tt>-INFINITY</tt>,
844 * the result is +Infinity+.
845 *
846 */
847
848static VALUE
849math_hypot(VALUE unused_obj, VALUE x, VALUE y)
850{
851 return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
852}
853
854/*
855 * call-seq:
856 * Math.erf(x) -> float
857 *
858 * Returns the value of the {Gauss error function}[https://en.wikipedia.org/wiki/Error_function] for +x+.
859 *
860 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
861 * - Range: <tt>[-1, 1]</tt>.
862 *
863 * Examples:
864 *
865 * erf(-INFINITY) # => -1.0
866 * erf(0.0) # => 0.0
867 * erf(INFINITY) # => 1.0
868 *
869 * Related: Math.erfc.
870 *
871 */
872
873static VALUE
874math_erf(VALUE unused_obj, VALUE x)
875{
876 return DBL2NUM(erf(Get_Double(x)));
877}
878
879/*
880 * call-seq:
881 * Math.erfc(x) -> Float
882 *
883 * Returns the value of the {complementary error function}[https://en.wikipedia.org/wiki/Error_function#Complementary_error_function] for +x+.
884 *
885 * - Domain: <tt>[-INFINITY, INFINITY]</tt>.
886 * - Range: <tt>[0, 2]</tt>.
887 *
888 * Examples:
889 *
890 * erfc(-INFINITY) # => 2.0
891 * erfc(0.0) # => 1.0
892 * erfc(INFINITY) # => 0.0
893 *
894 * Related: Math.erf.
895 *
896 */
897
898static VALUE
899math_erfc(VALUE unused_obj, VALUE x)
900{
901 return DBL2NUM(erfc(Get_Double(x)));
902}
903
904/*
905 * call-seq:
906 * Math.gamma(x) -> float
907 *
908 * Returns the value of the {gamma function}[https://en.wikipedia.org/wiki/Gamma_function] for +x+.
909 *
910 * - Domain: <tt>(-INFINITY, INFINITY]</tt> excluding negative integers.
911 * - Range: <tt>[-INFINITY, INFINITY]</tt>.
912 *
913 * Examples:
914 *
915 * gamma(-2.5) # => -0.9453087204829431
916 * gamma(-1.5) # => 2.3632718012073513
917 * gamma(-0.5) # => -3.5449077018110375
918 * gamma(0.0) # => Infinity
919 * gamma(1.0) # => 1.0
920 * gamma(2.0) # => 1.0
921 * gamma(3.0) # => 2.0
922 * gamma(4.0) # => 6.0
923 * gamma(5.0) # => 24.0
924 *
925 * Related: Math.lgamma.
926 *
927 */
928
929static VALUE
930math_gamma(VALUE unused_obj, VALUE x)
931{
932 static const double fact_table[] = {
933 /* fact(0) */ 1.0,
934 /* fact(1) */ 1.0,
935 /* fact(2) */ 2.0,
936 /* fact(3) */ 6.0,
937 /* fact(4) */ 24.0,
938 /* fact(5) */ 120.0,
939 /* fact(6) */ 720.0,
940 /* fact(7) */ 5040.0,
941 /* fact(8) */ 40320.0,
942 /* fact(9) */ 362880.0,
943 /* fact(10) */ 3628800.0,
944 /* fact(11) */ 39916800.0,
945 /* fact(12) */ 479001600.0,
946 /* fact(13) */ 6227020800.0,
947 /* fact(14) */ 87178291200.0,
948 /* fact(15) */ 1307674368000.0,
949 /* fact(16) */ 20922789888000.0,
950 /* fact(17) */ 355687428096000.0,
951 /* fact(18) */ 6402373705728000.0,
952 /* fact(19) */ 121645100408832000.0,
953 /* fact(20) */ 2432902008176640000.0,
954 /* fact(21) */ 51090942171709440000.0,
955 /* fact(22) */ 1124000727777607680000.0,
956 /* fact(23)=25852016738884976640000 needs 56bit mantissa which is
957 * impossible to represent exactly in IEEE 754 double which have
958 * 53bit mantissa. */
959 };
960 enum {NFACT_TABLE = numberof(fact_table)};
961 double d;
962 d = Get_Double(x);
963 /* check for domain error */
964 if (isinf(d)) {
965 if (signbit(d)) domain_error("gamma");
966 return DBL2NUM(HUGE_VAL);
967 }
968 if (d == 0.0) {
969 return signbit(d) ? DBL2NUM(-HUGE_VAL) : DBL2NUM(HUGE_VAL);
970 }
971 if (d == floor(d)) {
972 domain_check_min(d, 0.0, "gamma");
973 if (1.0 <= d && d <= (double)NFACT_TABLE) {
974 return DBL2NUM(fact_table[(int)d - 1]);
975 }
976 }
977 return DBL2NUM(tgamma(d));
978}
979
980/*
981 * call-seq:
982 * Math.lgamma(x) -> [float, -1 or 1]
983 *
984 * Returns a 2-element array equivalent to:
985 *
986 * [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
987 *
988 * See {logarithmic gamma function}[https://en.wikipedia.org/wiki/Gamma_function#The_log-gamma_function].
989 *
990 * - Domain: <tt>(-INFINITY, INFINITY]</tt>.
991 * - Range of first element: <tt>(-INFINITY, INFINITY]</tt>.
992 * - Second element is -1 or 1.
993 *
994 * Examples:
995 *
996 * lgamma(-4.0) # => [Infinity, -1]
997 * lgamma(-3.0) # => [Infinity, -1]
998 * lgamma(-2.0) # => [Infinity, -1]
999 * lgamma(-1.0) # => [Infinity, -1]
1000 * lgamma(0.0) # => [Infinity, 1]
1001 *
1002 * lgamma(1.0) # => [0.0, 1]
1003 * lgamma(2.0) # => [0.0, 1]
1004 * lgamma(3.0) # => [0.6931471805599436, 1]
1005 * lgamma(4.0) # => [1.7917594692280545, 1]
1006 *
1007 * lgamma(-2.5) # => [-0.05624371649767279, -1]
1008 * lgamma(-1.5) # => [0.8600470153764797, 1]
1009 * lgamma(-0.5) # => [1.265512123484647, -1]
1010 * lgamma(0.5) # => [0.5723649429247004, 1]
1011 * lgamma(1.5) # => [-0.12078223763524676, 1]
1012 * lgamma(2.5) # => [0.2846828704729205, 1]
1013 *
1014 * Related: Math.gamma.
1015 *
1016 */
1017
1018static VALUE
1019math_lgamma(VALUE unused_obj, VALUE x)
1020{
1021 double d;
1022 int sign=1;
1023 VALUE v;
1024 d = Get_Double(x);
1025 /* check for domain error */
1026 if (isinf(d)) {
1027 if (signbit(d)) domain_error("lgamma");
1028 return rb_assoc_new(DBL2NUM(HUGE_VAL), INT2FIX(1));
1029 }
1030 if (d == 0.0) {
1031 VALUE vsign = signbit(d) ? INT2FIX(-1) : INT2FIX(+1);
1032 return rb_assoc_new(DBL2NUM(HUGE_VAL), vsign);
1033 }
1034 v = DBL2NUM(lgamma_r(d, &sign));
1035 return rb_assoc_new(v, INT2FIX(sign));
1036}
1037
1038
1039#define exp1(n) \
1040VALUE \
1041rb_math_##n(VALUE x)\
1042{\
1043 return math_##n(0, x);\
1044}
1045
1046#define exp2(n) \
1047VALUE \
1048rb_math_##n(VALUE x, VALUE y)\
1049{\
1050 return math_##n(0, x, y);\
1051}
1052
1053exp2(atan2)
1054exp1(cos)
1055exp1(cosh)
1056exp1(exp)
1057exp2(hypot)
1058exp1(sin)
1059exp1(sinh)
1060#if 0
1061exp1(sqrt)
1062#endif
1063
1064
1065/*
1066 * Document-class: Math::DomainError
1067 *
1068 * Raised when a mathematical function is evaluated outside of its
1069 * domain of definition.
1070 *
1071 * For example, since +cos+ returns values in the range -1..1,
1072 * its inverse function +acos+ is only defined on that interval:
1073 *
1074 * Math.acos(42)
1075 *
1076 * <em>produces:</em>
1077 *
1078 * Math::DomainError: Numerical argument is out of domain - "acos"
1079 */
1080
1081/*
1082 * Document-class: Math
1083 *
1084 * :include: doc/math/math.rdoc
1085 *
1086 */
1087
1088
1089void
1090InitVM_Math(void)
1091{
1092 rb_mMath = rb_define_module("Math");
1094
1095 /* Definition of the mathematical constant PI as a Float number. */
1096 rb_define_const(rb_mMath, "PI", DBL2NUM(M_PI));
1097
1098#ifdef M_E
1099 /* Definition of the mathematical constant E for Euler's number (e) as a Float number. */
1100 rb_define_const(rb_mMath, "E", DBL2NUM(M_E));
1101#else
1102 rb_define_const(rb_mMath, "E", DBL2NUM(exp(1.0)));
1103#endif
1104
1105 rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
1106 rb_define_module_function(rb_mMath, "cos", math_cos, 1);
1107 rb_define_module_function(rb_mMath, "sin", math_sin, 1);
1108 rb_define_module_function(rb_mMath, "tan", math_tan, 1);
1109
1110 rb_define_module_function(rb_mMath, "acos", math_acos, 1);
1111 rb_define_module_function(rb_mMath, "asin", math_asin, 1);
1112 rb_define_module_function(rb_mMath, "atan", math_atan, 1);
1113
1114 rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
1115 rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
1116 rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
1117
1118 rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
1119 rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
1120 rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
1121
1122 rb_define_module_function(rb_mMath, "exp", math_exp, 1);
1123 rb_define_module_function(rb_mMath, "log", math_log, -1);
1124 rb_define_module_function(rb_mMath, "log2", math_log2, 1);
1125 rb_define_module_function(rb_mMath, "log10", math_log10, 1);
1126 rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
1127 rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
1128
1129 rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
1130 rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
1131
1132 rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
1133
1134 rb_define_module_function(rb_mMath, "erf", math_erf, 1);
1135 rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
1136
1137 rb_define_module_function(rb_mMath, "gamma", math_gamma, 1);
1138 rb_define_module_function(rb_mMath, "lgamma", math_lgamma, 1);
1139}
1140
1141void
1142Init_Math(void)
1143{
1144 InitVM(Math);
1145}
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1510
VALUE rb_define_module(const char *name)
Defines a top-level module.
Definition class.c:1592
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3133
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
Definition value_type.h:59
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define SIZET2NUM
Old name of RB_SIZE2NUM.
Definition size_t.h:62
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define FIXNUM_P
Old name of RB_FIXNUM_P.
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
VALUE rb_eMathDomainError
Math::DomainError exception.
Definition math.c:29
VALUE rb_mMath
Math module.
Definition math.c:28
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:231
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376