Skip to content
Newer
Older
100644 530 lines (445 sloc) 9.48 KB
b3fe019 @tmm1 raw src
authored Oct 2, 2008
1 /**********************************************************************
2
3 math.c -
4
5 $Author: shyouhei $
6 $Date: 2008-07-02 18:26:29 +0900 (Wed, 02 Jul 2008) $
7 created at: Tue Jan 25 14:12:56 JST 1994
8
9 Copyright (C) 1993-2003 Yukihiro Matsumoto
10
11 **********************************************************************/
12
13 #include "ruby.h"
14 #include <math.h>
15 #include <errno.h>
16
17 VALUE rb_mMath;
18
19 #define Need_Float(x) (x) = rb_Float(x)
20 #define Need_Float2(x,y) do {\
21 Need_Float(x);\
22 Need_Float(y);\
23 } while (0)
24
25 static void
26 domain_check(x, msg)
27 double x;
28 char *msg;
29 {
30 while(1) {
31 if (errno) {
32 rb_sys_fail(msg);
33 }
34 if (isnan(x)) {
35 #if defined(EDOM)
36 errno = EDOM;
37 #elif defined(ERANGE)
38 errno = ERANGE;
39 #endif
40 continue;
41 }
42 break;
43 }
44 }
45
46
47 /*
48 * call-seq:
49 * Math.atan2(y, x) => float
50 *
51 * Computes the arc tangent given <i>y</i> and <i>x</i>. Returns
52 * -PI..PI.
53 *
54 */
55
56 static VALUE
57 math_atan2(obj, y, x)
58 VALUE obj, x, y;
59 {
60 Need_Float2(y, x);
61 return rb_float_new(atan2(RFLOAT(y)->value, RFLOAT(x)->value));
62 }
63
64
65 /*
66 * call-seq:
67 * Math.cos(x) => float
68 *
69 * Computes the cosine of <i>x</i> (expressed in radians). Returns
70 * -1..1.
71 */
72
73 static VALUE
74 math_cos(obj, x)
75 VALUE obj, x;
76 {
77 Need_Float(x);
78 return rb_float_new(cos(RFLOAT(x)->value));
79 }
80
81 /*
82 * call-seq:
83 * Math.sin(x) => float
84 *
85 * Computes the sine of <i>x</i> (expressed in radians). Returns
86 * -1..1.
87 */
88
89 static VALUE
90 math_sin(obj, x)
91 VALUE obj, x;
92 {
93 Need_Float(x);
94
95 return rb_float_new(sin(RFLOAT(x)->value));
96 }
97
98
99 /*
100 * call-seq:
101 * Math.tan(x) => float
102 *
103 * Returns the tangent of <i>x</i> (expressed in radians).
104 */
105
106 static VALUE
107 math_tan(obj, x)
108 VALUE obj, x;
109 {
110 Need_Float(x);
111
112 return rb_float_new(tan(RFLOAT(x)->value));
113 }
114
115 /*
116 * call-seq:
117 * Math.acos(x) => float
118 *
119 * Computes the arc cosine of <i>x</i>. Returns 0..PI.
120 */
121
122 static VALUE
123 math_acos(obj, x)
124 VALUE obj, x;
125 {
126 double d;
127
128 Need_Float(x);
129 errno = 0;
130 d = acos(RFLOAT(x)->value);
131 domain_check(d, "acos");
132 return rb_float_new(d);
133 }
134
135 /*
136 * call-seq:
137 * Math.asin(x) => float
138 *
139 * Computes the arc sine of <i>x</i>. Returns -{PI/2} .. {PI/2}.
140 */
141
142 static VALUE
143 math_asin(obj, x)
144 VALUE obj, x;
145 {
146 double d;
147
148 Need_Float(x);
149 errno = 0;
150 d = asin(RFLOAT(x)->value);
151 domain_check(d, "asin");
152 return rb_float_new(d);
153 }
154
155 /*
156 * call-seq:
157 * Math.atan(x) => float
158 *
159 * Computes the arc tangent of <i>x</i>. Returns -{PI/2} .. {PI/2}.
160 */
161
162 static VALUE
163 math_atan(obj, x)
164 VALUE obj, x;
165 {
166 Need_Float(x);
167 return rb_float_new(atan(RFLOAT(x)->value));
168 }
169
170 #ifndef HAVE_COSH
171 double
172 cosh(x)
173 double x;
174 {
175 return (exp(x) + exp(-x)) / 2;
176 }
177 #endif
178
179 /*
180 * call-seq:
181 * Math.cosh(x) => float
182 *
183 * Computes the hyperbolic cosine of <i>x</i> (expressed in radians).
184 */
185
186 static VALUE
187 math_cosh(obj, x)
188 VALUE obj, x;
189 {
190 Need_Float(x);
191
192 return rb_float_new(cosh(RFLOAT(x)->value));
193 }
194
195 #ifndef HAVE_SINH
196 double
197 sinh(x)
198 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
212 static VALUE
213 math_sinh(obj, x)
214 VALUE obj, x;
215 {
216 Need_Float(x);
217 return rb_float_new(sinh(RFLOAT(x)->value));
218 }
219
220 #ifndef HAVE_TANH
221 double
222 tanh(x)
223 double x;
224 {
225 return sinh(x) / cosh(x);
226 }
227 #endif
228
229 /*
230 * call-seq:
231 * Math.tanh() => float
232 *
233 * Computes the hyperbolic tangent of <i>x</i> (expressed in
234 * radians).
235 */
236
237 static VALUE
238 math_tanh(obj, x)
239 VALUE obj, x;
240 {
241 Need_Float(x);
242 return rb_float_new(tanh(RFLOAT(x)->value));
243 }
244
245 /*
246 * call-seq:
247 * Math.acosh(x) => float
248 *
249 * Computes the inverse hyperbolic cosine of <i>x</i>.
250 */
251
252 static VALUE
253 math_acosh(obj, x)
254 VALUE obj, x;
255 {
256 double d;
257
258 Need_Float(x);
259 errno = 0;
260 d = acosh(RFLOAT(x)->value);
261 domain_check(d, "acosh");
262 return rb_float_new(d);
263 }
264
265 /*
266 * call-seq:
267 * Math.asinh(x) => float
268 *
269 * Computes the inverse hyperbolic sine of <i>x</i>.
270 */
271
272 static VALUE
273 math_asinh(obj, x)
274 VALUE obj, x;
275 {
276 Need_Float(x);
277 return rb_float_new(asinh(RFLOAT(x)->value));
278 }
279
280 /*
281 * call-seq:
282 * Math.atanh(x) => float
283 *
284 * Computes the inverse hyperbolic tangent of <i>x</i>.
285 */
286
287 static VALUE
288 math_atanh(obj, x)
289 VALUE obj, x;
290 {
291 double d;
292
293 Need_Float(x);
294 errno = 0;
295 d = atanh(RFLOAT(x)->value);
296 domain_check(d, "atanh");
297 return rb_float_new(d);
298 }
299
300 /*
301 * call-seq:
302 * Math.exp(x) => float
303 *
304 * Returns e**x.
305 */
306
307 static VALUE
308 math_exp(obj, x)
309 VALUE obj, x;
310 {
311 Need_Float(x);
312 return rb_float_new(exp(RFLOAT(x)->value));
313 }
314
315 #if defined __CYGWIN__
316 # include <cygwin/version.h>
317 # if CYGWIN_VERSION_DLL_MAJOR < 1005
318 # define nan(x) nan()
319 # endif
320 # define log(x) ((x) < 0.0 ? nan("") : log(x))
321 # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
322 #endif
323
324 /*
325 * call-seq:
326 * Math.log(numeric) => float
327 *
328 * Returns the natural logarithm of <i>numeric</i>.
329 */
330
331 static VALUE
332 math_log(obj, x)
333 VALUE obj, x;
334 {
335 double d;
336
337 Need_Float(x);
338 errno = 0;
339 d = log(RFLOAT(x)->value);
340 domain_check(d, "log");
341 return rb_float_new(d);
342 }
343
344 /*
345 * call-seq:
346 * Math.log10(numeric) => float
347 *
348 * Returns the base 10 logarithm of <i>numeric</i>.
349 */
350
351 static VALUE
352 math_log10(obj, x)
353 VALUE obj, x;
354 {
355 double d;
356
357 Need_Float(x);
358 errno = 0;
359 d = log10(RFLOAT(x)->value);
360 domain_check(d, "log10");
361 return rb_float_new(d);
362 }
363
364 /*
365 * call-seq:
366 * Math.sqrt(numeric) => float
367 *
368 * Returns the non-negative square root of <i>numeric</i>.
369 */
370
371 static VALUE
372 math_sqrt(obj, x)
373 VALUE obj, x;
374 {
375 double d;
376
377 Need_Float(x);
378 errno = 0;
379 d = sqrt(RFLOAT(x)->value);
380 domain_check(d, "sqrt");
381 return rb_float_new(d);
382 }
383
384 /*
385 * call-seq:
386 * Math.frexp(numeric) => [ fraction, exponent ]
387 *
388 * Returns a two-element array containing the normalized fraction (a
389 * <code>Float</code>) and exponent (a <code>Fixnum</code>) of
390 * <i>numeric</i>.
391 *
392 * fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
393 * fraction * 2**exponent #=> 1234.0
394 */
395
396 static VALUE
397 math_frexp(obj, x)
398 VALUE obj, x;
399 {
400 double d;
401 int exp;
402
403 Need_Float(x);
404
405 d = frexp(RFLOAT(x)->value, &exp);
406 return rb_assoc_new(rb_float_new(d), INT2NUM(exp));
407 }
408
409 /*
410 * call-seq:
411 * Math.ldexp(flt, int) -> float
412 *
413 * Returns the value of <i>flt</i>*(2**<i>int</i>).
414 *
415 * fraction, exponent = Math.frexp(1234)
416 * Math.ldexp(fraction, exponent) #=> 1234.0
417 */
418
419 static VALUE
420 math_ldexp(obj, x, n)
421 VALUE obj, x, n;
422 {
423 Need_Float(x);
424 return rb_float_new(ldexp(RFLOAT(x)->value, NUM2INT(n)));
425 }
426
427 /*
428 * call-seq:
429 * Math.hypot(x, y) => float
430 *
431 * Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled triangle
432 * with sides <i>x</i> and <i>y</i>.
433 *
434 * Math.hypot(3, 4) #=> 5.0
435 */
436
437 static VALUE
438 math_hypot(obj, x, y)
439 VALUE obj, x, y;
440 {
441 Need_Float2(x, y);
442 return rb_float_new(hypot(RFLOAT(x)->value, RFLOAT(y)->value));
443 }
444
445 /*
446 * call-seq:
447 * Math.erf(x) => float
448 *
449 * Calculates the error function of x.
450 */
451
452 static VALUE
453 math_erf(obj, x)
454 VALUE obj, x;
455 {
456 Need_Float(x);
457 return rb_float_new(erf(RFLOAT(x)->value));
458 }
459
460 /*
461 * call-seq:
462 * Math.erfc(x) => float
463 *
464 * Calculates the complementary error function of x.
465 */
466
467 static VALUE
468 math_erfc(obj, x)
469 VALUE obj, x;
470 {
471 Need_Float(x);
472 return rb_float_new(erfc(RFLOAT(x)->value));
473 }
474
475 /*
476 * The <code>Math</code> module contains module functions for basic
477 * trigonometric and transcendental functions. See class
478 * <code>Float</code> for a list of constants that
479 * define Ruby's floating point accuracy.
480 */
481
482
483 void
484 Init_Math()
485 {
486 rb_mMath = rb_define_module("Math");
487
488 #ifdef M_PI
489 rb_define_const(rb_mMath, "PI", rb_float_new(M_PI));
490 #else
491 rb_define_const(rb_mMath, "PI", rb_float_new(atan(1.0)*4.0));
492 #endif
493
494 #ifdef M_E
495 rb_define_const(rb_mMath, "E", rb_float_new(M_E));
496 #else
497 rb_define_const(rb_mMath, "E", rb_float_new(exp(1.0)));
498 #endif
499
500 rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
501 rb_define_module_function(rb_mMath, "cos", math_cos, 1);
502 rb_define_module_function(rb_mMath, "sin", math_sin, 1);
503 rb_define_module_function(rb_mMath, "tan", math_tan, 1);
504
505 rb_define_module_function(rb_mMath, "acos", math_acos, 1);
506 rb_define_module_function(rb_mMath, "asin", math_asin, 1);
507 rb_define_module_function(rb_mMath, "atan", math_atan, 1);
508
509 rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
510 rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
511 rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
512
513 rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
514 rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
515 rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
516
517 rb_define_module_function(rb_mMath, "exp", math_exp, 1);
518 rb_define_module_function(rb_mMath, "log", math_log, 1);
519 rb_define_module_function(rb_mMath, "log10", math_log10, 1);
520 rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
521
522 rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
523 rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
524
525 rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
526
527 rb_define_module_function(rb_mMath, "erf", math_erf, 1);
528 rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
529 }
Something went wrong with that request. Please try again.