poor man's rubyのパッチ

まだ、一杯バグがありますけど、パッチを晒します。
ライセンスはruby's でお願いします。

変更情報
バグがあったので直しました。 2007/12/9
直したのは、

  1. 条件比較が思い切りバグっていたので直しました。Floatの数値をポインタのまま比較していました。
  2. EPSILONやMAXをdoubleのものから、floatのものに変更しました。実現方法が汚いです。



Index: time.c
===================================================================
--- time.c	(revision 14077)
+++ time.c	(working copy)
@@ -193,6 +193,7 @@
 	t.tv_nsec = 0;
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (interval && RFLOAT_VALUE(num) < 0.0)
 	    rb_raise(rb_eArgError, "%s must be positive", tstr);
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 14077)
+++ include/ruby/intern.h	(working copy)
@@ -83,6 +83,7 @@
 VALUE rb_int2big(SIGNED_VALUE);
 VALUE rb_uint2inum(VALUE);
 VALUE rb_int2inum(SIGNED_VALUE);
+VALUE rb_int2id(SIGNED_VALUE);
 VALUE rb_cstr_to_inum(const char*, int, int);
 VALUE rb_str_to_inum(VALUE, int, int);
 VALUE rb_cstr2inum(const char*, int);
@@ -367,7 +368,8 @@
 VALUE rb_num_coerce_bin(VALUE, VALUE);
 VALUE rb_num_coerce_cmp(VALUE, VALUE);
 VALUE rb_num_coerce_relop(VALUE, VALUE);
-VALUE rb_float_new(double);
+float rb_value2float(VALUE);
+VALUE rb_float_new(float);
 VALUE rb_num2fix(VALUE);
 VALUE rb_fix2str(VALUE, int);
 VALUE rb_dbl_cmp(double, double);
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 14077)
+++ include/ruby/ruby.h	(working copy)
@@ -151,16 +151,18 @@
 # endif
 #endif
 
-#define FIXNUM_MAX (LONG_MAX>>1)
-#define FIXNUM_MIN RSHIFT((long)LONG_MIN,1)
+#define FIXNUM_MAX (LONG_MAX>>2)
+#define FIXNUM_MIN RSHIFT((long)LONG_MIN,2)
 
-#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))
+#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<2 | FIXNUM_FLAG))
+#define INT2ID(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | 1))
 #define LONG2FIX(i) INT2FIX(i)
 #define rb_fix_new(v) INT2FIX(v)
 VALUE rb_int2inum(SIGNED_VALUE);
 #define INT2NUM(v) rb_int2inum(v)
 #define LONG2NUM(v) INT2NUM(v)
 #define rb_int_new(v) rb_int2inum(v)
+#define LONG2ID(v) rb_int2id(v)
 VALUE rb_uint2inum(VALUE);
 #define UINT2NUM(v) rb_uint2inum(v)
 #define ULONG2NUM(v) UINT2NUM(v)
@@ -200,9 +202,10 @@
 #define NUM2GIDT(v) NUM2LONG(v)
 #endif
 
-#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,1)
-#define FIX2ULONG(x) ((((VALUE)(x))>>1)&LONG_MAX)
-#define FIXNUM_P(f) (((SIGNED_VALUE)(f))&FIXNUM_FLAG)
+#define FIX2LONG(x) RSHIFT((SIGNED_VALUE)x,2)
+#define FIX2ULONG(x) ((((VALUE)(x))>>2)&LONG_MAX)
+#define FIXNUM_P(f) ((((SIGNED_VALUE)(f))&FIXNUM_FLAG) == 3)
+#define FIXFLOAT_P(f) ((((SIGNED_VALUE)(f))&FIXNUM_FLAG) == 1)
 #define POSFIXABLE(f) ((f) <= FIXNUM_MAX)
 #define NEGFIXABLE(f) ((f) >= FIXNUM_MIN)
 #define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
