Index: EcnlProtoTool/trunk/mruby-2.1.1/src/numeric.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.3.0/src/numeric.c	(revision 331)
+++ EcnlProtoTool/trunk/mruby-2.1.1/src/numeric.c	(revision 439)
@@ -5,8 +5,11 @@
 */
 
+#ifndef MRB_WITHOUT_FLOAT
 #include <float.h>
+#include <math.h>
+#endif
 #include <limits.h>
-#include <math.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include <mruby.h>
@@ -16,4 +19,5 @@
 #include <mruby/class.h>
 
+#ifndef MRB_WITHOUT_FLOAT
 #ifdef MRB_USE_FLOAT
 #define trunc(f) truncf(f)
@@ -21,9 +25,11 @@
 #define ceil(f) ceilf(f)
 #define fmod(x,y) fmodf(x,y)
-#define MRB_FLO_TO_STR_FMT "%.7g"
-#else
-#define MRB_FLO_TO_STR_FMT "%.14g"
-#endif
-
+#define FLO_TO_STR_PREC 8
+#else
+#define FLO_TO_STR_PREC 16
+#endif
+#endif
+
+#ifndef MRB_WITHOUT_FLOAT
 MRB_API mrb_float
 mrb_to_flo(mrb_state *mrb, mrb_value val)
@@ -40,4 +46,14 @@
 }
 
+MRB_API mrb_value
+mrb_int_value(mrb_state *mrb, mrb_float f)
+{
+  if (FIXABLE_FLOAT(f)) {
+    return mrb_fixnum_value((mrb_int)f);
+  }
+  return mrb_float_value(mrb, f);
+}
+#endif
+
 /*
  * call-seq:
@@ -50,8 +66,10 @@
  */
 static mrb_value
-num_pow(mrb_state *mrb, mrb_value x)
-{
-  mrb_value y;
+integral_pow(mrb_state *mrb, mrb_value x)
+{
+  mrb_value y;
+#ifndef MRB_WITHOUT_FLOAT
   mrb_float d;
+#endif
 
   mrb_get_args(mrb, "o", &y);
@@ -62,9 +80,16 @@
     mrb_int result = 1;
 
-    if (exp < 0) goto float_pow;
+    if (exp < 0)
+#ifdef MRB_WITHOUT_FLOAT
+      return mrb_fixnum_value(0);
+#else
+      goto float_pow;
+#endif
     for (;;) {
       if (exp & 1) {
         if (mrb_int_mul_overflow(result, base, &result)) {
+#ifndef MRB_WITHOUT_FLOAT
           goto float_pow;
+#endif
         }
       }
@@ -72,12 +97,37 @@
       if (exp == 0) break;
       if (mrb_int_mul_overflow(base, base, &base)) {
+#ifndef MRB_WITHOUT_FLOAT
         goto float_pow;
+#endif
       }
     }
     return mrb_fixnum_value(result);
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
  float_pow:
   d = pow(mrb_to_flo(mrb, x), mrb_to_flo(mrb, y));
   return mrb_float_value(mrb, d);
+#endif
+}
+
+static mrb_value
+integral_idiv(mrb_state *mrb, mrb_value x)
+{
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_value y;
+
+  mrb_get_args(mrb, "o", &y);
+  if (!mrb_fixnum_p(y)) {
+    mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+  }
+  return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
+#else
+  mrb_float y;
+
+  mrb_get_args(mrb, "f", &y);
+  return mrb_int_value(mrb, mrb_to_flo(mrb, x) / y);
+#endif
 }
 
@@ -93,10 +143,4 @@
  */
 
-mrb_value
-mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
-{
-  return mrb_float_value(mrb, mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
-}
-
 /* 15.2.9.3.19(x) */
 /*
@@ -108,12 +152,39 @@
 
 static mrb_value
-num_div(mrb_state *mrb, mrb_value x)
-{
+integral_div(mrb_state *mrb, mrb_value x)
+{
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_value y;
+
+  mrb_get_args(mrb, "o", &y);
+  if (!mrb_fixnum_p(y)) {
+    mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+  }
+  return mrb_fixnum_value(mrb_fixnum(x) / mrb_fixnum(y));
+#else
   mrb_float y;
 
   mrb_get_args(mrb, "f", &y);
   return mrb_float_value(mrb, mrb_to_flo(mrb, x) / y);
-}
-
+#endif
+}
+
+static mrb_value
+integral_coerce_step_counter(mrb_state *mrb, mrb_value self)
+{
+  mrb_value num, step;
+
+  mrb_get_args(mrb, "oo", &num, &step);
+
+#ifndef MRB_WITHOUT_FLOAT
+  if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) {
+    return mrb_Float(mrb, self);
+  }
+#endif
+
+  return self;
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 /********************************************************************
  *
@@ -139,8 +210,44 @@
 flo_to_s(mrb_state *mrb, mrb_value flt)
 {
-  if (isnan(mrb_float(flt))) {
+  mrb_float f = mrb_float(flt);
+
+  if (isinf(f)) {
+    return f < 0 ? mrb_str_new_lit(mrb, "-Infinity")
+                 : mrb_str_new_lit(mrb, "Infinity");
+  }
+  else if (isnan(f)) {
     return mrb_str_new_lit(mrb, "NaN");
   }
-  return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT);
+  else {
+    char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g";
+    mrb_value str = mrb_float_to_str(mrb, flt, fmt);
+    mrb_int len;
+    char *begp, *p, *endp;
+
+    insert_dot_zero:
+    begp = RSTRING_PTR(str);
+    len = RSTRING_LEN(str);
+    for (p = begp, endp = p + len; p < endp; ++p) {
+      if (*p == '.') {
+        return str;
+      }
+      else if (*p == 'e') {
+        ptrdiff_t e_pos = p - begp;
+        mrb_str_cat(mrb, str, ".0", 2);
+        p = RSTRING_PTR(str) + e_pos;
+        memmove(p + 2, p, len - e_pos);
+        memcpy(p, ".0", 2);
+        return str;
+      }
+    }
+
+    if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) {
+      --fmt[sizeof(fmt) - 3];  /* %.16g(%.8g) -> %.15g(%.7g) */
+      str = mrb_float_to_str(mrb, flt, fmt);
+      goto insert_dot_zero;
+    }
+
+    return str;
+  }
 }
 
