[macruby-changes] [4501] MacRuby/trunk/ext/bigdecimal

source_changes at macosforge.org source_changes at macosforge.org
Fri Sep 10 00:41:30 PDT 2010


Revision: 4501
          http://trac.macosforge.org/projects/ruby/changeset/4501
Author:   lsansonetti at apple.com
Date:     2010-09-10 00:41:26 -0700 (Fri, 10 Sep 2010)
Log Message:
-----------
sync bigdecimal extension with upstream code + fix some crashers (heap/stack corruption)

Modified Paths:
--------------
    MacRuby/trunk/ext/bigdecimal/bigdecimal.c
    MacRuby/trunk/ext/bigdecimal/bigdecimal.h
    MacRuby/trunk/ext/bigdecimal/extconf.rb

Modified: MacRuby/trunk/ext/bigdecimal/bigdecimal.c
===================================================================
--- MacRuby/trunk/ext/bigdecimal/bigdecimal.c	2010-09-10 06:03:14 UTC (rev 4500)
+++ MacRuby/trunk/ext/bigdecimal/bigdecimal.c	2010-09-10 07:41:26 UTC (rev 4501)
@@ -8,150 +8,63 @@
  * License or the Artistic License, as specified in the README file
  * of this BigDecimal distribution.
  *
- *  NOTE: Change log in this source removed to reduce source code size. 
+ *  NOTE: Change log in this source removed to reduce source code size.
  *        See rev. 1.25 if needed.
  *
  */
 
+/* #define BIGDECIMAL_DEBUG 1 */
+#include "bigdecimal.h"
 #include "ruby/macruby.h"
+
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <float.h>
 #include <math.h>
 #include "math.h"
- 
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
 /* #define ENABLE_NUMERIC_STRING */
 
 VALUE rb_cBigDecimal;
 
-#include "bigdecimal.h"
+static ID id_BigDecimal_exception_mode = 0;
+static ID id_BigDecimal_rounding_mode = 0;
+static ID id_BigDecimal_precision_limit = 0;
 
+#if 0
 /* MACRO's to guard objects from GC by keeping them in stack */
 #define ENTER(n) volatile VALUE vStack[n];int iStack=0
 #define PUSH(x)  vStack[iStack++] = (unsigned long)(x);
 #define SAVE(p)  PUSH(p->obj);
 #define GUARD_OBJ(p,y) {p=y;SAVE(p);}
+#endif
+// MacRuby does not need these macros since it has a real GC.
+#define ENTER(n)
+#define PUSH(x)
+#define SAVE(p)
+#define GUARD_OBJ(p,y) p=y
 
+#define BASE_FIG  RMPD_COMPONENT_FIGURES
+#define BASE      RMPD_BASE
+
+#define HALF_BASE (BASE/2)
+#define BASE1 (BASE/10)
+
+#ifndef DBLE_FIG
+#define DBLE_FIG (DBL_DIG+1)    /* figure of double */
+#endif
+
 /*
  * ================== Ruby Interface part ==========================
  */
 #define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
 
-#if 0
-/* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
- *
- * Copyright (C) 2002 by Shigeo Kobayashi <shigeo at tinyforest.gr.jp>.
- * You may distribute under the terms of either the GNU General Public
- * License or the Artistic License, as specified in the README file
- * of the BigDecimal distribution.
- *
- * Documented by mathew <meta at pobox.com>.
- *
- * = Introduction
- *
- * Ruby provides built-in support for arbitrary precision integer arithmetic.
- * For example:
- *
- * 42**13   ->   1265437718438866624512
- *
- * BigDecimal provides similar support for very large or very accurate floating
- * point numbers.
- *
- * Decimal arithmetic is also useful for general calculation, because it
- * provides the correct answers people expect--whereas normal binary floating
- * point arithmetic often introduces subtle errors because of the conversion
- * between base 10 and base 2. For example, try:
- *
- *   sum = 0
- *   for i in (1..10000)
- *     sum = sum + 0.0001
- *   end
- *   print sum
- *
- * and contrast with the output from:
- *
- *   require 'bigdecimal'
- *
- *   sum = BigDecimal.new("0")
- *   for i in (1..10000)
- *     sum = sum + BigDecimal.new("0.0001")
- *   end
- *   print sum
- *
- * Similarly:
- *
- * (BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") -> true
- *
- * (1.2 - 1.0) == 0.2 -> false
- *
- * = Special features of accurate decimal arithmetic
- *
- * Because BigDecimal is more accurate than normal binary floating point
- * arithmetic, it requires some special values.
- *
- * == Infinity
- *
- * BigDecimal sometimes needs to return infinity, for example if you divide
- * a value by zero.
- *
- * BigDecimal.new("1.0") / BigDecimal.new("0.0")  -> infinity
- *
- * BigDecimal.new("-1.0") / BigDecimal.new("0.0")  -> -infinity
- *
- * You can represent infinite numbers to BigDecimal using the strings
- * 'Infinity', '+Infinity' and '-Infinity' (case-sensitive)
- *
- * == Not a Number
- *
- * When a computation results in an undefined value, the special value NaN
- * (for 'not a number') is returned.
- *
- * Example:
- *
- * BigDecimal.new("0.0") / BigDecimal.new("0.0") -> NaN
- *
- * You can also create undefined values.  NaN is never considered to be the
- * same as any other value, even NaN itself:
- *
- * n = BigDecimal.new('NaN')
- *
- * n == 0.0 -> nil
- *
- * n == n -> nil
- *
- * == Positive and negative zero
- *
- * If a computation results in a value which is too small to be represented as
- * a BigDecimal within the currently specified limits of precision, zero must
- * be returned.
- *
- * If the value which is too small to be represented is negative, a BigDecimal
- * value of negative zero is returned. If the value is positive, a value of
- * positive zero is returned.
- *
- * BigDecimal.new("1.0") / BigDecimal.new("-Infinity") -> -0.0
- *
- * BigDecimal.new("1.0") / BigDecimal.new("Infinity") -> 0.0
- *
- * (See BigDecimal.mode for how to specify limits of precision.)
- *
- * Note that -0.0 and 0.0 are considered to be the same for the purposes of
- * comparison.
- *
- * Note also that in mathematics, there is no particular concept of negative 
- * or positive zero; true mathematical zero has no sign.
- */
-void
-Init_BigDecimal()
-{
-    /* This is a #if-ed out function to fool Rdoc into documenting the class. */
-    /* The real init function is Init_bigdecimal() further down. */
-}
-#endif
-
 /*
  * Returns the BigDecimal version number.
  *
@@ -159,7 +72,7 @@
  * Ruby 1.8.1 thru 1.8.3 return 1.0.1.
  */
 static VALUE
-BigDecimal_version(VALUE self, SEL sel)
+BigDecimal_version(VALUE self)
 {
     /*
      * 1.0.0: Ruby 1.8.0
@@ -169,19 +82,19 @@
 }
 
 /*
- *   VP routines used in BigDecimal part 
+ *   VP routines used in BigDecimal part
  */
 static unsigned short VpGetException(void);
 static void  VpSetException(unsigned short f);
-static void  VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v);
-static int   VpLimitRound(Real *c,U_LONG ixDigit);
+static void  VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v);
+static int   VpLimitRound(Real *c, size_t ixDigit);
 
 /*
  *  **** BigDecimal part ****
  */
 
 static void
-BigDecimal_delete(Real *pv)
+BigDecimal_delete(void *pv)
 {
     VpFree(pv);
 }
@@ -205,12 +118,27 @@
     Real *pv;
     VALUE bg;
     char szD[128];
+    VALUE orig = Qundef;
+    int util_loaded = 0;
 
+again:
     switch(TYPE(v))
     {
+    case T_RATIONAL:
+        if(orig == Qundef ? (orig = v, 1) : orig != v) {
+            if(!util_loaded) {
+                rb_require("bigdecimal/util");
+                util_loaded = 1;
+            }
+            v = rb_funcall2(v, rb_intern("to_d"), 0, 0);
+            goto again;
+        }
+        v = orig;
+        goto SomeOneMayDoIt;
+
     case T_DATA:
-        if(RDATA(v)->dfree ==(void *) BigDecimal_delete) {
-            Data_Get_Struct(v, Real, pv);
+	if(rb_obj_is_kind_of(v, rb_cBigDecimal)) {
+            pv = DATA_PTR(v);
             return pv;
         } else {
             goto SomeOneMayDoIt;
@@ -254,7 +182,7 @@
  * in use.
  */
 static VALUE
-BigDecimal_double_fig(VALUE self, SEL sel)
+BigDecimal_double_fig(VALUE self)
 {
     return INT2FIX(VpDblFig());
 }
@@ -264,12 +192,12 @@
  *
  * Returns an Array of two Integer values.
  *
- * The first value is the current number of significant digits in the 
+ * The first value is the current number of significant digits in the
  * BigDecimal. The second value is the maximum number of significant digits
  * for the BigDecimal.
  */
 static VALUE
-BigDecimal_prec(VALUE self, SEL sel)
+BigDecimal_prec(VALUE self)
 {
     ENTER(1);
     Real *p;
@@ -282,56 +210,56 @@
 }
 
 static VALUE
-BigDecimal_hash(VALUE self, SEL sel)
+BigDecimal_hash(VALUE self)
 {
     ENTER(1);
     Real *p;
-    U_LONG hash,i;
+    st_index_t hash;
 
     GUARD_OBJ(p,GetVpValue(self,1));
-    hash = (U_LONG)p->sign;
+    hash = (st_index_t)p->sign;
     /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
-    if(hash==2) {
-        for(i = 0; i < p->Prec;i++) {
-            hash = 31 * hash + p->frac[i];
-            hash ^= p->frac[i];
-        }
-        hash += p->exponent;
+    if(hash == 2 || hash == (st_index_t)-2) {
+	hash ^= rb_memhash(p->frac, sizeof(BDIGIT)*p->Prec);
+	hash += p->exponent;
     }
     return INT2FIX(hash);
 }
 
 static VALUE
-BigDecimal_dump(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_dump(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
-    char sz[50];
     Real *vp;
     char *psz;
     VALUE dummy;
+    volatile VALUE dump;
+
     rb_scan_args(argc, argv, "01", &dummy);
     GUARD_OBJ(vp,GetVpValue(self,1));
-    sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
-    psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
-    sprintf(psz,"%s",sz);
+    const size_t len = VpNumOfChars(vp,"E")+50;
+    dump = rb_bstr_new_with_data(NULL, len);
+    psz = (char *)rb_bstr_bytes(dump);
+    snprintf(psz, len, "%ld:", VpMaxPrec(vp)*VpBaseFig());
     VpToString(vp, psz+strlen(psz), 0, 0);
-    return rb_str_new2(psz);
+    rb_bstr_resize(dump, strlen(psz));
+    return dump;
 }
 
 /*
  * Internal method used to provide marshalling support. See the Marshal module.
  */
 static VALUE
-BigDecimal_load(VALUE self, SEL sel, VALUE str)
+BigDecimal_load(VALUE self, VALUE str)
 {
     ENTER(2);
     Real *pv;
-    unsigned char *pch;
+    const unsigned char *pch;
     unsigned char ch;
     unsigned long m=0;
 
     SafeStringValue(str);
-    pch = (unsigned char *)RSTRING_PTR(str);
+    pch = (const unsigned char *)RSTRING_PTR(str);
     /* First get max prec */
     while((*pch)!=(unsigned char)'\0' && (ch=*pch++)!=(unsigned char)':') {
         if(!ISDIGIT(ch)) {
@@ -340,7 +268,7 @@
         m = m*10 + (unsigned long)(ch-'0');
     }
     if(m>VpBaseFig()) m -= VpBaseFig();
-    GUARD_OBJ(pv,VpNewRbClass(m,(char *)pch,self));
+    GUARD_OBJ(pv,VpNewRbClass(m,(const char *)pch,self));
     m /= VpBaseFig();
     if(m && pv->MaxPrec>m) pv->MaxPrec = m+1;
     return ToValue(pv);
@@ -362,8 +290,8 @@
   * BigDecimal::EXCEPTION_ZERODIVIDE
   * BigDecimal::EXCEPTION_ALL
   *
-  * For each mode parameter above, if the value set is false, computation 
-  * continues after an arithmetic exception of the appropriate type. 
+  * For each mode parameter above, if the value set is false, computation
+  * continues after an arithmetic exception of the appropriate type.
   * When computation continues, results are as follows:
   *
   * EXCEPTION_NaN:: NaN
@@ -385,12 +313,12 @@
   *
   */
 static VALUE
-BigDecimal_mode(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_mode(int argc, VALUE *argv, VALUE self)
 {
     VALUE which;
     VALUE val;
     unsigned long f,fo;
- 
+
     if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil;
 
     Check_Type(which, T_FIXNUM);
@@ -408,11 +336,22 @@
             VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY):
                            (fo&(~VP_EXCEPTION_INFINITY))));
         }
+        fo = VpGetException();
         if(f&VP_EXCEPTION_NaN) {
             VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
                            (fo&(~VP_EXCEPTION_NaN))));
         }
         fo = VpGetException();
+        if(f&VP_EXCEPTION_UNDERFLOW) {
+            VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_UNDERFLOW):
+                           (fo&(~VP_EXCEPTION_UNDERFLOW))));
+        }
+        fo = VpGetException();
+        if(f&VP_EXCEPTION_ZERODIVIDE) {
+            VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_ZERODIVIDE):
+                           (fo&(~VP_EXCEPTION_ZERODIVIDE))));
+        }
+        fo = VpGetException();
         return INT2FIX(fo);
     }
     if(VP_ROUND_MODE==f) {
@@ -420,78 +359,80 @@
         fo = VpGetRoundMode();
         if(val==Qnil) return INT2FIX(fo);
         Check_Type(val, T_FIXNUM);
-        if(!VpIsRoundMode(FIX2INT(val))) {
+        if(!VpIsRoundMode((unsigned short)FIX2INT(val))) {
             rb_raise(rb_eTypeError, "invalid rounding mode");
             return Qnil;
         }
-        fo = VpSetRoundMode((unsigned long)FIX2INT(val));
+        fo = VpSetRoundMode((unsigned short)FIX2INT(val));
         return INT2FIX(fo);
     }
     rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
     return Qnil;
 }
 
