12#include "ruby/internal/config.h"
15# define _USE_MATH_DEFINES 1
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"
31#define Get_Double(x) rb_num_to_dbl(x)
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)
66 if (dx == 0.0 && dy == 0.0) {
74 if (isinf(dx) && isinf(dy)) {
77 const double dz = (3.0 * M_PI / 4.0);
81 const double dz = (M_PI / 4.0);
114 return DBL2NUM(cos(Get_Double(x)));
141 return DBL2NUM(sin(Get_Double(x)));
169 return DBL2NUM(tan(Get_Double(x)));
172#define math_arc(num, func) \
174 d = Get_Double((num)); \
175 domain_check_range(d, -1.0, 1.0, #func); \
176 return DBL2NUM(func(d));
248 return DBL2NUM(atan(Get_Double(x)));
255 return (exp(x) + exp(-x)) / 2;
280 return DBL2NUM(cosh(Get_Double(x)));
287 return (exp(x) - exp(-x)) / 2;
312 return DBL2NUM(sinh(Get_Double(x)));
319# if defined(HAVE_SINH) && defined(HAVE_COSH)
320 const double c = cosh(x);
321 if (!isinf(c))
return sinh(x) / c;
323 const double e = exp(x+x);
324 if (!isinf(e))
return (e - 1) / (e + 1);
326 return x > 0 ? 1.0 : -1.0;
351 return DBL2NUM(tanh(Get_Double(x)));
376 domain_check_min(d, 1.0,
"acosh");
400 return DBL2NUM(asinh(Get_Double(x)));
426 domain_check_range(d, -1.0, +1.0,
"atanh");
428 if (d == -1.0)
return DBL2NUM(-HUGE_VAL);
429 if (d == +1.0)
return DBL2NUM(+HUGE_VAL);
457 return DBL2NUM(exp(Get_Double(x)));
460#if defined __CYGWIN__
461# include <cygwin/version.h>
462# if CYGWIN_VERSION_DLL_MAJOR < 1005
465# define log(x) ((x) < 0.0 ? nan("") : log(x))
466# define log10(x) ((x) < 0.0 ? nan("") : log10(x))
470# define M_LN2 0.693147180559945309417232121458176568
473# define M_LN10 2.30258509299404568401799145468436421
505math_log(
int argc,
const VALUE *argv,
VALUE unused_obj)
507 return rb_math_log(argc, argv);
511get_double_rshift(
VALUE x,
size_t *pnumbits)
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));
524 return Get_Double(x);
528math_log_split(
VALUE x,
size_t *numbits)
530 double d = get_double_rshift(x, numbits);
532 domain_check_min(d, 0.0,
"log");
536#if defined(log2) || defined(HAVE_LOG2)
537# define log_intermediate log2
539# define log_intermediate log10
540double log2(
double x);
544rb_math_log(
int argc,
const VALUE *argv)
551 d = math_log_split(x, &numbits);
554 double b = math_log_split(base, &numbits_2);
563 d = log_intermediate(d) / log_intermediate(b);
564 d += (numbits - numbits_2) / log2(b);
568 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
570 d += numbits * M_LN2;
580 return log10(x)/log10(2.0);
583extern double log2(
double);
609 double d = get_double_rshift(x, &numbits);
611 domain_check_min(d, 0.0,
"log2");
613 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
615 return DBL2NUM(log2(d) + numbits);
640 double d = get_double_rshift(x, &numbits);
642 domain_check_min(d, 0.0,
"log10");
644 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
646 return DBL2NUM(log10(d) + numbits * log10(2));
675 return rb_math_sqrt(x);
690 return RBOOL(!isnan(f) && signbit(f));
692 return f_negative_p(x);
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);
710 domain_check_min(d, 0.0,
"sqrt");
711 if (d == 0.0)
return DBL2NUM(0.0);
743 double f = Get_Double(x);
746 if (isfinite(r) && !(f == 0.0 && r == 0.0)) {
747 r = (2.0 * r + (f / r / r)) / 3.0;
787 d = frexp(Get_Double(x), &exp);
851 return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
876 return DBL2NUM(erf(Get_Double(x)));
901 return DBL2NUM(erfc(Get_Double(x)));
932 static const double fact_table[] = {
952 121645100408832000.0,
953 2432902008176640000.0,
954 51090942171709440000.0,
955 1124000727777607680000.0,
960 enum {NFACT_TABLE = numberof(fact_table)};
965 if (signbit(d)) domain_error(
"gamma");
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]);
1027 if (signbit(d)) domain_error(
"lgamma");
1034 v =
DBL2NUM(lgamma_r(d, &sign));
1041rb_math_##n(VALUE x)\
1043 return math_##n(0, x);\
1048rb_math_##n(VALUE x, VALUE y)\
1050 return math_##n(0, x, y);\
#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.
VALUE rb_define_module(const char *name)
Defines a top-level module.
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.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define INT2FIX
Old name of RB_INT2FIX.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define NUM2INT
Old name of RB_NUM2INT.
#define INT2NUM
Old name of RB_INT2NUM.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define DBL2NUM
Old name of rb_float_new.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
VALUE rb_eStandardError
StandardError exception.
VALUE rb_eMathDomainError
Math::DomainError exception.
VALUE rb_mMath
Math module.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
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.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.