@@ -182,25 +289,40 @@
 
 static void
-flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp)
-{
-  mrb_float div;
-  mrb_float mod;
-
+flodivmod(mrb_state *mrb, double x, double y, mrb_float *divp, mrb_float *modp)
+{
+  double div, mod;
+
+  if (isnan(y)) {
+    /* y is NaN so all results are NaN */
+    div = mod = y;
+    goto exit;
+  }
   if (y == 0.0) {
-    div = INFINITY;
+    if (x == 0) div = NAN;
+    else if (x > 0.0) div = INFINITY;
+    else div = -INFINITY;       /* x < 0.0 */
     mod = NAN;
+    goto exit;
+  }
+  if ((x == 0.0) || (isinf(y) && !isinf(x))) {
+    mod = x;
   }
   else {
     mod = fmod(x, y);
-    if (isinf(x) && isfinite(y))
-      div = x;
-    else
-      div = (x - mod) / y;
-    if (y*mod < 0) {
-      mod += y;
-      div -= 1.0;
-    }
-  }
-
+  }
+  if (isinf(x) && !isinf(y)) {
+    div = x;
+  }
+  else {
+    div = (x - mod) / y;
+    if (modp && divp) div = round(div);
+  }
+  if (div == 0) div = 0.0;
+  if (mod == 0) mod = 0.0;
+  if (y*mod < 0) {
+    mod += y;
+    div -= 1.0;
+  }
+ exit:
   if (modp) *modp = mod;
   if (divp) *divp = div;
@@ -230,4 +352,5 @@
   return mrb_float_value(mrb, mod);
 }
+#endif
 
 /* 15.2.8.3.16 */
@@ -253,4 +376,5 @@
 }
 
+#ifndef MRB_WITHOUT_FLOAT
 static mrb_value
 flo_eql(mrb_state *mrb, mrb_value x)
@@ -260,5 +384,5 @@
   mrb_get_args(mrb, "o", &y);
   if (!mrb_float_p(y)) return mrb_false_value();
-  return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y));
+  return mrb_bool_value(mrb_float(x) == mrb_float(y));
 }
 
