source: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-math/src/math.c@ 331

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

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

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