summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-08-17 18:27:36 +0000
committerwyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-08-17 18:27:36 +0000
commit6f1649e091dfc2c58d29e524f31d0295e885da84 (patch)
tree46f5e2be95973842c2e9ffa19fb682e991940ae8 /ext
parent2176130373f03ad76c814dd652044f23f9158a69 (diff)
ext/bigdecimal/bigdecimal.c: Backport #2349 [ruby-core:26646]; fix comparisons. Also fix a bunch of bugs that lead to broken-ness and failing tests.
test/bigdecimal/test_bigdecimal.rb: Backport #2349 [ruby-core:26646]; added a test suite. test/ruby/test_exception.rb: The test suite was breaking ZeroDivisionError, which in turn would break bigdecimal/test_bigdecimal.rb. Made a simple fix that keeps that test but does so non-destructively. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_6@29025 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r--ext/bigdecimal/bigdecimal.c126
-rw-r--r--ext/bigdecimal/bigdecimal.h2
2 files changed, 101 insertions, 27 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index e16d1d62e9..4984075c79 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -414,11 +414,22 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
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) {
@@ -533,14 +544,11 @@ BigDecimal_to_i(VALUE self)
/* Infinity or NaN not converted. */
if(VpIsNaN(p)) {
- VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
- return Qnil;
+ VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",1);
} else if(VpIsPosInf(p)) {
- VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
- return Qnil;
+ VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",1);
} else if(VpIsNegInf(p)) {
- VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
- return Qnil;
+ VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",1);
}
e = VpExponent10(p);
@@ -732,6 +740,7 @@ BigDecimal_sub(VALUE self, VALUE r)
return ToValue(c);
}
+/*
static VALUE
BigDecimalCmp(VALUE self, VALUE r,char op)
{
@@ -746,7 +755,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
if(e==999) return Qnil;
switch(op)
{
- case '*': return INT2FIX(e); /* any op */
+ case '*': return INT2FIX(e);
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;
@@ -756,6 +765,48 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
}
rb_bug("Undefined operation in BigDecimalCmp()");
}
+*/
+
+
+static VALUE
+BigDecimalCmp(VALUE self, VALUE r,char op)
+{
+ ENTER(5);
+ S_INT e;
+ Real *a, *b;
+ GUARD_OBJ(a,GetVpValue(self,1));
+ b = GetVpValue(r,0);
+ if(!b) {
+ ID f = 0;
+
+ switch(op)
+ {
+ /* case '*': return rb_num_coerce_cmp(self,r,rb_intern("<=>")); */
+ case '*': return rb_num_coerce_cmp(self,r);
+ /* case '=': return RTEST(rb_num_coerce_cmp(self,r,rb_intern("=="))) ? Qtrue : Qfalse; */
+ case '=': return RTEST(rb_num_coerce_cmp(self,r)) ? Qtrue : Qfalse;
+ case 'G': f = rb_intern(">="); break;
+ case 'L': f = rb_intern("<="); break;
+ case '>': case '<': f = (ID)op; break;
+ }
+ /* return rb_num_coerce_relop(self,r,f); */
+ return rb_num_coerce_relop(self,r);
+ }
+ SAVE(b);
+ e = VpComp(a, b);
+ if(e==999) return (op == '*') ? Qnil : Qfalse;
+ switch(op)
+ {
+ case '*': return INT2FIX(e); /* any op */
+ 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;
+ case '<': if(e< 0) return Qtrue ; return Qfalse;
+ }
+ rb_bug("Undefined operation in BigDecimalCmp()");
+}
+
/* Returns True if the value is zero. */
static VALUE
@@ -962,7 +1013,9 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
if(VpIsInf(a) || VpIsInf(b)) goto NaN;
- if(VpIsZero(b)) goto NaN;
+ if(VpIsZero(b)) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
if(VpIsZero(a)) {
GUARD_OBJ(c,VpCreateRbObject(1, "0"));
GUARD_OBJ(d,VpCreateRbObject(1, "0"));
@@ -2105,9 +2158,9 @@ VpGetRoundMode(void)
VP_EXPORT int
VpIsRoundMode(unsigned long 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 ||
+ 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;
@@ -2225,18 +2278,12 @@ VpException(unsigned short f, const char *str,int always)
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;
@@ -3924,14 +3971,15 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con
{
U_LONG i, j, ind_a, ma, mi, me;
U_LONG loc;
- S_INT e,es, eb, ef;
- S_INT sign, signe;
+ S_LONG e,es, eb, ef;
+ S_INT sign, signe, exponent_overflow;
/* get exponent part */
e = 0;
ma = a->MaxPrec;
mi = ni;
me = ne;
signe = 1;
+ exponent_overflow = 0;
memset(a->frac, 0, ma * sizeof(U_LONG));
if(ne > 0) {
i = 0;
@@ -3946,8 +3994,10 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con
while(i < me) {
es = e*((S_INT)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 > (S_INT)(e*BASE_FIG)) {
+ exponent_overflow = 1;
+ e = es; /* keep sign */
+ break;
}
++i;
}
@@ -3956,7 +4006,7 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con
/* get integer part */
i = 0;
sign = 1;
- if(ni >= 0) {
+ if(1 /*ni >= 0*/) {
if(int_chr[0] == '-') {
sign = -1;
++i;
@@ -3989,6 +4039,18 @@ VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, con
eb = e / ((S_INT)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) {
a->frac[ind_a] = 0;
@@ -4032,7 +4094,7 @@ Final:
++j;
}
a->Prec = ind_a + 1;
- a->exponent = eb;
+ a->exponent = (S_INT)eb;
VpSetSign(a,sign);
VpNmlz(a);
return 1;
@@ -4633,8 +4695,20 @@ VpPower(Real *y, Real *x, S_INT n)
}
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;
}
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
index 4f77feab00..70a48a3c34 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -45,7 +45,7 @@ extern "C" {
#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)