@@ -312,5 +436,5 @@
 int64_value(mrb_state *mrb, int64_t v)
 {
-  if (FIXABLE(v)) {
+  if (TYPED_FIXABLE(v,int64_t)) {
     return mrb_fixnum_value((mrb_int)v);
   }
@@ -322,5 +446,4 @@
 {
   int64_t v1;
-  mrb_get_args(mrb, "");
   v1 = (int64_t)mrb_float(x);
   return int64_value(mrb, ~v1);
@@ -375,9 +498,17 @@
     while (width++) {
       val /= 2;
+      if (val < 1.0) {
+        val = 0;
+        break;
+      }
     }
 #if defined(_ISOC99_SOURCE)
     val = trunc(val);
 #else
-    val = val > 0 ? floor(val) : ceil(val);
+    if (val > 0){
+        val = floor(val);
+    } else {
+        val = ceil(val);
+    }
 #endif
     if (val == 0 && mrb_float(x) < 0) {
@@ -390,12 +521,9 @@
     }
   }
-  if (FIXABLE_FLOAT(val)) {
-    return mrb_fixnum_value((mrb_int)val);
-  }
-  return mrb_float_value(mrb, val);
-}
-
-static mrb_value
-flo_lshift(mrb_state *mrb, mrb_value x)
+  return mrb_int_value(mrb, val);
+}
+
+static mrb_value
+flo_rshift(mrb_state *mrb, mrb_value x)
 {
   mrb_int width;
@@ -406,5 +534,5 @@
 
 static mrb_value
-flo_rshift(mrb_state *mrb, mrb_value x)
+flo_lshift(mrb_state *mrb, mrb_value x)
 {
   mrb_int width;
@@ -412,30 +540,4 @@
   mrb_get_args(mrb, "i", &width);
   return flo_shift(mrb, x, width);
-}
-
-/* 15.2.8.3.18 */
-/*
- * call-seq:
- *   flt.hash  ->  integer
- *
- * Returns a hash code for this float.
- */
-static mrb_value
-flo_hash(mrb_state *mrb, mrb_value num)
-{
-  mrb_float d;
-  char *c;
-  size_t i;
-  mrb_int hash;
-
-  d = (mrb_float)mrb_fixnum(num);
-  /* normalize -0.0 to 0.0 */
-  if (d == 0) d = 0.0;
-  c = (char*)&d;
-  for (hash=0,i=0; i<sizeof(mrb_float); i++) {
-    hash = (hash * 971) ^ (unsigned char)c[i];
-  }
-  if (hash < 0) hash = -hash;
-  return mrb_fixnum_value(hash);
 }
 
@@ -525,8 +627,5 @@
 
   mrb_check_num_exact(mrb, f);
-  if (!FIXABLE_FLOAT(f)) {
-    return mrb_float_value(mrb, f);
-  }
-  return mrb_fixnum_value((mrb_int)f);
+  return mrb_int_value(mrb, f);
 }
 
@@ -551,8 +650,5 @@
 
   mrb_check_num_exact(mrb, f);
-  if (!FIXABLE_FLOAT(f)) {
-    return mrb_float_value(mrb, f);
-  }
-  return mrb_fixnum_value((mrb_int)f);
+  return mrb_int_value(mrb, f);
 }
 
@@ -605,4 +701,5 @@
   f = 1.0;
   i = ndigits >= 0 ? ndigits : -ndigits;
+  if (ndigits > DBL_DIG+2) return num;
   while  (--i >= 0)
     f = f*10.0;
@@ -635,5 +732,5 @@
     return mrb_float_value(mrb, number);
   }
-  return mrb_fixnum_value((mrb_int)number);
+  return mrb_int_value(mrb, number);
 }
 
@@ -643,5 +740,4 @@
  *  call-seq:
  *     flt.to_i      ->  integer
- *     flt.to_int    ->  integer
  *     flt.truncate  ->  integer
  *
@@ -658,8 +754,5 @@
 
   mrb_check_num_exact(mrb, f);
-  if (!FIXABLE_FLOAT(f)) {
-    return mrb_float_value(mrb, f);
-  }
-  return mrb_fixnum_value((mrb_int)f);
+  return mrb_int_value(mrb, f);
 }
 
@@ -669,4 +762,5 @@
   return mrb_bool_value(isnan(mrb_float(num)));
 }