@@ -221,7 +224,7 @@
     RUBY_Qundef = 6,
 
     RUBY_IMMEDIATE_MASK = 0x03,
-    RUBY_FIXNUM_FLAG    = 0x01,
+    RUBY_FIXNUM_FLAG    = 0x03,
     RUBY_SYMBOL_FLAG    = 0x0e,
     RUBY_SPECIAL_SHIFT  = 8,
 };
@@ -289,6 +292,8 @@
 #define T_BLOCK  RUBY_T_BLOCK
     RUBY_T_UNDEF  = 0x1c,
 #define T_UNDEF  RUBY_T_UNDEF
+    RUBY_T_FIXFLOAT = 0x1d,
+#define T_FIXFLOAT RUBY_T_FIXFLOAT
     RUBY_T_NODE   = 0x1f,
 #define T_NODE   RUBY_T_NODE
 
@@ -339,6 +344,7 @@
 VALUE rb_num2ulong(VALUE);
 #define NUM2LONG(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2long((VALUE)x))
 #define NUM2ULONG(x) rb_num2ulong((VALUE)x)
+#define ID2ULONG(x) rb_id2ulong((VALUE)x)
 #if SIZEOF_INT < SIZEOF_LONG
 long rb_num2int(VALUE);
 #define NUM2INT(x) (FIXNUM_P(x)?FIX2INT(x):rb_num2int((VALUE)x))
@@ -451,9 +457,9 @@
 
 struct RFloat {
     struct RBasic basic;
-    double float_value;
+    float float_value;
 };
-#define RFLOAT_VALUE(v) (RFLOAT(v)->float_value)
+/* #define RFLOAT_VALUE(v) (RFLOAT(v)->float_value)*/
 #define DOUBLE2NUM(dbl)  rb_float_new(dbl)
 
 #define ELTS_SHARED FL_USER2
@@ -616,6 +622,7 @@
 #define RCLASS(obj)  (R_CAST(RClass)(obj))
 #define RMODULE(obj) RCLASS(obj)
 #define RFLOAT(obj)  (R_CAST(RFloat)(obj))
+#define RFLOAT_VALUE(obj)  ((FIXFLOAT_P(obj)) ? rb_value2float(obj) : (RFLOAT(obj)->float_value))
 #define RSTRING(obj) (R_CAST(RString)(obj))
 #define RREGEXP(obj) (R_CAST(RRegexp)(obj))
 #define RARRAY(obj)  (R_CAST(RArray)(obj))
@@ -886,6 +893,7 @@
 rb_class_of(VALUE obj)
 {
     if (IMMEDIATE_P(obj)) {
+        if (FIXFLOAT_P(obj)) return rb_cFloat;
 	if (FIXNUM_P(obj)) return rb_cFixnum;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (SYMBOL_P(obj)) return rb_cSymbol;
@@ -901,6 +909,7 @@
 rb_type(VALUE obj)
 {
     if (IMMEDIATE_P(obj)) {
+        if (FIXFLOAT_P(obj)) return T_FIXFLOAT;
 	if (FIXNUM_P(obj)) return T_FIXNUM;
 	if (obj == Qtrue) return T_TRUE;
 	if (SYMBOL_P(obj)) return T_SYMBOL;
Index: insns.def
===================================================================
--- insns.def	(revision 14077)
+++ insns.def	(working copy)
@@ -1361,7 +1361,7 @@
 	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
 	/* fixnum + fixnum */
 #ifndef LONG_LONG_VALUE
-	val = (recv + (obj & (~1)));
+	val = (recv + (obj & (~3)));
 	if ((~(recv ^ obj) & (recv ^ val)) &
 	    ((VALUE)0x01 << ((sizeof(VALUE) * CHAR_BIT) - 1))) {
 	    val = rb_big_plus(rb_int2big(FIX2LONG(recv)),
@@ -1382,6 +1382,12 @@
     }
 #endif
 
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat + fixfloat */
+      val = rb_float_new(rb_value2float(recv) + rb_value2float(obj));
+    }
+
     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
 	if (0) {
 	}
@@ -1444,6 +1450,11 @@
 	    val = rb_big_minus(rb_int2big(a), rb_int2big(b));
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat - fixfloat */
+      val = rb_float_new(rb_value2float(recv) - rb_value2float(obj));
+    }
     else {
 	/* other */
 	PUSH(recv);
@@ -1483,6 +1494,11 @@
 	    }
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat * fixfloat */
+      val = rb_float_new(rb_value2float(recv) * rb_value2float(obj));
+    }
     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
 	if (0) {
 	}
@@ -1547,6 +1563,11 @@
 	}
 	val = LONG2NUM(div);
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat / fixfloat */
+      val = rb_float_new(rb_value2float(recv) / rb_value2float(obj));
+    }
     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
 	if (0) {
 	}
