1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/ruby.h"
14: #include "ruby/encoding.h"
15: #include <ctype.h>
16: #include <math.h>
17: #include <stdio.h>
18:
19: #if defined(__FreeBSD__) && __FreeBSD__ < 4
20: #include <floatingpoint.h>
21: #endif
22:
23: #ifdef HAVE_FLOAT_H
24: #include <float.h>
25: #endif
26:
27: #ifdef HAVE_IEEEFP_H
28: #include <ieeefp.h>
29: #endif
30:
31:
32: #ifndef FLT_RADIX
33: #define FLT_RADIX 2
34: #endif
35: #ifndef FLT_ROUNDS
36: #define FLT_ROUNDS 1
37: #endif
38: #ifndef DBL_MIN
39: #define DBL_MIN 2.2250738585072014e-308
40: #endif
41: #ifndef DBL_MAX
42: #define DBL_MAX 1.7976931348623157e+308
43: #endif
44: #ifndef DBL_MIN_EXP
45: #define DBL_MIN_EXP (-1021)
46: #endif
47: #ifndef DBL_MAX_EXP
48: #define DBL_MAX_EXP 1024
49: #endif
50: #ifndef DBL_MIN_10_EXP
51: #define DBL_MIN_10_EXP (-307)
52: #endif
53: #ifndef DBL_MAX_10_EXP
54: #define DBL_MAX_10_EXP 308
55: #endif
56: #ifndef DBL_DIG
57: #define DBL_DIG 15
58: #endif
59: #ifndef DBL_MANT_DIG
60: #define DBL_MANT_DIG 53
61: #endif
62: #ifndef DBL_EPSILON
63: #define DBL_EPSILON 2.2204460492503131e-16
64: #endif
65:
66: #ifndef HAVE_ROUND
67: double
68: round(double x)
69: {
70: double f;
71:
72: if (x > 0.0) {
73: f = floor(x);
74: x = f + (x - f >= 0.5);
75: }
76: else if (x < 0.0) {
77: f = ceil(x);
78: x = f - (f - x >= 0.5);
79: }
80: return x;
81: }
82: #endif
83:
84: static ID id_coerce, id_to_i, id_eq;
85:
86: VALUE rb_cNumeric;
87: VALUE rb_cFloat;
88: VALUE rb_cInteger;
89: VALUE rb_cFixnum;
90:
91: VALUE rb_eZeroDivError;
92: VALUE rb_eFloatDomainError;
93:
94: void
95: rb_num_zerodiv(void)
96: {
97: rb_raise(rb_eZeroDivError, "divided by 0");
98: }
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117: static VALUE
118: num_coerce(VALUE x, VALUE y)
119: {
120: if (CLASS_OF(x) == CLASS_OF(y))
121: return rb_assoc_new(y, x);
122: return rb_assoc_new(rb_Float(y), rb_Float(x));
123: }
124:
125: static VALUE
126: coerce_body(VALUE *x)
127: {
128: return rb_funcall(x[1], id_coerce, 1, x[0]);
129: }
130:
131: static VALUE
132: coerce_rescue(VALUE *x)
133: {
134: volatile VALUE v = rb_inspect(x[1]);
135:
136: rb_raise(rb_eTypeError, "%s can't be coerced into %s",
137: rb_special_const_p(x[1])?
138: RSTRING_PTR(v):
139: rb_obj_classname(x[1]),
140: rb_obj_classname(x[0]));
141: return Qnil;
142: }
143:
144: static int
145: do_coerce(VALUE *x, VALUE *y, int err)
146: {
147: VALUE ary;
148: VALUE a[2];
149:
150: a[0] = *x; a[1] = *y;
151:
152: ary = rb_rescue(coerce_body, (VALUE)a, err?coerce_rescue:0, (VALUE)a);
153: if (TYPE(ary) != T_ARRAY || RARRAY_LEN(ary) != 2) {
154: if (err) {
155: rb_raise(rb_eTypeError, "coerce must return [x, y]");
156: }
157: return Qfalse;
158: }
159:
160: *x = RARRAY_PTR(ary)[0];
161: *y = RARRAY_PTR(ary)[1];
162: return Qtrue;
163: }
164:
165: VALUE
166: rb_num_coerce_bin(VALUE x, VALUE y)
167: {
168: do_coerce(&x, &y, Qtrue);
169: return rb_funcall(x, rb_frame_this_func(), 1, y);
170: }
171:
172: VALUE
173: rb_num_coerce_cmp(VALUE x, VALUE y)
174: {
175: if (do_coerce(&x, &y, Qfalse))
176: return rb_funcall(x, rb_frame_this_func(), 1, y);
177: return Qnil;
178: }
179:
180: VALUE
181: rb_num_coerce_relop(VALUE x, VALUE y)
182: {
183: VALUE c, x0 = x, y0 = y;
184:
185: if (!do_coerce(&x, &y, Qfalse) ||
186: NIL_P(c = rb_funcall(x, rb_frame_this_func(), 1, y))) {
187: rb_cmperr(x0, y0);
188: return Qnil;
189: }
190: return c;
191: }
192:
193:
194:
195:
196:
197:
198: static VALUE
199: num_sadded(VALUE x, VALUE name)
200: {
201:
202:
203: rb_raise(rb_eTypeError,
204: "can't define singleton method \"%s\" for %s",
205: rb_id2name(rb_to_id(name)),
206: rb_obj_classname(x));
207: return Qnil;
208: }
209:
210:
211: static VALUE
212: num_init_copy(VALUE x, VALUE y)
213: {
214:
215: rb_raise(rb_eTypeError, "can't copy %s", rb_obj_classname(x));
216: return Qnil;
217: }
218:
219:
220:
221:
222:
223:
224:
225:
226: static VALUE
227: num_uplus(VALUE num)
228: {
229: return num;
230: }
231:
232:
233:
234:
235:
236:
237:
238:
239: static VALUE
240: num_uminus(VALUE num)
241: {
242: VALUE zero;
243:
244: zero = INT2FIX(0);
245: do_coerce(&zero, &num, Qtrue);
246:
247: return rb_funcall(zero, '-', 1, num);
248: }
249:
250:
251:
252:
253:
254:
255:
256:
257:
258: static VALUE
259: num_quo(VALUE x, VALUE y)
260: {
261: return rb_funcall(x, '/', 1, y);
262: }
263:
264:
265: static VALUE num_floor(VALUE num);
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276: static VALUE
277: num_div(VALUE x, VALUE y)
278: {
279: return num_floor(rb_funcall(x, '/', 1, y));
280: }
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323: static VALUE
324: num_divmod(VALUE x, VALUE y)
325: {
326: return rb_assoc_new(num_div(x, y), rb_funcall(x, '%', 1, y));
327: }
328:
329:
330:
331:
332:
333:
334:
335:
336:
337: static VALUE
338: num_modulo(VALUE x, VALUE y)
339: {
340: return rb_funcall(x, '%', 1, y);
341: }
342:
343:
344:
345:
346:
347:
348:
349:
350:
351:
352:
353:
354:
355: static VALUE
356: num_remainder(VALUE x, VALUE y)
357: {
358: VALUE z = rb_funcall(x, '%', 1, y);
359:
360: if ((!rb_equal(z, INT2FIX(0))) &&
361: ((RTEST(rb_funcall(x, '<', 1, INT2FIX(0))) &&
362: RTEST(rb_funcall(y, '>', 1, INT2FIX(0)))) ||
363: (RTEST(rb_funcall(x, '>', 1, INT2FIX(0))) &&
364: RTEST(rb_funcall(y, '<', 1, INT2FIX(0)))))) {
365: return rb_funcall(z, '-', 1, y);
366: }
367: return z;
368: }
369:
370:
371:
372:
373:
374:
375:
376:
377:
378: static VALUE
379: num_scalar_p(VALUE num)
380: {
381: return Qtrue;
382: }
383:
384:
385:
386:
387:
388:
389:
390:
391:
392: static VALUE
393: num_int_p(VALUE num)
394: {
395: return Qfalse;
396: }
397:
398:
399:
400:
401:
402:
403:
404:
405:
406:
407:
408:
409: static VALUE
410: num_abs(VALUE num)
411: {
412: if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) {
413: return rb_funcall(num, rb_intern("-@"), 0);
414: }
415: return num;
416: }
417:
418:
419:
420:
421:
422:
423:
424:
425:
426: static VALUE
427: num_zero_p(VALUE num)
428: {
429: if (rb_equal(num, INT2FIX(0))) {
430: return Qtrue;
431: }
432: return Qfalse;
433: }
434:
435:
436:
437:
438:
439:
440:
441:
442:
443:
444:
445:
446:
447:
448: static VALUE
449: num_nonzero_p(VALUE num)
450: {
451: if (RTEST(rb_funcall(num, rb_intern("zero?"), 0, 0))) {
452: return Qnil;
453: }
454: return num;
455: }
456:
457:
458:
459:
460:
461:
462:
463:
464:
465: static VALUE
466: num_to_int(VALUE num)
467: {
468: return rb_funcall(num, id_to_i, 0, 0);
469: }
470:
471:
472:
473:
474:
475:
476:
477:
478:
479:
480: VALUE
481: rb_float_new(double d)
482: {
483: NEWOBJ(flt, struct RFloat);
484: OBJSETUP(flt, rb_cFloat, T_FLOAT);
485:
486: flt->float_value = d;
487: return (VALUE)flt;
488: }
489:
490:
491:
492:
493:
494:
495:
496:
497:
498:
499:
500: static VALUE
501: flo_to_s(VALUE flt)
502: {
503: char buf[32];
504: double value = RFLOAT_VALUE(flt);
505: char *p, *e;
506:
507: if (isinf(value))
508: return rb_str_new2(value < 0 ? "-Infinity" : "Infinity");
509: else if(isnan(value))
510: return rb_str_new2("NaN");
511:
512: sprintf(buf, "%#.15g", value);
513: if (!(e = strchr(buf, 'e'))) {
514: e = buf + strlen(buf);
515: }
516: if (!ISDIGIT(e[-1])) {
517: sprintf(buf, "%#.14e", value);
518: if (!(e = strchr(buf, 'e'))) {
519: e = buf + strlen(buf);
520: }
521: }
522: p = e;
523: while (p[-1]=='0' && ISDIGIT(p[-2]))
524: p--;
525: memmove(p, e, strlen(e)+1);
526: return rb_str_new2(buf);
527: }
528:
529:
530:
531:
532:
533: static VALUE
534: flo_coerce(VALUE x, VALUE y)
535: {
536: return rb_assoc_new(rb_Float(y), x);
537: }
538:
539:
540:
541:
542:
543:
544:
545:
546: static VALUE
547: flo_uminus(VALUE flt)
548: {
549: return DOUBLE2NUM(-RFLOAT_VALUE(flt));
550: }
551:
552:
553:
554:
555:
556:
557:
558:
559:
560: static VALUE
561: flo_plus(VALUE x, VALUE y)
562: {
563: switch (TYPE(y)) {
564: case T_FIXNUM:
565: return DOUBLE2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
566: case T_BIGNUM:
567: return DOUBLE2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
568: case T_FLOAT:
569: return DOUBLE2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
570: default:
571: return rb_num_coerce_bin(x, y);
572: }
573: }
574:
575:
576:
577:
578:
579:
580:
581:
582:
583: static VALUE
584: flo_minus(VALUE x, VALUE y)
585: {
586: switch (TYPE(y)) {
587: case T_FIXNUM:
588: return DOUBLE2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
589: case T_BIGNUM:
590: return DOUBLE2NUM(RFLOAT_VALUE(x) - rb_big2dbl(y));
591: case T_FLOAT:
592: return DOUBLE2NUM(RFLOAT_VALUE(x) - RFLOAT_VALUE(y));
593: default:
594: return rb_num_coerce_bin(x, y);
595: }
596: }
597:
598:
599:
600:
601:
602:
603:
604:
605:
606: static VALUE
607: flo_mul(VALUE x, VALUE y)
608: {
609: switch (TYPE(y)) {
610: case T_FIXNUM:
611: return DOUBLE2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
612: case T_BIGNUM:
613: return DOUBLE2NUM(RFLOAT_VALUE(x) * rb_big2dbl(y));
614: case T_FLOAT:
615: return DOUBLE2NUM(RFLOAT_VALUE(x) * RFLOAT_VALUE(y));
616: default:
617: return rb_num_coerce_bin(x, y);
618: }
619: }
620:
621:
622:
623:
624:
625:
626:
627:
628:
629: static VALUE
630: flo_div(VALUE x, VALUE y)
631: {
632: long f_y;
633: double d;
634:
635: switch (TYPE(y)) {
636: case T_FIXNUM:
637: f_y = FIX2LONG(y);
638: return DOUBLE2NUM(RFLOAT_VALUE(x) / (double)f_y);
639: case T_BIGNUM:
640: d = rb_big2dbl(y);
641: return DOUBLE2NUM(RFLOAT_VALUE(x) / d);
642: case T_FL