+#endif
 
 /*
@@ -682,5 +776,4 @@
  *  call-seq:
  *     int.to_i      ->  integer
- *     int.to_int    ->  integer
  *
  *  As <i>int</i> is already an <code>Integer</code>, all these
@@ -694,6 +787,6 @@
 }
 
-mrb_value
-mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
+static mrb_value
+fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
 {
   mrb_int a;
@@ -706,9 +799,30 @@
     b = mrb_fixnum(y);
     if (mrb_int_mul_overflow(a, b, &c)) {
+#ifndef MRB_WITHOUT_FLOAT
       return mrb_float_value(mrb, (mrb_float)a * (mrb_float)b);
+#endif
     }
     return mrb_fixnum_value(c);
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
   return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+#endif
+}
+
+MRB_API mrb_value
+mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+  if (mrb_fixnum_p(x)) {
+    return fixnum_mul(mrb, x, y);
+  }
+#ifndef MRB_WITHOUT_FLOAT
+  if (mrb_float_p(x)) {
+    return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y));
+  }
+#endif
+  mrb_raise(mrb, E_TYPE_ERROR, "no number multiply");
+  return mrb_nil_value();       /* not reached */
 }
 
@@ -729,5 +843,5 @@
 
   mrb_get_args(mrb, "o", &y);
-  return mrb_fixnum_mul(mrb, x, y);
+  return fixnum_mul(mrb, x, y);
 }
 
@@ -774,23 +888,34 @@
 {
   mrb_value y;
-  mrb_int a;
+  mrb_int a, b;
 
   mrb_get_args(mrb, "o", &y);
   a = mrb_fixnum(x);
-  if (mrb_fixnum_p(y)) {
-    mrb_int b, mod;
-
-    if ((b=mrb_fixnum(y)) == 0) {
+   if (mrb_fixnum_p(y) && a != MRB_INT_MIN && (b=mrb_fixnum(y)) != MRB_INT_MIN) {
+    mrb_int mod;
+
+    if (b == 0) {
+#ifdef MRB_WITHOUT_FLOAT
+      /* ZeroDivisionError */
+      return mrb_fixnum_value(0);
+#else
+      if (a > 0) return mrb_float_value(mrb, INFINITY);
+      if (a < 0) return mrb_float_value(mrb, INFINITY);
       return mrb_float_value(mrb, NAN);
-    }
-    fixdivmod(mrb, a, b, 0, &mod);
+#endif
+    }
+    fixdivmod(mrb, a, b, NULL, &mod);
     return mrb_fixnum_value(mod);
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
   else {
     mrb_float mod;
 
-    flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod);
+    flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), NULL, &mod);
     return mrb_float_value(mrb, mod);
   }
+#endif
 }
 
@@ -812,10 +937,19 @@
 
     if (mrb_fixnum(y) == 0) {
-      return mrb_assoc_new(mrb, mrb_float_value(mrb, INFINITY),
-        mrb_float_value(mrb, NAN));
+#ifdef MRB_WITHOUT_FLOAT
+      return mrb_assoc_new(mrb, mrb_fixnum_value(0), mrb_fixnum_value(0));
+#else
+      return mrb_assoc_new(mrb, ((mrb_fixnum(x) == 0) ?
+                                 mrb_float_value(mrb, NAN):
+                                 mrb_float_value(mrb, INFINITY)),
+                           mrb_float_value(mrb, NAN));
+#endif
     }
     fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod);
     return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod));
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
   else {
     mrb_float div, mod;
@@ -823,10 +957,12 @@
 
     flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod);
-    a = mrb_float_value(mrb, (mrb_int)div);
+    a = mrb_int_value(mrb, div);
     b = mrb_float_value(mrb, mod);
     return mrb_assoc_new(mrb, a, b);
   }
-}
-
+#endif
+}
+
+#ifndef MRB_WITHOUT_FLOAT
 static mrb_value
 flo_divmod(mrb_state *mrb, mrb_value x)
@@ -839,8 +975,9 @@
 
   flodivmod(mrb, mrb_float(x), mrb_to_flo(mrb, y), &div, &mod);
-  a = mrb_float_value(mrb, (mrb_int)div);
+  a = mrb_int_value(mrb, div);
   b = mrb_float_value(mrb, mod);
   return mrb_assoc_new(mrb, a, b);
 }
+#endif
 
 /* 15.2.8.3.7  */