@@ -1612,6 +1633,26 @@
 	}
 	val = LONG2FIX(mod);
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+      /* fixfloat + fixfloat */
+      double x = RFLOAT_VALUE(recv);
+      double y = RFLOAT_VALUE(obj);
+      double div, mod;
+      {
+	double z;
+
+	modf(x / y, &z);
+	mod = x - z * y;
+      }
+
+      div = (x - mod) / y;
+      if (y * mod < 0) {
+	mod += y;
+	div -= 1.0;
+      }
+      val = rb_float_new(mod);
+    }
     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
 	if (0) {
 	}
@@ -1670,6 +1711,11 @@
 	    val = Qfalse;
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat == fixfloat */
+      val = (RFLOAT_VALUE(recv) == RFLOAT_VALUE(obj)) ? Qtrue : Qfalse;
+    }
     else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) {
 	if (0) {
 	}
@@ -1730,6 +1776,11 @@
 	    val = Qfalse;
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat <= fixfloat */
+      val = (RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj)) ? Qtrue : Qfalse;
+    }
     else {
 	PUSH(recv);
 	PUSH(obj);
@@ -1759,6 +1810,11 @@
 	    val = Qfalse;
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat <= fixfloat */
+      val = (RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj)) ? Qtrue : Qfalse;
+    }
     else {
 	/* other */
 	PUSH(recv);
@@ -1789,6 +1845,11 @@
 	    val = Qfalse;
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat > fixfloat */
+      val = (RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj)) ? Qtrue : Qfalse;
+    }
     else {
 	PUSH(recv);
 	PUSH(obj);
@@ -1818,6 +1879,11 @@
 	    val = Qfalse;
 	}
     }
