diff src/bytecode.c @ 1983:9c872f33ecbe

[xemacs-hg @ 2004-04-05 22:49:31 by james] Add bignum, ratio, and bigfloat support.
author james
date Mon, 05 Apr 2004 22:50:11 +0000
parents c66036f59678
children 4e6a63799f08
line wrap: on
line diff
--- a/src/bytecode.c	Mon Apr 05 21:50:47 2004 +0000
+++ b/src/bytecode.c	Mon Apr 05 22:50:11 2004 +0000
@@ -246,10 +246,19 @@
 {
  retry:
 
-  if (INTP    (obj)) return make_int (- XINT (obj));
+  if (INTP    (obj)) return make_integer (- XINT (obj));
   if (FLOATP  (obj)) return make_float (- XFLOAT_DATA (obj));
-  if (CHARP   (obj)) return make_int (- ((int) XCHAR (obj)));
-  if (MARKERP (obj)) return make_int (- ((int) marker_position (obj)));
+  if (CHARP   (obj)) return make_integer (- ((int) XCHAR (obj)));
+  if (MARKERP (obj)) return make_integer (- ((int) marker_position (obj)));
+#ifdef HAVE_BIGNUM
+  if (BIGNUMP (obj)) BIGNUM_ARITH_RETURN (obj, neg);
+#endif
+#ifdef HAVE_RATIO
+  if (RATIOP (obj)) RATIO_ARITH_RETURN (obj, neg);
+#endif
+#ifdef HAVE_BIG_FLOAT
+  if (BIGFLOAT_P (obj)) BIGFLOAT_ARITH_RETURN (obj, neg);
+#endif
 
   obj = wrong_type_argument (Qnumber_char_or_marker_p, obj);
   goto retry;
@@ -279,6 +288,33 @@
 static int
 bytecode_arithcompare (Lisp_Object obj1, Lisp_Object obj2)
 {
+#ifdef WITH_NUMBER_TYPES
+  switch (promote_args (&obj1, &obj2))
+    {
+    case FIXNUM_T:
+      {
+	EMACS_INT ival1 = XREALINT (obj1), ival2 = XREALINT (obj2);
+	return ival1 < ival2 ? -1 : ival1 > ival2 ? 1 : 0;
+      }
+#ifdef HAVE_BIGNUM
+    case BIGNUM_T:
+      return bignum_cmp (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2));
+#endif
+#ifdef HAVE_RATIO
+    case RATIO_T:
+      return ratio_cmp (XRATIO_DATA (obj1), XRATIO_DATA (obj2));
+#endif
+    case FLOAT_T:
+      {
+	double dval1 = XFLOAT_DATA (obj1), dval2 = XFLOAT_DATA (obj2);
+	return dval1 < dval2 ? -1 : dval1 > dval2 ? 1 : 0;
+      }
+#ifdef HAVE_BIGFLOAT
+    case BIGFLOAT_T:
+      return bigfloat_cmp (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2));
+#endif
+    }
+#else /* !WITH_NUMBER_TYPES */
   retry:
 
   {
@@ -324,11 +360,151 @@
 
     return dval1 < dval2 ? -1 : dval1 > dval2 ? 1 : 0;
   }
