0 ** 0 bug fixed.

ROUND_MODE introduced,COMP_MODE removed & round method substantially changed.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4174 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shigek 2003-07-26 13:04:57 +00:00
parent 92aee059e8
commit 472efdfeb4
2 changed files with 70 additions and 56 deletions

View File

@ -288,10 +288,10 @@ BigDecimal_mode(VALUE self, VALUE which, VALUE val)
} }
return INT2FIX(fo); return INT2FIX(fo);
} }
if(VP_COMP_MODE==f) { if(VP_ROUND_MODE==f) {
/* Computaion mode setting */ /* Rounding mode setting */
if(TYPE(val)!=T_FIXNUM) return Qnil; if(TYPE(val)!=T_FIXNUM) return Qnil;
fo = VpSetCompMode((unsigned long)FIX2INT(val)); fo = VpSetRoundMode((unsigned long)FIX2INT(val));
return INT2FIX(fo); return INT2FIX(fo);
} }
return Qnil; return Qnil;
@ -729,7 +729,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
VpDivd(c, res, a, b); VpDivd(c, res, a, b);
mx = c->Prec *(VpBaseFig() + 1); mx = c->Prec *(VpBaseFig() + 1);
GUARD_OBJ(d,VpCreateRbObject(mx, "0")); GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
VpActiveRound(d,c,VP_COMP_MODE_FLOOR,0); VpActiveRound(d,c,VP_ROUND_FLOOR,0);
VpMult(res,d,b); VpMult(res,d,b);
VpAddSub(c,a,res,-1); VpAddSub(c,a,res,-1);
*div = d; *div = d;
@ -776,7 +776,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
GUARD_OBJ(d,VpCreateRbObject(mx, "0")); GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
GUARD_OBJ(f,VpCreateRbObject(mx, "0")); GUARD_OBJ(f,VpCreateRbObject(mx, "0"));
VpActiveRound(d,c,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */ VpActiveRound(d,c,VP_ROUND_DOWN,0); /* 0: round off */
VpFrac(f, c); VpFrac(f, c);
VpMult(rr,f,b); VpMult(rr,f,b);
@ -828,7 +828,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
mx = cv->MaxPrec+1; mx = cv->MaxPrec+1;
GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0")); GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
VpDivd(cv,res,av,bv); VpDivd(cv,res,av,bv);
VpLeftRound(cv,VpGetCompMode(),ix); VpLeftRound(cv,VpGetRoundMode(),ix);
return ToValue(cv); return ToValue(cv);
} }
@ -840,7 +840,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_add(self,b); VALUE c = BigDecimal_add(self,b);
GUARD_OBJ(cv,GetVpValue(c,1)); GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx); VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv); return ToValue(cv);
} }
@ -852,7 +852,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_sub(self,b); VALUE c = BigDecimal_sub(self,b);
GUARD_OBJ(cv,GetVpValue(c,1)); GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx); VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv); return ToValue(cv);
} }
@ -864,7 +864,7 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_mult(self,b); VALUE c = BigDecimal_mult(self,b);
GUARD_OBJ(cv,GetVpValue(c,1)); GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx); VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv); return ToValue(cv);
} }
@ -911,7 +911,7 @@ BigDecimal_fix(VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */ VpActiveRound(c,a,VP_ROUND_DOWN,0); /* 0: round off */
return ToValue(c); return ToValue(c);
} }
@ -924,9 +924,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
int sw; int sw;
U_LONG mx; U_LONG mx;
VALUE vLoc; VALUE vLoc;
VALUE vBanker; int na = rb_scan_args(argc,argv,"01",&vLoc);
int na = rb_scan_args(argc,argv,"02",&vLoc,&vBanker);
sw = VP_COMP_MODE_ROUNDUP; /* round up */
switch(na) { switch(na) {
case 0: case 0:
iLoc = 0; iLoc = 0;
@ -935,18 +933,12 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
Check_Type(vLoc, T_FIXNUM); Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc); iLoc = FIX2INT(vLoc);
break; break;
case 2:
Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc);
Check_Type(vBanker, T_FIXNUM);
if(FIX2INT(vBanker)) sw = VP_COMP_MODE_EVEN; /* Banker's rounding */
break;
} }
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,sw,iLoc); VpActiveRound(c,a,VpGetRoundMode(),iLoc);
return ToValue(c); return ToValue(c);
} }
@ -969,7 +961,7 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,iLoc); /* 0: truncate */ VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */
return ToValue(c); return ToValue(c);
} }
@ -1006,7 +998,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_FLOOR,iLoc); VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
return ToValue(c); return ToValue(c);
} }
@ -1029,7 +1021,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_CEIL,iLoc); VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
return ToValue(c); return ToValue(c);
} }
@ -1292,12 +1284,14 @@ Init_bigdecimal(void)
rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE)); rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));
/* Computation mode */ /* Computation mode */
rb_define_const(rb_cBigDecimal, "COMP_MODE",INT2FIX(VP_COMP_MODE)); rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));
rb_define_const(rb_cBigDecimal, "COMP_MODE_TRUNCATE",INT2FIX(VP_COMP_MODE_TRUNCATE)); rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));
rb_define_const(rb_cBigDecimal, "COMP_MODE_ROUND",INT2FIX(VP_COMP_MODE_ROUNDUP)); rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));
rb_define_const(rb_cBigDecimal, "COMP_MODE_CEIL",INT2FIX(VP_COMP_MODE_CEIL)); rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));
rb_define_const(rb_cBigDecimal, "COMP_MODE_FLOOR",INT2FIX(VP_COMP_MODE_FLOOR)); rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
rb_define_const(rb_cBigDecimal, "COMP_MODE_EVEN",INT2FIX(VP_COMP_MODE_EVEN)); rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL));
rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));
rb_define_const(rb_cBigDecimal, "ROUND_EVEN",INT2FIX(VP_ROUND_EVEN));
/* Constants for sign value */ /* Constants for sign value */
rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN)); rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
@ -1383,7 +1377,7 @@ static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
#endif /* _DEBUG */ #endif /* _DEBUG */
static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */ static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */
static short gfCompMode = VP_COMP_MODE_ROUNDUP; /* Mode for general computation */ static short gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation */
static U_LONG BASE_FIG = 4; /* =log10(BASE) */ static U_LONG BASE_FIG = 4; /* =log10(BASE) */
static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */ static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */
@ -1482,18 +1476,20 @@ VpSetPrecLimit(U_LONG n)
} }
VP_EXPORT unsigned long VP_EXPORT unsigned long
VpGetCompMode(void) VpGetRoundMode(void)
{ {
return gfCompMode; return gfRoundMode;
} }
VP_EXPORT unsigned long VP_EXPORT unsigned long
VpSetCompMode(unsigned long n) VpSetRoundMode(unsigned long n)
{ {
unsigned long s = gfCompMode; unsigned long s = gfRoundMode;
if(n!=VP_COMP_MODE_TRUNCATE && n!= VP_COMP_MODE_ROUNDUP && n!=VP_COMP_MODE_CEIL && if(n!=VP_ROUND_UP && n!=VP_ROUND_DOWN &&
n!=VP_COMP_MODE_FLOOR && n!= VP_COMP_MODE_EVEN) return s; n!=VP_ROUND_HALF_UP && n!=VP_ROUND_HALF_DOWN &&
gfCompMode = n; n!=VP_ROUND_CEIL && n!=VP_ROUND_FLOOR &&
n!=VP_ROUND_EVEN) return s;
gfRoundMode = n;
return s; return s;
} }
@ -3656,18 +3652,24 @@ VpMidRound(Real *y, int f, int nf)
div = v/10; div = v/10;
v = v - div*10; v = v - div*10;
switch(f) { switch(f) {
case VP_COMP_MODE_TRUNCATE: /* Truncate/Round off */ case VP_ROUND_DOWN: /* Truncate */
break; break;
case VP_COMP_MODE_ROUNDUP: /* Round up */ case VP_ROUND_UP: /* Roundup */
if(v) ++div;
break;
case VP_ROUND_HALF_UP: /* Round half up */
if(v>=5) ++div; if(v>=5) ++div;
break; break;
case VP_COMP_MODE_CEIL: /* ceil */ case VP_ROUND_HALF_DOWN: /* Round half down */
if(v>=6) ++div;
break;
case VP_ROUND_CEIL: /* ceil */
if(v && (VpGetSign(y)>0)) ++div; if(v && (VpGetSign(y)>0)) ++div;
break; break;
case VP_COMP_MODE_FLOOR: /* floor */ case VP_ROUND_FLOOR: /* floor */
if(v && (VpGetSign(y)<0)) ++div; if(v && (VpGetSign(y)<0)) ++div;
break; break;
case VP_COMP_MODE_EVEN: /* Banker's rounding */ case VP_ROUND_EVEN: /* Banker's rounding */
if(v>5) ++div; if(v>5) ++div;
else if(v==5) { else if(v==5) {
if(i==(BASE_FIG-1)) { if(i==(BASE_FIG-1)) {
@ -3731,19 +3733,25 @@ VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
if(VpIsZero(c)) return f; if(VpIsZero(c)) return f;
v /= BASE1; v /= BASE1;
switch(gfCompMode) { switch(gfRoundMode) {
case VP_COMP_MODE_TRUNCATE: case VP_ROUND_DOWN:
break; break;
case VP_COMP_MODE_ROUNDUP: case VP_ROUND_UP:
if(v) f = 1;
break;
case VP_ROUND_HALF_UP:
if(v >= 5) f = 1; if(v >= 5) f = 1;
break; break;
case VP_COMP_MODE_CEIL: /* ceil */ case VP_ROUND_HALF_DOWN:
if(v >= 6) f = 1;
break;
case VP_ROUND_CEIL: /* ceil */
if(v && (VpGetSign(c)>0)) f = 1; if(v && (VpGetSign(c)>0)) f = 1;
break; break;
case VP_COMP_MODE_FLOOR: /* floor */ case VP_ROUND_FLOOR: /* floor */
if(v && (VpGetSign(c)<0)) f = 1; if(v && (VpGetSign(c)<0)) f = 1;
break; break;
case VP_COMP_MODE_EVEN: /* Banker's rounding */ case VP_ROUND_EVEN: /* Banker's rounding */
if(v>5) f = 1; if(v>5) f = 1;
else if(v==5 && vPrev%2) f = 1; else if(v==5 && vPrev%2) f = 1;
break; break;
@ -3832,6 +3840,10 @@ VpPower(Real *y, Real *x, S_INT n)
Real *w2 = NULL; Real *w2 = NULL;
if(VpIsZero(x)) { if(VpIsZero(x)) {
if(n==0) {
VpSetOne(y);
goto Exit;
}
sign = VpGetSign(x); sign = VpGetSign(x);
if(n<0) { if(n<0) {
n = -n; n = -n;

View File

@ -52,12 +52,14 @@ extern "C" {
#define VP_EXCEPTION_MEMORY ((unsigned short)0x0040) #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)
/* Computation mode */ /* Computation mode */
#define VP_COMP_MODE ((unsigned short)0x0100) #define VP_ROUND_MODE ((unsigned short)0x0100)
#define VP_COMP_MODE_TRUNCATE 0 #define VP_ROUND_UP 1
#define VP_COMP_MODE_ROUNDUP 1 #define VP_ROUND_DOWN 2
#define VP_COMP_MODE_CEIL 2 #define VP_ROUND_HALF_UP 3
#define VP_COMP_MODE_FLOOR 3 #define VP_ROUND_HALF_DOWN 4
#define VP_COMP_MODE_EVEN 4 #define VP_ROUND_CEIL 5
#define VP_ROUND_FLOOR 6
#define VP_ROUND_EVEN 7
#define VP_SIGN_NaN 0 /* NaN */ #define VP_SIGN_NaN 0 /* NaN */
#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */ #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
@ -120,8 +122,8 @@ VP_EXPORT U_LONG VpGetPrecLimit(void);
VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n); VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);
/* Computation mode */ /* Computation mode */
VP_EXPORT unsigned long VpGetCompMode(void); VP_EXPORT unsigned long VpGetRoundMode(void);
VP_EXPORT unsigned long VpSetCompMode(unsigned long n); VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);
VP_EXPORT int VpException(unsigned short f,char *str,int always); VP_EXPORT int VpException(unsigned short f,char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v); VP_EXPORT int VpIsNegDoubleZero(double v);