@@ -865,6 +1002,8 @@
   case MRB_TT_FIXNUM:
     return mrb_bool_value(mrb_fixnum(x) == mrb_fixnum(y));
+#ifndef MRB_WITHOUT_FLOAT
   case MRB_TT_FLOAT:
     return mrb_bool_value((mrb_float)mrb_fixnum(x) == mrb_float(y));
+#endif
   default:
     return mrb_false_value();
@@ -891,4 +1030,9 @@
 }
 
+#ifdef MRB_WITHOUT_FLOAT
+#define bit_op(x,y,op1,op2) do {\
+  return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
+} while(0)
+#else
 static mrb_value flo_and(mrb_state *mrb, mrb_value x);
 static mrb_value flo_or(mrb_state *mrb, mrb_value x);
@@ -896,6 +1040,7 @@
 #define bit_op(x,y,op1,op2) do {\
   if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\
-  return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\
+  return flo_ ## op1(mrb, mrb_float_value(mrb, (mrb_float)mrb_fixnum(x)));\
 } while(0)
+#endif
 
 /* 15.2.8.3.9  */
@@ -956,21 +1101,34 @@
 {
   if (width < 0) {              /* mrb_int overflow */
+#ifdef MRB_WITHOUT_FLOAT
+    return mrb_fixnum_value(0);
+#else
     return mrb_float_value(mrb, INFINITY);
+#endif
   }
   if (val > 0) {
     if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
         (val   > (MRB_INT_MAX >> width))) {
+#ifdef MRB_WITHOUT_FLOAT
+      return mrb_fixnum_value(-1);
+#else
       goto bit_overflow;
-    }
+#endif
+    }
+    return mrb_fixnum_value(val << width);
   }
   else {
     if ((width > NUMERIC_SHIFT_WIDTH_MAX) ||
-        (val   < (MRB_INT_MIN >> width))) {
+        (val   <= (MRB_INT_MIN >> width))) {
+#ifdef MRB_WITHOUT_FLOAT
+      return mrb_fixnum_value(0);
+#else
       goto bit_overflow;
-    }
-  }
-
-  return mrb_fixnum_value(val << width);
-
+#endif
+    }
+    return mrb_fixnum_value(val * ((mrb_int)1 << width));
+  }
+
+#ifndef MRB_WITHOUT_FLOAT
 bit_overflow:
   {
@@ -981,4 +1139,5 @@
     return mrb_float_value(mrb, f);
   }
+#endif
 }
 
@@ -1057,4 +1216,5 @@
  */
 
+#ifndef MRB_WITHOUT_FLOAT
 static mrb_value
 fix_to_f(mrb_state *mrb, mrb_value num)
@@ -1070,5 +1230,5 @@
  *  to numerical classes which don't support them.
  *
- *     Float::INFINITY.to_r
+ *     Float::INFINITY.to_i
  *
  *  <em>raises the exception:</em>
@@ -1089,22 +1249,18 @@
     mrb_float d = mrb_float(x);
 
-    if (isinf(d)) {
-      mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity");
-    }
-    if (isnan(d)) {
-      mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN");
-    }
+    mrb_check_num_exact(mrb, d);
     if (FIXABLE_FLOAT(d)) {
       z = (mrb_int)d;
     }
     else {
-      mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x);
+      mrb_raisef(mrb, E_RANGE_ERROR, "number (%v) too big for integer", x);
     }
   }
   return mrb_fixnum_value(z);
 }
-
-mrb_value
-mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+#endif
+
+static mrb_value
+fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
 {
   mrb_int a;
@@ -1117,9 +1273,30 @@
     b = mrb_fixnum(y);
     if (mrb_int_add_overflow(a, b, &c)) {
+#ifndef MRB_WITHOUT_FLOAT
       return mrb_float_value(mrb, (mrb_float)a + (mrb_float)b);
+#endif
     }
     return mrb_fixnum_value(c);
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
   return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y));
+#endif
+}
+
+MRB_API mrb_value
+mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+  if (mrb_fixnum_p(x)) {
+    return fixnum_plus(mrb, x, y);
+  }
+#ifndef MRB_WITHOUT_FLOAT
+  if (mrb_float_p(x)) {
+    return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
+  }
+#endif
+  mrb_raise(mrb, E_TYPE_ERROR, "no number addition");
+  return mrb_nil_value();       /* not reached */
 }
 
