Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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.