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)));
485 return DBL2NUM(expm1(Get_Double(x)));
488#if defined __CYGWIN__
489# include <cygwin/version.h>
490# if CYGWIN_VERSION_DLL_MAJOR < 1005
493# define log(x) ((x) < 0.0 ? nan("") : log(x))
494# define log10(x) ((x) < 0.0 ? nan("") : log10(x))
498# define M_LN2 0.693147180559945309417232121458176568
501# define M_LN10 2.30258509299404568401799145468436421
533math_log(
int argc,
const VALUE *argv,
VALUE unused_obj)
535 return rb_math_log(argc, argv);
539get_double_rshift(
VALUE x,
size_t *pnumbits)
543 if (RB_BIGNUM_TYPE_P(x) && BIGNUM_POSITIVE_P(x) &&
544 DBL_MAX_EXP <= (numbits = rb_absint_numwords(x, 1, NULL))) {
545 numbits -= DBL_MANT_DIG;
546 x = rb_big_rshift(x,
SIZET2NUM(numbits));
552 return Get_Double(x);
556math_log_split(
VALUE x,
size_t *numbits)
558 double d = get_double_rshift(x, numbits);
560 domain_check_min(d, 0.0,
"log");
564#if defined(log2) || defined(HAVE_LOG2)
565# define log_intermediate log2
567# define log_intermediate log10
568double log2(
double x);
572rb_math_log(
int argc,
const VALUE *argv)
579 d = math_log_split(x, &numbits);
582 double b = math_log_split(base, &numbits_2);
591 d = log_intermediate(d) / log_intermediate(b);
592 d += (numbits - numbits_2) / log2(b);
596 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
598 d += numbits * M_LN2;
608 return log10(x)/log10(2.0);
611extern double log2(
double);
637 double d = get_double_rshift(x, &numbits);
639 domain_check_min(d, 0.0,
"log2");
641 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
643 return DBL2NUM(log2(d) + numbits);
668 double d = get_double_rshift(x, &numbits);
670 domain_check_min(d, 0.0,
"log10");
672 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
674 return DBL2NUM(log10(d) + numbits * log10(2));
699 double d = get_double_rshift(x, &numbits);
702 x = rb_big_plus(x,
INT2FIX(1));
703 d = math_log_split(x, &numbits);
705 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
707 d += numbits * M_LN2;
711 domain_check_min(d, -1.0,
"log1p");
713 if (d == -1.0)
return DBL2NUM(-HUGE_VAL);
744 return rb_math_sqrt(x);
759 return RBOOL(!isnan(f) && signbit(f));
761 return f_negative_p(x);
770 VALUE neg = f_signbit(RCOMPLEX(x)->imag);
771 double re = Get_Double(RCOMPLEX(x)->real), im;
772 d = Get_Double(rb_complex_abs(x));
773 im = sqrt((d - re) / 2.0);
774 re = sqrt((d + re) / 2.0);
779 domain_check_min(d, 0.0,
"sqrt");
780 if (d == 0.0)
return DBL2NUM(0.0);
812 double f = Get_Double(x);
815 if (isfinite(r) && !(f == 0.0 && r == 0.0)) {
816 r = (2.0 * r + (f / r / r)) / 3.0;
856 d = frexp(Get_Double(x), &exp);
920 return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
945 return DBL2NUM(erf(Get_Double(x)));
970 return DBL2NUM(erfc(Get_Double(x)));
1001 static const double fact_table[] = {
1021 121645100408832000.0,
1022 2432902008176640000.0,
1023 51090942171709440000.0,
1024 1124000727777607680000.0,
1029 enum {NFACT_TABLE = numberof(fact_table)};
1034 if (signbit(d)) domain_error(
"gamma");
1040 if (d == floor(d)) {
1041 domain_check_min(d, 0.0,
"gamma");
1042 if (1.0 <= d && d <= (
double)NFACT_TABLE) {
1043 return DBL2NUM(fact_table[(
int)d - 1]);
1096 if (signbit(d)) domain_error(
"lgamma");
1103 v =
DBL2NUM(lgamma_r(d, &sign));
1110rb_math_##n(VALUE x)\
1112 return math_##n(0, x);\
1117rb_math_##n(VALUE x, VALUE y)\
1119 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.