-static U_LONG
+static size_t
 GetAddSubPrec(Real *a, Real *b)
 {
-    U_LONG mxs;
-    U_LONG mx = a->Prec;
-    S_INT d;
+    size_t mxs;
+    size_t mx = a->Prec;
+    SIGNED_VALUE d;
 
-    if(!VpIsDef(a) || !VpIsDef(b)) return (-1L);
+    if(!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
     if(mx < b->Prec) mx = b->Prec;
     if(a->exponent!=b->exponent) {
         mxs = mx;
         d = a->exponent - b->exponent;
-        if(d<0) d = -d;
-        mx = mx+(U_LONG)d;
-        if(mx<mxs) {
+        if (d < 0) d = -d;
+        mx = mx + (size_t)d;
+        if (mx<mxs) {
             return VpException(VP_EXCEPTION_INFINITY,"Exponent overflow",0);
         }
     }
     return mx;
 }
 
-static S_INT
+static SIGNED_VALUE
 GetPositiveInt(VALUE v)
 {
-    S_INT n;
+    SIGNED_VALUE n;
     Check_Type(v, T_FIXNUM);
     n = FIX2INT(v);
-    if(n < 0) {
+    if (n < 0) {
         rb_raise(rb_eArgError, "argument must be positive");
     }
     return n;
 }
 
 VP_EXPORT Real *
-VpNewRbClass(U_LONG mx, const char *str, VALUE klass)
+VpNewRbClass(size_t mx, const char *str, VALUE klass)
 {
     Real *pv = VpAlloc(mx,str);
-    pv->obj = (VALUE)Data_Wrap_Struct(klass, 0, BigDecimal_delete, pv);
+    GC_WB(&pv->obj, (VALUE)Data_Wrap_Struct(klass, 0, BigDecimal_delete, pv));
     return pv;
 }
 
 VP_EXPORT Real *
-VpCreateRbObject(U_LONG mx, const char *str)
+VpCreateRbObject(size_t mx, const char *str)
 {
     Real *pv = VpAlloc(mx,str);
-    pv->obj = (VALUE)Data_Wrap_Struct(rb_cBigDecimal, 0, BigDecimal_delete, pv);
+    GC_WB(&pv->obj, (VALUE)Data_Wrap_Struct(rb_cBigDecimal, 0, BigDecimal_delete, pv));
     return pv;
 }
 
 /* Returns True if the value is Not a Number */
 static VALUE
-BigDecimal_IsNaN(VALUE self, SEL sel)
+BigDecimal_IsNaN(VALUE self)
 {
     Real *p = GetVpValue(self,1);
     if(VpIsNaN(p))  return Qtrue;
     return Qfalse;
 }
 
-/* Returns True if the value is infinite */
+/* Returns nil, -1, or +1 depending on whether the value is finite,
+ * -infinity, or +infinity.
+ */
 static VALUE
-BigDecimal_IsInfinite(VALUE self, SEL sel)
+BigDecimal_IsInfinite(VALUE self)
 {
     Real *p = GetVpValue(self,1);
     if(VpIsPosInf(p)) return INT2FIX(1);
@@ -501,7 +442,7 @@
 
 /* Returns True if the value is finite (not NaN or infinite) */
 static VALUE
-BigDecimal_IsFinite(VALUE self, SEL sel)
+BigDecimal_IsFinite(VALUE self)
 {
     Real *p = GetVpValue(self,1);
     if(VpIsNaN(p)) return Qfalse;
@@ -509,104 +450,143 @@
     return Qtrue;
 }
 
+static void
+BigDecimal_check_num(Real *p)
+{
+    if(VpIsNaN(p)) {
+       VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",1);
+    } else if(VpIsPosInf(p)) {
+       VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",1);
+    } else if(VpIsNegInf(p)) {
+       VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",1);
+    }
+}
+
+static VALUE BigDecimal_split(VALUE self);
+
 /* Returns the value as an integer (Fixnum or Bignum).
  *
- * If the BigNumber is infinity or NaN, returns nil.
+ * If the BigNumber is infinity or NaN, raises FloatDomainError.
  */
 static VALUE
-BigDecimal_to_i(VALUE self, SEL sel)
+BigDecimal_to_i(VALUE self)
 {
     ENTER(5);
-    int e,n,i,nf;
-    U_LONG v,b,j;
-    char *psz,*pch;
+    ssize_t e, nf;
     Real *p;
 
     GUARD_OBJ(p,GetVpValue(self,1));
+    BigDecimal_check_num(p);
 
-    /* Infinity or NaN not converted. */
-    if(VpIsNaN(p)) {
-       VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
-       return Qnil;
-    } else if(VpIsPosInf(p)) {
-       VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
-       return Qnil;
-    } else if(VpIsNegInf(p)) {
-       VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
-       return Qnil;
-    }
-
     e = VpExponent10(p);
     if(e<=0) return INT2FIX(0);
     nf = VpBaseFig();
     if(e<=nf) {
-        e = VpGetSign(p)*p->frac[0];
-        return INT2FIX(e);
+        return LONG2NUM((long)(VpGetSign(p)*(BDIGIT_DBL_SIGNED)p->frac[0]));
     }
-    psz = ALLOCA_N(char,(unsigned int)(e+nf+2));
+    else {
+	VALUE a = BigDecimal_split(self);
+	VALUE digits = RARRAY_PTR(a)[1];
+	VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
+	ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
 
-    n = (e+nf-1)/nf;
-    pch = psz;
-    if(VpGetSign(p)<0) *pch++ = '-';
-    for(i=0;i<n;++i) {
-        b = VpBaseVal()/10;
-        if(i>=(int)p->Prec) {
-            while(b) {
-                *pch++ = '0';
-                b /= 10;
-            }
-            continue;
-        }
-        v = p->frac[i];
-        while(b) {
-            j = v/b;
-            *pch++ = (char)(j + '0');
-            v -= j*b;
-            b /= 10;
-        }
+	if (VpGetSign(p) < 0) {
+	    numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
+	}
+	if (dpower < 0) {
+	    return rb_funcall(numerator, rb_intern("div"), 1,
+			      rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+					 INT2FIX(-dpower)));
+	}
+        return rb_funcall(numerator, '*', 1,
+			  rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+				     INT2FIX(dpower)));
     }
-    *pch++ = 0;
-    return rb_cstr2inum(psz,10);
 }
 
-static VALUE
-BigDecimal_induced_from(VALUE self, SEL sel, VALUE x)
-{
-    Real *p = GetVpValue(x,1);
-    return p->obj;
-}
-
 /* Returns a new Float object having approximately the same value as the
  * BigDecimal number. Normal accuracy limits and built-in errors of binary
  * Float arithmetic apply.
  */
 static VALUE
-BigDecimal_to_f(VALUE self, SEL sel)
+BigDecimal_to_f(VALUE self)
 {
     ENTER(1);
     Real *p;
     double d;
-    S_LONG e;
+    SIGNED_VALUE e;
     char *buf;
 
-    GUARD_OBJ(p,GetVpValue(self,1));
-    if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
-    buf = ALLOCA_N(char,(unsigned int)VpNumOfChars(p,"E"));
+    GUARD_OBJ(p, GetVpValue(self, 1));
+    if (VpVtoD(&d, &e, p) != 1)
+	return rb_float_new(d);
+    if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
+	goto overflow;
+    if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
+	goto underflow;
+
+    buf = xmalloc(VpNumOfChars(p,"E"));
     VpToString(p, buf, 0, 0);
     errno = 0;
     d = strtod(buf, 0);
-    if(errno == ERANGE) {
-       VpException(VP_EXCEPTION_OVERFLOW,"BigDecimal to Float conversion",0);
-       if(d>0.0) return rb_float_new(DBL_MAX);
-       else      return rb_float_new(-DBL_MAX);
-    }
+    if (errno == ERANGE)
+	goto overflow;
     return rb_float_new(d);
+
+overflow:
+    VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
+    if (d > 0.0)
+	return rb_float_new(VpGetDoublePosInf());
+    else
+	return rb_float_new(VpGetDoubleNegInf());
+
+underflow:
+    VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
+    if (d > 0.0)
+	return rb_float_new(0.0);
+    else
+	return rb_float_new(-0.0);
 }
 
+
+/* Converts a BigDecimal to a Rational.
+ */
+static VALUE
+BigDecimal_to_r(VALUE self)
+{
+    Real *p;
+    ssize_t sign, power, denomi_power;
+    VALUE a, digits, numerator;
+
+    p = GetVpValue(self,1);
+    BigDecimal_check_num(p);
+
+    sign = VpGetSign(p);
+    power = VpExponent10(p);
+    a = BigDecimal_split(self);
+    digits = RARRAY_PTR(a)[1];
+    denomi_power = power - RSTRING_LEN(digits);
+    numerator = rb_funcall(digits, rb_intern("to_i"), 0);
+
+    if (sign < 0) {
+	numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
+    }
+    if (denomi_power < 0) {
+	return rb_Rational(numerator,
+			   rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+				      INT2FIX(-denomi_power)));
+    }
+    else {
+        return rb_Rational1(rb_funcall(numerator, '*', 1,
+				       rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+						  INT2FIX(denomi_power))));
+    }
+}
+
 /* The coerce method provides support for Ruby type coercion. It is not
  * enabled by default.
- * 
- * This means that binary operations like + * / or - can often be performed 
+ *
+ * This means that binary operations like + * / or - can often be performed
  * on a BigDecimal and an object of another type, if the other object can
  * be coerced into a BigDecimal value.
  *
@@ -618,22 +598,22 @@
  * it requires a special compile-time option when building Ruby.
  */
 static VALUE
-BigDecimal_coerce(VALUE self, SEL sel, VALUE other)
+BigDecimal_coerce(VALUE self, VALUE other)
 {
     ENTER(2);
     VALUE obj;
     Real *b;
-    if(TYPE(other) == T_FLOAT) {
-       obj = rb_assoc_new(other, BigDecimal_to_f(self, 0));
+    if (TYPE(other) == T_FLOAT) {
+	obj = rb_assoc_new(other, BigDecimal_to_f(self));
     } else {
-       GUARD_OBJ(b,GetVpValue(other,1));
-       obj = rb_assoc_new(b->obj, self);
+	GUARD_OBJ(b,GetVpValue(other,1));
+	obj = rb_assoc_new(b->obj, self);
     }
     return obj;
 }
 
 static VALUE
-BigDecimal_uplus(VALUE self, SEL sel)
+BigDecimal_uplus(VALUE self)
 {
     return self;
 }
@@ -641,7 +621,7 @@
  /* call-seq:
   * add(value, digits)
   *
-  * Add the specified value. 
+  * Add the specified value.
   *
   * e.g.
   *   c = a.add(b,n)
@@ -650,11 +630,11 @@
   * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
   */
 static VALUE
-BigDecimal_add(VALUE self, SEL sel, VALUE r)
+BigDecimal_add(VALUE self, VALUE r)
 {
     ENTER(5);
     Real *c, *a, *b;
-    U_LONG mx;
+    size_t mx;
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
     if(!b) return DoSomeOne(self,r,'+');
@@ -662,7 +642,7 @@
     if(VpIsNaN(b)) return b->obj;
     if(VpIsNaN(a)) return a->obj;
     mx = GetAddSubPrec(a,b);
-    if(mx==(-1L)) {
+    if (mx == (size_t)-1L) {
         GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
         VpAddSub(c, a, b, 1);
     } else {
@@ -679,7 +659,7 @@
  /* call-seq:
   * sub(value, digits)
   *
-  * Subtract the specified value. 
+  * Subtract the specified value.
   *
   * e.g.
   *   c = a.sub(b,n)
@@ -688,11 +668,11 @@
   * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
   */
 static VALUE
-BigDecimal_sub(VALUE self, SEL sel, VALUE r)
+BigDecimal_sub(VALUE self, VALUE r)
 {
     ENTER(5);
     Real *c, *a, *b;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
@@ -703,7 +683,7 @@
     if(VpIsNaN(a)) return a->obj;
 
     mx = GetAddSubPrec(a,b);
-    if(mx==(-1L)) {
+    if (mx == (size_t)-1L) {
         GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
         VpAddSub(c, a, b, -1);
     } else {
@@ -721,7 +701,7 @@
 BigDecimalCmp(VALUE self, VALUE r,char op)
 {
     ENTER(5);
-    S_INT e;
+    SIGNED_VALUE e;
     Real *a, *b;
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
@@ -730,9 +710,8 @@
 
 	switch(op)
 	{
-	  case '*': f = rb_intern("<=>");break;
-	  case '=': f = rb_intern("=="); break;
-	  case '!': f = rb_intern("!="); break;
+	  case '*': return rb_num_coerce_cmp(self,r,rb_intern("<=>"));
+	  case '=': return RTEST(rb_num_coerce_cmp(self,r,rb_intern("=="))) ? Qtrue : Qfalse;
 	  case 'G': f = rb_intern(">="); break;
 	  case 'L': f = rb_intern("<="); break;
 	  case '>': case '<': f = (ID)op; break;
@@ -741,12 +720,11 @@
     }
     SAVE(b);
     e = VpComp(a, b);
-    if(e==999) return Qnil;
+    if(e==999) return (op == '*') ? Qnil : Qfalse;
     switch(op)
     {
     case '*': return   INT2FIX(e); /* any op */
     case '=': if(e==0) return Qtrue ; return Qfalse;
-    case '!': if(e!=0) return Qtrue ; return Qfalse;
     case 'G': if(e>=0) return Qtrue ; return Qfalse;
     case '>': if(e> 0) return Qtrue ; return Qfalse;
     case 'L': if(e<=0) return Qtrue ; return Qfalse;
@@ -757,15 +735,15 @@
 
 /* Returns True if the value is zero. */
 static VALUE
-BigDecimal_zero(VALUE self, SEL sel)
+BigDecimal_zero(VALUE self)
 {
     Real *a = GetVpValue(self,1);
     return VpIsZero(a) ? Qtrue : Qfalse;
 }
 
-/* Returns True if the value is non-zero. */
+/* Returns self if the value is non-zero, nil otherwise. */
 static VALUE
-BigDecimal_nonzero(VALUE self, SEL sel)
+BigDecimal_nonzero(VALUE self)
 {
     Real *a = GetVpValue(self,1);
     return VpIsZero(a) ? Qnil : self;
@@ -775,7 +753,7 @@
  * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
  */
 static VALUE
-BigDecimal_comp(VALUE self, SEL sel, VALUE r)
+BigDecimal_comp(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, '*');
 }
@@ -783,7 +761,7 @@
 /*
  * Tests for value equality; returns true if the values are equal.
  *
- * The == and === operators and the eql? method have the same implementation 
+ * The == and === operators and the eql? method have the same implementation
  * for BigDecimal.
  *
  * Values may be coerced to perform the comparison:
@@ -791,7 +769,7 @@
  * BigDecimal.new('1.0') == 1.0  -> true
  */
 static VALUE
-BigDecimal_eq(VALUE self, SEL sel, VALUE r)
+BigDecimal_eq(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, '=');
 }
@@ -803,7 +781,7 @@
  * comparison (see ==, coerce).
  */
 static VALUE
-BigDecimal_lt(VALUE self, SEL sel, VALUE r)
+BigDecimal_lt(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, '<');
 }
@@ -811,11 +789,11 @@
 /* call-seq:
  * a <= b
  *
- * Returns true if a is less than or equal to b. Values may be coerced to 
+ * Returns true if a is less than or equal to b. Values may be coerced to
  * perform the comparison (see ==, coerce).
  */
 static VALUE
-BigDecimal_le(VALUE self, SEL sel, VALUE r)
+BigDecimal_le(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, 'L');
 }
@@ -823,11 +801,11 @@
 /* call-seq:
  * a > b
  *
- * Returns true if a is greater than b.  Values may be coerced to 
+ * Returns true if a is greater than b.  Values may be coerced to
  * perform the comparison (see ==, coerce).
  */
 static VALUE
-BigDecimal_gt(VALUE self, SEL sel, VALUE r)
+BigDecimal_gt(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, '>');
 }
@@ -835,17 +813,17 @@
 /* call-seq:
  * a >= b
  *
- * Returns true if a is greater than or equal to b. Values may be coerced to 
+ * Returns true if a is greater than or equal to b. Values may be coerced to
  * perform the comparison (see ==, coerce)
  */
 static VALUE
-BigDecimal_ge(VALUE self, SEL sel, VALUE r)
+BigDecimal_ge(VALUE self, VALUE r)
 {
     return BigDecimalCmp(self, r, 'G');
 }
 
 static VALUE
-BigDecimal_neg(VALUE self, SEL sel)
+BigDecimal_neg(VALUE self)
 {
     ENTER(5);
     Real *c, *a;
@@ -858,7 +836,7 @@
  /* call-seq:
   * mult(value, digits)
   *
-  * Multiply by the specified value. 
+  * Multiply by the specified value.
   *
   * e.g.
   *   c = a.mult(b,n)
@@ -867,11 +845,11 @@
   * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
   */
 static VALUE
-BigDecimal_mult(VALUE self, SEL sel, VALUE r)
+BigDecimal_mult(VALUE self, VALUE r)
 {
     ENTER(5);
     Real *c, *a, *b;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
@@ -890,14 +868,16 @@
 {
     ENTER(5);
     Real *a, *b;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
     if(!b) return DoSomeOne(self,r,'/');
     SAVE(b);
     *div = b;
-    mx =(a->MaxPrec + b->MaxPrec + 1) * VpBaseFig();
+    mx = a->Prec + vabs(a->exponent);
+    if(mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
+    mx =(mx + 1) * VpBaseFig();
     GUARD_OBJ((*c),VpCreateRbObject(mx, "#0"));
     GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
     VpDivd(*c, *res, a, b);
@@ -908,13 +888,13 @@
   * div(value, digits)
   * quo(value)
   *
-  * Divide by the specified value. 
+  * Divide by the specified value.
   *
   * e.g.
   *   c = a.div(b,n)
   *
   * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
-  * 
+  *
   * If digits is 0, the result is the same as the / operator. If not, the
   * result is an integer BigDecimal, by analogy with Float#div.
   *
@@ -922,7 +902,7 @@
   * the quotient; see divmod.
   */
 static VALUE
-BigDecimal_div(VALUE self, SEL sel, VALUE r)
+BigDecimal_div(VALUE self, VALUE r)
 /* For c = self/r: with round operation */
 {
     ENTER(5);
@@ -936,7 +916,7 @@
      */
     /* Round */
     if(VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
-       VpInternalRound(c,0,c->frac[c->Prec-1],(VpBaseVal()*res->frac[0])/div->frac[0]);
+	VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal()*(BDIGIT_DBL)res->frac[0]/div->frac[0]));
     }
     return ToValue(c);
 }
@@ -951,26 +931,42 @@
     ENTER(8);
     Real *c=NULL, *d=NULL, *res=NULL;
     Real *a, *b;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     b = GetVpValue(r,0);
-    if(!b) return DoSomeOne(self,r,rb_intern("divmod"));
+    if(!b) return Qfalse;
     SAVE(b);
 
     if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
-    if(VpIsInf(a) || VpIsInf(b)) goto NaN;
-    if(VpIsZero(b))              goto NaN;
+    if(VpIsInf(a) && VpIsInf(b)) goto NaN;
+    if(VpIsZero(b)) {
+	rb_raise(rb_eZeroDivError, "divided by 0");
+    }
+    if(VpIsInf(a)) {
+       GUARD_OBJ(d,VpCreateRbObject(1, "0"));
+       VpSetInf(d, (SIGNED_VALUE)(VpGetSign(a) == VpGetSign(b) ? 1 : -1));
+       GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
+       *div = d;
+       *mod = c;
+       return Qtrue;
+    }
+    if(VpIsInf(b)) {
+       GUARD_OBJ(d,VpCreateRbObject(1, "0"));
+       *div = d;
+       *mod = a;
+       return Qtrue;
+    }
     if(VpIsZero(a)) {
        GUARD_OBJ(c,VpCreateRbObject(1, "0"));
        GUARD_OBJ(d,VpCreateRbObject(1, "0"));
        *div = d;
        *mod = c;
-       return (VALUE)0;
+       return Qtrue;
     }
 
-    mx = a->Prec;
-    if(mx<b->Prec) mx = b->Prec;
+    mx = a->Prec + vabs(a->exponent);
+    if(mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
     mx =(mx + 1) * VpBaseFig();
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
@@ -982,6 +978,7 @@
     VpAddSub(c,a,res,-1);
     if(!VpIsZero(c) && (VpGetSign(a)*VpGetSign(b)<0)) {
         VpAddSub(res,d,VpOne(),-1);
+	GUARD_OBJ(d,VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0"));
         VpAddSub(d  ,c,b,       1);
         *div = res;
         *mod = d;
@@ -989,14 +986,14 @@
         *div = d;
         *mod = c;
     }
-    return (VALUE)0;
+    return Qtrue;
 
 NaN:
     GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
     GUARD_OBJ(d,VpCreateRbObject(1, "NaN"));
     *div = d;
     *mod = c;
-    return (VALUE)0;
+    return Qtrue;
 }
 
 /* call-seq:
@@ -1006,23 +1003,23 @@
  * Returns the modulus from dividing by b. See divmod.
  */
 static VALUE
-BigDecimal_mod(VALUE self, SEL sel, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
+BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
 {
     ENTER(3);
-    VALUE obj;
     Real *div=NULL, *mod=NULL;
 
-    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
-    if(obj!=(VALUE)0) return obj;
-    SAVE(div);SAVE(mod);
-    return ToValue(mod);
+    if(BigDecimal_DoDivmod(self,r,&div,&mod)) {
+	SAVE(div); SAVE(mod);
+	return ToValue(mod);
+    }
+    return DoSomeOne(self,r,'%');
 }
 
 static VALUE
 BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
 {
     ENTER(10);
-    U_LONG mx;
+    size_t mx;
     Real *a=NULL, *b=NULL, *c=NULL, *res=NULL, *d=NULL, *rr=NULL, *ff=NULL;
     Real *f=NULL;
 
@@ -1057,13 +1054,10 @@
 
 /* Returns the remainder from dividing by the value.
  *
- * If the values divided are of the same sign, the remainder is the same as
- * the modulus (see divmod).
- *
- * Otherwise, the remainder is the modulus minus the value divided by.
+ * x.remainder(y) means x-y*(x/y).truncate
  */
 static VALUE
-BigDecimal_remainder(VALUE self, SEL sel, VALUE r) /* remainder */
+BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
 {
     VALUE  f;
     Real  *d,*rv=0;
@@ -1088,44 +1082,43 @@
  *
  * a == c  -> true
  *
- * The quotient q is (a/b).floor, and the modulus is the amount that must be 
+ * The quotient q is (a/b).floor, and the modulus is the amount that must be
  * added to q * b to get a.
  */
 static VALUE
-BigDecimal_divmod(VALUE self, SEL sel, VALUE r)
+BigDecimal_divmod(VALUE self, VALUE r)
 {
     ENTER(5);
-    VALUE obj;
     Real *div=NULL, *mod=NULL;
 
-    obj = BigDecimal_DoDivmod(self,r,&div,&mod);
-    if(obj!=(VALUE)0) return obj;
-    SAVE(div);SAVE(mod);
-    obj = rb_assoc_new(ToValue(div), ToValue(mod));
-    return obj;
+    if(BigDecimal_DoDivmod(self,r,&div,&mod)) {
+	SAVE(div); SAVE(mod);
+	return rb_assoc_new(ToValue(div), ToValue(mod));
+    }
+    return DoSomeOne(self,r,rb_intern("divmod"));
 }
 
 static VALUE
-BigDecimal_div2(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_div2(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     VALUE b,n;
     int na = rb_scan_args(argc,argv,"11",&b,&n);
     if(na==1) { /* div in Float sense */
-       VALUE obj;
        Real *div=NULL;
        Real *mod;
-       obj = BigDecimal_DoDivmod(self,b,&div,&mod);
-       if(obj!=(VALUE)0) return obj;
-       return ToValue(div);
+       if(BigDecimal_DoDivmod(self,b,&div,&mod)) {
+	  return BigDecimal_to_i(ToValue(div));
+       }
+       return DoSomeOne(self,b,rb_intern("div"));
     } else {    /* div in BigDecimal sense */
-       U_LONG ix = (U_LONG)GetPositiveInt(n);
-       if(ix==0) return BigDecimal_div(self, 0, b);
+       SIGNED_VALUE ix = GetPositiveInt(n);
+       if (ix == 0) return BigDecimal_div(self, b);
        else {
           Real *res=NULL;
           Real *av=NULL, *bv=NULL, *cv=NULL;
-          U_LONG mx = (ix+VpBaseFig()*2);
-          U_LONG pl = VpSetPrecLimit(0);
+          size_t mx = (ix+VpBaseFig()*2);
+          size_t pl = VpSetPrecLimit(0);
 
           GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
           GUARD_OBJ(av,GetVpValue(self,1));
@@ -1135,59 +1128,59 @@
           GUARD_OBJ(res,VpCreateRbObject((mx * 2  + 2)*VpBaseFig(), "#0"));
           VpDivd(cv,res,av,bv);
           VpSetPrecLimit(pl);
-          VpLeftRound(cv,VpGetRoundMode(),ix);
+          VpLeftRound(cv,(int)VpGetRoundMode(),ix);
           return ToValue(cv);
        }
     }
 }
 
 static VALUE
-BigDecimal_add2(VALUE self, SEL sel, VALUE b, VALUE n)
+BigDecimal_add2(VALUE self, VALUE b, VALUE n)
 {
     ENTER(2);
     Real   *cv;
-    U_LONG mx = (U_LONG)GetPositiveInt(n);
-    if(mx==0) return BigDecimal_add(self, 0, b);
+    SIGNED_VALUE mx = GetPositiveInt(n);
+    if (mx == 0) return BigDecimal_add(self, b);
     else {
-       U_LONG pl = VpSetPrecLimit(0);
-       VALUE   c = BigDecimal_add(self, 0, b);
+       size_t pl = VpSetPrecLimit(0);
+       VALUE   c = BigDecimal_add(self,b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv,GetVpValue(c,1));
-       VpLeftRound(cv,VpGetRoundMode(),mx);
+       VpLeftRound(cv,(int)VpGetRoundMode(),mx);
        return ToValue(cv);
     }
 }
 
 static VALUE
-BigDecimal_sub2(VALUE self, SEL sel, VALUE b, VALUE n)
+BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
 {
     ENTER(2);
     Real *cv;
-    U_LONG mx = (U_LONG)GetPositiveInt(n);
-    if(mx==0) return BigDecimal_sub(self, 0, b);
+    SIGNED_VALUE mx = GetPositiveInt(n);
+    if (mx == 0) return BigDecimal_sub(self, b);
     else {
-       U_LONG pl = VpSetPrecLimit(0);
-       VALUE   c = BigDecimal_sub(self, 0, b);
+       size_t pl = VpSetPrecLimit(0);
+       VALUE   c = BigDecimal_sub(self,b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv,GetVpValue(c,1));
-       VpLeftRound(cv,VpGetRoundMode(),mx);
+       VpLeftRound(cv,(int)VpGetRoundMode(),mx);
        return ToValue(cv);
     }
 }
 
 static VALUE
-BigDecimal_mult2(VALUE self, SEL sel, VALUE b, VALUE n)
+BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
 {
     ENTER(2);
     Real *cv;
-    U_LONG mx = (U_LONG)GetPositiveInt(n);
-    if(mx==0) return BigDecimal_mult(self, 0, b);
+    SIGNED_VALUE mx = GetPositiveInt(n);
+    if (mx == 0) return BigDecimal_mult(self, b);
     else {
-       U_LONG pl = VpSetPrecLimit(0);
-       VALUE   c = BigDecimal_mult(self, 0, b);
+       size_t pl = VpSetPrecLimit(0);
+       VALUE   c = BigDecimal_mult(self,b);
        VpSetPrecLimit(pl);
        GUARD_OBJ(cv,GetVpValue(c,1));
-       VpLeftRound(cv,VpGetRoundMode(),mx);
+       VpLeftRound(cv,(int)VpGetRoundMode(),mx);
        return ToValue(cv);
     }
 }
@@ -1199,17 +1192,17 @@
  * BigDecimal('-3').abs -> 3
  */
 static VALUE
-BigDecimal_abs(VALUE self, SEL sel)
+BigDecimal_abs(VALUE self)
 {
     ENTER(5);
     Real *c, *a;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     mx = a->Prec *(VpBaseFig() + 1);
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     VpAsgn(c, a, 1);
-    VpChangeSign(c,(S_INT)1);
+    VpChangeSign(c, 1);
     return ToValue(c);
 }
 
@@ -1221,11 +1214,11 @@
  * If n is specified, returns at least that many significant digits.
  */
 static VALUE
-BigDecimal_sqrt(VALUE self, SEL sel, VALUE nFig)
+BigDecimal_sqrt(VALUE self, VALUE nFig)
 {
     ENTER(5);
     Real *c, *a;
-    S_INT mx, n;
+    size_t mx, n;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     mx = a->Prec *(VpBaseFig() + 1);
@@ -1240,11 +1233,11 @@
 /* Return the integer part of the number.
  */
 static VALUE
-BigDecimal_fix(VALUE self, SEL sel)
+BigDecimal_fix(VALUE self)
 {
     ENTER(5);
     Real *c, *a;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     mx = a->Prec *(VpBaseFig() + 1);
@@ -1263,7 +1256,7 @@
  * BigDecimal('8.7').round -> 9
  *
  * If n is specified and positive, the fractional part of the result has no
- * more than that many digits. 
+ * more than that many digits.
  *
  * If n is specified and negative, at least that many digits to the left of the
  * decimal point will be 0 in the result.
@@ -1272,21 +1265,20 @@
  *
  * BigDecimal('13345.234').round(-2) -> 13300.0
  *
- * The value of the optional mode argument can be used to determine how 
+ * The value of the optional mode argument can be used to determine how
  * rounding is performed; see BigDecimal.mode.
  */
 static VALUE
-BigDecimal_round(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_round(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real   *c, *a;
     int    iLoc = 0;
-    U_LONG mx;
     VALUE  vLoc;
     VALUE  vRound;
-    U_LONG pl;
+    size_t mx, pl;
 
-    int    sw = VpGetRoundMode();
+    unsigned short sw = VpGetRoundMode();
 
     int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound);
     switch(na) {
@@ -1301,7 +1293,7 @@
         Check_Type(vLoc, T_FIXNUM);
         iLoc = FIX2INT(vLoc);
         Check_Type(vRound, T_FIXNUM);
-        sw   = FIX2INT(vRound);
+        sw   = (unsigned short)FIX2INT(vRound);
         if(!VpIsRoundMode(sw)) {
             rb_raise(rb_eTypeError, "invalid rounding mode");
             return Qnil;
@@ -1315,6 +1307,9 @@
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     VpSetPrecLimit(pl);
     VpActiveRound(c,a,sw,iLoc);
+    if (argc == 0) {
+	return BigDecimal_to_i(ToValue(c));
+    }
     return ToValue(c);
 }
 
@@ -1328,7 +1323,7 @@
  * BigDecimal('8.7').truncate -> 8
  *
  * If n is specified and positive, the fractional part of the result has no
- * more than that many digits. 
+ * more than that many digits.
  *
  * If n is specified and negative, at least that many digits to the left of the
  * decimal point will be 0 in the result.
@@ -1338,14 +1333,13 @@
  * BigDecimal('13345.234').truncate(-2) -> 13300.0
  */
 static VALUE
-BigDecimal_truncate(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real *c, *a;
     int iLoc;
-    U_LONG mx;
     VALUE vLoc;
-    U_LONG pl = VpSetPrecLimit(0);
+    size_t mx, pl = VpSetPrecLimit(0);
 
     if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
         iLoc = 0;
@@ -1359,17 +1353,20 @@
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     VpSetPrecLimit(pl);
     VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */
+    if (argc == 0) {
+	return BigDecimal_to_i(ToValue(c));
+    }
     return ToValue(c);
 }
 
 /* Return the fractional part of the number.
  */
 static VALUE
-BigDecimal_frac(VALUE self, SEL sel)
+BigDecimal_frac(VALUE self)
 {
     ENTER(5);
     Real *c, *a;
-    U_LONG mx;
+    size_t mx;
 
     GUARD_OBJ(a,GetVpValue(self,1));
     mx = a->Prec *(VpBaseFig() + 1);
@@ -1388,7 +1385,7 @@
  * BigDecimal('-9.1').floor -> -10
  *
  * If n is specified and positive, the fractional part of the result has no
- * more than that many digits.  
+ * more than that many digits.
  *
  * If n is specified and negative, at least that
  * many digits to the left of the decimal point will be 0 in the result.
@@ -1398,14 +1395,13 @@
  * BigDecimal('13345.234').floor(-2) -> 13300.0
  */
 static VALUE
-BigDecimal_floor(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_floor(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real *c, *a;
-    U_LONG mx;
     int iLoc;
     VALUE vLoc;
-    U_LONG pl = VpSetPrecLimit(0);
+    size_t mx, pl = VpSetPrecLimit(0);
 
     if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
         iLoc = 0;
@@ -1419,6 +1415,12 @@
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     VpSetPrecLimit(pl);
     VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
+#ifdef BIGDECIMAL_DEBUG
+    VPrint(stderr, "floor: c=%\n", c);
+#endif
+    if (argc == 0) {
+	return BigDecimal_to_i(ToValue(c));
+    }
     return ToValue(c);
 }
 
@@ -1432,7 +1434,7 @@
  * BigDecimal('-9.1').ceil -> -9
  *
  * If n is specified and positive, the fractional part of the result has no
- * more than that many digits.  
+ * more than that many digits.
  *
  * If n is specified and negative, at least that
  * many digits to the left of the decimal point will be 0 in the result.
@@ -1442,14 +1444,13 @@
  * BigDecimal('13345.234').ceil(-2) -> 13400.0
  */
 static VALUE
-BigDecimal_ceil(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real *c, *a;
-    U_LONG mx;
     int iLoc;
     VALUE vLoc;
-    U_LONG pl = VpSetPrecLimit(0);
+    size_t mx, pl = VpSetPrecLimit(0);
 
     if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
         iLoc = 0;
@@ -1463,6 +1464,9 @@
     GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
     VpSetPrecLimit(pl);
     VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
+    if (argc == 0) {
+	return BigDecimal_to_i(ToValue(c));
+    }
     return ToValue(c);
 }
 
@@ -1481,7 +1485,7 @@
  *
  * A space at the start of s returns positive values with a leading space.
  *
- * If s contains a number, a space is inserted after each group of that many 
+ * If s contains a number, a space is inserted after each group of that many
  * fractional digits.
  *
  * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
@@ -1497,20 +1501,20 @@
  * BigDecimal.new('123.45678901234567890').to_s(' F') -> ' 123.4567890123456789'
  */
 static VALUE
-BigDecimal_to_s(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     int   fmt=0;   /* 0:E format */
     int   fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
     Real  *vp;
+    volatile VALUE str;
     const char  *psz;
     char   ch;
-    U_LONG nc;
-    S_INT  mc = 0;
+    size_t nc, mc = 0;
     VALUE  f;
 
     GUARD_OBJ(vp,GetVpValue(self,1));
-    
+
     if(rb_scan_args(argc,argv,"01",&f)==1) {
         if(TYPE(f)==T_STRING) {
             SafeStringValue(f);
@@ -1528,9 +1532,10 @@
                 }
                 mc = mc * 10 + ch - '0';
             }
-        } else {
-            mc  = GetPositiveInt(f);
         }
+	else {
+            mc = (size_t)GetPositiveInt(f);
+        }
     }
     if(fmt) {
         nc = VpNumOfChars(vp,"F");
@@ -1539,14 +1544,16 @@
     }
     if(mc>0) nc += (nc + mc - 1) / mc + 1;
 
-    char *buf = ALLOCA_N(char,(unsigned int)nc);
+    str = rb_bstr_new_with_data(0, nc);
+    char *buf = (char *)rb_bstr_bytes(str);
 
     if(fmt) {
         VpToFString(vp, buf, mc, fPlus);
     } else {
         VpToString (vp, buf, mc, fPlus);
     }
-    return rb_str_new2(buf);
+    rb_bstr_resize(str, strlen(buf));
+    return str;
 }
 
 /* Splits a BigDecimal number into four parts, returned as an array of values.
@@ -1562,7 +1569,7 @@
  *
  * The fourth value is an Integer exponent.
  *
- * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the 
+ * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
  * string of significant digits with no leading zeros, and n is the exponent.
  *
  * From these values, you can translate a BigDecimal to a float as follows:
@@ -1570,32 +1577,36 @@
  *   sign, significant_digits, base, exponent = a.split
  *   f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
  *
- * (Note that the to_f method is provided as a more convenient way to translate 
+ * (Note that the to_f method is provided as a more convenient way to translate
  * a BigDecimal to a Float.)
  */
 static VALUE
-BigDecimal_split(VALUE self, SEL sel)
+BigDecimal_split(VALUE self)
 {
     ENTER(5);
     Real *vp;
-    VALUE obj,obj1;
-    S_LONG e;
-    S_LONG s;
+    VALUE obj,str;
+    ssize_t e, s;
     char *psz1;
 
     GUARD_OBJ(vp,GetVpValue(self,1));
-    psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
+    str = rb_bstr_new_with_data(0, VpNumOfChars(vp,"E"));
+    psz1 = (char *)rb_bstr_bytes(str);
     VpSzMantissa(vp,psz1);
     s = 1;
     if(psz1[0]=='-') {
-        s = -1; ++psz1;
+	size_t len = strlen(psz1+1);
+
+	memmove(psz1, psz1+1, len);
+	psz1[len] = '\0';
+        s = -1;
     }
     if(psz1[0]=='N') s=0; /* NaN */
     e = VpExponent10(vp);
-    obj1 = rb_str_new2(psz1);
     obj  = rb_ary_new2(4);
     rb_ary_push(obj, INT2FIX(s));
-    rb_ary_push(obj, obj1);
+    rb_bstr_resize(str, strlen(psz1));
+    rb_ary_push(obj, str);
     rb_ary_push(obj, INT2FIX(10));
     rb_ary_push(obj, INT2NUM(e));
     return obj;
@@ -1607,9 +1618,9 @@
  * of digits with no leading zeros, then n is the exponent.
  */
 static VALUE
-BigDecimal_exponent(VALUE self, SEL sel)
+BigDecimal_exponent(VALUE self)
 {
-    S_LONG e = VpExponent10(GetVpValue(self,1));
+    ssize_t e = VpExponent10(GetVpValue(self, 1));
     return INT2NUM(e);
 }
 
@@ -1624,24 +1635,26 @@
  * maximum number of significant digits, respectively.
  */
 static VALUE
-BigDecimal_inspect(VALUE self, SEL sel)
+BigDecimal_inspect(VALUE self)
 {
     ENTER(5);
     Real *vp;
-    VALUE obj;
-    unsigned int nc;
-    char *psz1;
-    char *pszAll;
+    volatile VALUE obj;
+    size_t nc;
+    char *psz, *tmp;
 
     GUARD_OBJ(vp,GetVpValue(self,1));
     nc = VpNumOfChars(vp,"E");
     nc +=(nc + 9) / 10;
 
-    psz1   = ALLOCA_N(char,nc);
-    pszAll = ALLOCA_N(char,nc+256);
-    VpToString(vp, psz1, 10, 0);
-    sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
-    obj = rb_str_new2(pszAll);
+    obj = rb_bstr_new_with_data(0, nc+256);
+    psz = (char *)rb_bstr_bytes(obj);
+    snprintf(psz,nc+256,"#<BigDecimal:%p,'",(void *)self);
+    tmp = psz + strlen(psz);
+    VpToString(vp, tmp, 10, 0);
+    tmp += strlen(tmp);
+    sprintf(tmp, "',%ld(%ld)>", VpPrec(vp)*VpBaseFig(), VpMaxPrec(vp)*VpBaseFig());
+    rb_bstr_resize(obj, strlen(psz));
     return obj;
 }
 
@@ -1653,42 +1666,44 @@
  * Also available as the operator **
  */
 static VALUE
-BigDecimal_power(VALUE self, SEL sel, VALUE p)
+BigDecimal_power(VALUE self, VALUE p)
 {
     ENTER(5);
     Real *x, *y;
-    S_LONG mp, ma, n;
+    ssize_t mp, ma;
+    SIGNED_VALUE n;
 
     Check_Type(p, T_FIXNUM);
     n = FIX2INT(p);
     ma = n;
-    if(ma < 0)  ma = -ma;
-    if(ma == 0) ma = 1;
+    if (ma < 0)  ma = -ma;
+    if (ma == 0) ma = 1;
 
-    GUARD_OBJ(x,GetVpValue(self,1));
-    if(VpIsDef(x)) {
-        mp = x->Prec *(VpBaseFig() + 1);
-        GUARD_OBJ(y,VpCreateRbObject(mp *(ma + 1), "0"));
-    } else {
-        GUARD_OBJ(y,VpCreateRbObject(1, "0"));
+    GUARD_OBJ(x, GetVpValue(self, 1));
+    if (VpIsDef(x)) {
+        mp = x->Prec * (VpBaseFig() + 1);
+        GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
     }
+    else {
+        GUARD_OBJ(y, VpCreateRbObject(1, "0"));
+    }
     VpPower(y, x, n);
     return ToValue(y);
 }
 
 static VALUE
-BigDecimal_global_new(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real *pv;
-    S_LONG mf;
+    size_t mf;
     VALUE  nFig;
     VALUE  iniValue;
 
     if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
-        mf = 0;
+	mf = 0;
     } else {
-        mf = GetPositiveInt(nFig);
+	mf = GetPositiveInt(nFig);
     }
     SafeStringValue(iniValue);
     GUARD_OBJ(pv,VpCreateRbObject(mf, RSTRING_PTR(iniValue)));
@@ -1708,11 +1723,11 @@
   * larger than the specified number.
   */
 static VALUE
-BigDecimal_new(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_new(int argc, VALUE *argv, VALUE self)
 {
     ENTER(5);
     Real *pv;
-    S_LONG mf;
+    size_t mf;
     VALUE  nFig;
     VALUE  iniValue;
 
@@ -1729,17 +1744,17 @@
  /* call-seq:
   * BigDecimal.limit(digits)
   *
-  * Limit the number of significant digits in newly created BigDecimal 
-  * numbers to the specified value. Rounding is performed as necessary, 
+  * Limit the number of significant digits in newly created BigDecimal
+  * numbers to the specified value. Rounding is performed as necessary,
   * as specified by BigDecimal.mode.
   *
   * A limit of 0, the default, means no upper limit.
   *
-  * The limit specified by this method takes priority over any limit 
+  * The limit specified by this method takes less priority over any limit
   * specified to instance methods such as ceil, floor, truncate, or round.
   */
 static VALUE
-BigDecimal_limit(VALUE self, SEL sel, int argc, VALUE *argv)
+BigDecimal_limit(int argc, VALUE *argv, VALUE self)
 {
     VALUE  nFig;
     VALUE  nCur = INT2NUM(VpGetPrecLimit());
@@ -1759,10 +1774,10 @@
 
 /* Returns the sign of the value.
  *
- * Returns a positive value if > 0, a negative value if < 0, and a 
+ * Returns a positive value if > 0, a negative value if < 0, and a
  * zero if == 0.
  *
- * The specific value returned indicates the type and sign of the BigDecimal, 
+ * The specific value returned indicates the type and sign of the BigDecimal,
  * as follows:
  *
  * BigDecimal::SIGN_NaN:: value is Not a Number
@@ -1774,83 +1789,238 @@
  * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
  */
 static VALUE
-BigDecimal_sign(VALUE self, SEL sel)
+BigDecimal_sign(VALUE self)
 { /* sign */
     int s = GetVpValue(self,1)->sign;
     return INT2FIX(s);
 }
 
+/* call-seq:
+ * BigDecimal.save_exception_mode { ... }
+ */
+static VALUE
+BigDecimal_save_exception_mode(VALUE self)
+{
+    unsigned short const exception_mode = VpGetException();
+    int state;
+    VALUE ret = rb_protect(rb_yield, Qnil, &state);
+    VpSetException(exception_mode);
+    if (state) rb_jump_tag(state);
+    return ret;
+}
+
+/* call-seq:
+ * BigDecimal.save_rounding_mode { ... }
+ */
+static VALUE
+BigDecimal_save_rounding_mode(VALUE self)
+{
+    unsigned short const round_mode = VpGetRoundMode();
+    int state;
+    /*VALUE ret =*/ rb_protect(rb_yield, Qnil, &state);
+    VpSetRoundMode(round_mode);
+    if (state) rb_jump_tag(state);
+    return Qnil;
+}
+
+/* call-seq:
+ * BigDecimal.save_limit { ... }
+ */
+static VALUE
+BigDecimal_save_limit(VALUE self)
+{
+    size_t const limit = VpGetPrecLimit();
+    int state;
+    /*VALUE ret =*/ rb_protect(rb_yield, Qnil, &state);
+    VpSetPrecLimit(limit);
+    if (state) rb_jump_tag(state);
+    return Qnil;
+}
+
+/* Document-class: BigDecimal
+ * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
+ *
+ * Copyright (C) 2002 by Shigeo Kobayashi <shigeo at tinyforest.gr.jp>.
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file
+ * of the BigDecimal distribution.
+ *
+ * Documented by mathew <meta at pobox.com>.
+ *
+ * = Introduction
+ *
+ * Ruby provides built-in support for arbitrary precision integer arithmetic.
+ * For example:
+ *
+ * 42**13   ->   1265437718438866624512
+ *
+ * BigDecimal provides similar support for very large or very accurate floating
+ * point numbers.
+ *
+ * Decimal arithmetic is also useful for general calculation, because it
+ * provides the correct answers people expect--whereas normal binary floating
+ * point arithmetic often introduces subtle errors because of the conversion
+ * between base 10 and base 2. For example, try:
+ *
+ *   sum = 0
+ *   for i in (1..10000)
+ *     sum = sum + 0.0001
+ *   end
+ *   print sum
+ *
+ * and contrast with the output from:
+ *
+ *   require 'bigdecimal'
+ *
+ *   sum = BigDecimal.new("0")
+ *   for i in (1..10000)
+ *     sum = sum + BigDecimal.new("0.0001")
+ *   end
+ *   print sum
+ *
+ * Similarly:
+ *
+ * (BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") -> true
+ *
+ * (1.2 - 1.0) == 0.2 -> false
+ *
+ * = Special features of accurate decimal arithmetic
+ *
+ * Because BigDecimal is more accurate than normal binary floating point
+ * arithmetic, it requires some special values.
+ *
+ * == Infinity
+ *
+ * BigDecimal sometimes needs to return infinity, for example if you divide
+ * a value by zero.
+ *
+ * BigDecimal.new("1.0") / BigDecimal.new("0.0")  -> infinity
+ *
+ * BigDecimal.new("-1.0") / BigDecimal.new("0.0")  -> -infinity
+ *
+ * You can represent infinite numbers to BigDecimal using the strings
+ * 'Infinity', '+Infinity' and '-Infinity' (case-sensitive)
+ *
+ * == Not a Number
+ *
+ * When a computation results in an undefined value, the special value NaN
+ * (for 'not a number') is returned.
+ *
+ * Example:
+ *
+ * BigDecimal.new("0.0") / BigDecimal.new("0.0") -> NaN
+ *
+ * You can also create undefined values.  NaN is never considered to be the
+ * same as any other value, even NaN itself:
+ *
+ * n = BigDecimal.new('NaN')
+ *
+ * n == 0.0 -> nil
+ *
+ * n == n -> nil
+ *
+ * == Positive and negative zero
+ *
+ * If a computation results in a value which is too small to be represented as
+ * a BigDecimal within the currently specified limits of precision, zero must
+ * be returned.
+ *
+ * If the value which is too small to be represented is negative, a BigDecimal
+ * value of negative zero is returned. If the value is positive, a value of
+ * positive zero is returned.
+ *
+ * BigDecimal.new("1.0") / BigDecimal.new("-Infinity") -> -0.0
+ *
+ * BigDecimal.new("1.0") / BigDecimal.new("Infinity") -> 0.0
+ *
+ * (See BigDecimal.mode for how to specify limits of precision.)
+ *
+ * Note that -0.0 and 0.0 are considered to be the same for the purposes of
+ * comparison.
+ *
+ * Note also that in mathematics, there is no particular concept of negative
+ * or positive zero; true mathematical zero has no sign.
+ */
 void
 Init_bigdecimal(void)
 {
+    VALUE arg;
+
+    id_BigDecimal_exception_mode = rb_intern("BigDecimal.exception_mode");
+    id_BigDecimal_rounding_mode = rb_intern("BigDecimal.rounding_mode");
+    id_BigDecimal_precision_limit = rb_intern("BigDecimal.precision_limit");
+
     /* Initialize VP routines */
-    VpInit((U_LONG)0);
+    VpInit(0UL);
 
     /* Class and method registration */
     rb_cBigDecimal = rb_define_class("BigDecimal",rb_cNumeric);
 
     /* Global function */
-    rb_objc_define_module_function(rb_mKernel, "BigDecimal", BigDecimal_global_new, -1);
+    rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
 
     /* Class methods */
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "new", BigDecimal_new, -1);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "mode", BigDecimal_mode, -1);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "limit", BigDecimal_limit, -1);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "_load", BigDecimal_load, 1);
-    rb_objc_define_method(*(VALUE *)rb_cBigDecimal, "ver", BigDecimal_version, 0);
+    rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1);
+    rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
+    rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
+    rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
+    rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
+    rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);
 
+    rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
+    rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
+    rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0);
+
     /* Constants definition */
 
-    /* 
-     * Base value used in internal calculations.  On a 32 bit system, BASE 
-     * is 10000, indicating that calculation is done in groups of 4 digits.  
+    /*
+     * Base value used in internal calculations.  On a 32 bit system, BASE
+     * is 10000, indicating that calculation is done in groups of 4 digits.
      * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
-     * guarantee that two groups could always be multiplied together without 
-     * overflow.) 
+     * guarantee that two groups could always be multiplied together without
+     * overflow.)
      */
-    rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal()));
+    rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
 
     /* Exceptions */
 
     /*
-     * 0xff: Determines whether overflow, underflow or zero divide result in 
+     * 0xff: Determines whether overflow, underflow or zero divide result in
      * an exception being thrown. See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL));
 
-    /* 
-     * 0x02: Determines what happens when the result of a computation is not a 
-     * number (NaN). See BigDecimal.mode. 
+    /*
+     * 0x02: Determines what happens when the result of a computation is not a
+     * number (NaN). See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));
 
-    /* 
+    /*
      * 0x01: Determines what happens when the result of a computation is
      * infinity.  See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY));
 
-    /* 
+    /*
      * 0x04: Determines what happens when the result of a computation is an
      * underflow (a result too small to be represented). See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW));
 
-    /* 
+    /*
      * 0x01: Determines what happens when the result of a computation is an
-     * underflow (a result too large to be represented). See BigDecimal.mode.
+     * overflow (a result too large to be represented). See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
 
-    /* 
+    /*
      * 0x01: Determines what happens when a division by zero is performed.
      * See BigDecimal.mode.
      */
     rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));
 
-    /* 
+    /*
      * 0x100: Determines what happens when a result must be rounded in order to
      * fit in the appropriate number of significant digits. See
      * BigDecimal.mode.
@@ -1905,59 +2075,66 @@
     /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
     rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
 
+    arg = rb_str_new2("+Infinity");
+    rb_define_const(rb_cBigDecimal, "INFINITY", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
+    arg = rb_str_new2("NaN");
+    rb_define_const(rb_cBigDecimal, "NAN", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
+
+
     /* instance methods */
-    rb_objc_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
+    rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
 
-    rb_objc_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
-    rb_objc_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
-    rb_objc_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
-    rb_objc_define_method(rb_cBigDecimal, "div", BigDecimal_div2, -1);
-    rb_objc_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
-    rb_objc_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
-    rb_objc_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
-    rb_objc_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
-    rb_objc_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
-    rb_objc_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
-    rb_objc_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
-    rb_objc_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
-    rb_objc_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
-    rb_objc_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
-    rb_objc_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
-    rb_objc_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
-    rb_objc_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
-    rb_objc_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
-    rb_objc_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
-    rb_objc_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
+    rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
+    rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
+    rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
+    rb_define_method(rb_cBigDecimal, "div", BigDecimal_div2, -1);
+    rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
+    rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
+    rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
+    rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
+    rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0);
+    rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
+    rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
+    rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
+    rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
+    rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
+    rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
+    rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
+    rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
+    rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
+    rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
+    rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
+    rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
     /* rb_define_method(rb_cBigDecimal, "dup", BigDecimal_dup, 0); */
-    rb_objc_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
-    rb_objc_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
-    rb_objc_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
-    rb_objc_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
-    rb_objc_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
-    rb_objc_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
-    rb_objc_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
-    rb_objc_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
-    rb_objc_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1);
-    rb_objc_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1);
-    rb_objc_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
-    rb_objc_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
-    rb_objc_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
-    rb_objc_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
-    rb_objc_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
-    rb_objc_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
-    rb_objc_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
-    rb_objc_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
-    rb_objc_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
-    rb_objc_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
-    rb_objc_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
-    rb_objc_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
-    rb_objc_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
-    rb_objc_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
-    rb_objc_define_method(rb_cBigDecimal, "nan?",      BigDecimal_IsNaN, 0);
-    rb_objc_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
-    rb_objc_define_method(rb_cBigDecimal, "finite?",   BigDecimal_IsFinite, 0);
-    rb_objc_define_method(rb_cBigDecimal, "truncate",  BigDecimal_truncate, -1);
-    rb_objc_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
+    rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
+    rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
+    rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
+    rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
+    rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
+    rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
+    rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
+    rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
+    rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1);
+    rb_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1);
+    rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
+    rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
+    rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
+    rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
+    rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
+    rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
+    rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
+    rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
+    rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
+    rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
+    rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
+    rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
+    rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
+    rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
+    rb_define_method(rb_cBigDecimal, "nan?",      BigDecimal_IsNaN, 0);
+    rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
+    rb_define_method(rb_cBigDecimal, "finite?",   BigDecimal_IsFinite, 0);
+    rb_define_method(rb_cBigDecimal, "truncate",  BigDecimal_truncate, -1);
+    rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
 }
 
 /*
@@ -1969,31 +2146,12 @@
  *  ============================================================================
  *
  */
-#ifdef _DEBUG
-/*static int gfDebug = 1;*/         /* Debug switch */
+#ifdef BIGDECIMAL_DEBUG
+static int gfDebug = 1;         /* Debug switch */
+#if 0
 static int gfCheckVal = 1;      /* Value checking flag in VpNmlz()  */
-#endif /* _DEBUG */
-
-static U_LONG gnPrecLimit = 0;  /* Global upper limit of the precision newly allocated */
-static U_LONG gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation   */
-
-#ifndef BASE_FIG
-static U_LONG BASE_FIG = 4;     /* =log10(BASE)  */
-static U_LONG BASE = 10000L;    /* Base value(value must be 10**BASE_FIG) */
-                /* The value of BASE**2 + BASE must be represented */
-                /* within one U_LONG. */
-static U_LONG HALF_BASE = 5000L;/* =BASE/2  */
-static U_LONG BASE1 = 1000L;    /* =BASE/10  */
-#else
-#ifndef BASE
-#error BASE_FIG is defined but BASE is not
 #endif
-#define HALF_BASE (BASE/2)
-#define BASE1 (BASE/10)
-#endif
-#ifndef DBLE_FIG
-#define DBLE_FIG (DBL_DIG+1)    /* figure of double */
-#endif
+#endif /* BIGDECIMAL_DEBUG */
 
 static Real *VpConstOne;    /* constant 1.0 */
 static Real *VpPt5;        /* constant 0.5 */
@@ -2005,29 +2163,29 @@
 #define StrCmp(x,y)   strcmp(x,y)
 
 static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
-static int AddExponent(Real *a,S_INT n);
-static U_LONG VpAddAbs(Real *a,Real *b,Real *c);
-static U_LONG VpSubAbs(Real *a,Real *b,Real *c);
-static U_LONG VpSetPTR(Real *a,Real *b,Real *c,U_LONG *a_pos,U_LONG *b_pos,U_LONG *c_pos,U_LONG *av,U_LONG *bv);
+static int AddExponent(Real *a, SIGNED_VALUE n);
+static BDIGIT VpAddAbs(Real *a,Real *b,Real *c);
+static BDIGIT VpSubAbs(Real *a,Real *b,Real *c);
+static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv);
 static int VpNmlz(Real *a);
-static void VpFormatSt(char *psz,S_INT fFmt);
-static int VpRdup(Real *m,U_LONG ind_m);
+static void VpFormatSt(char *psz, size_t fFmt);
+static int VpRdup(Real *m, size_t ind_m);
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
 static int gnAlloc=0; /* Memory allocation counter */
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
 VP_EXPORT void *
-VpMemAlloc(U_LONG mb)
+VpMemAlloc(size_t mb)
 {
-    void *p = xmalloc(mb);
+    void *p = xmalloc((unsigned int)mb);
     if(!p) {
         VpException(VP_EXCEPTION_MEMORY,"failed to allocate memory",1);
     }
     memset(p,0,mb);
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     gnAlloc++; /* Count allocation call */
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return p;
 }
 
@@ -2036,7 +2194,7 @@
 {
     if(pv != NULL) {
         xfree(pv);
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
         gnAlloc--; /* Decrement allocation count */
         if(gnAlloc==0) {
             printf(" *************** All memories allocated freed ****************");
@@ -2046,64 +2204,134 @@
             printf(" ??????????? Too many memory free calls(%d) ?????????????\n",gnAlloc);
             getchar();
         }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     }
 }
 
 /*
  * EXCEPTION Handling.
  */
-static unsigned short gfDoException = 0; /* Exception flag */
 
+#define rmpd_set_thread_local_exception_mode(mode) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_exception_mode, \
+	INT2FIX((int)(mode)) \
+    )
+
 static unsigned short
 VpGetException (void)
 {
-    return gfDoException;
+    VALUE const vmode = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_exception_mode
+    );
+
+    if (NIL_P(vmode)) {
+	rmpd_set_thread_local_exception_mode(RMPD_EXCEPTION_MODE_DEFAULT);
+	return RMPD_EXCEPTION_MODE_DEFAULT;
+    }
+
+    return (unsigned short)FIX2UINT(vmode);
 }
 
 static void
 VpSetException(unsigned short f)
 {
-    gfDoException = f;
+    rmpd_set_thread_local_exception_mode(f);
 }
 
+/*
+ * Precision limit.
+ */
+
+#define rmpd_set_thread_local_precision_limit(limit) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_precision_limit, \
+	SIZET2NUM(limit) \
+    )
+#define RMPD_PRECISION_LIMIT_DEFAULT ((size_t)0)
+
 /* These 2 functions added at v1.1.7 */
-VP_EXPORT U_LONG
+VP_EXPORT size_t
 VpGetPrecLimit(void)
 {
-    return gnPrecLimit;
+    VALUE const vlimit = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_precision_limit
+    );
+
+    if (NIL_P(vlimit)) {
+	rmpd_set_thread_local_precision_limit(RMPD_PRECISION_LIMIT_DEFAULT);
+	return RMPD_PRECISION_LIMIT_DEFAULT;
+    }
+
+    return NUM2SIZET(vlimit);
 }
 
-VP_EXPORT U_LONG
-VpSetPrecLimit(U_LONG n)
+VP_EXPORT size_t
+VpSetPrecLimit(size_t n)
 {
-    U_LONG s = gnPrecLimit;
-    gnPrecLimit = n;
+    size_t const s = VpGetPrecLimit();
+    rmpd_set_thread_local_precision_limit(n);
     return s;
 }
 
-VP_EXPORT unsigned long
+/*
+ * Rounding mode.
+ */
+
+#define rmpd_set_thread_local_rounding_mode(mode) \
+    rb_thread_local_aset( \
+	rb_thread_current(), \
+	id_BigDecimal_rounding_mode, \
+	INT2FIX((int)(mode)) \
+    )
+
+VP_EXPORT unsigned short
 VpGetRoundMode(void)
 {
-    return gfRoundMode;
+    VALUE const vmode = rb_thread_local_aref(
+	rb_thread_current(),
+	id_BigDecimal_rounding_mode
+    );
+
+    if (NIL_P(vmode)) {
+	rmpd_set_thread_local_rounding_mode(RMPD_ROUNDING_MODE_DEFAULT);
+	return RMPD_ROUNDING_MODE_DEFAULT;
+    }
+
+    return (unsigned short)FIX2INT(vmode);
 }
 
 VP_EXPORT int
-VpIsRoundMode(unsigned long n)
+VpIsRoundMode(unsigned short n)
 {
-    if(n==VP_ROUND_UP      || n!=VP_ROUND_DOWN      ||
-       n==VP_ROUND_HALF_UP || n!=VP_ROUND_HALF_DOWN ||
-       n==VP_ROUND_CEIL    || n!=VP_ROUND_FLOOR     ||
-       n==VP_ROUND_HALF_EVEN
-      ) return 1;
-    return 0;
+    switch (n) {
+      case VP_ROUND_UP:
+      case VP_ROUND_DOWN:
+      case VP_ROUND_HALF_UP:
+      case VP_ROUND_HALF_DOWN:
+      case VP_ROUND_CEIL:
+      case VP_ROUND_FLOOR:
+      case VP_ROUND_HALF_EVEN:
+	return 1;
+
+      default:
+	return 0;
+    }
 }
 
-VP_EXPORT unsigned long
-VpSetRoundMode(unsigned long n)
+VP_EXPORT unsigned short
+VpSetRoundMode(unsigned short n)
 {
-    if(VpIsRoundMode(n)) gfRoundMode = n;
-    return gfRoundMode;
+    if (VpIsRoundMode(n)) {
+	rmpd_set_thread_local_rounding_mode(n);
+	return n;
+    }
+
+    return VpGetRoundMode();
 }
 
 /*
@@ -2128,24 +2356,6 @@
     return gOne_ABCED9B4_CE73__00400511F31D;
 }
 
-VP_EXPORT U_LONG
-VpBaseFig(void)
-{
-    return BASE_FIG;
-}
-
-VP_EXPORT U_LONG
-VpDblFig(void)
-{
-    return DBLE_FIG;
-}
-
-VP_EXPORT U_LONG
-VpBaseVal(void)
-{
-    return BASE;
-}
-
 /*
   ----------------------------------------------------------------
   Value of sign in Real structure is reserved for future use.
@@ -2192,7 +2402,7 @@
     return nzero;
 }
 
-#if 0
+#if 0  /* unused */
 VP_EXPORT int
 VpIsNegDoubleZero(double v)
 {
@@ -2206,25 +2416,20 @@
 {
     VALUE exc;
     int   fatal=0;
+    unsigned short const exception_mode = VpGetException();
 
     if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1;
 
-    if(always||(gfDoException&f)) {
+    if (always || (exception_mode & f)) {
         switch(f)
         {
         /*
-        case VP_EXCEPTION_ZERODIVIDE:
         case VP_EXCEPTION_OVERFLOW:
         */
+        case VP_EXCEPTION_ZERODIVIDE:
         case VP_EXCEPTION_INFINITY:
-             exc = rb_eFloatDomainError;
-             goto raise;
         case VP_EXCEPTION_NaN:
-             exc = rb_eFloatDomainError;
-             goto raise;
         case VP_EXCEPTION_UNDERFLOW:
-             exc = rb_eFloatDomainError;
-             goto raise;
         case VP_EXCEPTION_OP:
              exc = rb_eFloatDomainError;
              goto raise;
@@ -2343,11 +2548,11 @@
 /*
  *    returns number of chars needed to represent vp in specified format.
  */
-VP_EXPORT U_LONG
+VP_EXPORT size_t
 VpNumOfChars(Real *vp,const char *pszFmt)
 {
-    S_INT  ex;
-    U_LONG nc;
+    SIGNED_VALUE  ex;
+    size_t nc;
 
     if(vp == NULL)   return BASE_FIG*2+6;
     if(!VpIsDef(vp)) return 32; /* not sure,may be OK */
@@ -2357,11 +2562,12 @@
     case 'F':
          nc = BASE_FIG*(vp->Prec + 1)+2;
          ex = vp->exponent;
-         if(ex<0) {
-             nc += BASE_FIG*(-ex);
-         } else {
-             if(ex > (S_INT)vp->Prec) {
-                 nc += BASE_FIG*(ex - (S_INT)vp->Prec);
+         if(ex < 0) {
+             nc += BASE_FIG*(size_t)(-ex);
+         }
+	 else {
+             if((size_t)ex > vp->Prec) {
+                 nc += BASE_FIG*((size_t)ex - vp->Prec);
              }
          }
          break;
@@ -2381,13 +2587,13 @@
  *   that BASE is as large as possible satisfying the
  *   relation MaxVal <= BASE*(BASE+1). Where the value
  *   MaxVal is the largest value which can be represented
- *   by one U_LONG word(LONG) in the computer used.
+ *   by one BDIGIT word in the computer used.
  *
  * [Returns]
- * DBLE_FIG   ... OK
+ * 1+DBL_DIG   ... OK
  */
-VP_EXPORT U_LONG
-VpInit(U_LONG BaseVal)
+VP_EXPORT size_t
+VpInit(BDIGIT BaseVal)
 {
     /* Setup +/- Inf  NaN -0 */
     VpGetDoubleNaN();
@@ -2395,47 +2601,28 @@
     VpGetDoubleNegInf();
     VpGetDoubleNegZero();
 
-#ifndef BASE_FIG
-    if(BaseVal <= 0) {
-        U_LONG w;
-        /* Base <= 0, then determine Base by calcuration. */
-        BASE = 1;
-        while(
-               (BASE > 0) &&
-               ((w = BASE *(BASE + 1)) > BASE) &&((w / BASE) ==(BASE + 1))
-            ) {
-            BaseVal = BASE;
-            BASE = BaseVal * 10L;
-        }
-    }
-    /* Set Base Values */
-    BASE = BaseVal;
-    HALF_BASE = BASE / 2;
-    BASE1 = BASE / 10;
-    BASE_FIG = 0;
-    while(BaseVal /= 10) ++BASE_FIG;
-#endif
-
     /* Allocates Vp constants. */
-    VpConstOne = VpAlloc((U_LONG)1, "1");
-    VpPt5 = VpAlloc((U_LONG)1, ".5");
+    VpConstOne = VpAlloc(1UL, "1");
+    VpPt5 = VpAlloc(1UL, ".5");
+    GC_RETAIN(VpConstOne);
+    GC_RETAIN(VpPt5);
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     gnAlloc = 0;
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         printf("VpInit: BaseVal   = %lu\n", BaseVal);
         printf("  BASE   = %lu\n", BASE);
         printf("  HALF_BASE = %lu\n", HALF_BASE);
         printf("  BASE1  = %lu\n", BASE1);
-        printf("  BASE_FIG  = %lu\n", BASE_FIG);
-        printf("  DBLE_FIG  = %lu\n", DBLE_FIG);
+        printf("  BASE_FIG  = %u\n", BASE_FIG);
+        printf("  DBLE_FIG  = %d\n", DBLE_FIG);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
-    return DBLE_FIG;
+    return rmpd_double_figures();
 }
 
 VP_EXPORT Real *
@@ -2446,20 +2633,20 @@
 
 /* If exponent overflows,then raise exception or returns 0 */
 static int
-AddExponent(Real *a,S_INT n)
+AddExponent(Real *a, SIGNED_VALUE n)
 {
-    S_INT e = a->exponent;
-    S_INT m = e+n;
-    S_INT eb,mb;
+    SIGNED_VALUE e = a->exponent;
+    SIGNED_VALUE m = e+n;
+    SIGNED_VALUE eb, mb;
     if(e>0) {
         if(n>0) {
-            mb = m*BASE_FIG;
-            eb = e*BASE_FIG;
+            mb = m*(SIGNED_VALUE)BASE_FIG;
+            eb = e*(SIGNED_VALUE)BASE_FIG;
             if(mb<eb) goto overflow;
         }
     } else if(n<0) {
-        mb = m*BASE_FIG;
-        eb = e*BASE_FIG;
+        mb = m*(SIGNED_VALUE)BASE_FIG;
+        eb = e*(SIGNED_VALUE)BASE_FIG;
         if(mb>eb) goto underflow;
     }
     a->exponent = m;
@@ -2489,32 +2676,34 @@
  *   NULL be returned if memory allocation is failed,or any error.
  */
 VP_EXPORT Real *
-VpAlloc(U_LONG mx, const char *szVal)
+VpAlloc(size_t mx, const char *szVal)
 {
-    U_LONG i, ni, ipn, ipf, nf, ipe, ne, nalloc;
+    size_t i, ni, ipn, ipf, nf, ipe, ne, nalloc;
     char v,*psz;
     int  sign=1;
     Real *vp = NULL;
-    U_LONG mf = VpGetPrecLimit();
+    size_t mf = VpGetPrecLimit();
 
     mx = (mx + BASE_FIG - 1) / BASE_FIG + 1;    /* Determine allocation unit. */
-    if(szVal) {
-        while(ISSPACE(*szVal)) szVal++;
-        if(*szVal!='#') {
-             if(mf) {
+    if (szVal) {
+        while (ISSPACE(*szVal)) szVal++;
+        if (*szVal != '#') {
+             if (mf) {
                 mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
-                if(mx>mf) {
+                if (mx > mf) {
                     mx = mf;
                 }
             }
-        } else {
+        }
+	else {
             ++szVal;
         }
-    } else {
+    }
+    else {
        /* necessary to be able to store */
        /* at least mx digits. */
        /* szVal==NULL ==> allocate zero value. */
-       vp = (Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
+       vp = (Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(BDIGIT));
        /* xmalloc() alway returns(or throw interruption) */
        vp->MaxPrec = mx;    /* set max precision */
        VpSetZero(vp,1);    /* initialize vp to zero. */
@@ -2523,41 +2712,42 @@
 
     /* Skip all '_' after digit: 2006-6-30 */
     ni = 0;
-    psz = (char *)xmalloc(strlen(szVal)+1);
+    psz = xmalloc(strlen(szVal) + 1);
     i   = 0;
     ipn = 0;
-    while((psz[i]=szVal[ipn])!=0) {
-        if(ISDIGIT(psz[i])) ++ni;
-        if(psz[i]=='_') {
-            if(ni>0) {ipn++;continue;}
-            psz[i]=0;
+    while ((psz[i]=szVal[ipn]) != 0) {
+        if (ISDIGIT(psz[i])) ++ni;
+        if (psz[i] == '_') {
+            if (ni > 0) { ipn++; continue; }
+            psz[i] = 0;
             break;
         }
-        ++i; ++ipn;
+        ++i;
+	++ipn;
     }
     /* Skip trailing spaces */
-    while((--i)>0) {
-        if(ISSPACE(psz[i])) psz[i] = 0;
-        else                break;
+    while (--i > 0) {
+        if (ISSPACE(psz[i])) psz[i] = 0;
+        else break;
     }
     szVal = psz;
 
     /* Check on Inf & NaN */
-    if(StrCmp(szVal,SZ_PINF)==0 ||
-       StrCmp(szVal,SZ_INF)==0 ) {
-        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
+    if (StrCmp(szVal, SZ_PINF) == 0 ||
+        StrCmp(szVal, SZ_INF)  == 0 ) {
+        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(BDIGIT));
         vp->MaxPrec = 1;    /* set max precision */
         VpSetPosInf(vp);
         return vp;
     }
-    if(StrCmp(szVal,SZ_NINF)==0) {
-        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
+    if (StrCmp(szVal, SZ_NINF) == 0) {
+        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(BDIGIT));
         vp->MaxPrec = 1;    /* set max precision */
         VpSetNegInf(vp);
         return vp;
     }
-    if(StrCmp(szVal,SZ_NaN)==0) {
-        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
+    if (StrCmp(szVal, SZ_NaN) == 0) {
+        vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(BDIGIT));
         vp->MaxPrec = 1;    /* set max precision */
         VpSetNaN(vp);
         return vp;
@@ -2565,12 +2755,12 @@
 
     /* check on number szVal[] */
     ipn = i = 0;
-    if     (szVal[i] == '-') {sign=-1;++i;}
-    else if(szVal[i] == '+')          ++i;
+    if      (szVal[i] == '-') { sign=-1; ++i; }
+    else if (szVal[i] == '+')            ++i;
     /* Skip digits */
     ni = 0;            /* digits in mantissa */
-    while((v = szVal[i]) != 0) {
-        if(!ISDIGIT(v)) break;
+    while ((v = szVal[i]) != 0) {
+        if (!ISDIGIT(v)) break;
         ++i;
         ++ni;
     }
@@ -2578,31 +2768,30 @@
     ipf = 0;
     ipe = 0;
     ne  = 0;
-    if(v) {
+    if (v) {
         /* other than digit nor \0 */
-        if(szVal[i] == '.') {    /* xxx. */
+        if (szVal[i] == '.') {    /* xxx. */
             ++i;
             ipf = i;
-            while((v = szVal[i]) != 0) {    /* get fraction part. */
-                if(!ISDIGIT(v)) break;
+            while ((v = szVal[i]) != 0) {    /* get fraction part. */
+                if (!ISDIGIT(v)) break;
                 ++i;
                 ++nf;
             }
         }
         ipe = 0;        /* Exponent */
 
-        switch(szVal[i]) {
-        case '\0': break;
-        case 'e':
-        case 'E':
-        case 'd':
-        case 'D':
+        switch (szVal[i]) {
+        case '\0':
+	    break;
+        case 'e': case 'E':
+        case 'd': case 'D':
             ++i;
             ipe = i;
             v = szVal[i];
-            if((v == '-') ||(v == '+')) ++i;
-            while((v=szVal[i])!=0) {
-                if(!ISDIGIT(v)) break;
+            if ((v == '-') || (v == '+')) ++i;
+            while ((v=szVal[i]) != 0) {
+                if (!ISDIGIT(v)) break;
                 ++i;
                 ++ne;
             }
@@ -2611,16 +2800,16 @@
             break;
         }
     }
-    nalloc =(ni + nf + BASE_FIG - 1) / BASE_FIG + 1;    /* set effective allocation  */
+    nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1;    /* set effective allocation  */
     /* units for szVal[]  */
-    if(mx <= 0) mx = 1;
+    if (mx <= 0) mx = 1;
     nalloc = Max(nalloc, mx);
     mx = nalloc;
-    vp =(Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
+    vp = (Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(BDIGIT));
     /* xmalloc() alway returns(or throw interruption) */
     vp->MaxPrec = mx;        /* set max precision */
-    VpSetZero(vp,sign);
-    VpCtoV(vp, &(szVal[ipn]), ni, &(szVal[ipf]), nf, &(szVal[ipe]), ne);
+    VpSetZero(vp, sign);
+    VpCtoV(vp, &szVal[ipn], ni, &szVal[ipf], nf, &szVal[ipe], ne);
     return vp;
 }
 
@@ -2636,10 +2825,10 @@
  * [Output]
  *  c  ... LHSV
  */
-VP_EXPORT int
+VP_EXPORT size_t
 VpAsgn(Real *c, Real *a, int isw)
 {
-    U_LONG n;
+    size_t n;
     if(VpIsNaN(a)) {
         VpSetNaN(c);
         return 0;
@@ -2655,14 +2844,14 @@
         VpSetSign(c,(isw*VpGetSign(a)));    /* set sign */
         n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec);
         c->Prec = n;
-        memcpy(c->frac, a->frac, n * sizeof(U_LONG));
+        memcpy(c->frac, a->frac, n * sizeof(BDIGIT));
         /* Needs round ? */
         if(isw!=10) {
             /* Not in ActiveRound */
             if(c->Prec < a->Prec) {
-               VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
+		VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
             } else {
-               VpLimitRound(c,0);
+		VpLimitRound(c,0);
             }
         }
     } else {
@@ -2678,21 +2867,21 @@
  *  = a - b  when operation = -1 or -2.
  *   Returns number of significant digits of c
  */
-VP_EXPORT int
+VP_EXPORT size_t
 VpAddSub(Real *c, Real *a, Real *b, int operation)
 {
-    S_INT sw, isw;
+    short sw, isw;
     Real *a_ptr, *b_ptr;
-    U_LONG n, na, nb, i;
-    U_LONG mrv;
+    size_t n, na, nb, i;
+    BDIGIT mrv;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpAddSub(enter) a=% \n", a);
         VPrint(stdout, "     b=% \n", b);
         printf(" operation=%d\n", operation);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
     if(!VpIsDefOP(c,a,b,(operation>0)?1:2)) return 0; /* No significant digits */
 
@@ -2776,11 +2965,11 @@
      *              else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
     */
     if(isw) {            /* addition */
-        VpSetSign(c,(S_INT)1);
+        VpSetSign(c, 1);
         mrv = VpAddAbs(a_ptr, b_ptr, c);
-        VpSetSign(c,isw / 2);
+        VpSetSign(c, isw / 2);
     } else {            /* subtraction */
-        VpSetSign(c,(S_INT)1);
+        VpSetSign(c, 1);
         mrv = VpSubAbs(a_ptr, b_ptr, c);
         if(a_ptr == a) {
             VpSetSign(c,VpGetSign(a));
@@ -2790,14 +2979,14 @@
     }
     VpInternalRound(c,0,(c->Prec>0)?c->frac[c->Prec-1]:0,mrv);
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpAddSub(result) c=% \n", c);
         VPrint(stdout, "     a=% \n", a);
         VPrint(stdout, "     b=% \n", b);
         printf(" operation=%d\n", operation);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return c->Prec*BASE_FIG;
 }
 
@@ -2806,32 +2995,31 @@
  * a and b assuming abs(a)>abs(b).
  *   c = abs(a) + abs(b) ; where |a|>=|b|
  */
-static U_LONG
+static BDIGIT
 VpAddAbs(Real *a, Real *b, Real *c)
 {
-    U_LONG word_shift;
-    U_LONG carry;
-    U_LONG ap;
-    U_LONG bp;
-    U_LONG cp;
-    U_LONG a_pos;
-    U_LONG b_pos;
-    U_LONG c_pos;
-    U_LONG av, bv, mrv;
+    size_t word_shift;
+    size_t ap;
+    size_t bp;
+    size_t cp;
+    size_t a_pos;
+    size_t b_pos, b_pos_with_word_shift;
+    size_t c_pos;
+    BDIGIT av, bv, carry, mrv;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpAddAbs called: a = %\n", a);
         VPrint(stdout, "     b = %\n", b);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
     word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
     a_pos = ap;
     b_pos = bp;
     c_pos = cp;
-    if(word_shift==-1L) return 0; /* Overflow */
-    if(b_pos == -1L) goto Assign_a;
+    if(word_shift==(size_t)-1L) return 0; /* Overflow */
+    if(b_pos == (size_t)-1L) goto Assign_a;
 
     mrv = av + bv; /* Most right val. Used for round. */
 
@@ -2849,8 +3037,8 @@
 
     /* Just assign the last few digits of a to c because b has no */
     /* corresponding digits to be added. */
-    bv = b_pos + word_shift;
-    while(a_pos > bv) {
+    b_pos_with_word_shift = b_pos + word_shift;
+    while(a_pos > b_pos_with_word_shift) {
         c->frac[--c_pos] = a->frac[--a_pos];
     }
     carry = 0;    /* set first carry be zero */
@@ -2887,44 +3075,42 @@
 
 Exit:
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpAddAbs exit: c=% \n", c);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return mrv;
 }
 
 /*
  * c = abs(a) - abs(b)
  */
-static U_LONG
+static BDIGIT
 VpSubAbs(Real *a, Real *b, Real *c)
 {
-    U_LONG word_shift;
-    U_LONG mrv;
-    U_LONG borrow;
-    U_LONG ap;
-    U_LONG bp;
-    U_LONG cp;
-    U_LONG a_pos;
-    U_LONG b_pos;
-    U_LONG c_pos;
-    U_LONG av, bv;
+    size_t word_shift;
+    size_t ap;
+    size_t bp;
+    size_t cp;
+    size_t a_pos;
+    size_t b_pos, b_pos_with_word_shift;
+    size_t c_pos;
+    BDIGIT av, bv, borrow, mrv;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpSubAbs called: a = %\n", a);
         VPrint(stdout, "     b = %\n", b);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
     word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
     a_pos = ap;
     b_pos = bp;
     c_pos = cp;
-    if(word_shift==-1L) return 0; /* Overflow */
-    if(b_pos == -1L) goto Assign_a;
+    if(word_shift==(size_t)-1L) return 0; /* Overflow */
+    if(b_pos == (size_t)-1L) goto Assign_a;
 
     if(av >= bv) {
         mrv = av - bv;
@@ -2952,8 +3138,8 @@
     /* Just assign the last few digits of a to c because b has no */
     /* corresponding digits to subtract. */
 
-    bv = b_pos + word_shift;
-    while(a_pos > bv) {
+    b_pos_with_word_shift = b_pos + word_shift;
+    while(a_pos > b_pos_with_word_shift) {
         c->frac[--c_pos] = a->frac[--a_pos];
     }
 
@@ -2990,11 +3176,11 @@
     mrv = 0;
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpSubAbs exit: c=% \n", c);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return mrv;
 }
 
@@ -3012,10 +3198,10 @@
  *      b_pos      =     |
  *      c_pos      =      |
  */
-static U_LONG
-VpSetPTR(Real *a, Real *b, Real *c, U_LONG *a_pos, U_LONG *b_pos, U_LONG *c_pos, U_LONG *av, U_LONG *bv)
+static size_t
+VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv)
 {
-    U_LONG left_word, right_word, word_shift;
+    size_t left_word, right_word, word_shift;
     c->frac[0] = 0;
     *av = *bv = 0;
     word_shift =((a->exponent) -(b->exponent));
@@ -3088,7 +3274,7 @@
     }
     c->Prec = *c_pos;
     c->exponent = a->exponent;
-    if(!AddExponent(c,(S_LONG)1)) return (-1L);
+    if(!AddExponent(c,1)) return (size_t)-1L;
     return word_shift;
 }
 
@@ -3107,21 +3293,22 @@
  *     nc      <---|
  *     MaxAB |--------------------|
  */
-VP_EXPORT int
+VP_EXPORT size_t
 VpMult(Real *c, Real *a, Real *b)
 {
-    U_LONG MxIndA, MxIndB, MxIndAB, MxIndC;
-    U_LONG ind_c, i, ii, nc;
-    U_LONG ind_as, ind_ae, ind_bs, ind_be;
-    U_LONG Carry, s;
+    size_t MxIndA, MxIndB, MxIndAB, MxIndC;
+    size_t ind_c, i, ii, nc;
+    size_t ind_as, ind_ae, ind_bs, ind_be;
+    BDIGIT carry;
+    BDIGIT_DBL s;
     Real *w;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpMult(Enter): a=% \n", a);
         VPrint(stdout, "      b=% \n", b);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
 
     if(!VpIsDefOP(c,a,b,3)) return 0; /* No significant digit */
 
@@ -3153,18 +3340,21 @@
 
     if(MxIndC < MxIndAB) {    /* The Max. prec. of c < Prec(a)+Prec(b) */
         w = c;
-        c = VpAlloc((U_LONG)((MxIndAB + 1) * BASE_FIG), "#0");
+        c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0");
         MxIndC = MxIndAB;
     }
 
     /* set LHSV c info */
 
     c->exponent = a->exponent;    /* set exponent */
-    if(!AddExponent(c,b->exponent)) return 0;
+    if(!AddExponent(c,b->exponent)) {
+	if(w) VpFree(c);
+	return 0;
+    }
     VpSetSign(c,VpGetSign(a)*VpGetSign(b));    /* set sign  */
-    Carry = 0;
+    carry = 0;
     nc = ind_c = MxIndAB;
-    memset(c->frac, 0, (nc + 1) * sizeof(U_LONG));        /* Initialize c  */
+    memset(c->frac, 0, (nc + 1) * sizeof(BDIGIT));        /* Initialize c  */
     c->Prec = nc + 1;        /* set precision */
     for(nc = 0; nc < MxIndAB; ++nc, --ind_c) {
         if(nc < MxIndB) {    /* The left triangle of the Fig. */
@@ -3185,22 +3375,22 @@
         }
 
         for(i = ind_as; i <= ind_ae; ++i) {
-            s =((a->frac[i]) *(b->frac[ind_bs--]));
-            Carry = s / BASE;
-            s = s -(Carry * BASE);
-            c->frac[ind_c] += s;
+            s = (BDIGIT_DBL)a->frac[i] * b->frac[ind_bs--];
+            carry = (BDIGIT)(s / BASE);
+            s -= (BDIGIT_DBL)carry * BASE;
+            c->frac[ind_c] += (BDIGIT)s;
             if(c->frac[ind_c] >= BASE) {
                 s = c->frac[ind_c] / BASE;
-                Carry += s;
-                c->frac[ind_c] -= (s * BASE);
+                carry += (BDIGIT)s;
+                c->frac[ind_c] -= (BDIGIT)(s * BASE);
             }
-            if(Carry) {
+            if(carry) {
                 ii = ind_c;
-                while((--ii) >= 0) {
-                    c->frac[ii] += Carry;
+                while(ii-- > 0) {
+                    c->frac[ii] += carry;
                     if(c->frac[ii] >= BASE) {
-                        Carry = c->frac[ii] / BASE;
-                        c->frac[ii] -=(Carry * BASE);
+                        carry = c->frac[ii] / BASE;
+                        c->frac[ii] -= (carry * BASE);
                     } else {
                         break;
                     }
@@ -3218,34 +3408,35 @@
     }
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
         VPrint(stdout, "      a=% \n", a);
         VPrint(stdout, "      b=% \n", b);
     }
-#endif /*_DEBUG */
+#endif /*BIGDECIMAL_DEBUG */
     return c->Prec*BASE_FIG;
 }
 
 /*
  *   c = a / b,  remainder = r
  */
-VP_EXPORT int
+VP_EXPORT size_t
 VpDivd(Real *c, Real *r, Real *a, Real *b)
 {
-    U_LONG word_a, word_b, word_c, word_r;
-    U_LONG i, n, ind_a, ind_b, ind_c, ind_r;
-    U_LONG nLoop;
-    U_LONG q, b1, b1p1, b1b2, b1b2p1, r1r2;
-    U_LONG borrow, borrow1, borrow2, qb;
+    size_t word_a, word_b, word_c, word_r;
+    size_t i, n, ind_a, ind_b, ind_c, ind_r;
+    size_t nLoop;
+    BDIGIT_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
+    BDIGIT borrow, borrow1, borrow2;
+    BDIGIT_DBL qb;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, " VpDivd(c=a/b)  a=% \n", a);
         VPrint(stdout, "    b=% \n", b);
     }
-#endif /*_DEBUG */
+#endif /*BIGDECIMAL_DEBUG */
 
     VpSetNaN(r);
     if(!VpIsDefOP(c,a,b,4)) goto Exit;
@@ -3309,7 +3500,7 @@
             ++ind_c;
             continue;
         }
-        r1r2 = r->frac[ind_c] * BASE + r->frac[ind_c + 1];
+        r1r2 = (BDIGIT_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
         if(r1r2 == b1b2) {
             /* The first two word digits is the same */
             ind_b = 2;
@@ -3330,7 +3521,7 @@
             n = ind_b;
             for(i = 0; i <= n; ++i) {
                 if(r->frac[ind_r] < b->frac[ind_b] + borrow) {
-                    r->frac[ind_r] +=(BASE -(b->frac[ind_b] + borrow));
+                    r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
                     borrow = 1;
                 } else {
                     r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
@@ -3339,22 +3530,22 @@
                 --ind_r;
                 --ind_b;
             }
-            ++(c->frac[ind_c]);
+            ++c->frac[ind_c];
             goto carry;
         }
         /* The first two word digits is not the same, */
         /* then compare magnitude, and divide actually. */
         if(r1r2 >= b1b2p1) {
-            q = r1r2 / b1b2p1;
-            c->frac[ind_c] += q;
+            q = r1r2 / b1b2p1;  /* q == (BDIGIT)q  */
+            c->frac[ind_c] += (BDIGIT)q;
             ind_r = b->Prec + ind_c - 1;
             goto sub_mult;
         }
 
 div_b1p1:
         if(ind_c + 1 >= word_c) goto out_side;
-        q = r1r2 / b1p1;
-        c->frac[ind_c + 1] += q;
+        q = r1r2 / b1p1;  /* q == (BDIGIT)q */
+        c->frac[ind_c + 1] += (BDIGIT)q;
         ind_r = b->Prec + ind_c;
 
 sub_mult:
@@ -3364,22 +3555,22 @@
         n = ind_b;
         for(i = 0; i <= n; ++i) {
             /* now, perform r = r - q * b */
-            qb = q *(b->frac[ind_b]);
-            if(qb < BASE) borrow1 = 0;
+            qb = q * b->frac[ind_b];
+            if (qb < BASE) borrow1 = 0;
             else {
-                borrow1 = qb / BASE;
-                qb = qb - borrow1 * BASE;
+                borrow1 = (BDIGIT)(qb / BASE);
+                qb -= (BDIGIT_DBL)borrow1 * BASE;	/* get qb < BASE */
             }
             if(r->frac[ind_r] < qb) {
-                r->frac[ind_r] +=(BASE - qb);
+                r->frac[ind_r] += (BDIGIT)(BASE - qb);
                 borrow2 = borrow2 + borrow1 + 1;
             } else {
-                r->frac[ind_r] -= qb;
+                r->frac[ind_r] -= (BDIGIT)qb;
                 borrow2 += borrow1;
             }
             if(borrow2) {
                 if(r->frac[ind_r - 1] < borrow2) {
-                    r->frac[ind_r - 1] +=(BASE - borrow2);
+                    r->frac[ind_r - 1] += (BASE - borrow2);
                     borrow2 = 1;
                 } else {
                     r->frac[ind_r - 1] -= borrow2;
@@ -3396,27 +3587,27 @@
         while(c->frac[ind_r] >= BASE) {
             c->frac[ind_r] -= BASE;
             --ind_r;
-            ++(c->frac[ind_r]);
+            ++c->frac[ind_r];
         }
     }
     /* End of operation, now final arrangement */
 out_side:
     c->Prec = word_c;
     c->exponent = a->exponent;
-    if(!AddExponent(c,(S_LONG)2))   return 0;
+    if(!AddExponent(c,2))   return 0;
     if(!AddExponent(c,-(b->exponent))) return 0;
 
     VpSetSign(c,VpGetSign(a)*VpGetSign(b));
     VpNmlz(c);            /* normalize c */
     r->Prec = word_r;
     r->exponent = a->exponent;
-    if(!AddExponent(r,(S_LONG)1)) return 0;
+    if(!AddExponent(r,1)) return 0;
     VpSetSign(r,VpGetSign(a));
     VpNmlz(r);            /* normalize r(remainder) */
     goto Exit;
 
 space_error:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         printf("   word_a=%lu\n", word_a);
         printf("   word_b=%lu\n", word_b);
@@ -3424,16 +3615,16 @@
         printf("   word_r=%lu\n", word_r);
         printf("   ind_r =%lu\n", ind_r);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     rb_bug("ERROR(VpDivd): space for remainder too small.");
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
         VPrint(stdout, "    r=% \n", r);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return c->Prec*BASE_FIG;
 }
 
@@ -3444,32 +3635,32 @@
 static int
 VpNmlz(Real *a)
 {
-    U_LONG ind_a, i;
+    size_t ind_a, i;
 
-    if(!VpIsDef(a)) goto NoVal;
-    if(VpIsZero(a)) goto NoVal;
+    if (!VpIsDef(a)) goto NoVal;
+    if (VpIsZero(a)) goto NoVal;
 
     ind_a = a->Prec;
-    while(ind_a--) {
-        if(a->frac[ind_a]) {
+    while (ind_a--) {
+        if (a->frac[ind_a]) {
             a->Prec = ind_a + 1;
             i = 0;
-            while(a->frac[i] == 0) ++i;        /* skip the first few zeros */
-            if(i) {
+            while (a->frac[i] == 0) ++i;        /* skip the first few zeros */
+            if (i) {
                 a->Prec -= i;
-                if(!AddExponent(a,-((S_INT)i))) return 0;
-                memmove(&(a->frac[0]),&(a->frac[i]),(a->Prec)*sizeof(U_LONG));
+                if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0;
+                memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(BDIGIT));
             }
             return 1;
         }
     }
     /* a is zero(no non-zero digit) */
-    VpSetZero(a,VpGetSign(a));
+    VpSetZero(a, VpGetSign(a));
     return 0;
 
 NoVal:
     a->frac[0] = 0;
-    a->Prec=1;
+    a->Prec = 1;
     return 0;
 }
 
@@ -3483,7 +3674,7 @@
 VpComp(Real *a, Real *b)
 {
     int val;
-    U_LONG mx, ind;
+    size_t mx, ind;
     int e;
     val = 0;
     if(VpIsNaN(a)||VpIsNaN(b)) return 999;
@@ -3554,17 +3745,16 @@
     if  (val> 1) val =  1;
     else if(val<-1) val = -1;
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, " VpComp a=%\n", a);
         VPrint(stdout, "  b=%\n", b);
         printf("  ans=%d\n", val);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return (int)val;
 }
 
-#ifdef _DEBUG
 /*
  *    cntl_chr ... ASCIIZ Character, print control characters
  *     Available control codes:
@@ -3575,11 +3765,12 @@
  *     Note: % must must not appear more than once
  *    a  ... VP variable to be printed
  */
+#ifdef BIGDECIMAL_DEBUG
 VP_EXPORT int
-VPrint(FILE *fp, char *cntl_chr, Real *a)
+VPrint(FILE *fp, const char *cntl_chr, Real *a)
 {
-    U_LONG i, j, nc, nd, ZeroSup;
-    U_LONG n, m, e, nn;
+    size_t i, j, nc, nd, ZeroSup;
+    BDIGIT m, e, nn;
 
     /* Check if NaN & Inf. */
     if(VpIsNaN(a)) {
@@ -3613,14 +3804,13 @@
                     ++nc;
                 }
                 nc += fprintf(fp, "0.");
-                n = a->Prec;
-                for(i=0;i < n;++i) {
-                 m = BASE1;
+                for(i=0; i < a->Prec; ++i) {
+		    m = BASE1;
                     e = a->frac[i];
                     while(m) {
                         nn = e / m;
                         if((!ZeroSup) || nn) {
-                            nc += fprintf(fp, "%lu", nn);    /* The reading zero(s) */
+                            nc += fprintf(fp, "%lu", (unsigned long)nn);    /* The leading zero(s) */
                             /* as 0.00xx will not */
                             /* be printed. */
                             ++nd;
@@ -3634,7 +3824,7 @@
                         m /= 10;
                     }
                 }
-                nc += fprintf(fp, "E%ld", VpExponent10(a));
+                nc += fprintf(fp, "E%"PRIdVALUE, VpExponent10(a));
             } else {
                 nc += fprintf(fp, "0.0");
             }
@@ -3667,14 +3857,12 @@
     }
     return (int)nc;
 }
-#endif /* _DEBUG */
+#endif
 
 static void
-VpFormatSt(char *psz,S_INT fFmt)
+VpFormatSt(char *psz, size_t fFmt)
 {
-    U_LONG ie;
-    U_LONG i;
-    S_INT nf = 0;
+    size_t ie, i, nf = 0;
     char ch;
 
     if(fFmt<=0) return;
@@ -3696,17 +3884,17 @@
     }
 }
 
-VP_EXPORT S_LONG
+VP_EXPORT ssize_t
 VpExponent10(Real *a)
 {
-    S_LONG ex;
-    U_LONG n;
+    ssize_t ex;
+    size_t n;
 
-    if(!VpHasVal(a)) return 0;
+    if (!VpHasVal(a)) return 0;
 
-    ex =(a->exponent) * BASE_FIG;
+    ex = a->exponent * (ssize_t)BASE_FIG;
     n = BASE1;
-    while((a->frac[0] / n) == 0) {
+    while ((a->frac[0] / n) == 0) {
          --ex;
          n /= 10;
     }
@@ -3716,8 +3904,8 @@
 VP_EXPORT void
 VpSzMantissa(Real *a,char *psz)
 {
-    U_LONG i, ZeroSup;
-    U_LONG n, m, e, nn;
+    size_t i, n, ZeroSup;
+    BDIGIT_DBL m, e, nn;
 
     if(VpIsNaN(a)) {
         sprintf(psz,SZ_NaN);
@@ -3736,13 +3924,13 @@
     if(!VpIsZero(a)) {
         if(VpGetSign(a) < 0) *psz++ = '-';
         n = a->Prec;
-        for(i=0;i < n;++i) {
+        for (i=0; i < n; ++i) {
             m = BASE1;
             e = a->frac[i];
-            while(m) {
+            while (m) {
                 nn = e / m;
                 if((!ZeroSup) || nn) {
-                    sprintf(psz, "%lu", nn);    /* The reading zero(s) */
+                    sprintf(psz, "%lu", (unsigned long)nn);    /* The leading zero(s) */
                     psz += strlen(psz);
                     /* as 0.00xx will be ignored. */
                     ZeroSup = 0;    /* Set to print succeeding zeros */
@@ -3793,21 +3981,21 @@
 }
 
 VP_EXPORT void
-VpToString(Real *a,char *psz,int fFmt,int fPlus)
+VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
 /* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
 {
-    U_LONG i, ZeroSup;
-    U_LONG n, m, e, nn;
+    size_t i, n, ZeroSup;
+    BDIGIT shift, m, e, nn;
     char *pszSav = psz;
-    S_LONG ex;
+    ssize_t ex;
 
-    if(VpToSpecialString(a,psz,fPlus)) return;
+    if (VpToSpecialString(a, psz, fPlus)) return;
 
     ZeroSup = 1;    /* Flag not to print the leading zeros as 0.00xxxxEnn */
 
-    if(VpGetSign(a) < 0) *psz++ = '-';
-    else if(fPlus==1)    *psz++ = ' ';
-    else if(fPlus==2)    *psz++ = '+';
+    if (VpGetSign(a) < 0) *psz++ = '-';
+    else if (fPlus == 1)  *psz++ = ' ';
+    else if (fPlus == 2)  *psz++ = '+';
 
     *psz++ = '0';
     *psz++ = '.';
@@ -3818,7 +4006,7 @@
         while(m) {
             nn = e / m;
             if((!ZeroSup) || nn) {
-                sprintf(psz, "%lu", nn);    /* The reading zero(s) */
+                sprintf(psz, "%lu", (unsigned long)nn);    /* The reading zero(s) */
                 psz += strlen(psz);
                 /* as 0.00xx will be ignored. */
                 ZeroSup = 0;    /* Set to print succeeding zeros */
@@ -3827,25 +4015,25 @@
             m /= 10;
         }
     }
-    ex =(a->exponent) * BASE_FIG;
-    n = BASE1;
-    while((a->frac[0] / n) == 0) {
+    ex = a->exponent * (ssize_t)BASE_FIG;
+    shift = BASE1;
+    while(a->frac[0] / shift == 0) {
         --ex;
-        n /= 10;
+        shift /= 10;
     }
     while(psz[-1]=='0') *(--psz) = 0;
-    sprintf(psz, "E%ld", ex);
+    sprintf(psz, "E%"PRIdVALUE, ex);
     if(fFmt) VpFormatSt(pszSav, fFmt);
 }
 
 VP_EXPORT void
-VpToFString(Real *a,char *psz,int fFmt,int fPlus)
+VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
 /* fPlus =0:default,=1: set ' ' before digits ,set '+' before digits. */
 {
-    U_LONG i;
-    U_LONG n, m, e, nn;
+    size_t i, n;
+    BDIGIT m, e, nn;
     char *pszSav = psz;
-    S_LONG ex;
+    ssize_t ex;
 
     if(VpToSpecialString(a,psz,fPlus)) return;
 
@@ -3867,7 +4055,7 @@
     for(i=0;i < n;++i) {
        --ex;
        if(i==0 && ex >= 0) {
-           sprintf(psz, "%lu", a->frac[i]);
+           sprintf(psz, "%lu", (unsigned long)a->frac[i]);
            psz += strlen(psz);
        } else {
            m = BASE1;
@@ -3904,34 +4092,39 @@
  *   ne   ... number of characters in exp_chr[],not including '+/-'.
  */
 VP_EXPORT int
-VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, const char *exp_chr, U_LONG ne)
+VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
 {
-    U_LONG i, j, ind_a, ma, mi, me;
-    U_LONG loc;
-    S_INT  e,es, eb, ef;
-    S_INT  sign, signe;
+    size_t i, j, ind_a, ma, mi, me;
+    size_t loc;
+    SIGNED_VALUE e, es, eb, ef;
+    int  sign, signe, exponent_overflow;
+
     /* get exponent part */
     e = 0;
     ma = a->MaxPrec;
     mi = ni;
     me = ne;
     signe = 1;
-    memset(a->frac, 0, ma * sizeof(U_LONG));
-    if(ne > 0) {
+    exponent_overflow = 0;
+    memset(a->frac, 0, ma * sizeof(BDIGIT));
+    if (ne > 0) {
         i = 0;
-        if(exp_chr[0] == '-') {
+        if (exp_chr[0] == '-') {
             signe = -1;
             ++i;
             ++me;
-        } else if(exp_chr[0] == '+') {
+        }
+	else if (exp_chr[0] == '+') {
             ++i;
             ++me;
         }
-        while(i < me) {
-            es = e*((S_INT)BASE_FIG);
+        while (i < me) {
+            es = e * (SIGNED_VALUE)BASE_FIG;
             e = e * 10 + exp_chr[i] - '0';
-            if(es>e*((S_INT)BASE_FIG)) {
-                return VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0);
+            if (es > (SIGNED_VALUE)(e*BASE_FIG)) {
+		exponent_overflow = 1;
+		e = es; /* keep sign */
+		break;
             }
             ++i;
         }
@@ -3940,7 +4133,7 @@
     /* get integer part */
     i = 0;
     sign = 1;
-    if(ni >= 0) {
+    if(1 /*ni >= 0*/) {
         if(int_chr[0] == '-') {
             sign = -1;
             ++i;
@@ -3954,36 +4147,48 @@
     e = signe * e;        /* e: The value of exponent part. */
     e = e + ni;        /* set actual exponent size. */
 
-    if(e > 0)    signe = 1;
-    else        signe = -1;
+    if (e > 0) signe = 1;
+    else       signe = -1;
 
     /* Adjust the exponent so that it is the multiple of BASE_FIG. */
     j = 0;
     ef = 1;
-    while(ef) {
-        if(e>=0) eb =  e;
-        else  eb = -e;
-        ef = eb / ((S_INT)BASE_FIG);
-        ef = eb - ef * ((S_INT)BASE_FIG);
-        if(ef) {
+    while (ef) {
+        if (e >= 0) eb =  e;
+        else        eb = -e;
+        ef = eb / (SIGNED_VALUE)BASE_FIG;
+        ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
+        if (ef) {
             ++j;        /* Means to add one more preceeding zero */
             ++e;
         }
     }
 
-    eb = e / ((S_INT)BASE_FIG);
+    eb = e / (SIGNED_VALUE)BASE_FIG;
 
+    if (exponent_overflow) {
+	int zero = 1;
+	for (     ; i < mi && zero; i++) zero = int_chr[i] == '0';
+	for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
+	if (!zero && signe > 0) {
+	    VpSetInf(a, sign);
+	    VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
+	}
+	else VpSetZero(a, sign);
+	return 1;
+    }
+
     ind_a = 0;
-    while(i < mi) {
+    while (i < mi) {
         a->frac[ind_a] = 0;
-        while((j < (U_LONG)BASE_FIG) &&(i < mi)) {
+        while ((j < BASE_FIG) && (i < mi)) {
             a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
             ++j;
             ++i;
         }
-        if(i < mi) {
+        if (i < mi) {
             ++ind_a;
-            if(ind_a >= ma) goto over_flow;
+            if (ind_a >= ma) goto over_flow;
             j = 0;
         }
     }
@@ -3993,7 +4198,7 @@
 
     i = 0;
     while(i < nf) {
-        while((j < (U_LONG)BASE_FIG) &&(i < nf)) {
+        while((j < BASE_FIG) && (i < nf)) {
             a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
             ++j;
             ++i;
@@ -4010,8 +4215,8 @@
     rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
 
 Final:
-    if(ind_a >= ma) ind_a = ma - 1;
-    while(j < (U_LONG)BASE_FIG) {
+    if (ind_a >= ma) ind_a = ma - 1;
+    while (j < BASE_FIG) {
         a->frac[ind_a] = a->frac[ind_a] * 10;
         ++j;
     }
@@ -4027,7 +4232,7 @@
  *   *m  ... Real
  * [Output]
  *   *d  ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
- *   *e  ... U_LONG,exponent of m.
+ *   *e  ... exponent of m.
  * DBLE_FIG ... Number of digits in a double variable.
  *
  *  m -> d*10**e, 0<d<BASE
@@ -4038,9 +4243,9 @@
  *  -1 ... NaN
  */
 VP_EXPORT int
-VpVtoD(double *d, S_LONG *e, Real *m)
+VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
 {
-    U_LONG ind_m, mm, fig;
+    size_t ind_m, mm, fig;
     double div;
     int    f = 1;
 
@@ -4081,20 +4286,20 @@
     *d = 0.0;
     div = 1.;
     while(ind_m < mm) {
-        div /=(double)((S_INT)BASE);
-        *d = *d +((double) ((S_INT)m->frac[ind_m++])) * div;
+        div /= (double)BASE;
+        *d = *d + (double)m->frac[ind_m++] * div;
     }
-    *e = m->exponent * ((S_INT)BASE_FIG);
+    *e = m->exponent * (SIGNED_VALUE)BASE_FIG;
     *d *= VpGetSign(m);
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, " VpVtoD: m=%\n", m);
         printf("   d=%e * 10 **%ld\n", *d, *e);
-        printf("   DBLE_FIG = %ld\n", DBLE_FIG);
+        printf("   DBLE_FIG = %d\n", DBLE_FIG);
     }
-#endif /*_DEBUG */
+#endif /*BIGDECIMAL_DEBUG */
     return f;
 }
 
@@ -4104,8 +4309,9 @@
 VP_EXPORT void
 VpDtoV(Real *m, double d)
 {
-    U_LONG i, ind_m, mm;
-    U_LONG ne;
+    size_t ind_m, mm;
+    SIGNED_VALUE ne;
+    BDIGIT i;
     double  val, val2;
 
     if(isnan(d)) {
@@ -4126,59 +4332,55 @@
     ne = 0;
     if(val >= 1.0) {
         while(val >= 1.0) {
-            val /=(double)((S_INT)BASE);
+            val /= (double)BASE;
             ++ne;
         }
     } else {
-        val2 = 1.0 /(double)((S_INT)BASE);
+        val2 = 1.0 /(double)BASE;
         while(val < val2) {
-            val *=(double)((S_INT)BASE);
+            val *= (double)BASE;
             --ne;
         }
     }
     /* Now val = 0.xxxxx*BASE**ne */
 
     mm = m->MaxPrec;
-    memset(m->frac, 0, mm * sizeof(U_LONG));
+    memset(m->frac, 0, mm * sizeof(BDIGIT));
     for(ind_m = 0;val > 0.0 && ind_m < mm;ind_m++) {
-        val *=(double)((S_INT)BASE);
-        i =(U_LONG) val;
-        val -=(double)((S_INT)i);
+        val *= (double)BASE;
+        i = (BDIGIT)val;
+        val -= (double)i;
         m->frac[ind_m] = i;
     }
     if(ind_m >= mm) ind_m = mm - 1;
-    if(d > 0.0) {
-        VpSetSign(m, (S_INT)1);
-    } else {
-        VpSetSign(m,-(S_INT)1);
-    }
+    VpSetSign(m, (d > 0.0) ? 1 : -1);
     m->Prec = ind_m + 1;
     m->exponent = ne;
 
-    VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0,
-                      (U_LONG)(val*((double)((S_INT)BASE))));
+    VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
+                      (BDIGIT)(val*(double)BASE));
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         printf("VpDtoV d=%30.30e\n", d);
         VPrint(stdout, "  m=%\n", m);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return;
 }
 
 /*
  *  m <- ival
  */
-#if 0
+#if 0  /* unused */
 VP_EXPORT void
-VpItoV(Real *m, S_INT ival)
+VpItoV(Real *m, SIGNED_VALUE ival)
 {
-    U_LONG mm, ind_m;
-    U_LONG val, v1, v2, v;
+    size_t mm, ind_m;
+    size_t val, v1, v2, v;
     int isign;
-    S_INT ne;
+    SIGNED_VALUE ne;
 
     if(ival == 0) {
         VpSetZero(m,1);
@@ -4188,7 +4390,7 @@
     val = ival;
     if(ival < 0) {
         isign = -1;
-        val =(U_LONG)(-ival);
+        val =(size_t)(-ival);
     }
     ne = 0;
     ind_m = 0;
@@ -4221,12 +4423,12 @@
     VpNmlz(m);
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         printf(" VpItoV i=%d\n", ival);
         VPrint(stdout, "  m=%\n", m);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return;
 }
 #endif
@@ -4239,11 +4441,10 @@
 {
     Real *f = NULL;
     Real *r = NULL;
-    S_LONG y_prec, f_prec;
-    S_LONG n;
-    S_LONG e;
-    S_LONG prec;
-    S_LONG nr;
+    size_t y_prec, f_prec;
+    SIGNED_VALUE n, e;
+    SIGNED_VALUE prec;
+    ssize_t nr;
     double val;
 
     /* Zero, NaN or Infinity ? */
@@ -4269,37 +4470,39 @@
         goto Exit;
     }
 
-    n = (S_LONG)y->MaxPrec;
-    if((S_LONG)x->MaxPrec > n) n = (S_LONG)x->MaxPrec;
+    n = (SIGNED_VALUE)y->MaxPrec;
+    if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
     /* allocate temporally variables  */
-    f = VpAlloc(y->MaxPrec *(BASE_FIG + 2), "#1");
-    r = VpAlloc((n + n) *(BASE_FIG + 2), "#1");
+    f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1");
+    r = VpAlloc((n + n) * (BASE_FIG + 2), "#1");
 
     nr = 0;
-    y_prec = (S_LONG)y->MaxPrec;
-    f_prec = (S_LONG)f->MaxPrec;
+    y_prec = y->MaxPrec;
+    f_prec = f->MaxPrec;
 
-    prec = x->exponent;
-    if(prec > 0)    ++prec;
-    else            --prec;
-    prec = prec - (S_LONG)y->MaxPrec;
+    prec = x->exponent - (ssize_t)y_prec;
+    if (x->exponent > 0)
+	++prec;
+    else
+	--prec;
+
     VpVtoD(&val, &e, x);    /* val <- x  */
-    e /= ((S_LONG)BASE_FIG);
+    e /= (SIGNED_VALUE)BASE_FIG;
     n = e / 2;
-    if(e - n * 2 != 0) {
-        val /=(double)((S_INT)BASE);
-        n =(e + 1) / 2;
+    if (e - n * 2 != 0) {
+        val /= BASE;
+        n = (e + 1) / 2;
     }
     VpDtoV(y, sqrt(val));    /* y <- sqrt(val) */
     y->exponent += n;
-    n = (DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
-    y->MaxPrec = (U_LONG)Min(n , y_prec);
+    n = (SIGNED_VALUE)((DBLE_FIG + BASE_FIG - 1) / BASE_FIG);
+    y->MaxPrec = Min((size_t)n , y_prec);
     f->MaxPrec = y->MaxPrec + 1;
-    n = y_prec*((S_LONG)BASE_FIG);
-    if((U_LONG)n<maxnr) n = (U_LONG)maxnr;
+    n = (SIGNED_VALUE)(y_prec * BASE_FIG);
+    if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
     do {
         y->MaxPrec *= 2;
-        if(y->MaxPrec > (U_LONG)y_prec) y->MaxPrec = (U_LONG)y_prec;
+        if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
         f->MaxPrec = y->MaxPrec;
         VpDivd(f, r, x, y);     /* f = x/y    */
         VpAddSub(r, f, y, -1);  /* r = f - y  */
@@ -4310,26 +4513,26 @@
         if(f->exponent <= prec) goto converge;
     } while(++nr < n);
     /* */
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         printf("ERROR(VpSqrt): did not converge within %ld iterations.\n",
             nr);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     y->MaxPrec = y_prec;
 
 converge:
-    VpChangeSign(y,(S_INT)1);
-#ifdef _DEBUG
+    VpChangeSign(y, 1);
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VpMult(r, y, y);
         VpAddSub(f, x, r, -1);
-        printf("VpSqrt: iterations = %lu\n", nr);
+        printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
         VPrint(stdout, "  y =% \n", y);
         VPrint(stdout, "  x =% \n", x);
         VPrint(stdout, "  x-y*y = % \n", f);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     y->MaxPrec = y_prec;
 
 Exit:
@@ -4344,7 +4547,7 @@
  *
  */
 VP_EXPORT int
-VpMidRound(Real *y, int f, int nf)
+VpMidRound(Real *y, unsigned short f, ssize_t nf)
 /*
  * Round reletively from the decimal point.
  *    f: rounding mode
@@ -4353,84 +4556,86 @@
 {
     /* fracf: any positive digit under rounding position? */
     /* exptoadd: number of digits needed to compensate negative nf */
-    int n,i,ix,ioffset,fracf,exptoadd;
-    U_LONG v,shifter;
-    U_LONG div;
+    int fracf;
+    ssize_t n,i,ix,ioffset, exptoadd;
+    BDIGIT v, shifter;
+    BDIGIT div;
 
-    nf += y->exponent*((int)BASE_FIG);
+    nf += y->exponent * (ssize_t)BASE_FIG;
     exptoadd=0;
     if (nf < 0) {
-		/* rounding position too left(large). */
-		if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
-			VpSetZero(y,VpGetSign(y)); /* truncate everything */
-			return 0;
-		}
+	/* rounding position too left(large). */
+	if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
+	    VpSetZero(y,VpGetSign(y)); /* truncate everything */
+	    return 0;
+	}
         exptoadd = -nf;
         nf = 0;
     }
 
     /* ix: x->fraq[ix] contains round position */
-    ix = nf/(int)BASE_FIG;
-    if(((U_LONG)ix)>=y->Prec) return 0;  /* rounding position too right(small). */
-    ioffset = nf - ix*((int)BASE_FIG);
+    ix = nf / (ssize_t)BASE_FIG;
+    if ((size_t)ix >= y->Prec) return 0;  /* rounding position too right(small). */
+    ioffset = nf - ix*(ssize_t)BASE_FIG;
 
     v = y->frac[ix];
 
     /* drop digits after pointed digit */
-    n = BASE_FIG - ioffset - 1;
-    for(shifter=1,i=0;i<n;++i) shifter *= 10;
-    fracf = (v%(shifter*10) > 0);
+    n = (ssize_t)BASE_FIG - ioffset - 1;
+    for (shifter=1,i=0; i<n; ++i) shifter *= 10;
+    fracf = (v % (shifter * 10) > 0);
     v /= shifter;
-    div = v/10;
+    div = v / 10;
     v = v - div*10;
     if (fracf == 0) {
-        for(i=ix+1;i<y->Prec;i++) {
-            if (y->frac[i]%BASE) {
+        for (i=ix+1; (size_t)i < y->Prec; i++) {
+            if (y->frac[i] % BASE) {
                 fracf = 1;
                 break;
             }
         }
     }
-    memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
+    memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(BDIGIT));
     switch(f) {
     case VP_ROUND_DOWN: /* Truncate */
          break;
     case VP_ROUND_UP:   /* Roundup */
-        if(fracf) ++div;
+        if (fracf) ++div;
          break;
     case VP_ROUND_HALF_UP:   /* Round half up  */
-        if(v>=5) ++div;
+        if (v>=5) ++div;
         break;
     case VP_ROUND_HALF_DOWN: /* Round half down  */
-        if(v>=6) ++div;
+        if (v>=6) ++div;
         break;
     case VP_ROUND_CEIL: /* ceil */
-        if(fracf && (VpGetSign(y)>0)) ++div;
+        if (fracf && (VpGetSign(y)>0)) ++div;
         break;
     case VP_ROUND_FLOOR: /* floor */
-        if(fracf && (VpGetSign(y)<0)) ++div;
+        if (fracf && (VpGetSign(y)<0)) ++div;
         break;
     case VP_ROUND_HALF_EVEN: /* Banker's rounding */
-        if(v>5) ++div;
-        else if(v==5) {
-            if((U_LONG)i==(BASE_FIG-1)) {
-                if(ix && (y->frac[ix-1]%2)) ++div;
-            } else {
-                if(div%2) ++div;
+        if (v>5) ++div;
+        else if (v==5) {
+            if ((size_t)i == (BASE_FIG-1)) {
+                if (ix && (y->frac[ix-1]%2)) ++div;
             }
+	    else {
+                if (div%2) ++div;
+            }
         }
         break;
     }
-    for(i=0;i<=n;++i) div *= 10;
-    if(div>=BASE) {
+    for (i=0; i<=n; ++i) div *= 10;
+    if (div>=BASE) {
         if(ix) {
             y->frac[ix] = 0;
             VpRdup(y,ix);
         } else {
-            S_INT s = VpGetSign(y);
-            int e = y->exponent;
+            short s = VpGetSign(y);
+            SIGNED_VALUE e = y->exponent;
             VpSetOne(y);
-            VpSetSign(y,s);
+            VpSetSign(y, s);
             y->exponent = e+1;
         }
     } else {
@@ -4438,8 +4643,8 @@
         VpNmlz(y);
     }
     if (exptoadd > 0) {
-        y->exponent += exptoadd/BASE_FIG;
-        exptoadd %= BASE_FIG;
+        y->exponent += (SIGNED_VALUE)(exptoadd/BASE_FIG);
+        exptoadd %= (ssize_t)BASE_FIG;
         for(i=0;i<exptoadd;i++) {
             y->frac[0] *= 10;
             if (y->frac[0] >= BASE) {
@@ -4452,49 +4657,51 @@
 }
 
 VP_EXPORT int
-VpLeftRound(Real *y, int f, int nf)
+VpLeftRound(Real *y, unsigned short f, ssize_t nf)
 /*
  * Round from the left hand side of the digits.
  */
 {
-    U_LONG v;
-    if(!VpHasVal(y)) return 0; /* Unable to round */
+    BDIGIT v;
+    if (!VpHasVal(y)) return 0; /* Unable to round */
     v = y->frac[0];
-    nf -= VpExponent(y)*BASE_FIG;
-    while((v /= 10) != 0) nf--;
-    nf += (BASE_FIG-1);
+    nf -= VpExponent(y)*(ssize_t)BASE_FIG;
+    while ((v /= 10) != 0) nf--;
+    nf += (ssize_t)BASE_FIG-1;
     return VpMidRound(y,f,nf);
 }
 
-VP_EXPORT int 
-VpActiveRound(Real *y, Real *x, int f, int nf)
+VP_EXPORT int
+VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
 {
     /* First,assign whole value in truncation mode */
-    if(VpAsgn(y, x, 10)<=1) return 0; /* Zero,NaN,or Infinity */
+    if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */
     return VpMidRound(y,f,nf);
 }
 
 static int
-VpLimitRound(Real *c,U_LONG ixDigit)
+VpLimitRound(Real *c, size_t ixDigit)
 {
-    U_LONG ix = VpGetPrecLimit();
+    size_t ix = VpGetPrecLimit();
     if(!VpNmlz(c))    return -1;
     if(!ix)           return 0;
     if(!ixDigit) ixDigit = c->Prec-1;
     if((ix+BASE_FIG-1)/BASE_FIG > ixDigit+1) return 0;
-    return VpLeftRound(c,VpGetRoundMode(),ix);
+    return VpLeftRound(c, (int)VpGetRoundMode(), (ssize_t)ix);
 }
 
-static void 
-VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
+static void
+VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v)
 {
     int f = 0;
 
+    unsigned short const rounding_mode = VpGetRoundMode();
+
     if(VpLimitRound(c,ixDigit)) return;
     if(!v)                      return;
 
     v /= BASE1;
-    switch(gfRoundMode) {
+    switch (rounding_mode) {
     case VP_ROUND_DOWN:
         break;
     case VP_ROUND_UP:
@@ -4527,20 +4734,20 @@
  *  Rounds up m(plus one to final digit of m).
  */
 static int
-VpRdup(Real *m,U_LONG ind_m)
+VpRdup(Real *m, size_t ind_m)
 {
-    U_LONG carry;
+    BDIGIT carry;
 
-    if(!ind_m) ind_m = m->Prec;
+    if (!ind_m) ind_m = m->Prec;
 
     carry = 1;
-    while(carry > 0 && (ind_m--)) {
+    while (carry > 0 && (ind_m--)) {
         m->frac[ind_m] += carry;
-        if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
-        else                       carry = 0;
+        if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
+        else                        carry = 0;
     }
     if(carry > 0) {        /* Overflow,count exponent and set fraction part be 1  */
-        if(!AddExponent(m,(S_LONG)1)) return 0;
+        if (!AddExponent(m, 1)) return 0;
         m->Prec = m->frac[0] = 1;
     } else {
         VpNmlz(m);
@@ -4554,22 +4761,25 @@
 VP_EXPORT void
 VpFrac(Real *y, Real *x)
 {
-    U_LONG my, ind_y, ind_x;
+    size_t my, ind_y, ind_x;
 
     if(!VpHasVal(x)) {
         VpAsgn(y,x,1);
         goto Exit;
     }
 
-    if(x->exponent > 0 && (U_LONG)x->exponent >= x->Prec) {
+    if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) {
         VpSetZero(y,VpGetSign(x));
         goto Exit;
-    } else if(x->exponent <= 0) {
+    }
+    else if(x->exponent <= 0) {
         VpAsgn(y, x, 1);
         goto Exit;
     }
 
-    y->Prec = x->Prec -(U_LONG) x->exponent;
+    /* satisfy: x->exponent > 0 */
+
+    y->Prec = x->Prec - (size_t)x->exponent;
     y->Prec = Min(y->Prec, y->MaxPrec);
     y->exponent = 0;
     VpSetSign(y,VpGetSign(x));
@@ -4584,12 +4794,12 @@
     VpNmlz(y);
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpFrac y=%\n", y);
         VPrint(stdout, "    x=%\n", x);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     return;
 }
 
@@ -4597,10 +4807,10 @@
  *   y = x ** n
  */
 VP_EXPORT int
-VpPower(Real *y, Real *x, S_INT n)
+VpPower(Real *y, Real *x, SIGNED_VALUE n)
 {
-    U_LONG s, ss;
-    S_LONG sign;
+    size_t s, ss;
+    ssize_t sign;
     Real *w1 = NULL;
     Real *w2 = NULL;
 
@@ -4620,17 +4830,29 @@
         }
         goto Exit;
     }
-    if(!VpIsDef(x)) {
-        VpSetNaN(y); /* Not sure !!! */
+    if(VpIsNaN(x)) {
+        VpSetNaN(y);
         goto Exit;
     }
+    if(VpIsInf(x)) {
+        if(n==0) {
+            VpSetOne(y);
+            goto Exit;
+        }
+        if(n>0) {
+            VpSetInf(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
+            goto Exit;
+        }
+        VpSetZero(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
+        goto Exit;
+    }
 
     if((x->exponent == 1) &&(x->Prec == 1) &&(x->frac[0] == 1)) {
         /* abs(x) = 1 */
         VpSetOne(y);
         if(VpGetSign(x) > 0) goto Exit;
         if((n % 2) == 0) goto Exit;
-        VpSetSign(y,-(S_INT)1);
+        VpSetSign(y, -1);
         goto Exit;
     }
 
@@ -4654,14 +4876,11 @@
     while(n > 0) {
         VpAsgn(w1, x, 1);
         s = 1;
-loop1:  ss = s;
-        s += s;
-        if(s >(U_LONG) n) goto out_loop1;
-        VpMult(w2, w1, w1);
-        VpAsgn(w1, w2, 1);
-        goto loop1;
-out_loop1:
-        n -= ss;
+	while (ss = s, (s += s) <= (size_t)n) {
+	    VpMult(w2, w1, w1);
+	    VpAsgn(w1, w2, 1);
+	}
+        n -= (SIGNED_VALUE)ss;
         VpMult(w2, y, w1);
         VpAsgn(y, w2, 1);
     }
@@ -4671,19 +4890,19 @@
     }
 
 Exit:
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
     if(gfDebug) {
         VPrint(stdout, "VpPower y=%\n", y);
         VPrint(stdout, "VpPower x=%\n", x);
         printf("  n=%d\n", n);
     }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */
     VpFree(w2);
     VpFree(w1);
     return 1;
 }
 
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
 int
 VpVarCheck(Real * v)
 /*
@@ -4695,28 +4914,28 @@
  *   other ... error
  */
 {
-    U_LONG i;
+    size_t i;
 
     if(v->MaxPrec <= 0) {
-        printf("ERROR(VpVarCheck): Illegal Max. Precision(=%lu)\n",
+        printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n",
             v->MaxPrec);
         return 1;
     }
     if((v->Prec <= 0) ||((v->Prec) >(v->MaxPrec))) {
-        printf("ERROR(VpVarCheck): Illegal Precision(=%lu)\n", v->Prec);
-        printf("       Max. Prec.=%lu\n", v->MaxPrec);
+        printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec);
+        printf("       Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec);
         return 2;
     }
     for(i = 0; i < v->Prec; ++i) {
         if((v->frac[i] >= BASE)) {
             printf("ERROR(VpVarCheck): Illegal fraction\n");
-            printf("       Frac[%ld]=%lu\n", i, v->frac[i]);
-            printf("       Prec.   =%lu\n", v->Prec);
-            printf("       Exp. =%d\n", v->exponent);
+            printf("       Frac[%"PRIuSIZE"]=%lu\n", i, v->frac[i]);
+            printf("       Prec.   =%"PRIuSIZE"\n", v->Prec);
+            printf("       Exp. =%"PRIdVALUE"\n", v->exponent);
             printf("       BASE =%lu\n", BASE);
             return 3;
         }
     }
     return 0;
 }
-#endif /* _DEBUG */
+#endif /* BIGDECIMAL_DEBUG */

Modified: MacRuby/trunk/ext/bigdecimal/bigdecimal.h
===================================================================
--- MacRuby/trunk/ext/bigdecimal/bigdecimal.h	2010-09-10 06:03:14 UTC (rev 4500)
+++ MacRuby/trunk/ext/bigdecimal/bigdecimal.h	2010-09-10 07:41:26 UTC (rev 4501)
@@ -1,25 +1,77 @@
 /*
  *
- * Ruby BigDecimal(Variable decimal precision) extension library. 
+ * Ruby BigDecimal(Variable decimal precision) extension library.
  *
- * Copyright(C) 2002 by Shigeo Kobayashi(shigeo at tinyforest.gr.jp) 
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo at tinyforest.gr.jp)
  *
- * You may distribute under the terms of either the GNU General Public 
- * License or the Artistic License, as specified in the README file 
- * of this BigDecimal distribution. 
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Artistic License, as specified in the README file
+ * of this BigDecimal distribution.
  *
  * NOTES:
  *   2003-03-28 V1.0 checked in.
  *
  */
 
-#ifndef  ____BIG_DECIMAL__H____
-#define  ____BIG_DECIMAL__H____
+#ifndef  RUBY_BIG_DECIMAL_H
+#define  RUBY_BIG_DECIMAL_H 1
 
+#include "ruby/ruby.h"
+#include <float.h>
+
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
+#ifndef HAVE_LABS
+static inline long
+labs(long const x)
+{
+    if (x < 0) return -x;
+    return x;
+}
+#endif
+
+#ifndef HAVE_LLABS
+static inline LONG_LONG
+llabs(LONG_LONG const x)
+{
+    if (x < 0) return -x;
+    return x;
+}
+#endif
+
+#ifdef vabs
+# undef vabs
+#endif
+#if SIZEOF_VALUE <= SIZEOF_INT
+# define vabs abs
+#elif SIZEOF_VALUE <= SIZEOF_LONG
+# define vabs labs
+#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
+# define vabs llabs
+#endif
+
+extern VALUE rb_cBigDecimal;
+
+#if 0 || SIZEOF_BDIGITS >= 16
+# define RMPD_COMPONENT_FIGURES 38
+# define RMPD_BASE ((BDIGIT)100000000000000000000000000000000000000U)
+#elif SIZEOF_BDIGITS >= 8
+# define RMPD_COMPONENT_FIGURES 19
+# define RMPD_BASE ((BDIGIT)10000000000000000000U)
+#elif SIZEOF_BDIGITS >= 4
+# define RMPD_COMPONENT_FIGURES 9
+# define RMPD_BASE ((BDIGIT)1000000000U)
+#elif SIZEOF_BDIGITS >= 2
+# define RMPD_COMPONENT_FIGURES 4
+# define RMPD_BASE ((BDIGIT)10000U)
+#else
+# define RMPD_COMPONENT_FIGURES 2
+# define RMPD_BASE ((BDIGIT)100U)
+#endif
+
+
 /*
  *  NaN & Infinity
  */
@@ -29,28 +81,25 @@
 #define SZ_NINF "-Infinity"
 
 /*
- *   #define VP_EXPORT other than static to let VP_ routines 
+ *   #define VP_EXPORT other than static to let VP_ routines
  *   be called from outside of this module.
  */
-#define VP_EXPORT static 
+#define VP_EXPORT static
 
-#define U_LONG unsigned long
-#define S_LONG long
-#define U_INT  unsigned int
-#define S_INT  int
-
 /* Exception codes */
 #define VP_EXCEPTION_ALL        ((unsigned short)0x00FF)
 #define VP_EXCEPTION_INFINITY   ((unsigned short)0x0001)
 #define VP_EXCEPTION_NaN        ((unsigned short)0x0002)
 #define VP_EXCEPTION_UNDERFLOW  ((unsigned short)0x0004)
 #define VP_EXCEPTION_OVERFLOW   ((unsigned short)0x0001) /* 0x0008) */
-#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0001) /* 0x0010) */
+#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0010)
 
 /* Following 2 exceptions cann't controlled by user */
 #define VP_EXCEPTION_OP         ((unsigned short)0x0020)
 #define VP_EXCEPTION_MEMORY     ((unsigned short)0x0040)
 
+#define RMPD_EXCEPTION_MODE_DEFAULT 0U
+
 /* Computation mode */
 #define VP_ROUND_MODE            ((unsigned short)0x0100)
 #define VP_ROUND_UP         1
@@ -61,6 +110,8 @@
 #define VP_ROUND_FLOOR      6
 #define VP_ROUND_HALF_EVEN  7
 
+#define RMPD_ROUNDING_MODE_DEFAULT  VP_ROUND_HALF_UP
+
 #define VP_SIGN_NaN                0 /* NaN                      */
 #define VP_SIGN_POSITIVE_ZERO      1 /* Positive zero            */
 #define VP_SIGN_NEGATIVE_ZERO     -1 /* Negative zero            */
@@ -75,13 +126,13 @@
  */
 typedef struct {
     VALUE  obj;     /* Back pointer(VALUE) for Ruby object.     */
-    U_LONG MaxPrec; /* Maximum precision size                   */
+    size_t MaxPrec; /* Maximum precision size                   */
                     /* This is the actual size of pfrac[]       */
                     /*(frac[0] to frac[MaxPrec] are available). */
-    U_LONG Prec;    /* Current precision size.                  */
+    size_t Prec;    /* Current precision size.                  */
                     /* This indicates how much the.             */
                     /* the array frac[] is actually used.       */
-    S_INT  exponent;/* Exponent part.                           */
+    SIGNED_VALUE exponent; /* Exponent part.                    */
     short  sign;    /* Attributes of the value.                 */
                     /*
                      *        ==0 : NaN
@@ -93,24 +144,31 @@
                      *         -3 : Negative infinite number
                      */
     short  flag;    /* Not used in vp_routines,space for user.  */
-    U_LONG frac[1]; /* Pointer to array of fraction part.       */
+    BDIGIT frac[1]; /* Pointer to array of fraction part.       */
 } Real;
 
-/*  
+/*
  *  ------------------
  *   EXPORTables.
  *  ------------------
  */
 
 VP_EXPORT  Real *
-VpNewRbClass(U_LONG mx,const char *str,VALUE klass);
+VpNewRbClass(size_t mx, const char *str, VALUE klass);
 
-VP_EXPORT  Real *VpCreateRbObject(U_LONG mx,const char *str);
+VP_EXPORT  Real *VpCreateRbObject(size_t mx,const char *str);
 
-VP_EXPORT U_LONG VpBaseFig(void);
-VP_EXPORT U_LONG VpDblFig(void);
-VP_EXPORT U_LONG VpBaseVal(void);
+static inline BDIGIT
+rmpd_base_value(void) { return RMPD_BASE; }
+static inline size_t
+rmpd_component_figures(void) { return RMPD_COMPONENT_FIGURES; }
+static inline size_t
+rmpd_double_figures(void) { return 1+DBL_DIG; }
 
+#define VpBaseFig() rmpd_component_figures()
+#define VpDblFig() rmpd_double_figures()
+#define VpBaseVal() rmpd_base_value()
+
 /* Zero,Inf,NaN (isinf(),isnan() used to check) */
 VP_EXPORT double VpGetDoubleNaN(void);
 VP_EXPORT double VpGetDoublePosInf(void);
@@ -118,46 +176,50 @@
 VP_EXPORT double VpGetDoubleNegZero(void);
 
 /* These 2 functions added at v1.1.7 */
-VP_EXPORT U_LONG VpGetPrecLimit(void);
-VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);
+VP_EXPORT size_t VpGetPrecLimit(void);
+VP_EXPORT size_t VpSetPrecLimit(size_t n);
 
 /* Round mode */
-VP_EXPORT int           VpIsRoundMode(unsigned long n);
-VP_EXPORT unsigned long VpGetRoundMode(void);
-VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);
+VP_EXPORT int            VpIsRoundMode(unsigned short n);
+VP_EXPORT unsigned short VpGetRoundMode(void);
+VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
 
 VP_EXPORT int VpException(unsigned short f,const char *str,int always);
-/*VP_EXPORT int VpIsNegDoubleZero(double v);*/
-VP_EXPORT U_LONG VpNumOfChars(Real *vp,const char *pszFmt);
-VP_EXPORT U_LONG VpInit(U_LONG BaseVal);
-VP_EXPORT void *VpMemAlloc(U_LONG mb);
+#if 0  /* unused */
+VP_EXPORT int VpIsNegDoubleZero(double v);
+#endif
+VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
+VP_EXPORT size_t VpInit(BDIGIT BaseVal);
+VP_EXPORT void *VpMemAlloc(size_t mb);
 VP_EXPORT void VpFree(Real *pv);
-VP_EXPORT Real *VpAlloc(U_LONG mx, const char *szVal);
-VP_EXPORT int VpAsgn(Real *c,Real *a,int isw);
-VP_EXPORT int VpAddSub(Real *c,Real *a,Real *b,int operation);
-VP_EXPORT int VpMult(Real *c,Real *a,Real *b);
-VP_EXPORT int VpDivd(Real *c,Real *r,Real *a,Real *b);
+VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal);
+VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
+VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
+VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
+VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
 VP_EXPORT int VpComp(Real *a,Real *b);
-VP_EXPORT S_LONG VpExponent10(Real *a);
+VP_EXPORT ssize_t VpExponent10(Real *a);
 VP_EXPORT void VpSzMantissa(Real *a,char *psz);
 VP_EXPORT int VpToSpecialString(Real *a,char *psz,int fPlus);
-VP_EXPORT void VpToString(Real *a,char *psz,int fFmt,int fPlus);
-VP_EXPORT void VpToFString(Real *a,char *psz,int fFmt,int fPlus);
-VP_EXPORT int VpCtoV(Real *a,const char *int_chr,U_LONG ni,const char *frac,U_LONG nf,const char *exp_chr,U_LONG ne);
-VP_EXPORT int VpVtoD(double *d,S_LONG *e,Real *m);
+VP_EXPORT void VpToString(Real *a, char *psz, size_t fFmt, int fPlus);
+VP_EXPORT void VpToFString(Real *a, char *psz, size_t fFmt, int fPlus);
+VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne);
+VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
 VP_EXPORT void VpDtoV(Real *m,double d);
-/*VP_EXPORT void VpItoV(Real *m,S_INT ival);*/
+#if 0  /* unused */
+VP_EXPORT void VpItoV(Real *m,S_INT ival);
+#endif
 VP_EXPORT int VpSqrt(Real *y,Real *x);
-VP_EXPORT int VpActiveRound(Real *y,Real *x,int f,int il);
-VP_EXPORT int VpMidRound(Real *y, int f, int nf);
-VP_EXPORT int VpLeftRound(Real *y, int f, int nf);
-VP_EXPORT void VpFrac(Real *y,Real *x);
-VP_EXPORT int VpPower(Real *y,Real *x,S_INT n);
+VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
+VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT void VpFrac(Real *y, Real *x);
+VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n);
 
 /* VP constants */
 VP_EXPORT Real *VpOne(void);
 
-/*  
+/*
  *  ------------------
  *  MACRO definitions.
  *  ------------------
@@ -175,12 +237,12 @@
 /* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */
 #define VpGetSign(a) (((a)->sign>0)?1:(-1))
 /* Change sign of a to a>0,a<0 if s = 1,-1 respectively */
-#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((S_LONG)(a)->sign);else (a)->sign=-(short)Abs((S_LONG)(a)->sign);}
+#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((ssize_t)(a)->sign);else (a)->sign=-(short)Abs((ssize_t)(a)->sign);}
 /* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */
 #define VpSetSign(a,s)    {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;}
 
 /* 1 */
-#define VpSetOne(a)       {(a)->frac[0]=(a)->exponent=(a)->Prec=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}
+#define VpSetOne(a)       {(a)->Prec=(a)->exponent=(a)->frac[0]=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}
 
 /* ZEROs */
 #define VpIsPosZero(a)  ((a)->sign==VP_SIGN_POSITIVE_ZERO)
@@ -205,12 +267,12 @@
 #define VpHasVal(a)     (a->frac[0])
 #define VpIsOne(a)      ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
 #define VpExponent(a)   (a->exponent)
-#ifdef _DEBUG
+#ifdef BIGDECIMAL_DEBUG
 int VpVarCheck(Real * v);
-VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);
-#endif /* _DEBUG */
+VP_EXPORT int VPrint(FILE *fp,const char *cntl_chr,Real *a);
+#endif /* BIGDECIMAL_DEBUG */
 
 #if defined(__cplusplus)
 }  /* extern "C" { */
 #endif
-#endif /* ____BIG_DECIMAL__H____ */
+#endif /* RUBY_BIG_DECIMAL_H */

Modified: MacRuby/trunk/ext/bigdecimal/extconf.rb
===================================================================
--- MacRuby/trunk/ext/bigdecimal/extconf.rb	2010-09-10 06:03:14 UTC (rev 4500)
+++ MacRuby/trunk/ext/bigdecimal/extconf.rb	2010-09-10 07:41:26 UTC (rev 4501)
@@ -1,10 +1,6 @@
 require 'mkmf'
 
-base_fig = 0
-src = "(BASE * (BASE+1)) / BASE == (BASE+1)"
-while try_static_assert(src, nil, "-DBASE=10#{'0'*base_fig}UL")
-  base_fig += 1
-end
-$defs << "-DBASE=1#{'0'*base_fig}UL" << "-DBASE_FIG=#{base_fig}"
+have_func("labs", "stdlib.h")
+have_func("llabs", "stdlib.h")
 
 create_makefile('bigdecimal')
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100910/0bd1e05f/attachment-0001.html>


More information about the macruby-changes mailing list