2 ** math.c - Math module
4 ** See Copyright Notice in mruby.h
7 #ifdef MRB_WITHOUT_FLOAT
8 # error Math conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb'
12 #include <mruby/array.h>
17 domain_error(mrb_state *mrb, const char *func)
19 struct RClass *math = mrb_module_get(mrb, "Math");
20 struct RClass *domainerror = mrb_class_get_under(mrb, math, "DomainError");
21 mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %s", func);
24 /* math functions not provided by Microsoft Visual C++ 2012 or older */
25 #if defined _MSC_VER && _MSC_VER <= 1700
34 /* Basic formula loses precision for x < 0, but asinh is an odd function */
36 if (xa > 3.16227E+18) {
37 /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */
38 ya = log(xa) + 0.69314718055994530942;
41 /* Basic formula for asinh */
42 ya = log(xa + sqrt(xa*xa + 1.0));
54 if (x > 3.16227E+18) {
55 /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */
56 y = log(x) + 0.69314718055994530942;
59 /* Basic formula for acosh */
60 y = log(x + sqrt(x*x - 1.0));
72 /* The sums 1+x and 1-x lose precision for small x. Use the polynomial
75 y = x*(1.0 + x2*(1.0/3.0 + x2*(1.0/5.0 + x2*(1.0/7.0))));
78 /* Basic formula for atanh */
79 y = 0.5 * (log(1.0+x) - log(1.0-x));
90 /* pow(x, y) is undefined for x < 0 and y not an integer, but cbrt is an
93 ya = pow(xa, 1.0/3.0);
98 /* Declaration of complementary Error function */
103 ** Implementations of error functions
104 ** credits to http://www.digitalmars.com/archives/cplusplus/3634.html
107 /* Implementation of Error function */
111 static const double two_sqrtpi = 1.128379167095512574;
117 return 1.0 - erfc(x);
127 } while (fabs(term/sum) > DBL_EPSILON);
128 return two_sqrtpi*sum;
131 /* Implementation of complementary Error function */
135 static const double one_sqrtpi= 0.564189583547756287;
147 if (x < 0.0) { /*signbit(x)*/
148 return 2.0 - erfc(-x);
160 } while (fabs(q1-q2)/q2 > DBL_EPSILON);
161 return one_sqrtpi*exp(-x*x)*q2;
166 #if defined __FreeBSD__ && !defined __FreeBSD_version
167 #include <osreldate.h> /* for __FreeBSD_version */
170 #if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000)
175 return log10(x)/log10(2.0);
181 TRIGONOMETRIC FUNCTIONS
186 * Math.sin(x) -> float
188 * Computes the sine of <i>x</i> (expressed in radians). Returns
192 math_sin(mrb_state *mrb, mrb_value obj)
196 mrb_get_args(mrb, "f", &x);
199 return mrb_float_value(mrb, x);
204 * Math.cos(x) -> float
206 * Computes the cosine of <i>x</i> (expressed in radians). Returns
210 math_cos(mrb_state *mrb, mrb_value obj)
214 mrb_get_args(mrb, "f", &x);
217 return mrb_float_value(mrb, x);
222 * Math.tan(x) -> float
224 * Returns the tangent of <i>x</i> (expressed in radians).
227 math_tan(mrb_state *mrb, mrb_value obj)
231 mrb_get_args(mrb, "f", &x);
234 return mrb_float_value(mrb, x);
238 INVERSE TRIGONOMETRIC FUNCTIONS
243 * Math.asin(x) -> float
245 * Computes the arc sine of <i>x</i>.
246 * @return computed value between `-(PI/2)` and `(PI/2)`.
249 math_asin(mrb_state *mrb, mrb_value obj)
253 mrb_get_args(mrb, "f", &x);
254 if (x < -1.0 || x > 1.0) {
255 domain_error(mrb, "asin");
259 return mrb_float_value(mrb, x);
264 * Math.acos(x) -> float
266 * Computes the arc cosine of <i>x</i>. Returns 0..PI.
269 math_acos(mrb_state *mrb, mrb_value obj)
273 mrb_get_args(mrb, "f", &x);
274 if (x < -1.0 || x > 1.0) {
275 domain_error(mrb, "acos");
279 return mrb_float_value(mrb, x);
284 * Math.atan(x) -> float
286 * Computes the arc tangent of <i>x</i>. Returns `-(PI/2) .. (PI/2)`.
289 math_atan(mrb_state *mrb, mrb_value obj)
293 mrb_get_args(mrb, "f", &x);
296 return mrb_float_value(mrb, x);
301 * Math.atan2(y, x) -> float
303 * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
306 * Math.atan2(-0.0, -1.0) #=> -3.141592653589793
307 * Math.atan2(-1.0, -1.0) #=> -2.356194490192345
308 * Math.atan2(-1.0, 0.0) #=> -1.5707963267948966
309 * Math.atan2(-1.0, 1.0) #=> -0.7853981633974483
310 * Math.atan2(-0.0, 1.0) #=> -0.0
311 * Math.atan2(0.0, 1.0) #=> 0.0
312 * Math.atan2(1.0, 1.0) #=> 0.7853981633974483
313 * Math.atan2(1.0, 0.0) #=> 1.5707963267948966
314 * Math.atan2(1.0, -1.0) #=> 2.356194490192345
315 * Math.atan2(0.0, -1.0) #=> 3.141592653589793
319 math_atan2(mrb_state *mrb, mrb_value obj)
323 mrb_get_args(mrb, "ff", &x, &y);
326 return mrb_float_value(mrb, x);
332 HYPERBOLIC TRIG FUNCTIONS
336 * Math.sinh(x) -> float
338 * Computes the hyperbolic sine of <i>x</i> (expressed in
342 math_sinh(mrb_state *mrb, mrb_value obj)
346 mrb_get_args(mrb, "f", &x);
349 return mrb_float_value(mrb, x);
354 * Math.cosh(x) -> float
356 * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
359 math_cosh(mrb_state *mrb, mrb_value obj)
363 mrb_get_args(mrb, "f", &x);
366 return mrb_float_value(mrb, x);
371 * Math.tanh() -> float
373 * Computes the hyperbolic tangent of <i>x</i> (expressed in
377 math_tanh(mrb_state *mrb, mrb_value obj)
381 mrb_get_args(mrb, "f", &x);
384 return mrb_float_value(mrb, x);
389 INVERSE HYPERBOLIC TRIG FUNCTIONS
394 * Math.asinh(x) -> float
396 * Computes the inverse hyperbolic sine of <i>x</i>.
399 math_asinh(mrb_state *mrb, mrb_value obj)
403 mrb_get_args(mrb, "f", &x);
407 return mrb_float_value(mrb, x);
412 * Math.acosh(x) -> float
414 * Computes the inverse hyperbolic cosine of <i>x</i>.
417 math_acosh(mrb_state *mrb, mrb_value obj)
421 mrb_get_args(mrb, "f", &x);
423 domain_error(mrb, "acosh");
427 return mrb_float_value(mrb, x);
432 * Math.atanh(x) -> float
434 * Computes the inverse hyperbolic tangent of <i>x</i>.
437 math_atanh(mrb_state *mrb, mrb_value obj)
441 mrb_get_args(mrb, "f", &x);
442 if (x < -1.0 || x > 1.0) {
443 domain_error(mrb, "atanh");
447 return mrb_float_value(mrb, x);
451 EXPONENTIALS AND LOGARITHMS
456 * Math.exp(x) -> float
460 * Math.exp(0) #=> 1.0
461 * Math.exp(1) #=> 2.718281828459045
462 * Math.exp(1.5) #=> 4.4816890703380645
466 math_exp(mrb_state *mrb, mrb_value obj)
470 mrb_get_args(mrb, "f", &x);
473 return mrb_float_value(mrb, x);
478 * Math.log(numeric) -> float
479 * Math.log(num,base) -> float
481 * Returns the natural logarithm of <i>numeric</i>.
482 * If additional second argument is given, it will be the base
485 * Math.log(1) #=> 0.0
486 * Math.log(Math::E) #=> 1.0
487 * Math.log(Math::E**3) #=> 3.0
488 * Math.log(12,3) #=> 2.2618595071429146
492 math_log(mrb_state *mrb, mrb_value obj)
497 argc = mrb_get_args(mrb, "f|f", &x, &base);
499 domain_error(mrb, "log");
504 domain_error(mrb, "log");
508 return mrb_float_value(mrb, x);
513 * Math.log2(numeric) -> float
515 * Returns the base 2 logarithm of <i>numeric</i>.
517 * Math.log2(1) #=> 0.0
518 * Math.log2(2) #=> 1.0
519 * Math.log2(32768) #=> 15.0
520 * Math.log2(65536) #=> 16.0
524 math_log2(mrb_state *mrb, mrb_value obj)
528 mrb_get_args(mrb, "f", &x);
530 domain_error(mrb, "log2");
534 return mrb_float_value(mrb, x);
539 * Math.log10(numeric) -> float
541 * Returns the base 10 logarithm of <i>numeric</i>.
543 * Math.log10(1) #=> 0.0
544 * Math.log10(10) #=> 1.0
545 * Math.log10(10**100) #=> 100.0
549 math_log10(mrb_state *mrb, mrb_value obj)
553 mrb_get_args(mrb, "f", &x);
555 domain_error(mrb, "log10");
559 return mrb_float_value(mrb, x);
564 * Math.sqrt(numeric) -> float
566 * Returns the square root of <i>numeric</i>.
570 math_sqrt(mrb_state *mrb, mrb_value obj)
574 mrb_get_args(mrb, "f", &x);
576 domain_error(mrb, "sqrt");
580 return mrb_float_value(mrb, x);
586 * Math.cbrt(numeric) -> float
588 * Returns the cube root of <i>numeric</i>.
591 * p [x, Math.cbrt(x), Math.cbrt(x)**3]
594 * [-9, -2.0800838230519, -9.0]
596 * [-7, -1.91293118277239, -7.0]
597 * [-6, -1.81712059283214, -6.0]
598 * [-5, -1.7099759466767, -5.0]
599 * [-4, -1.5874010519682, -4.0]
600 * [-3, -1.44224957030741, -3.0]
601 * [-2, -1.25992104989487, -2.0]
605 * [2, 1.25992104989487, 2.0]
606 * [3, 1.44224957030741, 3.0]
607 * [4, 1.5874010519682, 4.0]
608 * [5, 1.7099759466767, 5.0]
609 * [6, 1.81712059283214, 6.0]
610 * [7, 1.91293118277239, 7.0]
612 * [9, 2.0800838230519, 9.0]
616 math_cbrt(mrb_state *mrb, mrb_value obj)
620 mrb_get_args(mrb, "f", &x);
623 return mrb_float_value(mrb, x);
629 * Math.frexp(numeric) -> [ fraction, exponent ]
631 * Returns a two-element array containing the normalized fraction (a
632 * <code>Float</code>) and exponent (a <code>Fixnum</code>) of
635 * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
636 * fraction * 2**exponent #=> 1234.0
639 math_frexp(mrb_state *mrb, mrb_value obj)
644 mrb_get_args(mrb, "f", &x);
647 return mrb_assoc_new(mrb, mrb_float_value(mrb, x), mrb_fixnum_value(exp));
652 * Math.ldexp(flt, int) -> float
654 * Returns the value of <i>flt</i>*(2**<i>int</i>).
656 * fraction, exponent = Math.frexp(1234)
657 * Math.ldexp(fraction, exponent) #=> 1234.0
660 math_ldexp(mrb_state *mrb, mrb_value obj)
665 mrb_get_args(mrb, "fi", &x, &i);
666 x = ldexp(x, (int)i);
668 return mrb_float_value(mrb, x);
673 * Math.hypot(x, y) -> float
675 * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
676 * with sides <i>x</i> and <i>y</i>.
678 * Math.hypot(3, 4) #=> 5.0
681 math_hypot(mrb_state *mrb, mrb_value obj)
685 mrb_get_args(mrb, "ff", &x, &y);
688 return mrb_float_value(mrb, x);
693 * Math.erf(x) -> float
695 * Calculates the error function of x.
698 math_erf(mrb_state *mrb, mrb_value obj)
702 mrb_get_args(mrb, "f", &x);
705 return mrb_float_value(mrb, x);
711 * Math.erfc(x) -> float
713 * Calculates the complementary error function of x.
716 math_erfc(mrb_state *mrb, mrb_value obj)
720 mrb_get_args(mrb, "f", &x);
723 return mrb_float_value(mrb, x);
726 /* ------------------------------------------------------------------------*/
728 mrb_mruby_math_gem_init(mrb_state* mrb)
730 struct RClass *mrb_math;
731 mrb_math = mrb_define_module(mrb, "Math");
733 mrb_define_class_under(mrb, mrb_math, "DomainError", mrb->eStandardError_class);
736 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, M_PI));
738 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, atan(1.0)*4.0));
742 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, M_E));
744 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0)));
747 mrb_define_module_function(mrb, mrb_math, "sin", math_sin, MRB_ARGS_REQ(1));
748 mrb_define_module_function(mrb, mrb_math, "cos", math_cos, MRB_ARGS_REQ(1));
749 mrb_define_module_function(mrb, mrb_math, "tan", math_tan, MRB_ARGS_REQ(1));
751 mrb_define_module_function(mrb, mrb_math, "asin", math_asin, MRB_ARGS_REQ(1));
752 mrb_define_module_function(mrb, mrb_math, "acos", math_acos, MRB_ARGS_REQ(1));
753 mrb_define_module_function(mrb, mrb_math, "atan", math_atan, MRB_ARGS_REQ(1));
754 mrb_define_module_function(mrb, mrb_math, "atan2", math_atan2, MRB_ARGS_REQ(2));
756 mrb_define_module_function(mrb, mrb_math, "sinh", math_sinh, MRB_ARGS_REQ(1));
757 mrb_define_module_function(mrb, mrb_math, "cosh", math_cosh, MRB_ARGS_REQ(1));
758 mrb_define_module_function(mrb, mrb_math, "tanh", math_tanh, MRB_ARGS_REQ(1));
760 mrb_define_module_function(mrb, mrb_math, "asinh", math_asinh, MRB_ARGS_REQ(1));
761 mrb_define_module_function(mrb, mrb_math, "acosh", math_acosh, MRB_ARGS_REQ(1));
762 mrb_define_module_function(mrb, mrb_math, "atanh", math_atanh, MRB_ARGS_REQ(1));
764 mrb_define_module_function(mrb, mrb_math, "exp", math_exp, MRB_ARGS_REQ(1));
765 mrb_define_module_function(mrb, mrb_math, "log", math_log, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
766 mrb_define_module_function(mrb, mrb_math, "log2", math_log2, MRB_ARGS_REQ(1));
767 mrb_define_module_function(mrb, mrb_math, "log10", math_log10, MRB_ARGS_REQ(1));
768 mrb_define_module_function(mrb, mrb_math, "sqrt", math_sqrt, MRB_ARGS_REQ(1));
769 mrb_define_module_function(mrb, mrb_math, "cbrt", math_cbrt, MRB_ARGS_REQ(1));
771 mrb_define_module_function(mrb, mrb_math, "frexp", math_frexp, MRB_ARGS_REQ(1));
772 mrb_define_module_function(mrb, mrb_math, "ldexp", math_ldexp, MRB_ARGS_REQ(2));
774 mrb_define_module_function(mrb, mrb_math, "hypot", math_hypot, MRB_ARGS_REQ(2));
776 mrb_define_module_function(mrb, mrb_math, "erf", math_erf, MRB_ARGS_REQ(1));
777 mrb_define_module_function(mrb, mrb_math, "erfc", math_erfc, MRB_ARGS_REQ(1));
781 mrb_mruby_math_gem_final(mrb_state* mrb)