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