source: EcnlProtoTool/trunk/mruby-2.1.1/mrbgems/mruby-math/src/math.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 15.5 KB
Line 
1/*
2** math.c - Math module
3**
4** See Copyright Notice in mruby.h
5*/
6
7#ifdef MRB_WITHOUT_FLOAT
8# error Math conflicts 'MRB_WITHOUT_FLOAT' configuration in your 'build_config.rb'
9#endif
10
11#include <mruby.h>
12#include <mruby/array.h>
13
14#include <math.h>
15
16static void
17domain_error(mrb_state *mrb, const char *func)
18{
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);
22}
23
24/* math functions not provided by Microsoft Visual C++ 2012 or older */
25#if defined _MSC_VER && _MSC_VER <= 1700
26
27#include <float.h>
28
29double
30asinh(double x)
31{
32 double xa, ya, y;
33
34 /* Basic formula loses precision for x < 0, but asinh is an odd function */
35 xa = fabs(x);
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;
39 }
40 else {
41 /* Basic formula for asinh */
42 ya = log(xa + sqrt(xa*xa + 1.0));
43 }
44
45 y = _copysign(ya, x);
46 return y;
47}
48
49double
50acosh(double x)
51{
52 double y;
53
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;
57 }
58 else {
59 /* Basic formula for acosh */
60 y = log(x + sqrt(x*x - 1.0));
61 }
62
63 return y;
64}
65
66double
67atanh(double x)
68{
69 double y;
70
71 if (fabs(x) < 1E-2) {
72 /* The sums 1+x and 1-x lose precision for small x. Use the polynomial
73 instead. */
74 double x2 = x * x;
75 y = x*(1.0 + x2*(1.0/3.0 + x2*(1.0/5.0 + x2*(1.0/7.0))));
76 }
77 else {
78 /* Basic formula for atanh */
79 y = 0.5 * (log(1.0+x) - log(1.0-x));
80 }
81
82 return y;
83}
84
85double
86cbrt(double x)
87{
88 double xa, ya, y;
89
90 /* pow(x, y) is undefined for x < 0 and y not an integer, but cbrt is an
91 odd function */
92 xa = fabs(x);
93 ya = pow(xa, 1.0/3.0);
94 y = _copysign(ya, x);
95 return y;
96}
97
98/* Declaration of complementary Error function */
99double
100erfc(double x);
101
102/*
103** Implementations of error functions
104** credits to http://www.digitalmars.com/archives/cplusplus/3634.html
105*/
106
107/* Implementation of Error function */
108double
109erf(double x)
110{
111 static const double two_sqrtpi = 1.128379167095512574;
112 double sum = x;
113 double term = x;
114 double xsqr = x*x;
115 int j= 1;
116 if (fabs(x) > 2.2) {
117 return 1.0 - erfc(x);
118 }
119 do {
120 term *= xsqr/j;
121 sum -= term/(2*j+1);
122 ++j;
123 term *= xsqr/j;
124 sum += term/(2*j+1);
125 ++j;
126 if (sum == 0) break;
127 } while (fabs(term/sum) > DBL_EPSILON);
128 return two_sqrtpi*sum;
129}
130
131/* Implementation of complementary Error function */
132double
133erfc(double x)
134{
135 static const double one_sqrtpi= 0.564189583547756287;
136 double a = 1;
137 double b = x;
138 double c = x;
139 double d = x*x+0.5;
140 double q1;
141 double q2 = b/d;
142 double n = 1.0;
143 double t;
144 if (fabs(x) < 2.2) {
145 return 1.0 - erf(x);
146 }
147 if (x < 0.0) { /*signbit(x)*/
148 return 2.0 - erfc(-x);
149 }
150 do {
151 t = a*n+b*x;
152 a = b;
153 b = t;
154 t = c*n+d*x;
155 c = d;
156 d = t;
157 n += 0.5;
158 q1 = q2;
159 q2 = b/d;
160 } while (fabs(q1-q2)/q2 > DBL_EPSILON);
161 return one_sqrtpi*exp(-x*x)*q2;
162}
163
164#endif
165
166#if defined __FreeBSD__ && !defined __FreeBSD_version
167#include <osreldate.h> /* for __FreeBSD_version */
168#endif
169
170#if (defined _MSC_VER && _MSC_VER < 1800) || defined __ANDROID__ || (defined __FreeBSD__ && __FreeBSD_version < 803000)
171
172double
173log2(double x)
174{
175 return log10(x)/log10(2.0);
176}
177
178#endif
179
180/*
181 TRIGONOMETRIC FUNCTIONS
182*/
183
184/*
185 * call-seq:
186 * Math.sin(x) -> float
187 *
188 * Computes the sine of <i>x</i> (expressed in radians). Returns
189 * -1..1.
190 */
191static mrb_value
192math_sin(mrb_state *mrb, mrb_value obj)
193{
194 mrb_float x;
195
196 mrb_get_args(mrb, "f", &x);
197 x = sin(x);
198
199 return mrb_float_value(mrb, x);
200}
201
202/*
203 * call-seq:
204 * Math.cos(x) -> float
205 *
206 * Computes the cosine of <i>x</i> (expressed in radians). Returns
207 * -1..1.
208 */
209static mrb_value
210math_cos(mrb_state *mrb, mrb_value obj)
211{
212 mrb_float x;
213
214 mrb_get_args(mrb, "f", &x);
215 x = cos(x);
216
217 return mrb_float_value(mrb, x);
218}
219
220/*
221 * call-seq:
222 * Math.tan(x) -> float
223 *
224 * Returns the tangent of <i>x</i> (expressed in radians).
225 */
226static mrb_value
227math_tan(mrb_state *mrb, mrb_value obj)
228{
229 mrb_float x;
230
231 mrb_get_args(mrb, "f", &x);
232 x = tan(x);
233
234 return mrb_float_value(mrb, x);
235}
236
237/*
238 INVERSE TRIGONOMETRIC FUNCTIONS
239*/
240
241/*
242 * call-seq:
243 * Math.asin(x) -> float
244 *
245 * Computes the arc sine of <i>x</i>.
246 * @return computed value between `-(PI/2)` and `(PI/2)`.
247 */
248static mrb_value
249math_asin(mrb_state *mrb, mrb_value obj)
250{
251 mrb_float x;
252
253 mrb_get_args(mrb, "f", &x);
254 if (x < -1.0 || x > 1.0) {
255 domain_error(mrb, "asin");
256 }
257 x = asin(x);
258
259 return mrb_float_value(mrb, x);
260}
261
262/*
263 * call-seq:
264 * Math.acos(x) -> float
265 *
266 * Computes the arc cosine of <i>x</i>. Returns 0..PI.
267 */
268static mrb_value
269math_acos(mrb_state *mrb, mrb_value obj)
270{
271 mrb_float x;
272
273 mrb_get_args(mrb, "f", &x);
274 if (x < -1.0 || x > 1.0) {
275 domain_error(mrb, "acos");
276 }
277 x = acos(x);
278
279 return mrb_float_value(mrb, x);
280}
281
282/*
283 * call-seq:
284 * Math.atan(x) -> float
285 *
286 * Computes the arc tangent of <i>x</i>. Returns `-(PI/2) .. (PI/2)`.
287 */
288static mrb_value
289math_atan(mrb_state *mrb, mrb_value obj)
290{
291 mrb_float x;
292
293 mrb_get_args(mrb, "f", &x);
294 x = atan(x);
295
296 return mrb_float_value(mrb, x);
297}
298
299/*
300 * call-seq:
301 * Math.atan2(y, x) -> float
302 *
303 * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
304 * -PI..PI.
305 *
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
316 *
317 */
318static mrb_value
319math_atan2(mrb_state *mrb, mrb_value obj)
320{
321 mrb_float x, y;
322
323 mrb_get_args(mrb, "ff", &x, &y);
324 x = atan2(x, y);
325
326 return mrb_float_value(mrb, x);
327}
328
329
330
331/*
332 HYPERBOLIC TRIG FUNCTIONS
333*/
334/*
335 * call-seq:
336 * Math.sinh(x) -> float
337 *
338 * Computes the hyperbolic sine of <i>x</i> (expressed in
339 * radians).
340 */
341static mrb_value
342math_sinh(mrb_state *mrb, mrb_value obj)
343{
344 mrb_float x;
345
346 mrb_get_args(mrb, "f", &x);
347 x = sinh(x);
348
349 return mrb_float_value(mrb, x);
350}
351
352/*
353 * call-seq:
354 * Math.cosh(x) -> float
355 *
356 * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
357 */
358static mrb_value
359math_cosh(mrb_state *mrb, mrb_value obj)
360{
361 mrb_float x;
362
363 mrb_get_args(mrb, "f", &x);
364 x = cosh(x);
365
366 return mrb_float_value(mrb, x);
367}
368
369/*
370 * call-seq:
371 * Math.tanh() -> float
372 *
373 * Computes the hyperbolic tangent of <i>x</i> (expressed in
374 * radians).
375 */
376static mrb_value
377math_tanh(mrb_state *mrb, mrb_value obj)
378{
379 mrb_float x;
380
381 mrb_get_args(mrb, "f", &x);
382 x = tanh(x);
383
384 return mrb_float_value(mrb, x);
385}
386
387
388/*
389 INVERSE HYPERBOLIC TRIG FUNCTIONS
390*/
391
392/*
393 * call-seq:
394 * Math.asinh(x) -> float
395 *
396 * Computes the inverse hyperbolic sine of <i>x</i>.
397 */
398static mrb_value
399math_asinh(mrb_state *mrb, mrb_value obj)
400{
401 mrb_float x;
402
403 mrb_get_args(mrb, "f", &x);
404
405 x = asinh(x);
406
407 return mrb_float_value(mrb, x);
408}
409
410/*
411 * call-seq:
412 * Math.acosh(x) -> float
413 *
414 * Computes the inverse hyperbolic cosine of <i>x</i>.
415 */
416static mrb_value
417math_acosh(mrb_state *mrb, mrb_value obj)
418{
419 mrb_float x;
420
421 mrb_get_args(mrb, "f", &x);
422 if (x < 1.0) {
423 domain_error(mrb, "acosh");
424 }
425 x = acosh(x);
426
427 return mrb_float_value(mrb, x);
428}
429
430/*
431 * call-seq:
432 * Math.atanh(x) -> float
433 *
434 * Computes the inverse hyperbolic tangent of <i>x</i>.
435 */
436static mrb_value
437math_atanh(mrb_state *mrb, mrb_value obj)
438{
439 mrb_float x;
440
441 mrb_get_args(mrb, "f", &x);
442 if (x < -1.0 || x > 1.0) {
443 domain_error(mrb, "atanh");
444 }
445 x = atanh(x);
446
447 return mrb_float_value(mrb, x);
448}
449
450/*
451 EXPONENTIALS AND LOGARITHMS
452*/
453
454/*
455 * call-seq:
456 * Math.exp(x) -> float
457 *
458 * Returns e**x.
459 *
460 * Math.exp(0) #=> 1.0
461 * Math.exp(1) #=> 2.718281828459045
462 * Math.exp(1.5) #=> 4.4816890703380645
463 *
464 */
465static mrb_value
466math_exp(mrb_state *mrb, mrb_value obj)
467{
468 mrb_float x;
469
470 mrb_get_args(mrb, "f", &x);
471 x = exp(x);
472
473 return mrb_float_value(mrb, x);
474}
475
476/*
477 * call-seq:
478 * Math.log(numeric) -> float
479 * Math.log(num,base) -> float
480 *
481 * Returns the natural logarithm of <i>numeric</i>.
482 * If additional second argument is given, it will be the base
483 * of logarithm.
484 *
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
489 *
490 */
491static mrb_value
492math_log(mrb_state *mrb, mrb_value obj)
493{
494 mrb_float x, base;
495 mrb_int argc;
496
497 argc = mrb_get_args(mrb, "f|f", &x, &base);
498 if (x < 0.0) {
499 domain_error(mrb, "log");
500 }
501 x = log(x);
502 if (argc == 2) {
503 if (base < 0.0) {
504 domain_error(mrb, "log");
505 }
506 x /= log(base);
507 }
508 return mrb_float_value(mrb, x);
509}
510
511/*
512 * call-seq:
513 * Math.log2(numeric) -> float
514 *
515 * Returns the base 2 logarithm of <i>numeric</i>.
516 *
517 * Math.log2(1) #=> 0.0
518 * Math.log2(2) #=> 1.0
519 * Math.log2(32768) #=> 15.0
520 * Math.log2(65536) #=> 16.0
521 *
522 */
523static mrb_value
524math_log2(mrb_state *mrb, mrb_value obj)
525{
526 mrb_float x;
527
528 mrb_get_args(mrb, "f", &x);
529 if (x < 0.0) {
530 domain_error(mrb, "log2");
531 }
532 x = log2(x);
533
534 return mrb_float_value(mrb, x);
535}
536
537/*
538 * call-seq:
539 * Math.log10(numeric) -> float
540 *
541 * Returns the base 10 logarithm of <i>numeric</i>.
542 *
543 * Math.log10(1) #=> 0.0
544 * Math.log10(10) #=> 1.0
545 * Math.log10(10**100) #=> 100.0
546 *
547 */
548static mrb_value
549math_log10(mrb_state *mrb, mrb_value obj)
550{
551 mrb_float x;
552
553 mrb_get_args(mrb, "f", &x);
554 if (x < 0.0) {
555 domain_error(mrb, "log10");
556 }
557 x = log10(x);
558
559 return mrb_float_value(mrb, x);
560}
561
562/*
563 * call-seq:
564 * Math.sqrt(numeric) -> float
565 *
566 * Returns the square root of <i>numeric</i>.
567 *
568 */
569static mrb_value
570math_sqrt(mrb_state *mrb, mrb_value obj)
571{
572 mrb_float x;
573
574 mrb_get_args(mrb, "f", &x);
575 if (x < 0.0) {
576 domain_error(mrb, "sqrt");
577 }
578 x = sqrt(x);
579
580 return mrb_float_value(mrb, x);
581}
582
583
584/*
585 * call-seq:
586 * Math.cbrt(numeric) -> float
587 *
588 * Returns the cube root of <i>numeric</i>.
589 *
590 * -9.upto(9) {|x|
591 * p [x, Math.cbrt(x), Math.cbrt(x)**3]
592 * }
593 * #=>
594 * [-9, -2.0800838230519, -9.0]
595 * [-8, -2.0, -8.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]
602 * [-1, -1.0, -1.0]
603 * [0, 0.0, 0.0]
604 * [1, 1.0, 1.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]
611 * [8, 2.0, 8.0]
612 * [9, 2.0800838230519, 9.0]
613 *
614 */
615static mrb_value
616math_cbrt(mrb_state *mrb, mrb_value obj)
617{
618 mrb_float x;
619
620 mrb_get_args(mrb, "f", &x);
621 x = cbrt(x);
622
623 return mrb_float_value(mrb, x);
624}
625
626
627/*
628 * call-seq:
629 * Math.frexp(numeric) -> [ fraction, exponent ]
630 *
631 * Returns a two-element array containing the normalized fraction (a
632 * <code>Float</code>) and exponent (a <code>Fixnum</code>) of
633 * <i>numeric</i>.
634 *
635 * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
636 * fraction * 2**exponent #=> 1234.0
637 */
638static mrb_value
639math_frexp(mrb_state *mrb, mrb_value obj)
640{
641 mrb_float x;
642 int exp;
643
644 mrb_get_args(mrb, "f", &x);
645 x = frexp(x, &exp);
646
647 return mrb_assoc_new(mrb, mrb_float_value(mrb, x), mrb_fixnum_value(exp));
648}
649
650/*
651 * call-seq:
652 * Math.ldexp(flt, int) -> float
653 *
654 * Returns the value of <i>flt</i>*(2**<i>int</i>).
655 *
656 * fraction, exponent = Math.frexp(1234)
657 * Math.ldexp(fraction, exponent) #=> 1234.0
658 */
659static mrb_value
660math_ldexp(mrb_state *mrb, mrb_value obj)
661{
662 mrb_float x;
663 mrb_int i;
664
665 mrb_get_args(mrb, "fi", &x, &i);
666 x = ldexp(x, (int)i);
667
668 return mrb_float_value(mrb, x);
669}
670
671/*
672 * call-seq:
673 * Math.hypot(x, y) -> float
674 *
675 * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
676 * with sides <i>x</i> and <i>y</i>.
677 *
678 * Math.hypot(3, 4) #=> 5.0
679 */
680static mrb_value
681math_hypot(mrb_state *mrb, mrb_value obj)
682{
683 mrb_float x, y;
684
685 mrb_get_args(mrb, "ff", &x, &y);
686 x = hypot(x, y);
687
688 return mrb_float_value(mrb, x);
689}
690
691/*
692 * call-seq:
693 * Math.erf(x) -> float
694 *
695 * Calculates the error function of x.
696 */
697static mrb_value
698math_erf(mrb_state *mrb, mrb_value obj)
699{
700 mrb_float x;
701
702 mrb_get_args(mrb, "f", &x);
703 x = erf(x);
704
705 return mrb_float_value(mrb, x);
706}
707
708
709/*
710 * call-seq:
711 * Math.erfc(x) -> float
712 *
713 * Calculates the complementary error function of x.
714 */
715static mrb_value
716math_erfc(mrb_state *mrb, mrb_value obj)
717{
718 mrb_float x;
719
720 mrb_get_args(mrb, "f", &x);
721 x = erfc(x);
722
723 return mrb_float_value(mrb, x);
724}
725
726/* ------------------------------------------------------------------------*/
727void
728mrb_mruby_math_gem_init(mrb_state* mrb)
729{
730 struct RClass *mrb_math;
731 mrb_math = mrb_define_module(mrb, "Math");
732
733 mrb_define_class_under(mrb, mrb_math, "DomainError", mrb->eStandardError_class);
734
735#ifdef M_PI
736 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, M_PI));
737#else
738 mrb_define_const(mrb, mrb_math, "PI", mrb_float_value(mrb, atan(1.0)*4.0));
739#endif
740
741#ifdef M_E
742 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, M_E));
743#else
744 mrb_define_const(mrb, mrb_math, "E", mrb_float_value(mrb, exp(1.0)));
745#endif
746
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));
750
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));
755
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));
759
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));
763
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));
770
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));
773
774 mrb_define_module_function(mrb, mrb_math, "hypot", math_hypot, MRB_ARGS_REQ(2));
775
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));
778}
779
780void
781mrb_mruby_math_gem_final(mrb_state* mrb)
782{
783}
Note: See TracBrowser for help on using the repository browser.