diff options
author | wyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-08-17 18:27:36 +0000 |
---|---|---|
committer | wyhaines <wyhaines@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-08-17 18:27:36 +0000 |
commit | 6f1649e091dfc2c58d29e524f31d0295e885da84 (patch) | |
tree | 46f5e2be95973842c2e9ffa19fb682e991940ae8 /ext | |
parent | 2176130373f03ad76c814dd652044f23f9158a69 (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.c | 126 | ||||
-rw-r--r-- | ext/bigdecimal/bigdecimal.h | 2 |
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) |