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