@@ -1139,9 +1316,9 @@
 
   mrb_get_args(mrb, "o", &other);
-  return mrb_fixnum_plus(mrb, self, other);
-}
-
-mrb_value
-mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+  return fixnum_plus(mrb, self, other);
+}
+
+static mrb_value
+fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
 {
   mrb_int a;
@@ -1153,9 +1330,30 @@
     b = mrb_fixnum(y);
     if (mrb_int_sub_overflow(a, b, &c)) {
+#ifndef MRB_WITHOUT_FLOAT
       return mrb_float_value(mrb, (mrb_float)a - (mrb_float)b);
+#endif
     }
     return mrb_fixnum_value(c);
   }
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value");
+#else
   return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y));
+#endif
+}
+
+MRB_API mrb_value
+mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+  if (mrb_fixnum_p(x)) {
+    return fixnum_minus(mrb, x, y);
+  }
+#ifndef MRB_WITHOUT_FLOAT
+  if (mrb_float_p(x)) {
+    return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y));
+  }
+#endif
+  mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction");
+  return mrb_nil_value();       /* not reached */
 }
 
@@ -1176,10 +1374,10 @@
 
   mrb_get_args(mrb, "o", &other);
-  return mrb_fixnum_minus(mrb, self, other);
+  return fixnum_minus(mrb, self, other);
 }
 
 
 MRB_API mrb_value
-mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base)
+mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
 {
   char buf[MRB_INT_BIT+1];
@@ -1188,5 +1386,5 @@
 
   if (base < 2 || 36 < base) {
-    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
   }
 
@@ -1232,4 +1430,44 @@
   mrb_get_args(mrb, "|i", &base);
   return mrb_fixnum_to_str(mrb, self, base);
+}
+
+/* compare two numbers: (1:0:-1; -2 for error) */
+static mrb_int
+cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
+{
+#ifdef MRB_WITHOUT_FLOAT
+  mrb_int x, y;
+#else
+  mrb_float x, y;
+#endif
+
+#ifdef MRB_WITHOUT_FLOAT
+  x = mrb_fixnum(v1);
+#else
+  x = mrb_to_flo(mrb, v1);
+#endif
+  switch (mrb_type(v2)) {
+  case MRB_TT_FIXNUM:
+#ifdef MRB_WITHOUT_FLOAT
+    y = mrb_fixnum(v2);
+#else
+    y = (mrb_float)mrb_fixnum(v2);
+#endif
+    break;
+#ifndef MRB_WITHOUT_FLOAT
+  case MRB_TT_FLOAT:
+    y = mrb_float(v2);
+    break;
+#endif
+  default:
+    return -2;
+  }
+  if (x > y)
+    return 1;
+  else {
+    if (x < y)
+      return -1;
+    return 0;
+  }
 }
 
@@ -1246,29 +1484,104 @@
  */
 static mrb_value
