1 /*
2 ** numeric.c - Numeric, Integer, Float, Fixnum class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6
7 #ifndef MRB_WITHOUT_FLOAT
8 #include <float.h>
9 #include <math.h>
10 #endif
11 #include <limits.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <mruby.h>
16 #include <mruby/array.h>
17 #include <mruby/numeric.h>
18 #include <mruby/string.h>
19 #include <mruby/class.h>
20
21 #ifndef MRB_WITHOUT_FLOAT
22 #ifdef MRB_USE_FLOAT
23 #define trunc(f) truncf(f)
24 #define floor(f) floorf(f)
25 #define ceil(f) ceilf(f)
26 #define fmod(x,y) fmodf(x,y)
27 #define FLO_TO_STR_PREC 8
28 #else
29 #define FLO_TO_STR_PREC 16
30 #endif
31 #endif
32
33 #ifndef MRB_WITHOUT_FLOAT
34 MRB_API mrb_float
mrb_to_flo(mrb_state * mrb,mrb_value val)35 mrb_to_flo(mrb_state *mrb, mrb_value val)
36 {
37 switch (mrb_type(val)) {
38 case MRB_TT_FIXNUM:
39 return (mrb_float)mrb_fixnum(val);
40 case MRB_TT_FLOAT:
41 break;
42 default:
43 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
44 }
45 return mrb_float(val);
46 }
47
48 MRB_API mrb_value
mrb_int_value(mrb_state * mrb,mrb_float f)49 mrb_int_value(mrb_state *mrb, mrb_float f)
50 {
51 if (FIXABLE_FLOAT(f)) {
52 return mrb_fixnum_value((mrb_int)f);
53 }
54 return mrb_float_value(mrb, f);
55 }
56 #endif
57
58 /*
59 * call-seq:
60 *
61 * num ** other -> num
62 *
63 * Raises <code>num</code> the <code>other</code> power.
64 *
65 * 2.0**3 #=> 8.0
66 */
67 static mrb_value
integral_pow(mrb_state * mrb,mrb_value x)68 integral_pow(mrb_state *mrb, mrb_value x)
69 {
70 mrb_value y = mrb_get_arg1(mrb);
71 #ifndef MRB_WITHOUT_FLOAT
72 mrb_float d;
73 #endif
74
75 if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) {
76 /* try ipow() */
77 mrb_int base = mrb_fixnum(x);
78 mrb_int exp = mrb_fixnum(y);
79 mrb_int result = 1;
80
81 if (exp < 0)
82 #ifdef MRB_WITHOUT_FLOAT
83 return mrb_fixnum_value(0);
84 #else
85 goto float_pow;
86 #endif
87 for (;;) {
88 if (exp & 1) {
89 if (mrb_int_mul_overflow(result, base, &result)) {
90 #ifndef MRB_WITHOUT_FLOAT
91 goto float_pow;
92 #endif
93 }
94 }
95 exp >>= 1;
96 if (exp == 0) break;
97 if (mrb_int_mul_overflow(base, base, &base)) {
98 #ifndef MRB_WITHOUT_FLOAT
99 goto float_pow;
100 #endif
101 }
102 }
103 return mrb_fixnum_value(result);
104 }
105 #ifdef MRB_WITHOUT_FLOAT
106 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
107 #else
108 float_pow:
109 d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
110 return mrb_float_value(mrb, d);
111 #endif
112 }
113
114 static mrb_value
integral_idiv(mrb_state * mrb,mrb_value x)115 integral_idiv(mrb_state *mrb, mrb_value x)
116 {
117 #ifdef MRB_WITHOUT_FLOAT
118 mrb_value y = mrb_get_arg1(mrb);
119
120 if (!mrb_fixnum_p(y)) {
121 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
122 }
123 return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
124 #else
125 mrb_float y;
126
127 mrb_get_args(mrb, "f", &y);
128 return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y);
129 #endif
130 }
131
132 /* 15.2.8.3.4 */
133 /* 15.2.9.3.4 */
134 /*
135 * call-seq:
136 * num / other -> num
137 *
138 * Performs division: the class of the resulting object depends on
139 * the class of <code>num</code> and on the magnitude of the
140 * result.
141 */
142
143 /* 15.2.9.3.19(x) */
144 /*
145 * call-seq:
146 * num.quo(numeric) -> real
147 *
148 * Returns most exact division.
149 */
150
151 static mrb_value
integral_div(mrb_state * mrb,mrb_value x)152 integral_div(mrb_state *mrb, mrb_value x)
153 {
154 #ifdef MRB_WITHOUT_FLOAT
155 mrb_value y = mrb_get_arg1(mrb);
156
157 if (!mrb_fixnum_p(y)) {
158 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
159 }
160 return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
161 #else
162 mrb_float y;
163
164 mrb_get_args(mrb, "f", &y);
165 return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
166 #endif
167 }
168
169 static mrb_value
integral_coerce_step_counter(mrb_state * mrb,mrb_value self)170 integral_coerce_step_counter(mrb_state *mrb, mrb_value self)
171 {
172 mrb_value num, step;
173
174 mrb_get_args(mrb, "oo", &num, &step);
175
176 #ifndef MRB_WITHOUT_FLOAT
177 if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
178 return mrb_Float(mrb, self);
179 }
180 #endif
181
182 return self;
183 }
184
185 #ifndef MRB_WITHOUT_FLOAT
186 /********************************************************************
187 *
188 * Document-class: Float
189 *
190 * <code>Float</code> objects represent inexact real numbers using
191 * the native architecture's double-precision floating point
192 * representation.
193 */
194
195 /* 15.2.9.3.16(x) */
196 /*
197 * call-seq:
198 * flt.to_s -> string
199 *
200 * Returns a string containing a representation of self. As well as a
201 * fixed or exponential form of the number, the call may return
202 * "<code>NaN</code>", "<code>Infinity</code>", and
203 * "<code>-Infinity</code>".
204 */
205
206 static mrb_value
flo_to_s(mrb_state * mrb,mrb_value flt)207 flo_to_s(mrb_state *mrb, mrb_value flt)
208 {
209 mrb_float f = mrb_float(flt);
210 mrb_value str;
211
212 if (isinf(f)) {
213 str = f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
214 : mrb_str_new_lit(mrb, "Infinity");
215 goto exit;
216 }
217 else if (isnan(f)) {
218 str = mrb_str_new_lit(mrb, "NaN");
219 goto exit;
220 }
221 else {
222 char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
223 mrb_int len;
224 char *begp, *p, *endp;
225
226 str = mrb_float_to_str(mrb, flt, fmt);
227
228 insert_dot_zero:
229 begp = RSTRING_PTR(str);
230 len = RSTRING_LEN(str);
231 for (p = begp, endp = p + len; p < endp; ++p) {
232 if (*p == '.') {
233 goto exit;
234 }
235 else if (*p == 'e') {
236 ptrdiff_t e_pos = p - begp;
237 mrb_str_cat(mrb, str, ".0", 2);
238 p = RSTRING_PTR(str) + e_pos;
239 memmove(p + 2, p, len - e_pos);
240 memcpy(p, ".0", 2);
241 goto exit;
242 }
243 }
244
245 if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
246 --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */
247 str = mrb_float_to_str(mrb, flt, fmt);
248 goto insert_dot_zero;
249 }
250
251 goto exit;
252 }
253
254 exit:
255 RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
256 return str;
257 }
258
259 /* 15.2.9.3.2 */
260 /*
261 * call-seq:
262 * float - other -> float
263 *
264 * Returns a new float which is the difference of <code>float</code>
265 * and <code>other</code>.
266 */
267
268 static mrb_value
flo_minus(mrb_state * mrb,mrb_value x)269 flo_minus(mrb_state *mrb, mrb_value x)
270 {
271 mrb_value y = mrb_get_arg1(mrb);
272
273 return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
274 }
275
276 /* 15.2.9.3.3 */
277 /*
278 * call-seq:
279 * float * other -> float
280 *
281 * Returns a new float which is the product of <code>float</code>
282 * and <code>other</code>.
283 */
284
285 static mrb_value
flo_mul(mrb_state * mrb,mrb_value x)286 flo_mul(mrb_state *mrb, mrb_value x)
287 {
288 mrb_value y = mrb_get_arg1(mrb);
289
290 return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
291 }
292
293 static void
flodivmod(mrb_state * mrb,double x,double y,mrb_float * divp,mrb_float * modp)294 flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
295 {
296 double div, mod;
297
298 if (isnan(y)) {
299 /* y is NaN so all results are NaN */
300 div = mod = y;
301 goto exit;
302 }
303 if (y == 0.0) {
304 if (x == 0) div = NAN;
305 else if (x > 0.0) div = INFINITY;
306 else div = -INFINITY; /* x < 0.0 */
307 mod = NAN;
308 goto exit;
309 }
310 if ((x == 0.0) || (isinf(y) && !isinf(x))) {
311 mod = x;
312 }
313 else {
314 mod = fmod(x, y);
315 }
316 if (isinf(x) && !isinf(y)) {
317 div = x;
318 }
319 else {
320 div = (x - mod) / y;
321 if (modp && divp) div = round(div);
322 }
323 if (div == 0) div = 0.0;
324 if (mod == 0) mod = 0.0;
325 if (y*mod < 0) {
326 mod += y;
327 div -= 1.0;
328 }
329 exit:
330 if (modp) *modp = mod;
331 if (divp) *divp = div;
332 }
333
334 /* 15.2.9.3.5 */
335 /*
336 * call-seq:
337 * flt % other -> float
338 * flt.modulo(other) -> float
339 *
340 * Return the modulo after division of <code>flt</code> by <code>other</code>.
341 *
342 * 6543.21.modulo(137) #=> 104.21
343 * 6543.21.modulo(137.24) #=> 92.9299999999996
344 */
345
346 static mrb_value
flo_mod(mrb_state * mrb,mrb_value x)347 flo_mod(mrb_state *mrb, mrb_value x)
348 {
349 mrb_value y = mrb_get_arg1(mrb);
350 mrb_float mod;
351
352 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), 0, &mod);
353 return mrb_float_value(mrb, mod);
354 }
355 #endif
356
357 /* 15.2.8.3.16 */
358 /*
359 * call-seq:
360 * num.eql?(numeric) -> true or false
361 *
362 * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
363 * same type and have equal values.
364 *
365 * 1 == 1.0 #=> true
366 * 1.eql?(1.0) #=> false
367 * (1.0).eql?(1.0) #=> true
368 */
369 static mrb_value
fix_eql(mrb_state * mrb,mrb_value x)370 fix_eql(mrb_state *mrb, mrb_value x)
371 {
372 mrb_value y = mrb_get_arg1(mrb);
373
374 if (!mrb_fixnum_p(y)) return mrb_false_value();
375 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
376 }
377
378 #ifndef MRB_WITHOUT_FLOAT
379 static mrb_value
flo_eql(mrb_state * mrb,mrb_value x)380 flo_eql(mrb_state *mrb, mrb_value x)
381 {
382 mrb_value y = mrb_get_arg1(mrb);
383
384 if (!mrb_float_p(y)) return mrb_false_value();
385 return mrb_bool_value(mrb_float(x) == mrb_float(y));
386 }
387
388 /* 15.2.9.3.7 */
389 /*
390 * call-seq:
391 * flt == obj -> true or false
392 *
393 * Returns <code>true</code> only if <i>obj</i> has the same value
394 * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
395 * requires <i>obj</i> to be a <code>Float</code>.
396 *
397 * 1.0 == 1 #=> true
398 *
399 */
400
401 static mrb_value
flo_eq(mrb_state * mrb,mrb_value x)402 flo_eq(mrb_state *mrb, mrb_value x)
403 {
404 mrb_value y = mrb_get_arg1(mrb);
405
406 switch (mrb_type(y)) {
407 case MRB_TT_FIXNUM:
408 return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
409 case MRB_TT_FLOAT:
410 return mrb_bool_value(mrb_float(x) == mrb_float(y));
411 default:
412 return mrb_false_value();
413 }
414 }
415
416 static int64_t
value_int64(mrb_state * mrb,mrb_value x)417 value_int64(mrb_state *mrb, mrb_value x)
418 {
419 switch (mrb_type(x)) {
420 case MRB_TT_FIXNUM:
421 return (int64_t)mrb_fixnum(x);
422 case MRB_TT_FLOAT:
423 return (int64_t)mrb_float(x);
424 default:
425 mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer");
426 break;
427 }
428 /* not reached */
429 return 0;
430 }
431
432 static mrb_value
int64_value(mrb_state * mrb,int64_t v)433 int64_value(mrb_state *mrb, int64_t v)
434 {
435 if (TYPED_FIXABLE(v,int64_t)) {
436 return mrb_fixnum_value((mrb_int)v);
437 }
438 return mrb_float_value(mrb, (mrb_float)v);
439 }
440
441 static mrb_value
flo_rev(mrb_state * mrb,mrb_value x)442 flo_rev(mrb_state *mrb, mrb_value x)
443 {
444 int64_t v1;
445 v1 = (int64_t)mrb_float(x);
446 return int64_value(mrb, ~v1);
447 }
448
449 static mrb_value
flo_and(mrb_state * mrb,mrb_value x)450 flo_and(mrb_state *mrb, mrb_value x)
451 {
452 mrb_value y = mrb_get_arg1(mrb);
453 int64_t v1, v2;
454
455 v1 = (int64_t)mrb_float(x);
456 v2 = value_int64(mrb, y);
457 return int64_value(mrb, v1 & v2);
458 }
459
460 static mrb_value
flo_or(mrb_state * mrb,mrb_value x)461 flo_or(mrb_state *mrb, mrb_value x)
462 {
463 mrb_value y = mrb_get_arg1(mrb);
464 int64_t v1, v2;
465
466 v1 = (int64_t)mrb_float(x);
467 v2 = value_int64(mrb, y);
468 return int64_value(mrb, v1 | v2);
469 }
470
471 static mrb_value
flo_xor(mrb_state * mrb,mrb_value x)472 flo_xor(mrb_state *mrb, mrb_value x)
473 {
474 mrb_value y = mrb_get_arg1(mrb);
475 int64_t v1, v2;
476
477 v1 = (int64_t)mrb_float(x);
478 v2 = value_int64(mrb, y);
479 return int64_value(mrb, v1 ^ v2);
480 }
481
482 static mrb_value
flo_shift(mrb_state * mrb,mrb_value x,mrb_int width)483 flo_shift(mrb_state *mrb, mrb_value x, mrb_int width)
484 {
485 mrb_float val;
486
487 if (width == 0) {
488 return x;
489 }
490 val = mrb_float(x);
491 if (width < 0) {
492 while (width++) {
493 val /= 2;
494 if (val < 1.0) {
495 val = 0;
496 break;
497 }
498 }
499 #if defined(_ISOC99_SOURCE)
500 val = trunc(val);
501 #else
502 if (val > 0){
503 val = floor(val);
504 } else {
505 val = ceil(val);
506 }
507 #endif
508 if (val == 0 && mrb_float(x) < 0) {
509 return mrb_fixnum_value(-1);
510 }
511 }
512 else {
513 while (width--) {
514 val *= 2;
515 }
516 }
517 return mrb_int_value(mrb, val);
518 }
519
520 static mrb_value
flo_rshift(mrb_state * mrb,mrb_value x)521 flo_rshift(mrb_state *mrb, mrb_value x)
522 {
523 mrb_int width;
524
525 mrb_get_args(mrb, "i", &width);
526 return flo_shift(mrb, x, -width);
527 }
528
529 static mrb_value
flo_lshift(mrb_state * mrb,mrb_value x)530 flo_lshift(mrb_state *mrb, mrb_value x)
531 {
532 mrb_int width;
533
534 mrb_get_args(mrb, "i", &width);
535 return flo_shift(mrb, x, width);
536 }
537
538 /* 15.2.9.3.13 */
539 /*
540 * call-seq:
541 * flt.to_f -> self
542 *
543 * As <code>flt</code> is already a float, returns +self+.
544 */
545
546 static mrb_value
flo_to_f(mrb_state * mrb,mrb_value num)547 flo_to_f(mrb_state *mrb, mrb_value num)
548 {
549 return num;
550 }
551
552 /* 15.2.9.3.11 */
553 /*
554 * call-seq:
555 * flt.infinite? -> nil, -1, +1
556 *
557 * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
558 * is finite, -infinity, or +infinity.
559 *
560 * (0.0).infinite? #=> nil
561 * (-1.0/0.0).infinite? #=> -1
562 * (+1.0/0.0).infinite? #=> 1
563 */
564
565 static mrb_value
flo_infinite_p(mrb_state * mrb,mrb_value num)566 flo_infinite_p(mrb_state *mrb, mrb_value num)
567 {
568 mrb_float value = mrb_float(num);
569
570 if (isinf(value)) {
571 return mrb_fixnum_value(value < 0 ? -1 : 1);
572 }
573 return mrb_nil_value();
574 }
575
576 /* 15.2.9.3.9 */
577 /*
578 * call-seq:
579 * flt.finite? -> true or false
580 *
581 * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
582 * point number (it is not infinite, and <code>nan?</code> is
583 * <code>false</code>).
584 *
585 */
586
587 static mrb_value
flo_finite_p(mrb_state * mrb,mrb_value num)588 flo_finite_p(mrb_state *mrb, mrb_value num)
589 {
590 return mrb_bool_value(isfinite(mrb_float(num)));
591 }
592
593 void
mrb_check_num_exact(mrb_state * mrb,mrb_float num)594 mrb_check_num_exact(mrb_state *mrb, mrb_float num)
595 {
596 if (isinf(num)) {
597 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, num < 0 ? "-Infinity" : "Infinity");
598 }
599 if (isnan(num)) {
600 mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
601 }
602 }
603
604 /* 15.2.9.3.10 */
605 /*
606 * call-seq:
607 * flt.floor -> integer
608 *
609 * Returns the largest integer less than or equal to <i>flt</i>.
610 *
611 * 1.2.floor #=> 1
612 * 2.0.floor #=> 2
613 * (-1.2).floor #=> -2
614 * (-2.0).floor #=> -2
615 */
616
617 static mrb_value
flo_floor(mrb_state * mrb,mrb_value num)618 flo_floor(mrb_state *mrb, mrb_value num)
619 {
620 mrb_float f = floor(mrb_float(num));
621
622 mrb_check_num_exact(mrb, f);
623 return mrb_int_value(mrb, f);
624 }
625
626 /* 15.2.9.3.8 */
627 /*
628 * call-seq:
629 * flt.ceil -> integer
630 *
631 * Returns the smallest <code>Integer</code> greater than or equal to
632 * <i>flt</i>.
633 *
634 * 1.2.ceil #=> 2
635 * 2.0.ceil #=> 2
636 * (-1.2).ceil #=> -1
637 * (-2.0).ceil #=> -2
638 */
639
640 static mrb_value
flo_ceil(mrb_state * mrb,mrb_value num)641 flo_ceil(mrb_state *mrb, mrb_value num)
642 {
643 mrb_float f = ceil(mrb_float(num));
644
645 mrb_check_num_exact(mrb, f);
646 return mrb_int_value(mrb, f);
647 }
648
649 /* 15.2.9.3.12 */
650 /*
651 * call-seq:
652 * flt.round([ndigits]) -> integer or float
653 *
654 * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
655 * Precision may be negative. Returns a floating point number when ndigits
656 * is more than zero.
657 *
658 * 1.4.round #=> 1
659 * 1.5.round #=> 2
660 * 1.6.round #=> 2
661 * (-1.5).round #=> -2
662 *
663 * 1.234567.round(2) #=> 1.23
664 * 1.234567.round(3) #=> 1.235
665 * 1.234567.round(4) #=> 1.2346
666 * 1.234567.round(5) #=> 1.23457
667 *
668 * 34567.89.round(-5) #=> 0
669 * 34567.89.round(-4) #=> 30000
670 * 34567.89.round(-3) #=> 35000
671 * 34567.89.round(-2) #=> 34600
672 * 34567.89.round(-1) #=> 34570
673 * 34567.89.round(0) #=> 34568
674 * 34567.89.round(1) #=> 34567.9
675 * 34567.89.round(2) #=> 34567.89
676 * 34567.89.round(3) #=> 34567.89
677 *
678 */
679
680 static mrb_value
flo_round(mrb_state * mrb,mrb_value num)681 flo_round(mrb_state *mrb, mrb_value num)
682 {
683 double number, f;
684 mrb_int ndigits = 0;
685 mrb_int i;
686
687 mrb_get_args(mrb, "|i", &ndigits);
688 number = mrb_float(num);
689
690 if (0 < ndigits && (isinf(number) || isnan(number))) {
691 return num;
692 }
693 mrb_check_num_exact(mrb, number);
694
695 f = 1.0;
696 i = ndigits >= 0 ? ndigits : -ndigits;
697 if (ndigits > DBL_DIG+2) return num;
698 while (--i >= 0)
699 f = f*10.0;
700
701 if (isinf(f)) {
702 if (ndigits < 0) number = 0;
703 }
704 else {
705 double d;
706
707 if (ndigits < 0) number /= f;
708 else number *= f;
709
710 /* home-made inline implementation of round(3) */
711 if (number > 0.0) {
712 d = floor(number);
713 number = d + (number - d >= 0.5);
714 }
715 else if (number < 0.0) {
716 d = ceil(number);
717 number = d - (d - number >= 0.5);
718 }
719
720 if (ndigits < 0) number *= f;
721 else number /= f;
722 }
723
724 if (ndigits > 0) {
725 if (!isfinite(number)) return num;
726 return mrb_float_value(mrb, number);
727 }
728 return mrb_int_value(mrb, number);
729 }
730
731 /* 15.2.9.3.14 */
732 /* 15.2.9.3.15 */
733 /*
734 * call-seq:
735 * flt.to_i -> integer
736 * flt.truncate -> integer
737 *
738 * Returns <i>flt</i> truncated to an <code>Integer</code>.
739 */
740
741 static mrb_value
flo_truncate(mrb_state * mrb,mrb_value num)742 flo_truncate(mrb_state *mrb, mrb_value num)
743 {
744 mrb_float f = mrb_float(num);
745
746 if (f > 0.0) f = floor(f);
747 if (f < 0.0) f = ceil(f);
748
749 mrb_check_num_exact(mrb, f);
750 return mrb_int_value(mrb, f);
751 }
752
753 static mrb_value
flo_nan_p(mrb_state * mrb,mrb_value num)754 flo_nan_p(mrb_state *mrb, mrb_value num)
755 {
756 return mrb_bool_value(isnan(mrb_float(num)));
757 }
758 #endif
759
760 /*
761 * Document-class: Integer
762 *
763 * <code>Integer</code> is the basis for the two concrete classes that
764 * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
765 *
766 */
767
768
769 /*
770 * call-seq:
771 * int.to_i -> integer
772 *
773 * As <i>int</i> is already an <code>Integer</code>, all these
774 * methods simply return the receiver.
775 */
776
777 static mrb_value
int_to_i(mrb_state * mrb,mrb_value num)778 int_to_i(mrb_state *mrb, mrb_value num)
779 {
780 return num;
781 }
782
783 static mrb_value
fixnum_mul(mrb_state * mrb,mrb_value x,mrb_value y)784 fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
785 {
786 mrb_int a;
787
788 a = mrb_fixnum(x);
789 if (mrb_fixnum_p(y)) {
790 mrb_int b, c;
791
792 if (a == 0) return x;
793 b = mrb_fixnum(y);
794 if (mrb_int_mul_overflow(a, b, &c)) {
795 #ifndef MRB_WITHOUT_FLOAT
796 return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
797 #endif
798 }
799 return mrb_fixnum_value(c);
800 }
801 #ifdef MRB_WITHOUT_FLOAT
802 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
803 #else
804 return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
805 #endif
806 }
807
808 MRB_API mrb_value
mrb_num_mul(mrb_state * mrb,mrb_value x,mrb_value y)809 mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
810 {
811 if (mrb_fixnum_p(x)) {
812 return fixnum_mul(mrb, x, y);
813 }
814 #ifndef MRB_WITHOUT_FLOAT
815 if (mrb_float_p(x)) {
816 return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
817 }
818 #endif
819 mrb_raise(mrb, E_TYPE_ERROR, "no number multiply");
820 return mrb_nil_value(); /* not reached */
821 }
822
823 /* 15.2.8.3.3 */
824 /*
825 * call-seq:
826 * fix * numeric -> numeric_result
827 *
828 * Performs multiplication: the class of the resulting object depends on
829 * the class of <code>numeric</code> and on the magnitude of the
830 * result.
831 */
832
833 static mrb_value
fix_mul(mrb_state * mrb,mrb_value x)834 fix_mul(mrb_state *mrb, mrb_value x)
835 {
836 mrb_value y = mrb_get_arg1(mrb);
837
838 return fixnum_mul(mrb, x, y);
839 }
840
841 static void
fixdivmod(mrb_state * mrb,mrb_int x,mrb_int y,mrb_int * divp,mrb_int * modp)842 fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
843 {
844 mrb_int div, mod;
845
846 /* TODO: add mrb_assert(y != 0) to make sure */
847
848 if (y < 0) {
849 if (x < 0)
850 div = -x / -y;
851 else
852 div = - (x / -y);
853 }
854 else {
855 if (x < 0)
856 div = - (-x / y);
857 else
858 div = x / y;
859 }
860 mod = x - div*y;
861 if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
862 mod += y;
863 div -= 1;
864 }
865 if (divp) *divp = div;
866 if (modp) *modp = mod;
867 }
868
869 /* 15.2.8.3.5 */
870 /*
871 * call-seq:
872 * fix % other -> real
873 * fix.modulo(other) -> real
874 *
875 * Returns <code>fix</code> modulo <code>other</code>.
876 * See <code>numeric.divmod</code> for more information.
877 */
878
879 static mrb_value
fix_mod(mrb_state * mrb,mrb_value x)880 fix_mod(mrb_state *mrb, mrb_value x)
881 {
882 mrb_value y = mrb_get_arg1(mrb);
883 mrb_int a, b;
884
885 a = mrb_fixnum(x);
886 if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
887 mrb_int mod;
888
889 if (b == 0) {
890 #ifdef MRB_WITHOUT_FLOAT
891 /* ZeroDivisionError */
892 return mrb_fixnum_value(0);
893 #else
894 if (a > 0) return mrb_float_value(mrb, INFINITY);
895 if (a < 0) return mrb_float_value(mrb, INFINITY);
896 return mrb_float_value(mrb, NAN);
897 #endif
898 }
899 fixdivmod(mrb, a, b, NULL, &mod);
900 return mrb_fixnum_value(mod);
901 }
902 #ifdef MRB_WITHOUT_FLOAT
903 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
904 #else
905 else {
906 mrb_float mod;
907
908 flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
909 return mrb_float_value(mrb, mod);
910 }
911 #endif
912 }
913
914 /*
915 * call-seq:
916 * fix.divmod(numeric) -> array
917 *
918 * See <code>Numeric#divmod</code>.
919 */
920 static mrb_value
fix_divmod(mrb_state * mrb,mrb_value x)921 fix_divmod(mrb_state *mrb, mrb_value x)
922 {
923 mrb_value y = mrb_get_arg1(mrb);
924
925 if (mrb_fixnum_p(y)) {
926 mrb_int div, mod;
927
928 if (mrb_fixnum(y) == 0) {
929 #ifdef MRB_WITHOUT_FLOAT
930 return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0));
931 #else
932 return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
933 mrb_float_value(mrb, NAN):
934 mrb_float_value(mrb, INFINITY)),
935 mrb_float_value(mrb, NAN));
936 #endif
937 }
938 fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
939 return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
940 }
941 #ifdef MRB_WITHOUT_FLOAT
942 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
943 #else
944 else {
945 mrb_float div, mod;
946 mrb_value a, b;
947
948 flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
949 a = mrb_int_value(mrb, div);
950 b = mrb_float_value(mrb, mod);
951 return mrb_assoc_new(mrb, a, b);
952 }
953 #endif
954 }
955
956 #ifndef MRB_WITHOUT_FLOAT
957 static mrb_value
flo_divmod(mrb_state * mrb,mrb_value x)958 flo_divmod(mrb_state *mrb, mrb_value x)
959 {
960 mrb_value y = mrb_get_arg1(mrb);
961 mrb_float div, mod;
962 mrb_value a, b;
963
964 flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
965 a = mrb_int_value(mrb, div);
966 b = mrb_float_value(mrb, mod);
967 return mrb_assoc_new(mrb, a, b);
968 }
969 #endif
970
971 /* 15.2.8.3.7 */
972 /*
973 * call-seq:
974 * fix == other -> true or false
975 *
976 * Return <code>true</code> if <code>fix</code> equals <code>other</code>
977 * numerically.
978 *
979 * 1 == 2 #=> false
980 * 1 == 1.0 #=> true
981 */
982
983 static mrb_value
fix_equal(mrb_state * mrb,mrb_value x)984 fix_equal(mrb_state *mrb, mrb_value x)
985 {
986 mrb_value y = mrb_get_arg1(mrb);
987
988 switch (mrb_type(y)) {
989 case MRB_TT_FIXNUM:
990 return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
991 #ifndef MRB_WITHOUT_FLOAT
992 case MRB_TT_FLOAT:
993 return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
994 #endif
995 default:
996 return mrb_false_value();
997 }
998 }
999
1000 /* 15.2.8.3.8 */
1001 /*
1002 * call-seq:
1003 * ~fix -> integer
1004 *
1005 * One's complement: returns a number where each bit is flipped.
1006 * ex.0---00001 (1)-> 1---11110 (-2)
1007 * ex.0---00010 (2)-> 1---11101 (-3)
1008 * ex.0---00100 (4)-> 1---11011 (-5)
1009 */
1010
1011 static mrb_value
fix_rev(mrb_state * mrb,mrb_value num)1012 fix_rev(mrb_state *mrb, mrb_value num)
1013 {
1014 mrb_int val = mrb_fixnum(num);
1015
1016 return mrb_fixnum_value(~val);
1017 }
1018
1019 #ifdef MRB_WITHOUT_FLOAT
1020 #define bit_op(x,y,op1,op2) do {\
1021 return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
1022 } while(0)
1023 #else
1024 static mrb_value flo_and(mrb_state *mrb, mrb_value x);
1025 static mrb_value flo_or(mrb_state *mrb, mrb_value x);
1026 static mrb_value flo_xor(mrb_state *mrb, mrb_value x);
1027 #define bit_op(x,y,op1,op2) do {\
1028 if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
1029 return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
1030 } while(0)
1031 #endif
1032
1033 /* 15.2.8.3.9 */
1034 /*
1035 * call-seq:
1036 * fix & integer -> integer_result
1037 *
1038 * Bitwise AND.
1039 */
1040
1041 static mrb_value
fix_and(mrb_state * mrb,mrb_value x)1042 fix_and(mrb_state *mrb, mrb_value x)
1043 {
1044 mrb_value y = mrb_get_arg1(mrb);
1045
1046 bit_op(x, y, and, &);
1047 }
1048
1049 /* 15.2.8.3.10 */
1050 /*
1051 * call-seq:
1052 * fix | integer -> integer_result
1053 *
1054 * Bitwise OR.
1055 */
1056
1057 static mrb_value
fix_or(mrb_state * mrb,mrb_value x)1058 fix_or(mrb_state *mrb, mrb_value x)
1059 {
1060 mrb_value y = mrb_get_arg1(mrb);
1061
1062 bit_op(x, y, or, |);
1063 }
1064
1065 /* 15.2.8.3.11 */
1066 /*
1067 * call-seq:
1068 * fix ^ integer -> integer_result
1069 *
1070 * Bitwise EXCLUSIVE OR.
1071 */
1072
1073 static mrb_value
fix_xor(mrb_state * mrb,mrb_value x)1074 fix_xor(mrb_state *mrb, mrb_value x)
1075 {
1076 mrb_value y = mrb_get_arg1(mrb);
1077
1078 bit_op(x, y, or, ^);
1079 }
1080
1081 #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1)
1082
1083 static mrb_value
lshift(mrb_state * mrb,mrb_int val,mrb_int width)1084 lshift(mrb_state *mrb, mrb_int val, mrb_int width)
1085 {
1086 if (width < 0) { /* mrb_int overflow */
1087 #ifdef MRB_WITHOUT_FLOAT
1088 return mrb_fixnum_value(0);
1089 #else
1090 return mrb_float_value(mrb, INFINITY);
1091 #endif
1092 }
1093 if (val > 0) {
1094 if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1095 (val > (MRB_INT_MAX >> width))) {
1096 #ifdef MRB_WITHOUT_FLOAT
1097 return mrb_fixnum_value(-1);
1098 #else
1099 goto bit_overflow;
1100 #endif
1101 }
1102 return mrb_fixnum_value(val << width);
1103 }
1104 else {
1105 if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
1106 (val <= (MRB_INT_MIN >> width))) {
1107 #ifdef MRB_WITHOUT_FLOAT
1108 return mrb_fixnum_value(0);
1109 #else
1110 goto bit_overflow;
1111 #endif
1112 }
1113 return mrb_fixnum_value(val * ((mrb_int)1 << width));
1114 }
1115
1116 #ifndef MRB_WITHOUT_FLOAT
1117 bit_overflow:
1118 {
1119 mrb_float f = (mrb_float)val;
1120 while (width--) {
1121 f *= 2;
1122 }
1123 return mrb_float_value(mrb, f);
1124 }
1125 #endif
1126 }
1127
1128 static mrb_value
rshift(mrb_int val,mrb_int width)1129 rshift(mrb_int val, mrb_int width)
1130 {
1131 if (width < 0) { /* mrb_int overflow */
1132 return mrb_fixnum_value(0);
1133 }
1134 if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
1135 if (val < 0) {
1136 return mrb_fixnum_value(-1);
1137 }
1138 return mrb_fixnum_value(0);
1139 }
1140 return mrb_fixnum_value(val >> width);
1141 }
1142
1143 /* 15.2.8.3.12 */
1144 /*
1145 * call-seq:
1146 * fix << count -> integer or float
1147 *
1148 * Shifts _fix_ left _count_ positions (right if _count_ is negative).
1149 */
1150
1151 static mrb_value
fix_lshift(mrb_state * mrb,mrb_value x)1152 fix_lshift(mrb_state *mrb, mrb_value x)
1153 {
1154 mrb_int width, val;
1155
1156 mrb_get_args(mrb, "i", &width);
1157 if (width == 0) {
1158 return x;
1159 }
1160 val = mrb_fixnum(x);
1161 if (val == 0) return x;
1162 if (width < 0) {
1163 return rshift(val, -width);
1164 }
1165 return lshift(mrb, val, width);
1166 }
1167
1168 /* 15.2.8.3.13 */
1169 /*
1170 * call-seq:
1171 * fix >> count -> integer or float
1172 *
1173 * Shifts _fix_ right _count_ positions (left if _count_ is negative).
1174 */
1175
1176 static mrb_value
fix_rshift(mrb_state * mrb,mrb_value x)1177 fix_rshift(mrb_state *mrb, mrb_value x)
1178 {
1179 mrb_int width, val;
1180
1181 mrb_get_args(mrb, "i", &width);
1182 if (width == 0) {
1183 return x;
1184 }
1185 val = mrb_fixnum(x);
1186 if (val == 0) return x;
1187 if (width < 0) {
1188 return lshift(mrb, val, -width);
1189 }
1190 return rshift(val, width);
1191 }
1192
1193 /* 15.2.8.3.23 */
1194 /*
1195 * call-seq:
1196 * fix.to_f -> float
1197 *
1198 * Converts <i>fix</i> to a <code>Float</code>.
1199 *
1200 */
1201
1202 #ifndef MRB_WITHOUT_FLOAT
1203 static mrb_value
fix_to_f(mrb_state * mrb,mrb_value num)1204 fix_to_f(mrb_state *mrb, mrb_value num)
1205 {
1206 return mrb_float_value(mrb, (mrb_float)mrb_fixnum(num));
1207 }
1208
1209 /*
1210 * Document-class: FloatDomainError
1211 *
1212 * Raised when attempting to convert special float values
1213 * (in particular infinite or NaN)
1214 * to numerical classes which don't support them.
1215 *
1216 * Float::INFINITY.to_i
1217 *
1218 * <em>raises the exception:</em>
1219 *
1220 * FloatDomainError: Infinity
1221 */
1222 /* ------------------------------------------------------------------------*/
1223 MRB_API mrb_value
mrb_flo_to_fixnum(mrb_state * mrb,mrb_value x)1224 mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x)
1225 {
1226 mrb_int z = 0;
1227
1228 if (!mrb_float_p(x)) {
1229 mrb_raise(mrb, E_TYPE_ERROR, "non float value");
1230 z = 0; /* not reached. just suppress warnings. */
1231 }
1232 else {
1233 mrb_float d = mrb_float(x);
1234
1235 mrb_check_num_exact(mrb, d);
1236 if (FIXABLE_FLOAT(d)) {
1237 z = (mrb_int)d;
1238 }
1239 else {
1240 mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
1241 }
1242 }
1243 return mrb_fixnum_value(z);
1244 }
1245 #endif
1246
1247 static mrb_value
fixnum_plus(mrb_state * mrb,mrb_value x,mrb_value y)1248 fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
1249 {
1250 mrb_int a;
1251
1252 a = mrb_fixnum(x);
1253 if (mrb_fixnum_p(y)) {
1254 mrb_int b, c;
1255
1256 if (a == 0) return y;
1257 b = mrb_fixnum(y);
1258 if (mrb_int_add_overflow(a, b, &c)) {
1259 #ifndef MRB_WITHOUT_FLOAT
1260 return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
1261 #endif
1262 }
1263 return mrb_fixnum_value(c);
1264 }
1265 #ifdef MRB_WITHOUT_FLOAT
1266 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
1267 #else
1268 return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
1269 #endif
1270 }
1271
1272 MRB_API mrb_value
mrb_num_plus(mrb_state * mrb,mrb_value x,mrb_value y)1273 mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
1274 {
1275 if (mrb_fixnum_p(x)) {
1276 return fixnum_plus(mrb, x, y);
1277 }
1278 #ifndef MRB_WITHOUT_FLOAT
1279 if (mrb_float_p(x)) {
1280 return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
1281 }
1282 #endif
1283 mrb_raise(mrb, E_TYPE_ERROR, "no number addition");
1284 return mrb_nil_value(); /* not reached */
1285 }
1286
1287 /* 15.2.8.3.1 */
1288 /*
1289 * call-seq:
1290 * fix + numeric -> numeric_result
1291 *
1292 * Performs addition: the class of the resulting object depends on
1293 * the class of <code>numeric</code> and on the magnitude of the
1294 * result.
1295 */
1296 static mrb_value
fix_plus(mrb_state * mrb,mrb_value self)1297 fix_plus(mrb_state *mrb, mrb_value self)
1298 {
1299 mrb_value other = mrb_get_arg1(mrb);
1300
1301 return fixnum_plus(mrb, self, other);
1302 }
1303
1304 static mrb_value
fixnum_minus(mrb_state * mrb,mrb_value x,mrb_value y)1305 fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
1306 {
1307 mrb_int a;
1308
1309 a = mrb_fixnum(x);
1310 if (mrb_fixnum_p(y)) {
1311 mrb_int b, c;
1312
1313 b = mrb_fixnum(y);
1314 if (mrb_int_sub_overflow(a, b, &c)) {
1315 #ifndef MRB_WITHOUT_FLOAT
1316 return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
1317 #endif
1318 }
1319 return mrb_fixnum_value(c);
1320 }
1321 #ifdef MRB_WITHOUT_FLOAT
1322 mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
1323 #else
1324 return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
1325 #endif
1326 }
1327
1328 MRB_API mrb_value
mrb_num_minus(mrb_state * mrb,mrb_value x,mrb_value y)1329 mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
1330 {
1331 if (mrb_fixnum_p(x)) {
1332 return fixnum_minus(mrb, x, y);
1333 }
1334 #ifndef MRB_WITHOUT_FLOAT
1335 if (mrb_float_p(x)) {
1336 return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
1337 }
1338 #endif
1339 mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction");
1340 return mrb_nil_value(); /* not reached */
1341 }
1342
1343 /* 15.2.8.3.2 */
1344 /* 15.2.8.3.16 */
1345 /*
1346 * call-seq:
1347 * fix - numeric -> numeric_result
1348 *
1349 * Performs subtraction: the class of the resulting object depends on
1350 * the class of <code>numeric</code> and on the magnitude of the
1351 * result.
1352 */
1353 static mrb_value
fix_minus(mrb_state * mrb,mrb_value self)1354 fix_minus(mrb_state *mrb, mrb_value self)
1355 {
1356 mrb_value other = mrb_get_arg1(mrb);
1357
1358 return fixnum_minus(mrb, self, other);
1359 }
1360
1361
1362 MRB_API mrb_value
mrb_fixnum_to_str(mrb_state * mrb,mrb_value x,mrb_int base)1363 mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
1364 {
1365 char buf[MRB_INT_BIT+1];
1366 char *b = buf + sizeof buf;
1367 mrb_int val = mrb_fixnum(x);
1368 mrb_value str;
1369
1370 if (base < 2 || 36 < base) {
1371 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
1372 }
1373
1374 if (val == 0) {
1375 *--b = '0';
1376 }
1377 else if (val < 0) {
1378 do {
1379 *--b = mrb_digitmap[-(val % base)];
1380 } while (val /= base);
1381 *--b = '-';
1382 }
1383 else {
1384 do {
1385 *--b = mrb_digitmap[(int)(val % base)];
1386 } while (val /= base);
1387 }
1388
1389 str = mrb_str_new(mrb, b, buf + sizeof(buf) - b);
1390 RSTR_SET_ASCII_FLAG(mrb_str_ptr(str));
1391 return str;
1392 }
1393
1394 /* 15.2.8.3.25 */
1395 /*
1396 * call-seq:
1397 * fix.to_s(base=10) -> string
1398 *
1399 * Returns a string containing the representation of <i>fix</i> radix
1400 * <i>base</i> (between 2 and 36).
1401 *
1402 * 12345.to_s #=> "12345"
1403 * 12345.to_s(2) #=> "11000000111001"
1404 * 12345.to_s(8) #=> "30071"
1405 * 12345.to_s(10) #=> "12345"
1406 * 12345.to_s(16) #=> "3039"
1407 * 12345.to_s(36) #=> "9ix"
1408 *
1409 */
1410 static mrb_value
fix_to_s(mrb_state * mrb,mrb_value self)1411 fix_to_s(mrb_state *mrb, mrb_value self)
1412 {
1413 mrb_int base = 10;
1414
1415 mrb_get_args(mrb, "|i", &base);
1416 return mrb_fixnum_to_str(mrb, self, base);
1417 }
1418
1419 /* compare two numbers: (1:0:-1; -2 for error) */
1420 static mrb_int
cmpnum(mrb_state * mrb,mrb_value v1,mrb_value v2)1421 cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
1422 {
1423 #ifdef MRB_WITHOUT_FLOAT
1424 mrb_int x, y;
1425 #else
1426 mrb_float x, y;
1427 #endif
1428
1429 #ifdef MRB_WITHOUT_FLOAT
1430 x = mrb_fixnum(v1);
1431 #else
1432 x = mrb_to_flo(mrb, v1);
1433 #endif
1434 switch (mrb_type(v2)) {
1435 case MRB_TT_FIXNUM:
1436 #ifdef MRB_WITHOUT_FLOAT
1437 y = mrb_fixnum(v2);
1438 #else
1439 y = (mrb_float)mrb_fixnum(v2);
1440 #endif
1441 break;
1442 #ifndef MRB_WITHOUT_FLOAT
1443 case MRB_TT_FLOAT:
1444 y = mrb_float(v2);
1445 break;
1446 #endif
1447 default:
1448 return -2;
1449 }
1450 if (x > y)
1451 return 1;
1452 else {
1453 if (x < y)
1454 return -1;
1455 return 0;
1456 }
1457 }
1458
1459 /* 15.2.9.3.6 */
1460 /*
1461 * call-seq:
1462 * self.f <=> other.f => -1, 0, +1, or nil
1463 * < => -1
1464 * = => 0
1465 * > => +1
1466 * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
1467 * less than, equal to, or greater than <i>numeric</i>. This is the
1468 * basis for the tests in <code>Comparable</code>. When the operands are
1469 * not comparable, it returns nil instead of raising an exception.
1470 */
1471 static mrb_value
integral_cmp(mrb_state * mrb,mrb_value self)1472 integral_cmp(mrb_state *mrb, mrb_value self)
1473 {
1474 mrb_value other = mrb_get_arg1(mrb);
1475 mrb_int n;
1476
1477 n = cmpnum(mrb, self, other);
1478 if (n == -2) return mrb_nil_value();
1479 return mrb_fixnum_value(n);
1480 }
1481
1482 static mrb_noreturn void
cmperr(mrb_state * mrb,mrb_value v1,mrb_value v2)1483 cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
1484 {
1485 mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
1486 }
1487
1488 static mrb_value
integral_lt(mrb_state * mrb,mrb_value self)1489 integral_lt(mrb_state *mrb, mrb_value self)
1490 {
1491 mrb_value other = mrb_get_arg1(mrb);
1492 mrb_int n;
1493
1494 n = cmpnum(mrb, self, other);
1495 if (n == -2) cmperr(mrb, self, other);
1496 if (n < 0) return mrb_true_value();
1497 return mrb_false_value();
1498 }
1499
1500 static mrb_value
integral_le(mrb_state * mrb,mrb_value self)1501 integral_le(mrb_state *mrb, mrb_value self)
1502 {
1503 mrb_value other = mrb_get_arg1(mrb);
1504 mrb_int n;
1505
1506 n = cmpnum(mrb, self, other);
1507 if (n == -2) cmperr(mrb, self, other);
1508 if (n <= 0) return mrb_true_value();
1509 return mrb_false_value();
1510 }
1511
1512 static mrb_value
integral_gt(mrb_state * mrb,mrb_value self)1513 integral_gt(mrb_state *mrb, mrb_value self)
1514 {
1515 mrb_value other = mrb_get_arg1(mrb);
1516 mrb_int n;
1517
1518 n = cmpnum(mrb, self, other);
1519 if (n == -2) cmperr(mrb, self, other);
1520 if (n > 0) return mrb_true_value();
1521 return mrb_false_value();
1522 }
1523
1524 static mrb_value
integral_ge(mrb_state * mrb,mrb_value self)1525 integral_ge(mrb_state *mrb, mrb_value self)
1526 {
1527 mrb_value other = mrb_get_arg1(mrb);
1528 mrb_int n;
1529
1530 n = cmpnum(mrb, self, other);
1531 if (n == -2) cmperr(mrb, self, other);
1532 if (n >= 0) return mrb_true_value();
1533 return mrb_false_value();
1534 }
1535
1536 MRB_API mrb_int
mrb_cmp(mrb_state * mrb,mrb_value obj1,mrb_value obj2)1537 mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
1538 {
1539 mrb_value v;
1540
1541 switch (mrb_type(obj1)) {
1542 case MRB_TT_FIXNUM:
1543 case MRB_TT_FLOAT:
1544 return cmpnum(mrb, obj1, obj2);
1545 case MRB_TT_STRING:
1546 if (!mrb_string_p(obj2))
1547 return -2;
1548 return mrb_str_cmp(mrb, obj1, obj2);
1549 default:
1550 v = mrb_funcall(mrb, obj1, "<=>", 1, obj2);
1551 if (mrb_nil_p(v) || !mrb_fixnum_p(v))
1552 return -2;
1553 return mrb_fixnum(v);
1554 }
1555 }
1556
1557 static mrb_value
num_finite_p(mrb_state * mrb,mrb_value self)1558 num_finite_p(mrb_state *mrb, mrb_value self)
1559 {
1560 return mrb_true_value();
1561 }
1562
1563 static mrb_value
num_infinite_p(mrb_state * mrb,mrb_value self)1564 num_infinite_p(mrb_state *mrb, mrb_value self)
1565 {
1566 return mrb_false_value();
1567 }
1568
1569 /* 15.2.9.3.1 */
1570 /*
1571 * call-seq:
1572 * float + other -> float
1573 *
1574 * Returns a new float which is the sum of <code>float</code>
1575 * and <code>other</code>.
1576 */
1577 #ifndef MRB_WITHOUT_FLOAT
1578 static mrb_value
flo_plus(mrb_state * mrb,mrb_value x)1579 flo_plus(mrb_state *mrb, mrb_value x)
1580 {
1581 mrb_value y = mrb_get_arg1(mrb);
1582
1583 return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
1584 }
1585 #endif
1586
1587 /* ------------------------------------------------------------------------*/
1588 void
mrb_init_numeric(mrb_state * mrb)1589 mrb_init_numeric(mrb_state *mrb)
1590 {
1591 struct RClass *numeric, *integer, *fixnum, *integral;
1592 #ifndef MRB_WITHOUT_FLOAT
1593 struct RClass *fl;
1594 #endif
1595
1596 integral = mrb_define_module(mrb, "Integral");
1597 mrb_define_method(mrb, integral,"**", integral_pow, MRB_ARGS_REQ(1));
1598 mrb_define_method(mrb, integral,"/", integral_div, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6 */
1599 mrb_define_method(mrb, integral,"quo", integral_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
1600 mrb_define_method(mrb, integral,"div", integral_idiv, MRB_ARGS_REQ(1));
1601 mrb_define_method(mrb, integral,"<=>", integral_cmp, MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1 */
1602 mrb_define_method(mrb, integral,"<", integral_lt, MRB_ARGS_REQ(1));
1603 mrb_define_method(mrb, integral,"<=", integral_le, MRB_ARGS_REQ(1));
1604 mrb_define_method(mrb, integral,">", integral_gt, MRB_ARGS_REQ(1));
1605 mrb_define_method(mrb, integral,">=", integral_ge, MRB_ARGS_REQ(1));
1606 mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2));
1607
1608 /* Numeric Class */
1609 numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */
1610 mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE());
1611 mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE());
1612
1613 /* Integer Class */
1614 integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */
1615 MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM);
1616 mrb_undef_class_method(mrb, integer, "new");
1617 mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
1618 mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
1619 #ifndef MRB_WITHOUT_FLOAT
1620 mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.8 (x) */
1621 mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.10 (x) */
1622 mrb_define_method(mrb, integer, "round", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.12 (x) */
1623 mrb_define_method(mrb, integer, "truncate", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.15 (x) */
1624 #endif
1625
1626 /* Fixnum Class */
1627 mrb->fixnum_class = fixnum = mrb_define_class(mrb, "Fixnum", integer);
1628 mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
1629 mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
1630 mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
1631 mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
1632 mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
1633 mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
1634 mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
1635 mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
1636 mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
1637 mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
1638 mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
1639 mrb_define_method(mrb, fixnum, "eql?", fix_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1640 #ifndef MRB_WITHOUT_FLOAT
1641 mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
1642 #endif
1643 mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
1644 mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_OPT(1));
1645 mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
1646
1647 #ifndef MRB_WITHOUT_FLOAT
1648 /* Float Class */
1649 mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */
1650 MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT);
1651 mrb_undef_class_method(mrb, fl, "new");
1652 mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
1653 mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
1654 mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
1655 mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
1656 mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
1657 mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE());
1658 mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1));
1659 mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1));
1660 mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1));
1661 mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1));
1662 mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1));
1663 mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
1664 mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
1665 mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
1666 mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
1667 mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
1668 mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
1669 mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
1670 mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
1671 mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
1672 mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1));
1673 mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1674
1675 mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
1676 mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
1677 mrb_define_method(mrb, fl, "nan?", flo_nan_p, MRB_ARGS_NONE());
1678
1679 #ifdef INFINITY
1680 mrb_define_const(mrb, fl, "INFINITY", mrb_float_value(mrb, INFINITY));
1681 #endif
1682 #ifdef NAN
1683 mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
1684 #endif
1685
1686 mrb_include_module(mrb, fl, integral);
1687 #endif
1688 }
1689