+#endif /* WITH_NUMBER_TYPES */
 }
 
 static Lisp_Object
 bytecode_arithop (Lisp_Object obj1, Lisp_Object obj2, Opcode opcode)
 {
+#ifdef WITH_NUMBER_TYPES
+  switch (promote_args (&obj1, &obj2))
+    {
+    case FIXNUM_T:
+      {
+	EMACS_INT ival1 = XREALINT (obj1), ival2 = XREALINT (obj2);
+	switch (opcode)
+	  {
+	  case Bplus: ival1 += ival2; break;
+	  case Bdiff: ival1 -= ival2; break;
+	  case Bmult:
+#ifdef HAVE_BIGNUM
+	    /* Due to potential overflow, we compute using bignums */
+	    bignum_set_long (scratch_bignum, ival1);
+	    bignum_set_long (scratch_bignum2, ival2);
+	    bignum_mul (scratch_bignum, scratch_bignum, scratch_bignum2);
+	    return Fcanonicalize_number (make_bignum_bg (scratch_bignum));
+#else
+	    ival1 *= ival2; break;
+#endif
+	  case Bquo:
+	    if (ival2 == 0) Fsignal (Qarith_error, Qnil);
+	    ival1 /= ival2;
+	    break;
+	  case Bmax:  if (ival1 < ival2) ival1 = ival2; break;
+	  case Bmin:  if (ival1 > ival2) ival1 = ival2; break;
+	  }
+	return make_integer (ival1);
+      }
+#ifdef HAVE_BIGNUM
+    case BIGNUM_T:
+      switch (opcode)
+	{
+	case Bplus:
+	  bignum_add (scratch_bignum, XBIGNUM_DATA (obj1),
+		      XBIGNUM_DATA (obj2));
+	  break;
+	case Bdiff:
+	  bignum_sub (scratch_bignum, XBIGNUM_DATA (obj1),
+		      XBIGNUM_DATA (obj2));
+	  break;
+	case Bmult:
+	  bignum_mul (scratch_bignum, XBIGNUM_DATA (obj1),
+		      XBIGNUM_DATA (obj2));
+	  break;
+	case Bquo:
+	  if (bignum_sign (XBIGNUM_DATA (obj2)) == 0)
+	    Fsignal (Qarith_error, Qnil);
+	  bignum_div (scratch_bignum, XBIGNUM_DATA (obj1),
+		      XBIGNUM_DATA (obj2));
+	  break;
+	case Bmax:
+	  return bignum_gt (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2))
+	    ? obj1 : obj2;
+	case Bmin:
+	  return bignum_lt (XBIGNUM_DATA (obj1), XBIGNUM_DATA (obj2))
+	    ? obj1 : obj2;
+	}
+      return Fcanonicalize_number (make_bignum_bg (scratch_bignum));
+#endif
+#ifdef HAVE_RATIO
+    case RATIO_T:
+      switch (opcode)
+	{
+	case Bplus:
+	  ratio_add (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2));
+	  break;
+	case Bdiff:
+	  ratio_sub (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2));
+	  break;
+	case Bmult:
+	  ratio_mul (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2));
+	  break;
+	case Bquo:
+	  if (ratio_sign (XRATIO_DATA (obj2)) == 0)
+	    Fsignal (Qarith_error, Qnil);
+	  ratio_div (scratch_ratio, XRATIO_DATA (obj1), XRATIO_DATA (obj2));
+	  break;
+	case Bmax:
+	  return ratio_gt (XRATIO_DATA (obj1), XRATIO_DATA (obj2))
+	    ? obj1 : obj2;
+	case Bmin:
+	  return ratio_lt (XRATIO_DATA (obj1), XRATIO_DATA (obj2))
+	    ? obj1 : obj2;
+	}
+      return make_ratio_rt (scratch_ratio);
+#endif
+    case FLOAT_T:
+      {
+	double dval1 = XFLOAT_DATA (obj1), dval2 = XFLOAT_DATA (obj2);
+	switch (opcode)
+	  {
+	  case Bplus: dval1 += dval2; break;
+	  case Bdiff: dval1 -= dval2; break;
+	  case Bmult: dval1 *= dval2; break;
+	  case Bquo:
+	    if (dval2 == 0.0) Fsignal (Qarith_error, Qnil);
+	    dval1 /= dval2;
+	    break;
+	  case Bmax:  if (dval1 < dval2) dval1 = dval2; break;
+	  case Bmin:  if (dval1 > dval2) dval1 = dval2; break;
+	  }
+	return make_float (dval1);
+      }
+#ifdef HAVE_BIGFLOAT
+    case BIGFLOAT_T:
+      bigfloat_set_prec (scratch_bigfloat, max (XBIGFLOAT_GET_PREC (obj1),
+						XBIGFLOAT_GET_PREC (obj2)));
+      switch (opcode)
+	{
+	case Bplus:
+	  bigfloat_add (scratch_bigfloat, XBIGFLOAT_DATA (obj1),
+			XBIGFLOAT_DATA (obj2));
+	  break;
+	case Bdiff:
+	  bigfloat_sub (scratch_bigfloat, XBIGFLOAT_DATA (obj1),
+			XBIGFLOAT_DATA (obj2));
+	  break;
+	case Bmult:
+	  bigfloat_mul (scratch_bigfloat, XBIGFLOAT_DATA (obj1),
+			XBIGFLOAT_DATA (obj2));
+	  break;
+	case Bquo:
+	  if (bigfloat_sign (XBIGFLOAT_DATA (obj2)) == 0)
+	    Fsignal (Qarith_error, Qnil);
+	  bigfloat_div (scratch_bigfloat, XBIGFLOAT_DATA (obj1),
+			XBIGFLOAT_DATA (obj2));
+	  break;
+	case Bmax:
+	  return bigfloat_gt (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2))
+	    ? obj1 : obj2;
+	case Bmin:
+	  return bigfloat_lt (XBIGFLOAT_DATA (obj1), XBIGFLOAT_DATA (obj2))
+	    ? obj1 : obj2;
+	}
+      return make_bigfloat_bf (scratch_bigfloat);
+#endif
+    }
+#else /* !WITH_NUMBER_TYPES */
   EMACS_INT ival1, ival2;
   int float_p;
 