-num_cmp(mrb_state *mrb, mrb_value self)
+integral_cmp(mrb_state *mrb, mrb_value self)
 {
   mrb_value other;
-  mrb_float x, y;
+  mrb_int n;
 
   mrb_get_args(mrb, "o", &other);
-
-  x = mrb_to_flo(mrb, self);
-  switch (mrb_type(other)) {
+  n = cmpnum(mrb, self, other);
+  if (n == -2) return mrb_nil_value();
+  return mrb_fixnum_value(n);
+}
+
+static mrb_noreturn void
+cmperr(mrb_state *mrb, mrb_value v1, mrb_value v2)
+{
+  mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %t with %t failed", v1, v2);
+}
+
+static mrb_value
+integral_lt(mrb_state *mrb, mrb_value self)
+{
+  mrb_value other;
+  mrb_int n;
+
+  mrb_get_args(mrb, "o", &other);
+  n = cmpnum(mrb, self, other);
+  if (n == -2) cmperr(mrb, self, other);
+  if (n < 0) return mrb_true_value();
+  return mrb_false_value();
+}
+
+static mrb_value
+integral_le(mrb_state *mrb, mrb_value self)
+{
+  mrb_value other;
+  mrb_int n;
+
+  mrb_get_args(mrb, "o", &other);
+  n = cmpnum(mrb, self, other);
+  if (n == -2) cmperr(mrb, self, other);
+  if (n <= 0) return mrb_true_value();
+  return mrb_false_value();
+}
+
+static mrb_value
+integral_gt(mrb_state *mrb, mrb_value self)
+{
+  mrb_value other;
+  mrb_int n;
+
+  mrb_get_args(mrb, "o", &other);
+  n = cmpnum(mrb, self, other);
+  if (n == -2) cmperr(mrb, self, other);
+  if (n > 0) return mrb_true_value();
+  return mrb_false_value();
+}
+
+static mrb_value
+integral_ge(mrb_state *mrb, mrb_value self)
+{
+  mrb_value other;
+  mrb_int n;
+
+  mrb_get_args(mrb, "o", &other);
+  n = cmpnum(mrb, self, other);
+  if (n == -2) cmperr(mrb, self, other);
+  if (n >= 0) return mrb_true_value();
+  return mrb_false_value();
+}
+
+MRB_API mrb_int
+mrb_cmp(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
+{
+  mrb_value v;
+
+  switch (mrb_type(obj1)) {
   case MRB_TT_FIXNUM:
-    y = (mrb_float)mrb_fixnum(other);
-    break;
   case MRB_TT_FLOAT:
-    y = mrb_float(other);
-    break;
+    return cmpnum(mrb, obj1, obj2);
+  case MRB_TT_STRING:
+    if (!mrb_string_p(obj2))
+      return -2;
+    return mrb_str_cmp(mrb, obj1, obj2);
   default:
-    return mrb_nil_value();
-  }
-  if (x > y)
-    return mrb_fixnum_value(1);
-  else {
-    if (x < y)
-      return mrb_fixnum_value(-1);
-    return mrb_fixnum_value(0);
-  }
+    v = mrb_funcall(mrb, obj1, "<=>", 1, obj2);
+    if (mrb_nil_p(v) || !mrb_fixnum_p(v))
+      return -2;
+    return mrb_fixnum(v);
+  }
+}
+
+static mrb_value
+num_finite_p(mrb_state *mrb, mrb_value self)
+{
+  return mrb_true_value();
+}
+
+static mrb_value
+num_infinite_p(mrb_state *mrb, mrb_value self)
+{
+  return mrb_false_value();
 }
 
@@ -1281,4 +1594,5 @@
  * and <code>other</code>.
  */
+#ifndef MRB_WITHOUT_FLOAT
 static mrb_value
 flo_plus(mrb_state *mrb, mrb_value x)
@@ -1289,4 +1603,5 @@
   return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y));
 }
+#endif
 
 /* ------------------------------------------------------------------------*/
