12 #include "ruby/internal/config.h"
15 # define _USE_MATH_DEFINES 1
23 #include "internal/bignum.h"
24 #include "internal/complex.h"
25 #include "internal/math.h"
26 #include "internal/object.h"
27 #include "internal/vm.h"
32 #define Get_Double(x) rb_num_to_dbl(x)
34 #define domain_error(msg) \
35 rb_raise(rb_eMathDomainError, "Numerical argument is out of domain - " msg)
36 #define domain_check_min(val, min, msg) \
37 ((val) < (min) ? domain_error(msg) : (void)0)
38 #define domain_check_range(val, min, max, msg) \
39 ((val) < (min) || (max) < (val) ? domain_error(msg) : (void)0)
77 if (dx == 0.0 && dy == 0.0) {
85 if (isinf(dx) && isinf(dy)) {
88 const double dz = (3.0 * M_PI / 4.0);
92 const double dz = (M_PI / 4.0);
119 return DBL2NUM(cos(Get_Double(x)));
140 return DBL2NUM(sin(Get_Double(x)));
161 return DBL2NUM(tan(Get_Double(x)));
184 domain_check_range(d, -1.0, 1.0,
"acos");
207 domain_check_range(d, -1.0, 1.0,
"asin");
227 return DBL2NUM(atan(Get_Double(x)));
234 return (exp(x) + exp(-x)) / 2;
255 return DBL2NUM(cosh(Get_Double(x)));
262 return (exp(x) - exp(-x)) / 2;
283 return DBL2NUM(sinh(Get_Double(x)));
290 # if defined(HAVE_SINH) && defined(HAVE_COSH)
291 const double c = cosh(x);
292 if (!isinf(c))
return sinh(x) / c;
294 const double e = exp(x+x);
295 if (!isinf(e))
return (e - 1) / (e + 1);
297 return x > 0 ? 1.0 : -1.0;
318 return DBL2NUM(tanh(Get_Double(x)));
341 domain_check_min(d, 1.0,
"acosh");
362 return DBL2NUM(asinh(Get_Double(x)));
385 domain_check_range(d, -1.0, +1.0,
"atanh");
387 if (d == -1.0)
return DBL2NUM(-HUGE_VAL);
388 if (d == +1.0)
return DBL2NUM(+HUGE_VAL);
411 return DBL2NUM(exp(Get_Double(x)));
414 #if defined __CYGWIN__
415 # include <cygwin/version.h>
416 # if CYGWIN_VERSION_DLL_MAJOR < 1005
417 # define nan(x) nan()
419 # define log(x) ((x) < 0.0 ? nan("") : log(x))
420 # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
424 # define M_LN2 0.693147180559945309417232121458176568
427 # define M_LN10 2.30258509299404568401799145468436421
430 static double math_log1(
VALUE x);
455 math_log(
int argc,
const VALUE *argv,
VALUE unused_obj)
457 return rb_math_log(argc, argv);
461 rb_math_log(
int argc,
const VALUE *argv)
469 d /= math_log1(base);
475 get_double_rshift(
VALUE x,
size_t *pnumbits)
479 if (RB_BIGNUM_TYPE_P(x) && BIGNUM_POSITIVE_P(x) &&
481 numbits -= DBL_MANT_DIG;
488 return Get_Double(x);
495 double d = get_double_rshift(x, &numbits);
497 domain_check_min(d, 0.0,
"log");
499 if (d == 0.0)
return -HUGE_VAL;
501 return log(d) + numbits * M_LN2;
509 return log10(x)/log10(2.0);
512 extern double log2(
double);
537 double d = get_double_rshift(x, &numbits);
539 domain_check_min(d, 0.0,
"log2");
541 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
543 return DBL2NUM(log2(d) + numbits);
566 double d = get_double_rshift(x, &numbits);
568 domain_check_min(d, 0.0,
"log10");
570 if (d == 0.0)
return DBL2NUM(-HUGE_VAL);
572 return DBL2NUM(log10(d) + numbits * log10(2));
613 return rb_math_sqrt(x);
617 f_negative_p(
VALUE x)
628 return RBOOL(!isnan(f) && signbit(f));
630 return f_negative_p(x);
634 rb_math_sqrt(
VALUE x)
639 VALUE neg = f_signbit(RCOMPLEX(x)->imag);
640 double re = Get_Double(RCOMPLEX(x)->real), im;
642 im = sqrt((d - re) / 2.0);
643 re = sqrt((d + re) / 2.0);
648 domain_check_min(d, 0.0,
"sqrt");
649 if (d == 0.0)
return DBL2NUM(0.0);
691 double f = Get_Double(x);
693 #if defined __GLIBC__
694 if (isfinite(r) && !(f == 0.0 && r == 0.0)) {
695 r = (2.0 * r + (f / r / r)) / 3.0;
718 d = frexp(Get_Double(x), &exp);
751 return DBL2NUM(hypot(Get_Double(x), Get_Double(y)));
771 return DBL2NUM(erf(Get_Double(x)));
791 return DBL2NUM(erfc(Get_Double(x)));
837 static const double fact_table[] = {
857 121645100408832000.0,
858 2432902008176640000.0,
859 51090942171709440000.0,
860 1124000727777607680000.0,
865 enum {NFACT_TABLE = numberof(fact_table)};
870 if (signbit(d)) domain_error(
"gamma");
877 domain_check_min(d, 0.0,
"gamma");
878 if (1.0 <= d && d <= (
double)NFACT_TABLE) {
879 return DBL2NUM(fact_table[(
int)d - 1]);
908 if (signbit(d)) domain_error(
"lgamma");
915 v =
DBL2NUM(lgamma_r(d, &sign));
922 rb_math_##n(VALUE x)\
924 return math_##n(0, x);\
929 rb_math_##n(VALUE x, VALUE y)\
931 return math_##n(0, x, y);\
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.
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for a 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.
size_t rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
Calculates the number of words needed represent the absolute value of the passed integer.
VALUE rb_big_rshift(VALUE x, VALUE y)
Performs shift right.
VALUE rb_complex_new(VALUE real, VALUE imag)
Constructs a Complex, by first multiplying the imaginary part with 1i then adds it to the real part.
VALUE rb_complex_abs(VALUE z)
Queries the absolute (or the magnitude) of the passed object.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
#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.