Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 658 lines (560 sloc) 13.021 kb
511dc44 initial import
Laurent Sansonetti authored
1 /**********************************************************************
2
3 math.c -
4
26d0e1f merge with ruby trunk r16762 + better/faster objc-like dispatcher
Laurent Sansonetti authored
5 $Author: nobu $
511dc44 initial import
Laurent Sansonetti authored
6 created at: Tue Jan 25 14:12:56 JST 1994
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10 **********************************************************************/
11
12 #include "ruby/ruby.h"
13 #include <math.h>
14 #include <errno.h>
15
16 VALUE rb_mMath;
17
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
18 static VALUE
19 to_flo(VALUE x)
20 {
21 if (!rb_obj_is_kind_of(x, rb_cNumeric)) {
22 rb_raise(rb_eTypeError, "can't convert %s into Float",
23 NIL_P(x) ? "nil" :
24 x == Qtrue ? "true" :
25 x == Qfalse ? "false" :
26 rb_obj_classname(x));
27 }
28 return rb_convert_type(x, T_FLOAT, "Float", "to_f");
29 }
30
31 #define Need_Float(x) (x) = to_flo(x)
511dc44 initial import
Laurent Sansonetti authored
32 #define Need_Float2(x,y) do {\
33 Need_Float(x);\
34 Need_Float(y);\
35 } while (0)
36
37 static void
26d0e1f merge with ruby trunk r16762 + better/faster objc-like dispatcher
Laurent Sansonetti authored
38 domain_check(double x, const char *msg)
511dc44 initial import
Laurent Sansonetti authored
39 {
40 while(1) {
41 if (errno) {
42 rb_sys_fail(msg);
43 }
44 if (isnan(x)) {
45 #if defined(EDOM)
46 errno = EDOM;
47 #elif defined(ERANGE)
48 errno = ERANGE;
49 #endif
50 continue;
51 }
52 break;
53 }
54 }
55
56
57 /*
58 * call-seq:
59 * Math.atan2(y, x) => float
60 *
61 * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
62 * -PI..PI.
63 *
64 */
65
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
66 VALUE
511dc44 initial import
Laurent Sansonetti authored
67 math_atan2(VALUE obj, VALUE y, VALUE x)
68 {
69 Need_Float2(y, x);
70 return DOUBLE2NUM(atan2(RFLOAT_VALUE(y), RFLOAT_VALUE(x)));
71 }
72
73
74 /*
75 * call-seq:
76 * Math.cos(x) => float
77 *
78 * Computes the cosine of <i>x</i> (expressed in radians). Returns
79 * -1..1.
80 */
81
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
82 VALUE
511dc44 initial import
Laurent Sansonetti authored
83 math_cos(VALUE obj, VALUE x)
84 {
85 Need_Float(x);
86 return DOUBLE2NUM(cos(RFLOAT_VALUE(x)));
87 }
88
89 /*
90 * call-seq:
91 * Math.sin(x) => float
92 *
93 * Computes the sine of <i>x</i> (expressed in radians). Returns
94 * -1..1.
95 */
96
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
97 VALUE
511dc44 initial import
Laurent Sansonetti authored
98 math_sin(VALUE obj, VALUE x)
99 {
100 Need_Float(x);
101
102 return DOUBLE2NUM(sin(RFLOAT_VALUE(x)));
103 }
104
105
106 /*
107 * call-seq:
108 * Math.tan(x) => float
109 *
110 * Returns the tangent of <i>x</i> (expressed in radians).
111 */
112
113 static VALUE
114 math_tan(VALUE obj, VALUE x)
115 {
116 Need_Float(x);
117
118 return DOUBLE2NUM(tan(RFLOAT_VALUE(x)));
119 }
120
121 /*
122 * call-seq:
123 * Math.acos(x) => float
124 *
125 * Computes the arc cosine of <i>x</i>. Returns 0..PI.
126 */
127
128 static VALUE
129 math_acos(VALUE obj, VALUE x)
130 {
131 double d;
132
133 Need_Float(x);
134 errno = 0;
135 d = acos(RFLOAT_VALUE(x));
136 domain_check(d, "acos");
137 return DOUBLE2NUM(d);
138 }
139
140 /*
141 * call-seq:
142 * Math.asin(x) => float
143 *
144 * Computes the arc sine of <i>x</i>. Returns -{PI/2} .. {PI/2}.
145 */
146
147 static VALUE
148 math_asin(VALUE obj, VALUE x)
149 {
150 double d;
151
152 Need_Float(x);
153 errno = 0;
154 d = asin(RFLOAT_VALUE(x));
155 domain_check(d, "asin");
156 return DOUBLE2NUM(d);
157 }
158
159 /*
160 * call-seq:
161 * Math.atan(x) => float
162 *
163 * Computes the arc tangent of <i>x</i>. Returns -{PI/2} .. {PI/2}.
164 */
165
166 static VALUE
167 math_atan(VALUE obj, VALUE x)
168 {
169 Need_Float(x);
170 return DOUBLE2NUM(atan(RFLOAT_VALUE(x)));
171 }
172
173 #ifndef HAVE_COSH
174 double
175 cosh(double x)
176 {
177 return (exp(x) + exp(-x)) / 2;
178 }
179 #endif
180
181 /*
182 * call-seq:
183 * Math.cosh(x) => float
184 *
185 * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
186 */
187
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
188 VALUE
511dc44 initial import
Laurent Sansonetti authored
189 math_cosh(VALUE obj, VALUE x)
190 {
191 Need_Float(x);
192
193 return DOUBLE2NUM(cosh(RFLOAT_VALUE(x)));
194 }
195
196 #ifndef HAVE_SINH
197 double
198 sinh(double x)
199 {
200 return (exp(x) - exp(-x)) / 2;
201 }
202 #endif
203
204 /*
205 * call-seq:
206 * Math.sinh(x) => float
207 *
208 * Computes the hyperbolic sine of <i>x</i> (expressed in
209 * radians).
210 */
211
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
212 VALUE
511dc44 initial import
Laurent Sansonetti authored
213 math_sinh(VALUE obj, VALUE x)
214 {
215 Need_Float(x);
216 return DOUBLE2NUM(sinh(RFLOAT_VALUE(x)));
217 }
218
219 #ifndef HAVE_TANH
220 double
221 tanh(double x)
222 {
223 return sinh(x) / cosh(x);
224 }
225 #endif
226
227 /*
228 * call-seq:
229 * Math.tanh() => float
230 *
231 * Computes the hyperbolic tangent of <i>x</i> (expressed in
232 * radians).
233 */
234
235 static VALUE
236 math_tanh(VALUE obj, VALUE x)
237 {
238 Need_Float(x);
239 return DOUBLE2NUM(tanh(RFLOAT_VALUE(x)));
240 }
241
242 /*
243 * call-seq:
244 * Math.acosh(x) => float
245 *
246 * Computes the inverse hyperbolic cosine of <i>x</i>.
247 */
248
249 static VALUE
250 math_acosh(VALUE obj, VALUE x)
251 {
252 double d;
253
254 Need_Float(x);
255 errno = 0;
256 d = acosh(RFLOAT_VALUE(x));
257 domain_check(d, "acosh");
258 return DOUBLE2NUM(d);
259 }
260
261 /*
262 * call-seq:
263 * Math.asinh(x) => float
264 *
265 * Computes the inverse hyperbolic sine of <i>x</i>.
266 */
267
268 static VALUE
269 math_asinh(VALUE obj, VALUE x)
270 {
271 Need_Float(x);
272 return DOUBLE2NUM(asinh(RFLOAT_VALUE(x)));
273 }
274
275 /*
276 * call-seq:
277 * Math.atanh(x) => float
278 *
279 * Computes the inverse hyperbolic tangent of <i>x</i>.
280 */
281
282 static VALUE
283 math_atanh(VALUE obj, VALUE x)
284 {
285 double d;
286
287 Need_Float(x);
288 errno = 0;
289 d = atanh(RFLOAT_VALUE(x));
290 domain_check(d, "atanh");
291 return DOUBLE2NUM(d);
292 }
293
294 /*
295 * call-seq:
296 * Math.exp(x) => float
297 *
298 * Returns e**x.
299 */
300
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
301 VALUE
511dc44 initial import
Laurent Sansonetti authored
302 math_exp(VALUE obj, VALUE x)
303 {
304 Need_Float(x);
305 return DOUBLE2NUM(exp(RFLOAT_VALUE(x)));
306 }
307
308 #if defined __CYGWIN__
309 # include <cygwin/version.h>
310 # if CYGWIN_VERSION_DLL_MAJOR < 1005
311 # define nan(x) nan()
312 # endif
313 # define log(x) ((x) < 0.0 ? nan("") : log(x))
314 # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
315 #endif
316
317 /*
318 * call-seq:
319 * Math.log(numeric) => float
320 * Math.log(num,base) => float
321 *
322 * Returns the natural logarithm of <i>numeric</i>.
323 * If additional second argument is given, it will be the base
324 * of logarithm.
325 */
326
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
327 VALUE
511dc44 initial import
Laurent Sansonetti authored
328 math_log(int argc, VALUE *argv)
329 {
330 VALUE x, base;
331 double d;
332
333 rb_scan_args(argc, argv, "11", &x, &base);
334 Need_Float(x);
335 errno = 0;
336 d = log(RFLOAT_VALUE(x));
337 if (!NIL_P(base)) {
338 Need_Float(base);
339 d /= log(RFLOAT_VALUE(base));
340 }
341 domain_check(d, "log");
342 return DOUBLE2NUM(d);
343 }
344
345 #ifndef log2
346 #ifndef HAVE_LOG2
347 double
348 log2(double x)
349 {
350 return log10(x)/log10(2.0);
351 }
352 #else
353 extern double log2(double);
354 #endif
355 #endif
356
357 /*
358 * call-seq:
359 * Math.log2(numeric) => float
360 *
361 * Returns the base 2 logarithm of <i>numeric</i>.
362 */
363
364 static VALUE
365 math_log2(VALUE obj, VALUE x)
366 {
367 double d;
368
369 Need_Float(x);
370 errno = 0;
371 d = log2(RFLOAT_VALUE(x));
372 if (errno) {
373 rb_sys_fail("log2");
374 }
375 return DOUBLE2NUM(d);
376 }
377
378 /*
379 * call-seq:
380 * Math.log10(numeric) => float
381 *
382 * Returns the base 10 logarithm of <i>numeric</i>.
383 */
384
385 static VALUE
386 math_log10(VALUE obj, VALUE x)
387 {
388 double d;
389
390 Need_Float(x);
391 errno = 0;
392 d = log10(RFLOAT_VALUE(x));
393 domain_check(d, "log10");
394 return DOUBLE2NUM(d);
395 }
396
397 /*
398 * call-seq:
399 * Math.sqrt(numeric) => float
400 *
401 * Returns the non-negative square root of <i>numeric</i>.
402 */
403
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
404 VALUE
511dc44 initial import
Laurent Sansonetti authored
405 math_sqrt(VALUE obj, VALUE x)
406 {
407 double d;
408
409 Need_Float(x);
410 errno = 0;
411 d = sqrt(RFLOAT_VALUE(x));
412 domain_check(d, "sqrt");
413 return DOUBLE2NUM(d);
414 }
415
416 /*
417 * call-seq:
418 * Math.cbrt(numeric) => float
419 *
420 * Returns the cube root of <i>numeric</i>.
421 */
422
423 static VALUE
424 math_cbrt(VALUE obj, VALUE x)
425 {
426 Need_Float(x);
427 return DOUBLE2NUM(cbrt(RFLOAT_VALUE(x)));
428 }
429
430 /*
431 * call-seq:
432 * Math.frexp(numeric) => [ fraction, exponent ]
433 *
434 * Returns a two-element array containing the normalized fraction (a
435 * <code>Float</code>) and exponent (a <code>Fixnum</code>) of
436 * <i>numeric</i>.
437 *
438 * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
439 * fraction * 2**exponent #=> 1234.0
440 */
441
442 static VALUE
443 math_frexp(VALUE obj, VALUE x)
444 {
445 double d;
446 int exp;
447
448 Need_Float(x);
449
450 d = frexp(RFLOAT_VALUE(x), &exp);
451 return rb_assoc_new(DOUBLE2NUM(d), INT2NUM(exp));
452 }
453
454 /*
455 * call-seq:
456 * Math.ldexp(flt, int) -> float
457 *
458 * Returns the value of <i>flt</i>*(2**<i>int</i>).
459 *
460 * fraction, exponent = Math.frexp(1234)
461 * Math.ldexp(fraction, exponent) #=> 1234.0
462 */
463
464 static VALUE
465 math_ldexp(VALUE obj, VALUE x, VALUE n)
466 {
467 Need_Float(x);
468 return DOUBLE2NUM(ldexp(RFLOAT_VALUE(x), NUM2INT(n)));
469 }
470
471 /*
472 * call-seq:
473 * Math.hypot(x, y) => float
474 *
475 * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
476 * with sides <i>x</i> and <i>y</i>.
477 *
478 * Math.hypot(3, 4) #=> 5.0
479 */
480
eee9d7b sync with ruby trunk r15665
Laurent Sansonetti authored
481 VALUE
511dc44 initial import
Laurent Sansonetti authored
482 math_hypot(VALUE obj, VALUE x, VALUE y)
483 {
484 Need_Float2(x, y);
485 return DOUBLE2NUM(hypot(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
486 }
487
488 /*
489 * call-seq:
490 * Math.erf(x) => float
491 *
492 * Calculates the error function of x.
493 */
494
495 static VALUE
496 math_erf(VALUE obj, VALUE x)
497 {
498 Need_Float(x);
499 return DOUBLE2NUM(erf(RFLOAT_VALUE(x)));
500 }
501
502 /*
503 * call-seq:
504 * Math.erfc(x) => float
505 *
506 * Calculates the complementary error function of x.
507 */
508
509 static VALUE
510 math_erfc(VALUE obj, VALUE x)
511 {
512 Need_Float(x);
513 return DOUBLE2NUM(erfc(RFLOAT_VALUE(x)));
514 }
515
516 /*
517 * call-seq:
518 * Math.gamma(x) => float
519 *
520 * Calculates the gamma function of x.
521 *
522 * Note that gamma(n) is same as fact(n-1) for integer n >= 0.
523 * However gamma(n) returns float and possibly has error in calculation.
524 *
525 * def fact(n) (1..n).inject(1) {|r,i| r*i } end
526 * 0.upto(25) {|i| p [i, Math.gamma(i+1), fact(i)] }
527 * =>
528 * [0, 1.0, 1]
529 * [1, 1.0, 1]
530 * [2, 2.0, 2]
531 * [3, 6.0, 6]
532 * [4, 24.0, 24]
533 * [5, 120.0, 120]
534 * [6, 720.0, 720]
535 * [7, 5040.0, 5040]
536 * [8, 40320.0, 40320]
537 * [9, 362880.0, 362880]
538 * [10, 3628800.0, 3628800]
539 * [11, 39916800.0, 39916800]
540 * [12, 479001599.999999, 479001600]
541 * [13, 6227020800.00001, 6227020800]
542 * [14, 87178291199.9998, 87178291200]
543 * [15, 1307674368000.0, 1307674368000]
544 * [16, 20922789888000.0, 20922789888000]
545 * [17, 3.55687428096001e+14, 355687428096000]
546 * [18, 6.40237370572799e+15, 6402373705728000]
547 * [19, 1.21645100408832e+17, 121645100408832000]
548 * [20, 2.43290200817664e+18, 2432902008176640000]
549 * [21, 5.10909421717094e+19, 51090942171709440000]
550 * [22, 1.12400072777761e+21, 1124000727777607680000]
551 * [23, 2.58520167388851e+22, 25852016738884976640000]
552 * [24, 6.20448401733239e+23, 620448401733239439360000]
553 * [25, 1.5511210043331e+25, 15511210043330985984000000]
554 *
555 */
556
557 static VALUE
558 math_gamma(VALUE obj, VALUE x)
559 {
560 double d;
561 Need_Float(x);
562 errno = 0;
563 d = tgamma(RFLOAT_VALUE(x));
564 domain_check(d, "gamma");
565 return DOUBLE2NUM(d);
566 }
567
568 /*
569 * call-seq:
570 * Math.lgamma(x) => [float, -1 or 1]
571 *
572 * Calculates the logarithmic gamma of x and
573 * the sign of gamma of x.
574 *
575 * Math.lgamma(x) is same as
576 * [Math.log(Math.gamma(x).abs), Math.gamma(x) < 0 ? -1 : 1]
577 * but avoid overflow by Math.gamma(x) for large x.
578 */
579
5d36df8 fix PPC (#67)
Laurent Sansonetti authored
580 #if WITH_OBJC && HAVE_LGAMMA_R && BYTE_ORDER == LITTLE_ENDIAN
581 # include "missing/lgamma_r.c"
582 #endif
583
511dc44 initial import
Laurent Sansonetti authored
584 static VALUE
585 math_lgamma(VALUE obj, VALUE x)
586 {
587 double d;
588 int sign;
589 VALUE v;
590 Need_Float(x);
591 errno = 0;
592 d = lgamma_r(RFLOAT_VALUE(x), &sign);
593 domain_check(d, "lgamma");
594 v = DOUBLE2NUM(d);
595 return rb_assoc_new(v, INT2FIX(sign));
596 }
597
598 /*
599 * The <code>Math</code> module contains module functions for basic
600 * trigonometric and transcendental functions. See class
601 * <code>Float</code> for a list of constants that
602 * define Ruby's floating point accuracy.
603 */
604
605
606 void
607 Init_Math(void)
608 {
609 rb_mMath = rb_define_module("Math");
610
611 #ifdef M_PI
612 rb_define_const(rb_mMath, "PI", DOUBLE2NUM(M_PI));
613 #else
614 rb_define_const(rb_mMath, "PI", DOUBLE2NUM(atan(1.0)*4.0));
615 #endif
616
617 #ifdef M_E
618 rb_define_const(rb_mMath, "E", DOUBLE2NUM(M_E));
619 #else
620 rb_define_const(rb_mMath, "E", DOUBLE2NUM(exp(1.0)));
621 #endif
622
623 rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
624 rb_define_module_function(rb_mMath, "cos", math_cos, 1);
625 rb_define_module_function(rb_mMath, "sin", math_sin, 1);
626 rb_define_module_function(rb_mMath, "tan", math_tan, 1);
627
628 rb_define_module_function(rb_mMath, "acos", math_acos, 1);
629 rb_define_module_function(rb_mMath, "asin", math_asin, 1);
630 rb_define_module_function(rb_mMath, "atan", math_atan, 1);
631
632 rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
633 rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
634 rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
635
636 rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
637 rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
638 rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
639
640 rb_define_module_function(rb_mMath, "exp", math_exp, 1);
641 rb_define_module_function(rb_mMath, "log", math_log, -1);
642 rb_define_module_function(rb_mMath, "log2", math_log2, 1);
643 rb_define_module_function(rb_mMath, "log10", math_log10, 1);
644 rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
645 rb_define_module_function(rb_mMath, "cbrt", math_cbrt, 1);
646
647 rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
648 rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
649
650 rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
651
652 rb_define_module_function(rb_mMath, "erf", math_erf, 1);
653 rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
654
655 rb_define_module_function(rb_mMath, "gamma", math_gamma, 1);
656 rb_define_module_function(rb_mMath, "lgamma", math_lgamma, 1);
657 }
Something went wrong with that request. Please try again.