@@ -1294,13 +1609,25 @@
 mrb_init_numeric(mrb_state *mrb)
 {
-  struct RClass *numeric, *integer, *fixnum, *fl;
+  struct RClass *numeric, *integer, *fixnum, *integral;
+#ifndef MRB_WITHOUT_FLOAT
+  struct RClass *fl;
+#endif
+
+  integral = mrb_define_module(mrb, "Integral");
+  mrb_define_method(mrb, integral,"**",       integral_pow,    MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,"/",        integral_div,    MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.6  */
+  mrb_define_method(mrb, integral,"quo",      integral_div,    MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
+  mrb_define_method(mrb, integral,"div",      integral_idiv,   MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,"<=>",      integral_cmp,    MRB_ARGS_REQ(1)); /* 15.2.{8,9}.3.1  */
+  mrb_define_method(mrb, integral,"<",        integral_lt,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,"<=",       integral_le,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,">",        integral_gt,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,">=",       integral_ge,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, integral,"__coerce_step_counter", integral_coerce_step_counter, MRB_ARGS_REQ(2));
 
   /* Numeric Class */
   numeric = mrb_define_class(mrb, "Numeric",  mrb->object_class);                /* 15.2.7 */
-
-  mrb_define_method(mrb, numeric, "**",       num_pow,         MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, numeric, "/",        num_div,         MRB_ARGS_REQ(1)); /* 15.2.8.3.4  */
-  mrb_define_method(mrb, numeric, "quo",      num_div,         MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */
-  mrb_define_method(mrb, numeric, "<=>",      num_cmp,         MRB_ARGS_REQ(1)); /* 15.2.9.3.6  */
+  mrb_define_method(mrb, numeric, "finite?",  num_finite_p,    MRB_ARGS_NONE());
+  mrb_define_method(mrb, numeric, "infinite?",num_infinite_p,  MRB_ARGS_NONE());
 
   /* Integer Class */
@@ -1310,8 +1637,10 @@
   mrb_define_method(mrb, integer, "to_i",     int_to_i,        MRB_ARGS_NONE()); /* 15.2.8.3.24 */
   mrb_define_method(mrb, integer, "to_int",   int_to_i,        MRB_ARGS_NONE());
-  mrb_define_method(mrb, integer, "ceil",     int_to_i,        MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */
-  mrb_define_method(mrb, integer, "floor",    int_to_i,        MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */
-  mrb_define_method(mrb, integer, "round",    int_to_i,        MRB_ARGS_REQ(1)); /* 15.2.8.3.12 (x) */
-  mrb_define_method(mrb, integer, "truncate", int_to_i,        MRB_ARGS_REQ(1)); /* 15.2.8.3.15 (x) */
+#ifndef MRB_WITHOUT_FLOAT
+  mrb_define_method(mrb, integer, "ceil",     int_to_i,        MRB_ARGS_NONE()); /* 15.2.8.3.8 (x) */
+  mrb_define_method(mrb, integer, "floor",    int_to_i,        MRB_ARGS_NONE()); /* 15.2.8.3.10 (x) */
+  mrb_define_method(mrb, integer, "round",    int_to_i,        MRB_ARGS_NONE()); /* 15.2.8.3.12 (x) */
+  mrb_define_method(mrb, integer, "truncate", int_to_i,        MRB_ARGS_NONE()); /* 15.2.8.3.15 (x) */
+#endif
 
   /* Fixnum Class */
@@ -1329,10 +1658,12 @@
   mrb_define_method(mrb, fixnum,  ">>",       fix_rshift,      MRB_ARGS_REQ(1)); /* 15.2.8.3.13 */
   mrb_define_method(mrb, fixnum,  "eql?",     fix_eql,         MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */
-  mrb_define_method(mrb, fixnum,  "hash",     flo_hash,        MRB_ARGS_NONE()); /* 15.2.8.3.18 */
+#ifndef MRB_WITHOUT_FLOAT
   mrb_define_method(mrb, fixnum,  "to_f",     fix_to_f,        MRB_ARGS_NONE()); /* 15.2.8.3.23 */
-  mrb_define_method(mrb, fixnum,  "to_s",     fix_to_s,        MRB_ARGS_NONE()); /* 15.2.8.3.25 */
-  mrb_define_method(mrb, fixnum,  "inspect",  fix_to_s,        MRB_ARGS_NONE());
+#endif
+  mrb_define_method(mrb, fixnum,  "to_s",     fix_to_s,        MRB_ARGS_OPT(1)); /* 15.2.8.3.25 */
+  mrb_define_method(mrb, fixnum,  "inspect",  fix_to_s,        MRB_ARGS_OPT(1));
   mrb_define_method(mrb, fixnum,  "divmod",   fix_divmod,      MRB_ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
 
+#ifndef MRB_WITHOUT_FLOAT
   /* Float Class */
   mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric);                 /* 15.2.9 */
@@ -1348,6 +1679,6 @@
   mrb_define_method(mrb, fl,      "|",         flo_or,         MRB_ARGS_REQ(1));
   mrb_define_method(mrb, fl,      "^",         flo_xor,        MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, fl,      ">>",        flo_lshift,     MRB_ARGS_REQ(1));
-  mrb_define_method(mrb, fl,      "<<",        flo_rshift,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, fl,      ">>",        flo_rshift,     MRB_ARGS_REQ(1));
+  mrb_define_method(mrb, fl,      "<<",        flo_lshift,     MRB_ARGS_REQ(1));
   mrb_define_method(mrb, fl,      "ceil",      flo_ceil,       MRB_ARGS_NONE()); /* 15.2.9.3.8  */
   mrb_define_method(mrb, fl,      "finite?",   flo_finite_p,   MRB_ARGS_NONE()); /* 15.2.9.3.9  */
@@ -1372,3 +1703,6 @@
   mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN));
 #endif
-}
+
+  mrb_include_module(mrb, fl, integral);
+#endif
+}
