1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/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(double x, char *msg)
27: {
28: while(1) {
29: if (errno) {
30: rb_sys_fail(msg);
31: }
32: if (isnan(x)) {
33: #if defined(EDOM)
34: errno = EDOM;
35: #elif defined(ERANGE)
36: errno = ERANGE;
37: #endif
38: continue;
39: }
40: break;
41: }
42: }
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54: static VALUE
55: math_atan2(VALUE obj, VALUE y, VALUE x)
56: {
57: Need_Float2(y, x);
58: return DOUBLE2NUM(atan2(RFLOAT_VALUE(y), RFLOAT_VALUE(x)));
59: }
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70: static VALUE
71: math_cos(VALUE obj, VALUE x)
72: {
73: Need_Float(x);
74: return DOUBLE2NUM(cos(RFLOAT_VALUE(x)));
75: }
76:
77:
78:
79:
80:
81:
82:
83:
84:
85: static VALUE
86: math_sin(VALUE obj, VALUE x)
87: {
88: Need_Float(x);
89:
90: return DOUBLE2NUM(sin(RFLOAT_VALUE(x)));
91: }
92:
93:
94:
95:
96:
97:
98:
99:
100:
101: static VALUE
102: math_tan(VALUE obj, VALUE x)
103: {
104: Need_Float(x);
105:
106: return DOUBLE2NUM(tan(RFLOAT_VALUE(x)));
107: }
108:
109:
110:
111:
112:
113:
114:
115:
116: static VALUE
117: math_acos(VALUE obj, VALUE x)
118: {
119: double d;
120:
121: Need_Float(x);
122: errno = 0;
123: d = acos(RFLOAT_VALUE(x));
124: domain_check(d, "acos");
125: return DOUBLE2NUM(d);
126: }
127:
128:
129:
130:
131:
132:
133:
134:
135: static VALUE
136: math_asin(VALUE obj, VALUE x)
137: {
138: double d;
139:
140: Need_Float(x);
141: errno = 0;
142: d = asin(RFLOAT_VALUE(x));
143: domain_check(d, "asin");
144: return DOUBLE2NUM(d);
145: }
146:
147:
148:
149:
150:
151:
152:
153:
154: static VALUE
155: math_atan(VALUE obj, VALUE x)
156: {
157: Need_Float(x);
158: return DOUBLE2NUM(atan(RFLOAT_VALUE(x)));
159: }
160:
161: #ifndef HAVE_COSH
162: double
163: cosh(double x)
164: {
165: return (exp(x) + exp(-x)) / 2;
166: }
167: #endif
168:
169:
170:
171:
172:
173:
174:
175:
176: static VALUE
177: math_cosh(VALUE obj, VALUE x)
178: {
179: Need_Float(x);
180:
181: return DOUBLE2NUM(cosh(RFLOAT_VALUE(x)));
182: }
183:
184: #ifndef HAVE_SINH
185: double
186: sinh(double x)
187: {
188: return (exp(x) - exp(-x)) / 2;
189: }
190: #endif
191:
192:
193:
194:
195:
196:
197:
198:
199:
200: static VALUE
201: math_sinh(VALUE obj, VALUE x)
202: {
203: Need_Float(x);
204: return DOUBLE2NUM(sinh(RFLOAT_VALUE(x)));
205: }
206:
207: #ifndef HAVE_TANH
208: double
209: tanh(double x)
210: {
211: return sinh(x) / cosh(x);
212: }
213: #endif
214:
215:
216:
217:
218:
219:
220:
221:
222:
223: static VALUE
224: math_tanh(VALUE obj, VALUE x)
225: {
226: Need_Float(x);
227: return DOUBLE2NUM(tanh(RFLOAT_VALUE(x)));
228: }
229:
230:
231:
232:
233:
234:
235:
236:
237: static VALUE
238: math_acosh(VALUE obj, VALUE x)
239: {
240: double d;
241:
242: Need_Float(x);
243: errno = 0;
244: d = acosh(RFLOAT_VALUE(x));
245: domain_check(d, "acosh");
246: return DOUBLE2NUM(d);
247: }
248:
249:
250:
251:
252:
253:
254:
255:
256: static VALUE
257: math_asinh(VALUE obj, VALUE x)
258: {
259: Need_Float(x);
260: return DOUBLE2NUM(asinh(RFLOAT_VALUE(x)));
261: }
262:
263:
264:
265:
266:
267:
268:
269:
270: static VALUE
271: math_atanh(VALUE obj, VALUE x)
272: {
273: double d;
274:
275: Need_Float(x);
276: errno = 0;
277: d = atanh(RFLOAT_VALUE(x));
278: domain_check(d, "atanh");
279: return DOUBLE2NUM(d);
280: }
281:
282:
283:
284:
285:
286:
287:
288:
289: static VALUE
290: math_exp(VALUE obj, VALUE x)
291: {
292: Need_Float(x);
293: return DOUBLE2NUM(exp(RFLOAT_VALUE(x)));
294: }
295:
296: #if defined __CYGWIN__
297: # include <cygwin/version.h>
298: # if CYGWIN_VERSION_DLL_MAJOR < 1005
299: # define nan(x) nan()
300: # endif
301: # define log(x) ((x) < 0.0 ? nan("") : log(x))
302: # define log10(x) ((x) < 0.0 ? nan("") : log10(x))
303: #endif
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315: static VALUE
316: math_log(int argc, VALUE *argv)
317: {
318: VALUE x, base;
319: double d;
320:
321: rb_scan_args(argc, argv, "11", &x, &base);
322: Need_Float(x);
323: errno = 0;
324: d = log(RFLOAT_VALUE(x));
325: if (!NIL_P(base)) {
326: Need_Float(base);
327: d /= log(RFLOAT_VALUE(base));
328: }
329: domain_check(d, "log");
330: return DOUBLE2NUM(d);
331: }
332:
333: #ifndef log2
334: #ifndef HAVE_LOG2
335: double
336: log2(double x)
337: {
338: return log10(x)/log10(2.0);
339: }
340: #else
341: extern double log2(double);
342: #endif
343: #endif
344:
345:
346:
347:
348:
349:
350:
351:
352: static VALUE
353: math_log2(VALUE obj, VALUE x)
354: {
355: double d;
356:
357: Need_Float(x);
358: errno = 0;
359: d = log2(RFLOAT_VALUE(x));
360: if (errno) {
361: rb_sys_fail("log2");
362: }
363: return DOUBLE2NUM(d);
364: }
365:
366:
367:
368:
369:
370:
371:
372:
373: static VALUE
374: math_log10(VALUE obj, VALUE x)
375: {
376: double d;
377:
378: Need_Float(x);
379: errno = 0;
380: d = log10(RFLOAT_VALUE(x));
381: domain_check(d, "log10");
382: return DOUBLE2NUM(d);
383: }
384:
385:
386:
387:
388:
389:
390:
391:
392: static VALUE
393: math_sqrt(VALUE obj, VALUE x)
394: {
395: double d;
396:
397: Need_Float(x);
398: errno = 0;
399: d = sqrt(RFLOAT_VALUE(x));
400: domain_check(d, "sqrt");
401: return DOUBLE2NUM(d);
402: }
403:
404:
405:
406:
407:
408:
409:
410:
411:
412:
413:
414:
415:
416: static VALUE
417: math_frexp(VALUE obj, VALUE x)
418: {
419: double d;
420: int exp;
421:
422: Need_Float(x);
423:
424: d = frexp(RFLOAT_VALUE(x), &exp);
425: return rb_assoc_new(DOUBLE2NUM(d), INT2NUM(exp));
426: }
427:
428:
429:
430:
431:
432:
433:
434:
435:
436:
437:
438: static VALUE
439: math_ldexp(VALUE obj, VALUE x, VALUE n)
440: {
441: Need_Float(x);
442: return DOUBLE2NUM(ldexp(RFLOAT_VALUE(x), NUM2INT(n)));
443: }
444:
445:
446:
447:
448:
449:
450:
451:
452:
453:
454:
455: static VALUE
456: math_hypot(VALUE obj, VALUE x, VALUE y)
457: {
458: Need_Float2(x, y);
459: return DOUBLE2NUM(hypot(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
460: }
461:
462:
463:
464:
465:
466:
467:
468:
469: static VALUE
470: math_erf(VALUE obj, VALUE x)
471: {
472: Need_Float(x);
473: return DOUBLE2NUM(erf(RFLOAT_VALUE(x)));
474: }
475:
476:
477:
478:
479:
480:
481:
482:
483: static VALUE
484: math_erfc(VALUE obj, VALUE x)
485: {
486: Need_Float(x);
487: return DOUBLE2NUM(erfc(RFLOAT_VALUE(x)));
488: }
489:
490:
491:
492:
493:
494:
495:
496:
497:
498: void
499: Init_Math(void)
500: {
501: rb_mMath = rb_define_module("Math");
502:
503: #ifdef M_PI
504: rb_define_const(rb_mMath, "PI", DOUBLE2NUM(M_PI));
505: #else
506: rb_define_const(rb_mMath, "PI", DOUBLE2NUM(atan(1.0)*4.0));
507: #endif
508:
509: #ifdef M_E
510: rb_define_const(rb_mMath, "E", DOUBLE2NUM(M_E));
511: #else
512: rb_define_const(rb_mMath, "E", DOUBLE2NUM(exp(1.0)));
513: #endif
514:
515: rb_define_module_function(rb_mMath, "atan2", math_atan2, 2);
516: rb_define_module_function(rb_mMath, "cos", math_cos, 1);
517: rb_define_module_function(rb_mMath, "sin", math_sin, 1);
518: rb_define_module_function(rb_mMath, "tan", math_tan, 1);
519:
520: rb_define_module_function(rb_mMath, "acos", math_acos, 1);
521: rb_define_module_function(rb_mMath, "asin", math_asin, 1);
522: rb_define_module_function(rb_mMath, "atan", math_atan, 1);
523:
524: rb_define_module_function(rb_mMath, "cosh", math_cosh, 1);
525: rb_define_module_function(rb_mMath, "sinh", math_sinh, 1);
526: rb_define_module_function(rb_mMath, "tanh", math_tanh, 1);
527:
528: rb_define_module_function(rb_mMath, "acosh", math_acosh, 1);
529: rb_define_module_function(rb_mMath, "asinh", math_asinh, 1);
530: rb_define_module_function(rb_mMath, "atanh", math_atanh, 1);
531:
532: rb_define_module_function(rb_mMath, "exp", math_exp, 1);
533: rb_define_module_function(rb_mMath, "log", math_log, -1);
534: rb_define_module_function(rb_mMath, "log2", math_log2, 1);
535: rb_define_module_function(rb_mMath, "log10", math_log10, 1);
536: rb_define_module_function(rb_mMath, "sqrt", math_sqrt, 1);
537:
538: rb_define_module_function(rb_mMath, "frexp", math_frexp, 1);
539: rb_define_module_function(rb_mMath, "ldexp", math_ldexp, 2);
540:
541: rb_define_module_function(rb_mMath, "hypot", math_hypot, 2);
542:
543: rb_define_module_function(rb_mMath, "erf", math_erf, 1);
544: rb_define_module_function(rb_mMath, "erfc", math_erfc, 1);
545: }