Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
numeric.c
Go to the documentation of this file.
1 /*
2 ** numeric.c - Numeric, Integer, Float, Fixnum class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6 
7 #include <float.h>
8 #if defined(__FreeBSD__) && __FreeBSD__ < 4
9 # include <floatingpoint.h>
10 #endif
11 #ifdef HAVE_IEEEFP_H
12 # include <ieeefp.h>
13 #endif
14 #include <limits.h>
15 #include <math.h>
16 #include <stdlib.h>
17 
18 #include "mruby.h"
19 #include "mruby/array.h"
20 #include "mruby/numeric.h"
21 #include "mruby/string.h"
22 
23 #ifdef MRB_USE_FLOAT
24 #define floor(f) floorf(f)
25 #define ceil(f) ceilf(f)
26 #define floor(f) floorf(f)
27 #define fmod(x,y) fmodf(x,y)
28 #endif
29 
30 static mrb_float
31 mrb_to_flo(mrb_state *mrb, mrb_value val)
32 {
33  switch (mrb_type(val)) {
34  case MRB_TT_FIXNUM:
35  return (mrb_float)mrb_fixnum(val);
36  case MRB_TT_FLOAT:
37  break;
38  default:
39  mrb_raise(mrb, E_TYPE_ERROR, "non float value");
40  }
41  return mrb_float(val);
42 }
43 
44 /*
45  * call-seq:
46  * +num -> num
47  *
48  * Unary Plus---Returns the receiver's value.
49  */
50 
51 static mrb_value
52 num_uplus(mrb_state *mrb, mrb_value num)
53 {
54  return num;
55 }
56 
57 /*
58  * call-seq:
59  * -num -> numeric
60  *
61  * Unary Minus---Returns the receiver's value, negated.
62  */
63 
64 static mrb_value
65 num_uminus(mrb_state *mrb, mrb_value num)
66 {
67  return mrb_float_value(mrb, (mrb_float)0 - mrb_to_flo(mrb, num));
68 }
69 
70 static mrb_value
71 fix_uminus(mrb_state *mrb, mrb_value num)
72 {
73  return mrb_fixnum_value(0 - mrb_fixnum(num));
74 }
75 
76 /*
77  * call-seq:
78  *
79  * num ** other -> num
80  *
81  * Raises <code>num</code> the <code>other</code> power.
82  *
83  * 2.0**3 #=> 8.0
84  */
85 static mrb_value
86 num_pow(mrb_state *mrb, mrb_value x)
87 {
88  mrb_value y;
89  int both_int = FALSE;
90  mrb_float d;
91 
92  mrb_get_args(mrb, "o", &y);
93  if (mrb_fixnum_p(x) && mrb_fixnum_p(y)) both_int = TRUE;
94  d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
95  if (both_int && FIXABLE(d))
96  return mrb_fixnum_value((mrb_int)d);
97  return mrb_float_value(mrb, d);
98 }
99 
100 /* 15.2.8.3.4 */
101 /* 15.2.9.3.4 */
102 /*
103  * call-seq:
104  * num / other -> num
105  *
106  * Performs division: the class of the resulting object depends on
107  * the class of <code>num</code> and on the magnitude of the
108  * result.
109  */
110 
111 mrb_value
113 {
114  return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
115 }
116 
117 /* 15.2.9.3.19(x) */
118 /*
119  * call-seq:
120  * num.quo(numeric) -> real
121  *
122  * Returns most exact division.
123  */
124 
125 static mrb_value
126 num_div(mrb_state *mrb, mrb_value x)
127 {
128  mrb_float y;
129 
130  mrb_get_args(mrb, "f", &y);
131  return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
132 }
133 
134 /*
135  * call-seq:
136  * num.abs -> numeric
137  * num.magnitude -> numeric
138  *
139  * Returns the absolute value of <i>num</i>.
140  *
141  * 12.abs #=> 12
142  * (-34.56).abs #=> 34.56
143  * -34.56.abs #=> 34.56
144  */
145 
146 static mrb_value
147 num_abs(mrb_state *mrb, mrb_value num)
148 {
149  if (mrb_to_flo(mrb, num) < 0) {
150  return num_uminus(mrb, num);
151  }
152  return num;
153 }
154 
155 /********************************************************************
156  *
157  * Document-class: Float
158  *
159  * <code>Float</code> objects represent inexact real numbers using
160  * the native architecture's double-precision floating point
161  * representation.
162  */
163 
164 mrb_value
165 mrb_flo_to_str(mrb_state *mrb, mrb_value flo, int max_digit)
166 {
167  mrb_value result;
168  mrb_float n;
169 
170  if (max_digit > 40) {
171  mrb_raise(mrb, E_RANGE_ERROR, "Too large max_digit.");
172  }
173  else if (!mrb_float_p(flo)) {
174  mrb_raise(mrb, E_TYPE_ERROR, "non float value");
175  }
176 
177  n = mrb_float(flo);
178 
179  if (isnan(n)) {
180  result = mrb_str_new(mrb, "NaN", 3);
181  }
182  else if (isinf(n)) {
183  if (n < 0) {
184  result = mrb_str_new(mrb, "-inf", 4);
185  }
186  else {
187  result = mrb_str_new(mrb, "inf", 3);
188  }
189  }
190  else {
191  int digit;
192  int m;
193  int exp;
194  int e = 0;
195  char s[48];
196  char *c = &s[0];
197 
198  if (n < 0) {
199  n = -n;
200  *(c++) = '-';
201  }
202 
203  exp = (int)log10(n);
204 
205  if ((exp < 0 ? -exp : exp) > max_digit) {
206  /* exponent representation */
207  e = 1;
208  m = exp;
209  if (m < 0) {
210  m -= 1;
211  }
212  n = n / pow(10.0, m);
213  m = 0;
214  }
215  else {
216  /* un-exponent (normal) representation */
217  m = exp;
218  if (m < 0) {
219  m = 0;
220  }
221  }
222 
223  /* puts digits */
224  while (max_digit >= 0) {
225  mrb_float weight = pow(10.0, m);
226  digit = (int)floor(n / weight + FLT_EPSILON);
227  *(c++) = '0' + digit;
228  n -= (digit * weight);
229  max_digit--;
230  if (m-- == 0) {
231  *(c++) = '.';
232  }
233  else if (m < -1 && n < FLT_EPSILON) {
234  break;
235  }
236  }
237 
238  if (e) {
239  *(c++) = 'e';
240  if (exp > 0) {
241  *(c++) = '+';
242  }
243  else {
244  *(c++) = '-';
245  exp = -exp;
246  }
247 
248  if (exp >= 100) {
249  mrb_raise(mrb, E_RANGE_ERROR, "Too large expornent.");
250  }
251 
252  *(c++) = '0' + exp / 10;
253  *(c++) = '0' + exp % 10;
254  }
255 
256  *c = '\0';
257 
258  result = mrb_str_new(mrb, &s[0], c - &s[0]);
259  }
260 
261  return result;
262 }
263 
264 /* 15.2.9.3.16(x) */
265 /*
266  * call-seq:
267  * flt.to_s -> string
268  *
269  * Returns a string containing a representation of self. As well as a
270  * fixed or exponential form of the number, the call may return
271  * ``<code>NaN</code>'', ``<code>Infinity</code>'', and
272  * ``<code>-Infinity</code>''.
273  */
274 
275 static mrb_value
276 flo_to_s(mrb_state *mrb, mrb_value flt)
277 {
278 #ifdef MRB_USE_FLOAT
279  return mrb_flo_to_str(mrb, flt, 7);
280 #else
281  return mrb_flo_to_str(mrb, flt, 14);
282 #endif
283 }
284 
285 /* 15.2.9.3.2 */
286 /*
287  * call-seq:
288  * float - other -> float
289  *
290  * Returns a new float which is the difference of <code>float</code>
291  * and <code>other</code>.
292  */
293 
294 static mrb_value
295 flo_minus(mrb_state *mrb, mrb_value x)
296 {
297  mrb_value y;
298 
299  mrb_get_args(mrb, "o", &y);
300  return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
301 }
302 
303 /* 15.2.9.3.3 */
304 /*
305  * call-seq:
306  * float * other -> float
307  *
308  * Returns a new float which is the product of <code>float</code>
309  * and <code>other</code>.
310  */
311 
312 static mrb_value
313 flo_mul(mrb_state *mrb, mrb_value x)
314 {
315  mrb_value y;
316 
317  mrb_get_args(mrb, "o", &y);
318  return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
319 }
320 
321 static void
322 flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp)
323 {
324  mrb_float div;
325  mrb_float mod;
326 
327  if (y == 0.0) {
328  div = str_to_mrb_float("inf");
329  mod = str_to_mrb_float("nan");
330  }
331  else {
332  mod = fmod(x, y);
333  if (isinf(x) && !isinf(y) && !isnan(y))
334  div = x;
335  else
336  div = (x - mod) / y;
337  if (y*mod < 0) {
338  mod += y;
339  div -= 1.0;
340  }
341  }
342 
343  if (modp) *modp = mod;
344  if (divp) *divp = div;
345 }
346 
347 /* 15.2.9.3.5 */
348 /*
349  * call-seq:
350  * flt % other -> float
351  * flt.modulo(other) -> float
352  *
353  * Return the modulo after division of <code>flt</code> by <code>other</code>.
354  *
355  * 6543.21.modulo(137) #=> 104.21
356  * 6543.21.modulo(137.24) #=> 92.9299999999996
357  */
358 
359 static mrb_value
360 flo_mod(mrb_state *mrb, mrb_value x)
361 {
362  mrb_value y;
363  mrb_float fy, mod;
364 
365  mrb_get_args(mrb, "o", &y);
366 
367  fy = mrb_to_flo(mrb, y);
368  flodivmod(mrb, mrb_float(x), fy, 0, &mod);
369  return mrb_float_value(mrb, mod);
370 }
371 
372 /* 15.2.8.3.16 */
373 /*
374  * call-seq:
375  * num.eql?(numeric) -> true or false
376  *
377  * Returns <code>true</code> if <i>num</i> and <i>numeric</i> are the
378  * same type and have equal values.
379  *
380  * 1 == 1.0 #=> true
381  * 1.eql?(1.0) #=> false
382  * (1.0).eql?(1.0) #=> true
383  */
384 static mrb_value
385 num_eql(mrb_state *mrb, mrb_value x)
386 {
387  mrb_value y;
388  mrb_bool eql_p;
389 
390  mrb_get_args(mrb, "o", &y);
391  if (mrb_type(x) != mrb_type(y)) {
392  eql_p = 0;
393  }
394  else {
395  eql_p = mrb_equal(mrb, x, y);
396  }
397 
398  return mrb_bool_value(eql_p);
399 }
400 
401 static mrb_value
402 num_equal(mrb_state *mrb, mrb_value x, mrb_value y)
403 {
404  if (mrb_obj_equal(mrb, x, y)) return mrb_true_value();
405  return mrb_funcall(mrb, y, "==", 1, x);
406 }
407 
408 /* 15.2.9.3.7 */
409 /*
410  * call-seq:
411  * flt == obj -> true or false
412  *
413  * Returns <code>true</code> only if <i>obj</i> has the same value
414  * as <i>flt</i>. Contrast this with <code>Float#eql?</code>, which
415  * requires <i>obj</i> to be a <code>Float</code>.
416  *
417  * 1.0 == 1 #=> true
418  *
419  */
420 
421 static mrb_value
422 flo_eq(mrb_state *mrb, mrb_value x)
423 {
424  mrb_value y;
425  volatile mrb_float a, b;
426 
427  mrb_get_args(mrb, "o", &y);
428 
429  switch (mrb_type(y)) {
430  case MRB_TT_FIXNUM:
431  b = (mrb_float)mrb_fixnum(y);
432  break;
433  case MRB_TT_FLOAT:
434  b = mrb_float(y);
435  break;
436  default:
437  return num_equal(mrb, x, y);
438  }
439  a = mrb_float(x);
440  return mrb_bool_value(a == b);
441 }
442 
443 /* 15.2.8.3.18 */
444 /*
445  * call-seq:
446  * flt.hash -> integer
447  *
448  * Returns a hash code for this float.
449  */
450 static mrb_value
451 flo_hash(mrb_state *mrb, mrb_value num)
452 {
453  mrb_float d;
454  char *c;
455  size_t i;
456  int hash;
457 
458  d = (mrb_float)mrb_fixnum(num);
459  /* normalize -0.0 to 0.0 */
460  if (d == 0) d = 0.0;
461  c = (char*)&d;
462  for (hash=0, i=0; i<sizeof(mrb_float);i++) {
463  hash = (hash * 971) ^ (unsigned char)c[i];
464  }
465  if (hash < 0) hash = -hash;
466  return mrb_fixnum_value(hash);
467 }
468 
469 /* 15.2.9.3.13 */
470 /*
471  * call-seq:
472  * flt.to_f -> self
473  *
474  * As <code>flt</code> is already a float, returns +self+.
475  */
476 
477 static mrb_value
478 flo_to_f(mrb_state *mrb, mrb_value num)
479 {
480  return num;
481 }
482 
483 /* 15.2.9.3.11 */
484 /*
485  * call-seq:
486  * flt.infinite? -> nil, -1, +1
487  *
488  * Returns <code>nil</code>, -1, or +1 depending on whether <i>flt</i>
489  * is finite, -infinity, or +infinity.
490  *
491  * (0.0).infinite? #=> nil
492  * (-1.0/0.0).infinite? #=> -1
493  * (+1.0/0.0).infinite? #=> 1
494  */
495 
496 static mrb_value
497 flo_infinite_p(mrb_state *mrb, mrb_value num)
498 {
499  mrb_float value = mrb_float(num);
500 
501  if (isinf(value)) {
502  return mrb_fixnum_value( value < 0 ? -1 : 1 );
503  }
504  return mrb_nil_value();
505 }
506 
507 /* 15.2.9.3.9 */
508 /*
509  * call-seq:
510  * flt.finite? -> true or false
511  *
512  * Returns <code>true</code> if <i>flt</i> is a valid IEEE floating
513  * point number (it is not infinite, and <code>nan?</code> is
514  * <code>false</code>).
515  *
516  */
517 
518 static mrb_value
519 flo_finite_p(mrb_state *mrb, mrb_value num)
520 {
521  mrb_float value = mrb_float(num);
522  mrb_bool finite_p;
523 
524  finite_p = !(isinf(value) || isnan(value));
525 
526  return mrb_bool_value(finite_p);
527 }
528 
529 /* 15.2.9.3.10 */
530 /*
531  * call-seq:
532  * flt.floor -> integer
533  *
534  * Returns the largest integer less than or equal to <i>flt</i>.
535  *
536  * 1.2.floor #=> 1
537  * 2.0.floor #=> 2
538  * (-1.2).floor #=> -2
539  * (-2.0).floor #=> -2
540  */
541 
542 static mrb_value
543 flo_floor(mrb_state *mrb, mrb_value num)
544 {
545  mrb_float f = floor(mrb_float(num));
546 
547  if (!FIXABLE(f)) {
548  return mrb_float_value(mrb, f);
549  }
550  return mrb_fixnum_value((mrb_int)f);
551 }
552 
553 /* 15.2.9.3.8 */
554 /*
555  * call-seq:
556  * flt.ceil -> integer
557  *
558  * Returns the smallest <code>Integer</code> greater than or equal to
559  * <i>flt</i>.
560  *
561  * 1.2.ceil #=> 2
562  * 2.0.ceil #=> 2
563  * (-1.2).ceil #=> -1
564  * (-2.0).ceil #=> -2
565  */
566 
567 static mrb_value
568 flo_ceil(mrb_state *mrb, mrb_value num)
569 {
570  mrb_float f = ceil(mrb_float(num));
571 
572  if (!FIXABLE(f)) {
573  return mrb_float_value(mrb, f);
574  }
575  return mrb_fixnum_value((mrb_int)f);
576 }
577 
578 /* 15.2.9.3.12 */
579 /*
580  * call-seq:
581  * flt.round([ndigits]) -> integer or float
582  *
583  * Rounds <i>flt</i> to a given precision in decimal digits (default 0 digits).
584  * Precision may be negative. Returns a floating point number when ndigits
585  * is more than zero.
586  *
587  * 1.4.round #=> 1
588  * 1.5.round #=> 2
589  * 1.6.round #=> 2
590  * (-1.5).round #=> -2
591  *
592  * 1.234567.round(2) #=> 1.23
593  * 1.234567.round(3) #=> 1.235
594  * 1.234567.round(4) #=> 1.2346
595  * 1.234567.round(5) #=> 1.23457
596  *
597  * 34567.89.round(-5) #=> 0
598  * 34567.89.round(-4) #=> 30000
599  * 34567.89.round(-3) #=> 35000
600  * 34567.89.round(-2) #=> 34600
601  * 34567.89.round(-1) #=> 34570
602  * 34567.89.round(0) #=> 34568
603  * 34567.89.round(1) #=> 34567.9
604  * 34567.89.round(2) #=> 34567.89
605  * 34567.89.round(3) #=> 34567.89
606  *
607  */
608 
609 static mrb_value
610 flo_round(mrb_state *mrb, mrb_value num)
611 {
612  double number, f;
613  mrb_int ndigits = 0;
614  int i;
615 
616  mrb_get_args(mrb, "|i", &ndigits);
617  number = mrb_float(num);
618  f = 1.0;
619  i = abs(ndigits);
620  while (--i >= 0)
621  f = f*10.0;
622 
623  if (isinf(f)) {
624  if (ndigits < 0) number = 0;
625  }
626  else {
627  double d;
628 
629  if (ndigits < 0) number /= f;
630  else number *= f;
631 
632  /* home-made inline implementation of round(3) */
633  if (number > 0.0) {
634  d = floor(number);
635  number = d + (number - d >= 0.5);
636  }
637  else if (number < 0.0) {
638  d = ceil(number);
639  number = d - (d - number >= 0.5);
640  }
641 
642  if (ndigits < 0) number *= f;
643  else number /= f;
644  }
645  if (ndigits > 0) return mrb_float_value(mrb, number);
646  return mrb_fixnum_value((mrb_int)number);
647 }
648 
649 /* 15.2.9.3.14 */
650 /* 15.2.9.3.15 */
651 /*
652  * call-seq:
653  * flt.to_i -> integer
654  * flt.to_int -> integer
655  * flt.truncate -> integer
656  *
657  * Returns <i>flt</i> truncated to an <code>Integer</code>.
658  */
659 
660 static mrb_value
661 flo_truncate(mrb_state *mrb, mrb_value num)
662 {
663  mrb_float f = mrb_float(num);
664 
665  if (f > 0.0) f = floor(f);
666  if (f < 0.0) f = ceil(f);
667 
668  if (!FIXABLE(f)) {
669  return mrb_float_value(mrb, f);
670  }
671  return mrb_fixnum_value((mrb_int)f);
672 }
673 
674 /*
675  * Document-class: Integer
676  *
677  * <code>Integer</code> is the basis for the two concrete classes that
678  * hold whole numbers, <code>Bignum</code> and <code>Fixnum</code>.
679  *
680  */
681 
682 
683 /*
684  * call-seq:
685  * int.to_i -> integer
686  * int.to_int -> integer
687  *
688  * As <i>int</i> is already an <code>Integer</code>, all these
689  * methods simply return the receiver.
690  */
691 
692 static mrb_value
693 int_to_i(mrb_state *mrb, mrb_value num)
694 {
695  return num;
696 }
697 
698 /* 15.2.8.3.21 */
699 /*
700  * call-seq:
701  * fixnum.next -> integer
702  * fixnum.succ -> integer
703  *
704  * Returns the <code>Integer</code> equal to <i>int</i> + 1.
705  *
706  * 1.next #=> 2
707  * (-1).next #=> 0
708  */
709 
710 static mrb_value
711 fix_succ(mrb_state *mrb, mrb_value num)
712 {
713  return mrb_fixnum_value(mrb_fixnum(num)+1);
714 }
715 
716 /* 15.2.8.3.19 */
717 /*
718  * call-seq:
719  * int.next -> integer
720  * int.succ -> integer
721  *
722  * Returns the <code>Integer</code> equal to <i>int</i> + 1.
723  *
724  * 1.next #=> 2
725  * (-1).next #=> 0
726  */
727 static mrb_value
728 int_succ(mrb_state *mrb, mrb_value num)
729 {
730  if (mrb_fixnum_p(num)) return fix_succ(mrb, num);
731  return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1));
732 }
733 
734 #define SQRT_INT_MAX ((mrb_int)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
735 /*tests if N*N would overflow*/
736 #define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
737 
738 mrb_value
740 {
741  mrb_int a;
742 
743  a = mrb_fixnum(x);
744  if (a == 0) return x;
745  if (mrb_fixnum_p(y)) {
746  mrb_int b, c;
747 
748  b = mrb_fixnum(y);
749  if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
750  return mrb_fixnum_value(a*b);
751  c = a * b;
752  if (a != 0 && c/a != b) {
753  return mrb_float_value(mrb, (mrb_float)a*(mrb_float)b);
754  }
755  return mrb_fixnum_value(c);;
756  }
757  return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
758 }
759 
760 /* 15.2.8.3.3 */
761 /*
762  * call-seq:
763  * fix * numeric -> numeric_result
764  *
765  * Performs multiplication: the class of the resulting object depends on
766  * the class of <code>numeric</code> and on the magnitude of the
767  * result.
768  */
769 
770 static mrb_value
771 fix_mul(mrb_state *mrb, mrb_value x)
772 {
773  mrb_value y;
774 
775  mrb_get_args(mrb, "o", &y);
776  return mrb_fixnum_mul(mrb, x, y);
777 }
778 
779 static void
780 fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
781 {
782  mrb_int div, mod;
783 
784  /* TODO: add mrb_assert(y != 0) to make sure */
785 
786  if (y < 0) {
787  if (x < 0)
788  div = -x / -y;
789  else
790  div = - (x / -y);
791  }
792  else {
793  if (x < 0)
794  div = - (-x / y);
795  else
796  div = x / y;
797  }
798  mod = x - div*y;
799  if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
800  mod += y;
801  div -= 1;
802  }
803  if (divp) *divp = div;
804  if (modp) *modp = mod;
805 }
806 
807 /* 15.2.8.3.5 */
808 /*
809  * call-seq:
810  * fix % other -> real
811  * fix.modulo(other) -> real
812  *
813  * Returns <code>fix</code> modulo <code>other</code>.
814  * See <code>numeric.divmod</code> for more information.
815  */
816 
817 static mrb_value
818 fix_mod(mrb_state *mrb, mrb_value x)
819 {
820  mrb_value y;
821  mrb_int a, b;
822 
823  mrb_get_args(mrb, "o", &y);
824  a = mrb_fixnum(x);
825  if (mrb_fixnum_p(y) && (b=mrb_fixnum(y)) != 0) {
826  mrb_int mod;
827 
828  if (mrb_fixnum(y) == 0) {
829  return mrb_float_value(mrb, str_to_mrb_float("nan"));
830  }
831  fixdivmod(mrb, a, mrb_fixnum(y), 0, &mod);
832  return mrb_fixnum_value(mod);
833  }
834  else {
835  mrb_float mod;
836 
837  flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
838  return mrb_float_value(mrb, mod);
839  }
840 }
841 
842 /*
843  * call-seq:
844  * fix.divmod(numeric) -> array
845  *
846  * See <code>Numeric#divmod</code>.
847  */
848 static mrb_value
849 fix_divmod(mrb_state *mrb, mrb_value x)
850 {
851  mrb_value y;
852 
853  mrb_get_args(mrb, "o", &y);
854 
855  if (mrb_fixnum_p(y)) {
856  mrb_int div, mod;
857 
858  if (mrb_fixnum(y) == 0) {
859  return mrb_assoc_new(mrb, mrb_float_value(mrb, str_to_mrb_float("inf")),
860  mrb_float_value(mrb, str_to_mrb_float("nan")));
861  }
862  fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
863  return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
864  }
865  else {
866  mrb_float div, mod;
867  mrb_value a, b;
868 
869  flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
870  a = mrb_float_value(mrb, (mrb_int)div);
871  b = mrb_float_value(mrb, mod);
872  return mrb_assoc_new(mrb, a, b);
873  }
874 }
875 
876 /* 15.2.8.3.7 */
877 /*
878  * call-seq:
879  * fix == other -> true or false
880  *
881  * Return <code>true</code> if <code>fix</code> equals <code>other</code>
882  * numerically.
883  *
884  * 1 == 2 #=> false
885  * 1 == 1.0 #=> true
886  */
887 
888 static mrb_value
889 fix_equal(mrb_state *mrb, mrb_value x)
890 {
891  mrb_value y;
892  mrb_bool equal_p;
893 
894  mrb_get_args(mrb, "o", &y);
895 
896  equal_p = mrb_obj_equal(mrb, x, y) ||
897  (mrb_type(y) == MRB_TT_FLOAT &&
898  (mrb_float)mrb_fixnum(x) == mrb_float(y));
899 
900  return mrb_bool_value(equal_p);
901 }
902 
903 /* 15.2.8.3.8 */
904 /*
905  * call-seq:
906  * ~fix -> integer
907  *
908  * One's complement: returns a number where each bit is flipped.
909  * ex.0---00001 (1)-> 1---11110 (-2)
910  * ex.0---00010 (2)-> 1---11101 (-3)
911  * ex.0---00100 (4)-> 1---11011 (-5)
912  */
913 
914 static mrb_value
915 fix_rev(mrb_state *mrb, mrb_value num)
916 {
917  mrb_int val = mrb_fixnum(num);
918 
919  val = ~val;
920  return mrb_fixnum_value(val);
921 }
922 
923 static mrb_value
924 bit_coerce(mrb_state *mrb, mrb_value x)
925 {
926  while (!mrb_fixnum_p(x)) {
927  if (mrb_float_p(x)) {
928  mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer");
929  }
930  x = mrb_to_int(mrb, x);
931  }
932  return x;
933 }
934 
935 /* 15.2.8.3.9 */
936 /*
937  * call-seq:
938  * fix & integer -> integer_result
939  *
940  * Bitwise AND.
941  */
942 
943 static mrb_value
944 fix_and(mrb_state *mrb, mrb_value x)
945 {
946  mrb_value y;
947  mrb_int val;
948 
949  mrb_get_args(mrb, "o", &y);
950 
951  y = bit_coerce(mrb, y);
952  val = mrb_fixnum(x) & mrb_fixnum(y);
953  return mrb_fixnum_value(val);
954 }
955 
956 /* 15.2.8.3.10 */
957 /*
958  * call-seq:
959  * fix | integer -> integer_result
960  *
961  * Bitwise OR.
962  */
963 
964 static mrb_value
965 fix_or(mrb_state *mrb, mrb_value x)
966 {
967  mrb_value y;
968  mrb_int val;
969 
970  mrb_get_args(mrb, "o", &y);
971 
972  y = bit_coerce(mrb, y);
973  val = mrb_fixnum(x) | mrb_fixnum(y);
974  return mrb_fixnum_value(val);
975 }
976 
977 /* 15.2.8.3.11 */
978 /*
979  * call-seq:
980  * fix ^ integer -> integer_result
981  *
982  * Bitwise EXCLUSIVE OR.
983  */
984 
985 static mrb_value
986 fix_xor(mrb_state *mrb, mrb_value x)
987 {
988  mrb_value y;
989  mrb_int val;
990 
991  mrb_get_args(mrb, "o", &y);
992 
993  y = bit_coerce(mrb, y);
994  val = mrb_fixnum(x) ^ mrb_fixnum(y);
995  return mrb_fixnum_value(val);
996 }
997 
998 #define NUMERIC_SHIFT_WIDTH_MAX (sizeof(mrb_int)*CHAR_BIT-1)
999 
1000 static mrb_value
1001 lshift(mrb_state *mrb, mrb_int val, size_t width)
1002 {
1003  if (width > NUMERIC_SHIFT_WIDTH_MAX) {
1004  mrb_raisef(mrb, E_RANGE_ERROR, "width(%S) > (%S:sizeof(mrb_int)*CHAR_BIT-1)",
1005  mrb_fixnum_value(width),
1006  mrb_fixnum_value(NUMERIC_SHIFT_WIDTH_MAX));
1007  }
1008  val = val << width;
1009  return mrb_fixnum_value(val);
1010 }
1011 
1012 static mrb_value
1013 rshift(mrb_int val, size_t width)
1014 {
1015  if (width >= NUMERIC_SHIFT_WIDTH_MAX) {
1016  if (val < 0) {
1017  val = -1;
1018  }
1019  else {
1020  val = 0;
1021  }
1022  }
1023  else {
1024  val = val >> width;
1025  }
1026 
1027  return mrb_fixnum_value(val);
1028 }
1029 
1030 static inline void
1031 fix_shift_get_width(mrb_state *mrb, mrb_int *width)
1032 {
1033  mrb_value y;
1034 
1035  mrb_get_args(mrb, "o", &y);
1036  y = bit_coerce(mrb, y);
1037  *width = mrb_fixnum(y);
1038 }
1039 
1040 /* 15.2.8.3.12 */
1041 /*
1042  * call-seq:
1043  * fix << count -> integer
1044  *
1045  * Shifts _fix_ left _count_ positions (right if _count_ is negative).
1046  */
1047 
1048 static mrb_value
1049 fix_lshift(mrb_state *mrb, mrb_value x)
1050 {
1051  mrb_int width;
1052  mrb_value result;
1053 
1054  fix_shift_get_width(mrb, &width);
1055 
1056  if (width == 0) {
1057  result = x;
1058  }
1059  else {
1060  mrb_int val;
1061 
1062  val = mrb_fixnum(x);
1063  if (width < 0) {
1064  result = rshift(val, -width);
1065  }
1066  else {
1067  result = lshift(mrb, val, width);
1068  }
1069  }
1070 
1071  return result;
1072 }
1073 
1074 /* 15.2.8.3.13 */
1075 /*
1076  * call-seq:
1077  * fix >> count -> integer
1078  *
1079  * Shifts _fix_ right _count_ positions (left if _count_ is negative).
1080  */
1081 
1082 static mrb_value
1083 fix_rshift(mrb_state *mrb, mrb_value x)
1084 {
1085  mrb_int width;
1086  mrb_value result;
1087 
1088  fix_shift_get_width(mrb, &width);
1089 
1090  if (width == 0) {
1091  result = x;
1092  }
1093  else {
1094  mrb_int val;
1095 
1096  val = mrb_fixnum(x);
1097  if (width < 0) {
1098  result = lshift(mrb, val, -width);
1099  }
1100  else {
1101  result = rshift(val, width);
1102  }
1103  }
1104 
1105  return result;
1106 }
1107 
1108 /* 15.2.8.3.23 */
1109 /*
1110  * call-seq:
1111  * fix.to_f -> float
1112  *
1113  * Converts <i>fix</i> to a <code>Float</code>.
1114  *
1115  */
1116 
1117 static mrb_value
1118 fix_to_f(mrb_state *mrb, mrb_value num)
1119 {
1120  mrb_float val;
1121 
1122  val = (mrb_float)mrb_fixnum(num);
1123 
1124  return mrb_float_value(mrb, val);
1125 }
1126 
1127 /*
1128  * Document-class: FloatDomainError
1129  *
1130  * Raised when attempting to convert special float values
1131  * (in particular infinite or NaN)
1132  * to numerical classes which don't support them.
1133  *
1134  * Float::INFINITY.to_r
1135  *
1136  * <em>raises the exception:</em>
1137  *
1138  * FloatDomainError: Infinity
1139  */
1140 /* ------------------------------------------------------------------------*/
1141 mrb_value
1143 {
1144  mrb_int z;
1145 
1146  if (mrb_float_p(x)) {
1147  mrb_raise(mrb, E_TYPE_ERROR, "non float value");
1148  z = 0; /* not reached. just supress warnings. */
1149  }
1150  else {
1151  mrb_float d = mrb_float(x);
1152 
1153  if (isinf(d)) {
1154  mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity");
1155  }
1156  if (isnan(d)) {
1157  mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
1158  }
1159  z = (mrb_int)d;
1160  }
1161  return mrb_fixnum_value(z);
1162 }
1163 
1164 mrb_value
1166 {
1167  mrb_int a;
1168 
1169  a = mrb_fixnum(x);
1170  if (a == 0) return y;
1171  if (mrb_fixnum_p(y)) {
1172  mrb_int b, c;
1173 
1174  b = mrb_fixnum(y);
1175  c = a + b;
1176  if (((a < 0) ^ (b < 0)) == 0 && (a < 0) != (c < 0)) {
1177  /* integer overflow */
1178  return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
1179  }
1180  return mrb_fixnum_value(c);
1181  }
1182  return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
1183 }
1184 
1185 /* 15.2.8.3.1 */
1186 /*
1187  * call-seq:
1188  * fix + numeric -> numeric_result
1189  *
1190  * Performs addition: the class of the resulting object depends on
1191  * the class of <code>numeric</code> and on the magnitude of the
1192  * result.
1193  */
1194 static mrb_value
1195 fix_plus(mrb_state *mrb, mrb_value self)
1196 {
1197  mrb_value other;
1198 
1199  mrb_get_args(mrb, "o", &other);
1200  return mrb_fixnum_plus(mrb, self, other);
1201 }
1202 
1203 mrb_value
1205 {
1206  mrb_int a;
1207 
1208  a = mrb_fixnum(x);
1209  if (mrb_fixnum_p(y)) {
1210  mrb_int b, c;
1211 
1212  b = mrb_fixnum(y);
1213  c = a - b;
1214  if (((a < 0) ^ (b < 0)) != 0 && (a < 0) != (c < 0)) {
1215  /* integer overflow */
1216  return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
1217  }
1218  return mrb_fixnum_value(c);
1219  }
1220  return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
1221 }
1222 
1223 /* 15.2.8.3.2 */
1224 /* 15.2.8.3.16 */
1225 /*
1226  * call-seq:
1227  * fix - numeric -> numeric_result
1228  *
1229  * Performs subtraction: the class of the resulting object depends on
1230  * the class of <code>numeric</code> and on the magnitude of the
1231  * result.
1232  */
1233 static mrb_value
1234 fix_minus(mrb_state *mrb, mrb_value self)
1235 {
1236  mrb_value other;
1237 
1238  mrb_get_args(mrb, "o", &other);
1239  return mrb_fixnum_minus(mrb, self, other);
1240 }
1241 
1242 
1243 mrb_value
1245 {
1246  char buf[sizeof(mrb_int)*CHAR_BIT+1];
1247  char *b = buf + sizeof buf;
1248  mrb_int val = mrb_fixnum(x);
1249 
1250  if (base < 2 || 36 < base) {
1251  mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
1252  }
1253 
1254  if (val == 0) {
1255  *--b = '0';
1256  }
1257  else if (val < 0) {
1258  do {
1259  *--b = mrb_digitmap[-(val % base)];
1260  } while (val /= base);
1261  *--b = '-';
1262  }
1263  else {
1264  do {
1265  *--b = mrb_digitmap[(int)(val % base)];
1266  } while (val /= base);
1267  }
1268 
1269  return mrb_str_new(mrb, b, buf + sizeof(buf) - b);
1270 }
1271 
1272 /* 15.2.8.3.25 */
1273 /*
1274  * call-seq:
1275  * fix.to_s(base=10) -> string
1276  *
1277  * Returns a string containing the representation of <i>fix</i> radix
1278  * <i>base</i> (between 2 and 36).
1279  *
1280  * 12345.to_s #=> "12345"
1281  * 12345.to_s(2) #=> "11000000111001"
1282  * 12345.to_s(8) #=> "30071"
1283  * 12345.to_s(10) #=> "12345"
1284  * 12345.to_s(16) #=> "3039"
1285  * 12345.to_s(36) #=> "9ix"
1286  *
1287  */
1288 static mrb_value
1289 fix_to_s(mrb_state *mrb, mrb_value self)
1290 {
1291  mrb_int base = 10;
1292 
1293  mrb_get_args(mrb, "|i", &base);
1294  return mrb_fixnum_to_str(mrb, self, base);
1295 }
1296 
1297 /* 15.2.9.3.6 */
1298 /*
1299  * call-seq:
1300  * self.f <=> other.f => -1, 0, +1
1301  * < => -1
1302  * = => 0
1303  * > => +1
1304  * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is
1305  * less than, equal to, or greater than <i>numeric</i>. This is the
1306  * basis for the tests in <code>Comparable</code>.
1307  */
1308 static mrb_value
1309 num_cmp(mrb_state *mrb, mrb_value self)
1310 {
1311  mrb_value other;
1312  mrb_float x, y;
1313 
1314  mrb_get_args(mrb, "o", &other);
1315 
1316  x = mrb_to_flo(mrb, self);
1317  switch (mrb_type(other)) {
1318  case MRB_TT_FIXNUM:
1319  y = (mrb_float)mrb_fixnum(other);
1320  break;
1321  case MRB_TT_FLOAT:
1322  y = mrb_float(other);
1323  break;
1324  default:
1325  return mrb_nil_value();
1326  }
1327  if (x > y)
1328  return mrb_fixnum_value(1);
1329  else {
1330  if (x < y)
1331  return mrb_fixnum_value(-1);
1332  return mrb_fixnum_value(0);
1333  }
1334 }
1335 
1336 /* 15.2.9.3.1 */
1337 /*
1338  * call-seq:
1339  * float + other -> float
1340  *
1341  * Returns a new float which is the sum of <code>float</code>
1342  * and <code>other</code>.
1343  */
1344 static mrb_value
1345 flo_plus(mrb_state *mrb, mrb_value self)
1346 {
1347  mrb_float x, y;
1348 
1349  x = mrb_float(self);
1350  mrb_get_args(mrb, "f", &y);
1351 
1352  return mrb_float_value(mrb, x + y);
1353 }
1354 /* ------------------------------------------------------------------------*/
1355 void
1357 {
1358  struct RClass *numeric, *integer, *fixnum, *fl;
1359 
1360  /* Numeric Class */
1361  numeric = mrb_define_class(mrb, "Numeric", mrb->object_class);
1362  mrb_include_module(mrb, numeric, mrb_class_get(mrb, "Comparable"));
1363 
1364  mrb_define_method(mrb, numeric, "+@", num_uplus, MRB_ARGS_REQ(1)); /* 15.2.7.4.1 */
1365  mrb_define_method(mrb, numeric, "-@", num_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
1366  mrb_define_method(mrb, numeric, "**", num_pow, MRB_ARGS_REQ(1));
1367  mrb_define_method(mrb, numeric, "/", num_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.4 */
1368  mrb_define_method(mrb, numeric, "quo", num_div, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
1369  mrb_define_method(mrb, numeric, "abs", num_abs, MRB_ARGS_NONE()); /* 15.2.7.4.3 */
1370  mrb_define_method(mrb, numeric, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.9.3.6 */
1371 
1372  /* Integer Class */
1373  integer = mrb_define_class(mrb, "Integer", numeric);
1374  mrb_undef_class_method(mrb, integer, "new");
1375  mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
1376  mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE());
1377  fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
1378 
1379  mrb_define_method(mrb, fixnum, "+", fix_plus, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
1380  mrb_define_method(mrb, fixnum, "-", fix_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
1381  mrb_define_method(mrb, fixnum, "-@", fix_uminus, MRB_ARGS_REQ(1)); /* 15.2.7.4.2 */
1382  mrb_define_method(mrb, fixnum, "*", fix_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */
1383  mrb_define_method(mrb, fixnum, "%", fix_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */
1384  mrb_define_method(mrb, fixnum, "==", fix_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */
1385  mrb_define_method(mrb, fixnum, "~", fix_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */
1386  mrb_define_method(mrb, fixnum, "&", fix_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */
1387  mrb_define_method(mrb, fixnum, "|", fix_or, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 */
1388  mrb_define_method(mrb, fixnum, "^", fix_xor, MRB_ARGS_REQ(1)); /* 15.2.8.3.11 */
1389  mrb_define_method(mrb, fixnum, "<<", fix_lshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.12 */
1390  mrb_define_method(mrb, fixnum, ">>", fix_rshift, MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
1391  mrb_define_method(mrb, fixnum, "eql?", num_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
1392  mrb_define_method(mrb, fixnum, "hash", flo_hash, MRB_ARGS_NONE()); /* 15.2.8.3.18 */
1393  mrb_define_method(mrb, fixnum, "next", int_succ, MRB_ARGS_NONE()); /* 15.2.8.3.19 */
1394  mrb_define_method(mrb, fixnum, "succ", fix_succ, MRB_ARGS_NONE()); /* 15.2.8.3.21 */
1395  mrb_define_method(mrb, fixnum, "to_f", fix_to_f, MRB_ARGS_NONE()); /* 15.2.8.3.23 */
1396  mrb_define_method(mrb, fixnum, "to_s", fix_to_s, MRB_ARGS_NONE()); /* 15.2.8.3.25 */
1397  mrb_define_method(mrb, fixnum, "inspect", fix_to_s, MRB_ARGS_NONE());
1398  mrb_define_method(mrb, fixnum, "divmod", fix_divmod, MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
1399 
1400  /* Float Class */
1401  fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric);
1402  mrb_undef_class_method(mrb, fl, "new");
1403  mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */
1404  mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */
1405  mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */
1406  mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */
1407  mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */
1408  mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */
1409  mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */
1410  mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */
1411  mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
1412  mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_NONE()); /* 15.2.9.3.12 */
1413  mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
1414  mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
1415  mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE());
1416  mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */
1417 
1418  mrb_define_method(mrb, fl, "to_s", flo_to_s, MRB_ARGS_NONE()); /* 15.2.9.3.16(x) */
1419  mrb_define_method(mrb, fl, "inspect", flo_to_s, MRB_ARGS_NONE());
1420 }