@@ -390,6 +566,7 @@
 	}
       return make_float (dval1);
     }
+#endif /* WITH_NUMBER_TYPES */
 }
 
 
@@ -806,11 +983,19 @@
 	  break;
 
 	case Bnumberp:
+#ifdef WITH_NUMBER_TYPES
+	  TOP = NUMBERP (TOP) ? Qt : Qnil;
+#else
 	  TOP = INT_OR_FLOATP (TOP) ? Qt : Qnil;
+#endif
 	  break;
 
 	case Bintegerp:
+#ifdef HAVE_BIGNUM
+	  TOP = INTEGERP (TOP) ? Qt : Qnil;
+#else
 	  TOP = INTP (TOP) ? Qt : Qnil;
+#endif
 	  break;
 
 	case Beq:
@@ -907,11 +1092,19 @@
 	  }
 
 	case Bsub1:
+#ifdef HAVE_BIGNUM
+	  TOP = Fsub1 (TOP);
+#else
 	  TOP = INTP (TOP) ? INT_MINUS1 (TOP) : Fsub1 (TOP);
+#endif
 	  break;
 
 	case Badd1:
+#ifdef HAVE_BIGNUM
+	  TOP = Fadd1 (TOP);
+#else
 	  TOP = INTP (TOP) ? INT_PLUS1 (TOP) : Fadd1 (TOP);
+#endif
 	  break;
 
 
@@ -966,9 +1159,13 @@
 	  {
 	    Lisp_Object arg2 = POP;
 	    Lisp_Object arg1 = TOP;
+#ifdef HAVE_BIGNUM
+	    TOP = bytecode_arithop (arg1, arg2, opcode);
+#else
 	    TOP = INTP (arg1) && INTP (arg2) ?
 	      INT_PLUS (arg1, arg2) :
 	      bytecode_arithop (arg1, arg2, opcode);
+#endif
 	    break;
 	  }
 
@@ -976,9 +1173,13 @@
 	  {
 	    Lisp_Object arg2 = POP;
 	    Lisp_Object arg1 = TOP;
+#ifdef HAVE_BIGNUM
+	    TOP = bytecode_arithop (arg1, arg2, opcode);
+#else
 	    TOP = INTP (arg1) && INTP (arg2) ?
 	      INT_MINUS (arg1, arg2) :
 	      bytecode_arithop (arg1, arg2, opcode);
+#endif
 	    break;
 	  }