+    else if (FIXFLOAT_P(recv) && FIXFLOAT_P(obj) &&
+	     BASIC_OP_UNREDEFINED_P(BOP_PLUS)) {
+	/* fixfloat >= fixfloat */
+      val = (RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj)) ? Qtrue : Qfalse;
+    }
     else {
 	PUSH(recv);
 	PUSH(obj);
Index: object.c
===================================================================
--- object.c	(revision 14077)
+++ object.c	(working copy)
@@ -1919,6 +1919,7 @@
     VALUE tmp;
 
     switch (TYPE(val)) {
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (RFLOAT_VALUE(val) <= (double)FIXNUM_MAX
 	    && RFLOAT_VALUE(val) >= (double)FIXNUM_MIN) {
@@ -2066,6 +2067,7 @@
       case T_FIXNUM:
 	return DOUBLE2NUM((double)FIX2LONG(val));
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return val;
 
@@ -2112,6 +2114,7 @@
 rb_num2dbl(VALUE val)
 {
     switch (TYPE(val)) {
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return RFLOAT_VALUE(val);
 
Index: insnhelper.h
===================================================================
--- insnhelper.h	(revision 14077)
+++ insnhelper.h	(working copy)
@@ -137,7 +137,7 @@
 /**********************************************************/
 
 /* optimize insn */
-#define FIXNUM_2_P(a, b) ((a) & (b) & 1)
+#define FIXNUM_2_P(a, b) (((a) & (b) & 3) == 3)
 #define BASIC_OP_UNREDEFINED_P(op) ((ruby_vm_redefined_flag & (op)) == 0)
 #define HEAP_CLASS_OF(obj) RBASIC(obj)->klass
 
Index: sprintf.c
===================================================================
--- sprintf.c	(revision 14077)
+++ sprintf.c	(working copy)
@@ -551,6 +551,7 @@
 
 	      bin_retry:
 		switch (TYPE(val)) {
+		  case T_FIXFLOAT:
 		  case T_FLOAT:
 		    if (FIXABLE((long)RFLOAT_VALUE(val))) {
 			val = LONG2FIX((long)RFLOAT_VALUE(val));
Index: gc.c
===================================================================
--- gc.c	(revision 14077)
+++ gc.c	(working copy)
@@ -2053,7 +2053,7 @@
 id2ref(VALUE obj, VALUE objid)
 {
 #if SIZEOF_LONG == SIZEOF_VOIDP
-#define NUM2PTR(x) NUM2ULONG(x)
+#define NUM2PTR(x) ID2ULONG(x)
 #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
 #define NUM2PTR(x) NUM2ULL(x)
 #endif
@@ -2067,8 +2067,9 @@
     if (ptr == Qtrue) return Qtrue;
     if (ptr == Qfalse) return Qfalse;
     if (ptr == Qnil) return Qnil;
+    if (FIXFLOAT_P(ptr)) return (VALUE)ptr;
     if (FIXNUM_P(ptr)) return (VALUE)ptr;
-    ptr = objid ^ FIXNUM_FLAG;	/* unset FIXNUM_FLAG */
+    ptr = objid ^ 1;	/* unset FIXNUM_FLAG */
 
     if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
         ID symid = ptr / sizeof(RVALUE);
@@ -2146,12 +2147,12 @@
      *  40 if 64-bit
      */
     if (TYPE(obj) == T_SYMBOL) {
-        return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
+        return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | 1;
     }
     if (SPECIAL_CONST_P(obj)) {
-        return LONG2NUM((SIGNED_VALUE)obj);
+        return LONG2ID((SIGNED_VALUE)obj);
     }
-    return (VALUE)((SIGNED_VALUE)obj|FIXNUM_FLAG);
+    return (VALUE)((SIGNED_VALUE)obj|1);
 }
 
 /*
@@ -2225,6 +2226,7 @@
           case T_REGEXP:        type = ID2SYM(rb_intern("T_REGEXP")); break;
           case T_ARRAY:         type = ID2SYM(rb_intern("T_ARRAY")); break;
           case T_FIXNUM:        type = ID2SYM(rb_intern("T_FIXNUM")); break;
+          case T_FIXFLOAT:      type = ID2SYM(rb_intern("T_FIXFLOAT")); break;
           case T_HASH:          type = ID2SYM(rb_intern("T_HASH")); break;
           case T_STRUCT:        type = ID2SYM(rb_intern("T_STRUCT")); break;
           case T_BIGNUM:        type = ID2SYM(rb_intern("T_BIGNUM")); break;
Index: parse.y
===================================================================
--- parse.y	(revision 14077)
+++ parse.y	(working copy)
@@ -8255,6 +8255,9 @@
       case T_FLOAT:
 	RFLOAT(node->nd_lit)->float_value = -RFLOAT_VALUE(node->nd_lit);
 	break;
+      case T_FIXFLOAT:
+	node->nd_lit = DOUBLE2NUM(-RFLOAT_VALUE(node->nd_lit));
+	break;
       default:
 	break;
     }
@@ -9294,6 +9297,7 @@
     if (x == Qundef)
         rb_raise(rb_eArgError, "Qundef given");
     if (FIXNUM_P(x)) return x;
+    if (FIXFLOAT_P(x)) return x;
     if (SYMBOL_P(x)) return x;
     if (!rb_is_pointer_to_heap(x))
         rb_raise(rb_eArgError, "invalid pointer: %p", x);
Index: util.c
===================================================================
--- util.c	(revision 14077)
+++ util.c	(working copy)
@@ -751,8 +751,8 @@
  *	Llong, #define #ULLong to be the corresponding unsigned type.
  * #define KR_headers for old-style C function headers.
  * #define Bad_float_h if your system lacks a float.h or if it does not
- *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
- *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ *	define some or all of FLT_DIG, FLT_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and FLT_MAX.
  * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
  *	if memory is available and otherwise does something you deem
  *	appropriate.  If MALLOC is undefined, malloc will be invoked
Index: numeric.c
===================================================================
--- numeric.c	(revision 14077)
+++ numeric.c	(working copy)
@@ -29,39 +29,23 @@
 #endif
 
 /* use IEEE 64bit values if not defined */
+/* poor man's ruby use 32bit value, so rewrite parameter */
+/* For GCC */
 #ifndef FLT_RADIX
 #define FLT_RADIX 2
 #endif
 #ifndef FLT_ROUNDS
 #define FLT_ROUNDS 1
 #endif
-#ifndef DBL_MIN
-#define DBL_MIN 2.2250738585072014e-308
-#endif
-#ifndef DBL_MAX
-#define DBL_MAX 1.7976931348623157e+308
-#endif
-#ifndef DBL_MIN_EXP
-#define DBL_MIN_EXP (-1021)
-#endif
-#ifndef DBL_MAX_EXP
-#define DBL_MAX_EXP 1024
-#endif
-#ifndef DBL_MIN_10_EXP
-#define DBL_MIN_10_EXP (-307)
-#endif
-#ifndef DBL_MAX_10_EXP
-#define DBL_MAX_10_EXP 308
-#endif
-#ifndef DBL_DIG
-#define DBL_DIG 15
-#endif
-#ifndef DBL_MANT_DIG
-#define DBL_MANT_DIG 53
-#endif
-#ifndef DBL_EPSILON
-#define DBL_EPSILON 2.2204460492503131e-16
-#endif
+#define DBL_MIN __FLT_MIN__
+#define DBL_MAX __FLT_MAX__
+#define DBL_MIN_EXP __FLT_MIN_EXP__
+#define DBL_MAX_EXP __FLT_MAX_EXP__
+#define DBL_MIN_10_EXP __FLT_MIN_10_EXP__
+#define DBL_MAX_10_EXP __FLT_MAX_10_EXP__
+#define DBL_DIG __FLT_DIG__
+#define DBL_MANT_DIG __FLT_MANT_DIG__
+#define DBL_EPSILON __FLT_EPSILON__
 
 #ifndef HAVE_ROUND
 double
@@ -469,6 +453,38 @@
 }
 
 
+static VALUE
+d2v(float d)
+{
+    union {
+float d;
+VALUE v;
+    } u;
+    u.d = d;
+    return u.v;
+}
+
+static float
+v2d(VALUE v)
+{
+    union {
+float d;
+VALUE v;
+    } u;
+    u.v = v;
+    return u.d;
+}
+
+#define ROTL(v, n) (((v) << (n)) | ((v) >> ((sizeof(v) * 8) - n)))
+#define ROTR(v, n) (((v) >> (n)) | ((v) << ((sizeof(v) * 8) - n)))
+
+float
+rb_value2float(VALUE v)
+{
+    VALUE v1 = (v & 0x4) ? v & (~0x3) : v | 0x3;
+    VALUE v2 = ROTR(v1, 4);
+    return v2d(v2);
+}
 /********************************************************************
  *
  * Document-class: Float
@@ -478,13 +494,22 @@
  */
 
 VALUE
-rb_float_new(double d)
+rb_float_new(float d)
 {
-    NEWOBJ(flt, struct RFloat);
-    OBJSETUP(flt, rb_cFloat, T_FLOAT);
+    VALUE v1 = d2v(d);
+    VALUE v2 = ROTL(v1, 4);
 
-    flt->float_value = d;
-    return (VALUE)flt;
+    if ((v2 & 0x7) == 4 || (v2 & 0x7) == 3) {
+      //      printf("(float2value)%f ", d);
+      return ((v2 | 0x3) ^ 2);
+    }
+    else {
+      NEWOBJ(flt, struct RFloat);
+      OBJSETUP(flt, rb_cFloat, T_FLOAT);
+
+      flt->float_value = d;
+      return (VALUE)flt;
+    }
 }
 
 /*
@@ -546,7 +571,7 @@
 static VALUE
 flo_uminus(VALUE flt)
 {
-    return DOUBLE2NUM(-RFLOAT_VALUE(flt));
+  return DOUBLE2NUM(-RFLOAT_VALUE(flt)); 
 }
 
 /*
@@ -565,6 +590,7 @@
 	return DOUBLE2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y));
       case T_BIGNUM:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) + rb_big2dbl(y));
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) + RFLOAT_VALUE(y));
       default:
@@ -588,6 +614,7 @@
 	return DOUBLE2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
       case T_BIGNUM:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) - rb_big2dbl(y));
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) - RFLOAT_VALUE(y));
       default:
@@ -611,6 +638,7 @@
 	return DOUBLE2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y));
       case T_BIGNUM:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) * rb_big2dbl(y));
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) * RFLOAT_VALUE(y));
       default:
@@ -639,6 +667,7 @@
       case T_BIGNUM:
 	d = rb_big2dbl(y);
 	return DOUBLE2NUM(RFLOAT_VALUE(x) / d);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(RFLOAT_VALUE(x) / RFLOAT_VALUE(y));
       default:
@@ -698,6 +727,7 @@
       case T_BIGNUM:
 	fy = rb_big2dbl(y);
 	break;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	fy = RFLOAT_VALUE(y);
 	break;
@@ -728,6 +758,7 @@
       case T_BIGNUM:
 	fy = rb_big2dbl(y);
 	break;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	fy = RFLOAT_VALUE(y);
 	break;
@@ -765,6 +796,7 @@
 	return DOUBLE2NUM(pow(RFLOAT_VALUE(x), (double)FIX2LONG(y)));
       case T_BIGNUM:
 	return DOUBLE2NUM(pow(RFLOAT_VALUE(x), rb_big2dbl(y)));
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(pow(RFLOAT_VALUE(x), RFLOAT_VALUE(y)));
       default:
@@ -838,6 +870,7 @@
       case T_BIGNUM:
 	b = rb_big2dbl(y);
 	break;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	if (isnan(b)) return Qfalse;
@@ -902,6 +935,7 @@
 	b = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	break;
@@ -934,6 +968,7 @@
 	b = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	if (isnan(b)) return Qfalse;
@@ -969,6 +1004,7 @@
 	b = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	if (isnan(b)) return Qfalse;
@@ -1003,6 +1039,7 @@
 	b = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	if (isnan(b)) return Qfalse;
@@ -1038,6 +1075,7 @@
 	b = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	b = RFLOAT_VALUE(y);
 	if (isnan(b)) return Qfalse;
@@ -1064,7 +1102,8 @@
 static VALUE
 flo_eql(VALUE x, VALUE y)
 {
-    if (TYPE(y) == T_FLOAT) {
+    if (TYPE(y) == T_FLOAT ||
+	TYPE(y) == T_FIXFLOAT) {
 	double a = RFLOAT_VALUE(x);
 	double b = RFLOAT_VALUE(y);
 
@@ -1456,7 +1495,9 @@
 	    }
 	}
     }
-    else if (TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) {
+    else if ((TYPE(from) == T_FLOAT || TYPE(to) == T_FLOAT || TYPE(step) == T_FLOAT) ||
+	     (TYPE(from) == T_FIXFLOAT || TYPE(to) == T_FIXFLOAT || TYPE(step) == T_FIXFLOAT))
+ {
 	const double epsilon = DBL_EPSILON;
 	double beg = NUM2DBL(from);
 	double end = NUM2DBL(to);
@@ -1501,6 +1542,7 @@
 
     switch (TYPE(val)) {
       case T_FLOAT:
+      case T_FIXFLOAT:
 	if (RFLOAT_VALUE(val) <= (double)LONG_MAX
 	    && RFLOAT_VALUE(val) >= (double)LONG_MIN) {
 	    return (SIGNED_VALUE)(RFLOAT_VALUE(val));
@@ -1532,6 +1574,15 @@
     return (VALUE)rb_num2long(val);
 }
 
+VALUE
+rb_id2ulong(VALUE val)
+{
+    if (TYPE(val) == T_BIGNUM) {
+	return rb_big2ulong(val);
+    }
+    return (VALUE)(((SIGNED_VALUE)val) >> 1);
+}
+
 #if SIZEOF_INT < SIZEOF_VALUE
 static void
 check_int(SIGNED_VALUE num)
@@ -1648,6 +1699,7 @@
     if (FIXNUM_P(val)) return (LONG_LONG)FIX2LONG(val);
 
     switch (TYPE(val)) {
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (RFLOAT_VALUE(val) <= (double)LLONG_MAX
 	    && RFLOAT_VALUE(val) >= (double)LLONG_MIN) {
@@ -1913,6 +1965,7 @@
       case T_FIXNUM:
       case T_BIGNUM:
 	return x;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return rb_funcall(x, id_to_i, 0);
       default:
@@ -1935,6 +1988,7 @@
       case T_FIXNUM:
       case T_BIGNUM:
 	return rb_funcall(x, rb_intern("to_f"), 0);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return x;
       default:
@@ -2039,6 +2093,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return rb_big_plus(y, x);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) + RFLOAT_VALUE(y));
       default:
@@ -2073,6 +2128,7 @@
       case T_BIGNUM:
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_minus(x, y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) - RFLOAT_VALUE(y));
       default:
@@ -2132,6 +2188,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return rb_big_mul(y, x);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) * RFLOAT_VALUE(y));
       default:
@@ -2188,6 +2245,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return DOUBLE2NUM((double)FIX2LONG(y) / rb_big2dbl(y));
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
       default:
@@ -2208,6 +2266,7 @@
       case T_BIGNUM:
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_div(x, y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (flo) {
 	    return DOUBLE2NUM((double)FIX2LONG(x) / RFLOAT_VALUE(y));
@@ -2271,6 +2330,7 @@
       case T_BIGNUM:
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_modulo(x, y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	{
 	    double mod;
@@ -2303,6 +2363,7 @@
       case T_BIGNUM:
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_divmod(x, y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	{
 	    double div, mod;
@@ -2403,6 +2464,7 @@
 	}
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_pow(x, y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (RFLOAT_VALUE(y) == 0.0) return DOUBLE2NUM(1.0);
 	if (a == 0) {
@@ -2434,6 +2496,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return rb_big_eq(y, x);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return (double)FIX2LONG(x) == RFLOAT_VALUE(y) ? Qtrue : Qfalse;
       default:
@@ -2461,6 +2524,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return rb_big_cmp(rb_int2big(FIX2LONG(x)), y);
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return rb_dbl_cmp((double)FIX2LONG(x), RFLOAT_VALUE(y));
       default:
@@ -2486,6 +2550,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) > 0 ? Qtrue : Qfalse;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return (double)FIX2LONG(x) > RFLOAT_VALUE(y) ? Qtrue : Qfalse;
       default:
@@ -2511,6 +2576,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) >= 0 ? Qtrue : Qfalse;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return (double)FIX2LONG(x) >= RFLOAT_VALUE(y) ? Qtrue : Qfalse;
       default:
@@ -2536,6 +2602,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) < 0 ? Qtrue : Qfalse;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return (double)FIX2LONG(x) < RFLOAT_VALUE(y) ? Qtrue : Qfalse;
       default:
@@ -2561,6 +2628,7 @@
     switch (TYPE(y)) {
       case T_BIGNUM:
 	return FIX2INT(rb_big_cmp(rb_int2big(FIX2LONG(x)), y)) <= 0 ? Qtrue : Qfalse;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return (double)FIX2LONG(x) <= RFLOAT_VALUE(y) ? Qtrue : Qfalse;
       default:
Index: bignum.c
===================================================================
--- bignum.c	(revision 14077)
+++ bignum.c	(working copy)
@@ -245,6 +245,13 @@
     return rb_int2big(n);
 }
 
+VALUE
+rb_int2id(SIGNED_VALUE n)
+{
+    if (FIXABLE(n)) return INT2ID(n);
+    return rb_int2big(n);
+}
+
 #ifdef HAVE_LONG_LONG
 
 void
@@ -1174,6 +1181,7 @@
       case T_BIGNUM:
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return rb_dbl_cmp(rb_big2dbl(x), RFLOAT_VALUE(y));
 
@@ -1215,6 +1223,7 @@
 	break;
       case T_BIGNUM:
 	break;
+      case T_FIXFLOAT:
       case T_FLOAT:
 	{
 	    volatile double a, b;
@@ -1409,6 +1418,7 @@
       case T_BIGNUM:
 	return bignorm(bigadd(x, y, 1));
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(rb_big2dbl(x) + RFLOAT_VALUE(y));
 
@@ -1434,6 +1444,7 @@
       case T_BIGNUM:
 	return bignorm(bigadd(x, y, 0));
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(rb_big2dbl(x) - RFLOAT_VALUE(y));
 
@@ -1458,6 +1469,7 @@
       case T_BIGNUM:
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(rb_big2dbl(x) * RFLOAT_VALUE(y));
 
@@ -1664,6 +1676,7 @@
       case T_BIGNUM:
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	return DOUBLE2NUM(rb_big2dbl(x) / RFLOAT_VALUE(y));
 
@@ -1837,6 +1850,7 @@
 	    bigdivrem(x, y, &z, 0);
 	    return DOUBLE2NUM(ldexp(big2dbl(z), ex - ey));
 	  }
+	  case T_FIXFLOAT:
 	  case T_FLOAT:
 	    y = dbl2big(ldexp(frexp(RFLOAT_VALUE(y), &ey), DBL_MANT_DIG));
 	    ey -= DBL_MANT_DIG;
@@ -1852,6 +1866,7 @@
 	dy = rb_big2dbl(y);
 	break;
 
+      case T_FIXFLOAT:
       case T_FLOAT:
 	dy = RFLOAT_VALUE(y);
 	break;
@@ -1930,6 +1945,7 @@
 
     if (y == INT2FIX(0)) return INT2FIX(1);
     switch (TYPE(y)) {
+      case T_FIXFLOAT:
       case T_FLOAT:
 	d = RFLOAT_VALUE(y);
 	break;
Index: random.c
===================================================================
--- random.c	(revision 14077)
+++ random.c	(working copy)
@@ -436,6 +436,7 @@
 
     rb_scan_args(argc, argv, "01", &vmax);
     switch (TYPE(vmax)) {
+      case T_FIXFLOAT:
       case T_FLOAT:
 	if (RFLOAT_VALUE(vmax) <= LONG_MAX && RFLOAT_VALUE(vmax) >= LONG_MIN) {
 	    max = (long)RFLOAT_VALUE(vmax);