2 ** math.c - Math module
4 ** See Copyright Notice in mruby.h
8 #include <mruby/array.h>
13 domain_error(mrb_state *mrb, const char *func)
15 struct RClass *math = mrb_module_get(mrb, "Math");
16 struct RClass *domainerror = mrb_class_get_under(mrb, math, "DomainError");
17 mrb_value str = mrb_str_new_cstr(mrb, func);
18 mrb_raisef(mrb, domainerror, "Numerical argument is out of domain - %S", str);
21 /* math functions not provided by Microsoft Visual C++ 2012 or older */
22 #if defined _MSC_VER && _MSC_VER <= 1700
31 /* Basic formula loses precision for x < 0, but asinh is an odd function */
33 if (xa > 3.16227E+18) {
34 /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */
35 ya = log(xa) + 0.69314718055994530942;
38 /* Basic formula for asinh */
39 ya = log(xa + sqrt(xa*xa + 1.0));
51 if (x > 3.16227E+18) {
52 /* Prevent x*x from overflowing; basic formula reduces to log(2*x) */
53 y = log(x) + 0.69314718055994530942;
56 /* Basic formula for acosh */
57 y = log(x + sqrt(x*x - 1.0));
69 /* The sums 1+x and 1-x lose precision for small x. Use the polynomial
72 y = x*(1.0 + x2*(1.0/3.0 + x2*(1.0/5.0 + x2*(1.0/7.0))));
75 /* Basic formula for atanh */
76 y = 0.5 * (log(1.0+x) - log(1.0-x));
87 /* pow(x, y) is undefined for x < 0 and y not an integer, but cbrt is an
90 ya = pow(xa, 1.0/3.0);
95 /* Declaration of complementary Error function */
100 ** Implementations of error functions
101 ** credits to http://www.digitalmars.com/archives/cplusplus/3634.html
104 /* Implementation of Error function */
108 static const double two_sqrtpi = 1.128379167095512574;
114 return 1.0 - erfc(x);
124 } while (fabs(term/sum) > DBL_EPSILON);
125 return two_sqrtpi*sum;
128 /* Implementation of complementary Error function */
132 static const double one_sqrtpi= 0.564189583547756287;
144 if (x < 0.0) { /*signbit(x)*/
145 return 2.0 - erfc(-x);
157 } while (fabs(q1-q2)/q2 > DBL_EPSILON);
158 return one_sqrtpi*exp(-x*x)*q2;
163 #if defined __FreeBSD__ && !defined __FreeBSD_version
164 #include <osreldate.h> /* for __FreeBSD_version */
167 #if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000)
172 return log10(x)/log10(2.0);
178 TRIGONOMETRIC FUNCTIONS
183 * Math.sin(x) -> float
185 * Computes the sine of <i>x</i> (expressed in radians). Returns
189 math_sin(mrb_state *mrb, mrb_value obj)
193 mrb_get_args(mrb, "f", &x);
196 return mrb_float_value(mrb, x);
201 * Math.cos(x) -> float
203 * Computes the cosine of <i>x</i> (expressed in radians). Returns
207 math_cos(mrb_state *mrb, mrb_value obj)
211 mrb_get_args(mrb, "f", &x);
214 return mrb_float_value(mrb, x);
219 * Math.tan(x) -> float
221 * Returns the tangent of <i>x</i> (expressed in radians).
224 math_tan(mrb_state *mrb, mrb_value obj)
228 mrb_get_args(mrb, "f", &x);
231 return mrb_float_value(mrb, x);
235 INVERSE TRIGONOMETRIC FUNCTIONS
240 * Math.asin(x) -> float
242 * Computes the arc sine of <i>x</i>.
243 * @return computed value between `-(PI/2)` and `(PI/2)`.
246 math_asin(mrb_state *mrb, mrb_value obj)
250 mrb_get_args(mrb, "f", &x);
251 if (x < -1.0 || x > 1.0) {
252 domain_error(mrb, "asin");
256 return mrb_float_value(mrb, x);
261 * Math.acos(x) -> float
263 * Computes the arc cosine of <i>x</i>. Returns 0..PI.
266 math_acos(mrb_state *mrb, mrb_value obj)
270 mrb_get_args(mrb, "f", &x);
271 if (x < -1.0 || x > 1.0) {
272 domain_error(mrb, "acos");
276 return mrb_float_value(mrb, x);
281 * Math.atan(x) -> float
283 * Computes the arc tangent of <i>x</i>. Returns `-(PI/2) .. (PI/2)`.
286 math_atan(mrb_state *mrb, mrb_value obj)
290 mrb_get_args(mrb, "f", &x);
293 return mrb_float_value(mrb, x);
298 * Math.atan2(y, x) -> float
300 * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
303 * Math.atan2(-0.0, -1.0) #=> -3.141592653589793
304 * Math.atan2(-1.0, -1.0) #=> -2.356194490192345
305 * Math.atan2(-1.0, 0.0) #=> -1.5707963267948966
306 * Math.atan2(-1.0, 1.0) #=> -0.7853981633974483
307 * Math.atan2(-0.0, 1.0) #=> -0.0
308 * Math.atan2(0.0, 1.0) #=> 0.0
309 * Math.atan2(1.0, 1.0) #=> 0.7853981633974483
310 * Math.atan2(1.0, 0.0) #=> 1.5707963267948966
311 * Math.atan2(1.0, -1.0) #=> 2.356194490192345
312 * Math.atan2(0.0, -1.0) #=> 3.141592653589793
316 math_atan2(mrb_state *mrb, mrb_value obj)
320 mrb_get_args(mrb, "ff", &x, &y);
323 return mrb_float_value(mrb, x);
329 HYPERBOLIC TRIG FUNCTIONS
333 * Math.sinh(x) -> float
335 * Computes the hyperbolic sine of <i>x</i> (expressed in
339 math_sinh(mrb_state *mrb, mrb_value obj)
343 mrb_get_args(mrb, "f", &x);
346 return mrb_float_value(mrb, x);
351 * Math.cosh(x) -> float
353 * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
356 math_cosh(mrb_state *mrb, mrb_value obj)
360 mrb_get_args(mrb, "f", &x);
363 return mrb_float_value(mrb, x);
368 * Math.tanh() -> float
370 * Computes the hyperbolic tangent of <i>x</i> (expressed in
374 math_tanh(mrb_state *mrb, mrb_value obj)
378 mrb_get_args(mrb, "f", &x);
381 return mrb_float_value(mrb, x);
386 INVERSE HYPERBOLIC TRIG FUNCTIONS
391 * Math.asinh(x) -> float
393 * Computes the inverse hyperbolic sine of <i>x</i>.
396 math_asinh(mrb_state *mrb, mrb_value obj)
400 mrb_get_args(mrb, "f", &x);
404 return mrb_float_value(mrb, x);
409 * Math.acosh(x) -> float
411 * Computes the inverse hyperbolic cosine of <i>x</i>.
414 math_acosh(mrb_state *mrb, mrb_value obj)
418 mrb_get_args(mrb, "f", &x);
420 domain_error(mrb, "acosh");
424 return mrb_float_value(mrb, x);
429 * Math.atanh(x) -> float
431 * Computes the inverse hyperbolic tangent of <i>x</i>.
434 math_atanh(mrb_state *mrb, mrb_value obj)
438 mrb_get_args(mrb, "f", &x);
439 if (x < -1.0 || x > 1.0) {
440 domain_error(mrb, "atanh");
444 return mrb_float_value(mrb, x);
448 EXPONENTIALS AND LOGARITHMS
453 * Math.exp(x) -> float
457 * Math.exp(0) #=> 1.0
458 * Math.exp(1) #=> 2.718281828459045
459 * Math.exp(1.5) #=> 4.4816890703380645
463 math_exp(mrb_state *mrb, mrb_value obj)
467 mrb_get_args(mrb, "f", &x);
470 return mrb_float_value(mrb, x);
475 * Math.log(numeric) -> float
476 * Math.log(num,base) -> float
478 * Returns the natural logarithm of <i>numeric</i>.
479 * If additional second argument is given, it will be the base
482 * Math.log(1) #=> 0.0
483 * Math.log(Math::E) #=> 1.0
484 * Math.log(Math::E**3) #=> 3.0
485 * Math.log(12,3) #=> 2.2618595071429146
489 math_log(mrb_state *mrb, mrb_value obj)
494 argc = mrb_get_args(mrb, "f|f", &x, &base);
496 domain_error(mrb, "log");
501 domain_error(mrb, "log");
505 return mrb_float_value(mrb, x);
510 * Math.log2(numeric) -> float
512 * Returns the base 2 logarithm of <i>numeric</i>.
514 * Math.log2(1) #=> 0.0
515 * Math.log2(2) #=> 1.0
516 * Math.log2(32768) #=> 15.0
517 * Math.log2(65536) #=> 16.0
521 math_log2(mrb_state *mrb, mrb_value obj)
525 mrb_get_args(mrb, "f", &x);
527 domain_error(mrb, "log2");
531 return mrb_float_value(mrb, x);
536 * Math.log10(numeric) -> float
538 * Returns the base 10 logarithm of <i>numeric</i>.
540 * Math.log10(1) #=> 0.0
541 * Math.log10(10) #=> 1.0
542 * Math.log10(10**100) #=> 100.0
546 math_log10(mrb_state *mrb, mrb_value obj)
550 mrb_get_args(mrb, "f", &x);
552 domain_error(mrb, "log10");
556 return mrb_float_value(mrb, x);
561 * Math.sqrt(numeric) -> float
563 * Returns the square root of <i>numeric</i>.
567 math_sqrt(mrb_state *mrb, mrb_value obj)
571 mrb_get_args(mrb, "f", &x);
573 domain_error(mrb, "sqrt");
577 return mrb_float_value(mrb, x);
583 * Math.cbrt(numeric) -> float
585 * Returns the cube root of <i>numeric</i>.
588 * p [x, Math.cbrt(x), Math.cbrt(x)**3]
591 * [-9, -2.0800838230519, -9.0]
593 * [-7, -1.91293118277239, -7.0]
594 * [-6, -1.81712059283214, -6.0]
595 * [-5, -1.7099759466767, -5.0]
596 * [-4, -1.5874010519682, -4.0]
597 * [-3, -1.44224957030741, -3.0]
598 * [-2, -1.25992104989487, -2.0]
602 * [2, 1.25992104989487, 2.0]
603 * [3, 1.44224957030741, 3.0]
604 * [4, 1.5874010519682, 4.0]
605 * [5, 1.7099759466767, 5.0]
606 * [6, 1.81712059283214, 6.0]
607 * [7, 1.91293118277239, 7.0]
609 * [9, 2.0800838230519, 9.0]
613 math_cbrt(mrb_state *mrb, mrb_value obj)
617 mrb_get_args(mrb, "f", &x);
620 return mrb_float_value(mrb, x);
626 * Math.frexp(numeric) -> [ fraction, exponent ]
628 * Returns a two-element array containing the normalized fraction (a
629 * <code>Float</code>) and exponent (a <code>Fixnum</code>) of
632 * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
633 * fraction * 2**exponent #=> 1234.0
636 math_frexp(mrb_state *mrb, mrb_value obj)
641 mrb_get_args(mrb, "f", &x);
644 return mrb_assoc_new(mrb, mrb_float_value(mrb, x), mrb_fixnum_value(exp));
649 * Math.ldexp(flt, int) -> float
651 * Returns the value of <i>flt</i>*(2**<i>int</i>).
653 * fraction, exponent = Math.frexp(1234)
654 * Math.ldexp(fraction, exponent) #=> 1234.0
657 math_ldexp(mrb_state *mrb, mrb_value obj)
662 mrb_get_args(mrb, "fi", &x, &i);
663 x = ldexp(x, (int)i);
665 return mrb_float_value(mrb, x);
670 * Math.hypot(x, y) -> float
672 * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
673 * with sides <i>x</i> and <i>y</i>.
675 * Math.hypot(3, 4) #=> 5.0
678 math_hypot(mrb_state *mrb, mrb_value obj)
682 mrb_get_args(mrb, "ff", &x, &y);
685 return mrb_float_value(mrb, x);
690 * Math.erf(x) -> float
692 * Calculates the error function of x.
695 math_erf(mrb_state *mrb, mrb_value obj)
699 mrb_get_args(mrb, "f", &x);
702 return mrb_float_value(mrb, x);
708 * Math.erfc(x) -> float
710 * Calculates the complementary error function of x.
713 math_erfc(mrb_state *mrb, mrb_value obj)
717 mrb_get_args(mrb, "f", &x);
720 return mrb_float_value(mrb, x);
723 /* ------------------------------------------------------------------------*/
725 mrb_mruby_math_gem_init(mrb_state* mrb)
727 struct RClass *mrb_math;
728 mrb_math = mrb_define_module(mrb, "Math");
730 mrb_define_class_under(mrb, mrb_math, "DomainError", mrb->eStandardError_class);
733 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, M_PI));
735 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, atan(1.0)*4.0));
739 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, M_E));
741 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0)));
744 mrb_define_module_function(mrb, mrb_math, "sin", math_sin, MRB_ARGS_REQ(1));
745 mrb_define_module_function(mrb, mrb_math, "cos", math_cos, MRB_ARGS_REQ(1));
746 mrb_define_module_function(mrb, mrb_math, "tan", math_tan, MRB_ARGS_REQ(1));
748 mrb_define_module_function(mrb, mrb_math, "asin", math_asin, MRB_ARGS_REQ(1));
749 mrb_define_module_function(mrb, mrb_math, "acos", math_acos, MRB_ARGS_REQ(1));
750 mrb_define_module_function(mrb, mrb_math, "atan", math_atan, MRB_ARGS_REQ(1));
751 mrb_define_module_function(mrb, mrb_math, "atan2", math_atan2, MRB_ARGS_REQ(2));
753 mrb_define_module_function(mrb, mrb_math, "sinh", math_sinh, MRB_ARGS_REQ(1));
754 mrb_define_module_function(mrb, mrb_math, "cosh", math_cosh, MRB_ARGS_REQ(1));
755 mrb_define_module_function(mrb, mrb_math, "tanh", math_tanh, MRB_ARGS_REQ(1));
757 mrb_define_module_function(mrb, mrb_math, "asinh", math_asinh, MRB_ARGS_REQ(1));
758 mrb_define_module_function(mrb, mrb_math, "acosh", math_acosh, MRB_ARGS_REQ(1));
759 mrb_define_module_function(mrb, mrb_math, "atanh", math_atanh, MRB_ARGS_REQ(1));
761 mrb_define_module_function(mrb, mrb_math, "exp", math_exp, MRB_ARGS_REQ(1));
762 mrb_define_module_function(mrb, mrb_math, "log", math_log, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
763 mrb_define_module_function(mrb, mrb_math, "log2", math_log2, MRB_ARGS_REQ(1));
764 mrb_define_module_function(mrb, mrb_math, "log10", math_log10, MRB_ARGS_REQ(1));
765 mrb_define_module_function(mrb, mrb_math, "sqrt", math_sqrt, MRB_ARGS_REQ(1));
766 mrb_define_module_function(mrb, mrb_math, "cbrt", math_cbrt, MRB_ARGS_REQ(1));
768 mrb_define_module_function(mrb, mrb_math, "frexp", math_frexp, MRB_ARGS_REQ(1));
769 mrb_define_module_function(mrb, mrb_math, "ldexp", math_ldexp, MRB_ARGS_REQ(2));
771 mrb_define_module_function(mrb, mrb_math, "hypot", math_hypot, MRB_ARGS_REQ(2));
773 mrb_define_module_function(mrb, mrb_math, "erf", math_erf, MRB_ARGS_REQ(1));
774 mrb_define_module_function(mrb, mrb_math, "erfc", math_erfc, MRB_ARGS_REQ(1));
778 mrb_mruby_math_gem_final(mrb_state* mrb)