Skip to content

Commit

Permalink
0 ** 0 bug fixed.
Browse files Browse the repository at this point in the history
ROUND_MODE introduced,COMP_MODE removed & round method substantially changed.


git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@4174 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
shigek committed Jul 26, 2003
1 parent 29c0bd7 commit 858f51d
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 57 deletions.
110 changes: 61 additions & 49 deletions ext/bigdecimal/bigdecimal.c
Expand Up @@ -288,10 +288,10 @@ BigDecimal_mode(VALUE self, VALUE which, VALUE val)
}
return INT2FIX(fo);
}
if(VP_COMP_MODE==f) {
/* Computaion mode setting */
if(VP_ROUND_MODE==f) {
/* Rounding mode setting */
if(TYPE(val)!=T_FIXNUM) return Qnil;
fo = VpSetCompMode((unsigned long)FIX2INT(val));
fo = VpSetRoundMode((unsigned long)FIX2INT(val));
return INT2FIX(fo);
}
return Qnil;
Expand Down Expand Up @@ -729,7 +729,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
VpDivd(c, res, a, b);
mx = c->Prec *(VpBaseFig() + 1);
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);
VpAddSub(c,a,res,-1);
*div = d;
Expand Down Expand Up @@ -776,7 +776,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
GUARD_OBJ(d,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);
VpMult(rr,f,b);
Expand Down Expand Up @@ -828,7 +828,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
mx = cv->MaxPrec+1;
GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
VpDivd(cv,res,av,bv);
VpLeftRound(cv,VpGetCompMode(),ix);
VpLeftRound(cv,VpGetRoundMode(),ix);
return ToValue(cv);
}

Expand All @@ -840,7 +840,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_add(self,b);
GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx);
VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv);
}

Expand All @@ -852,7 +852,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_sub(self,b);
GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx);
VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv);
}

Expand All @@ -864,7 +864,7 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
U_LONG mx = (U_LONG)GetPositiveInt(n);
VALUE c = BigDecimal_mult(self,b);
GUARD_OBJ(cv,GetVpValue(c,1));
VpLeftRound(cv,VpGetCompMode(),mx);
VpLeftRound(cv,VpGetRoundMode(),mx);
return ToValue(cv);
}

Expand Down Expand Up @@ -911,7 +911,7 @@ BigDecimal_fix(VALUE self)
GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1);
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);
}

Expand All @@ -924,9 +924,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
int sw;
U_LONG mx;
VALUE vLoc;
VALUE vBanker;
int na = rb_scan_args(argc,argv,"02",&vLoc,&vBanker);
sw = VP_COMP_MODE_ROUNDUP; /* round up */
int na = rb_scan_args(argc,argv,"01",&vLoc);
switch(na) {
case 0:
iLoc = 0;
Expand All @@ -935,18 +933,12 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc);
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));
mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,sw,iLoc);
VpActiveRound(c,a,VpGetRoundMode(),iLoc);
return ToValue(c);
}

Expand All @@ -969,7 +961,7 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1);
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);
}

Expand Down Expand Up @@ -1006,7 +998,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_FLOOR,iLoc);
VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
return ToValue(c);
}

Expand All @@ -1029,7 +1021,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpActiveRound(c,a,VP_COMP_MODE_CEIL,iLoc);
VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
return ToValue(c);
}

Expand Down Expand Up @@ -1292,12 +1284,14 @@ Init_bigdecimal(void)
rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));

/* Computation mode */
rb_define_const(rb_cBigDecimal, "COMP_MODE",INT2FIX(VP_COMP_MODE));
rb_define_const(rb_cBigDecimal, "COMP_MODE_TRUNCATE",INT2FIX(VP_COMP_MODE_TRUNCATE));
rb_define_const(rb_cBigDecimal, "COMP_MODE_ROUND",INT2FIX(VP_COMP_MODE_ROUNDUP));
rb_define_const(rb_cBigDecimal, "COMP_MODE_CEIL",INT2FIX(VP_COMP_MODE_CEIL));
rb_define_const(rb_cBigDecimal, "COMP_MODE_FLOOR",INT2FIX(VP_COMP_MODE_FLOOR));
rb_define_const(rb_cBigDecimal, "COMP_MODE_EVEN",INT2FIX(VP_COMP_MODE_EVEN));
rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));
rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));
rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));
rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));
rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
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 */
rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
Expand Down Expand Up @@ -1383,7 +1377,7 @@ 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 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 = 10000L; /* Base value(value must be 10**BASE_FIG) */
Expand Down Expand Up @@ -1482,18 +1476,20 @@ VpSetPrecLimit(U_LONG n)
}

VP_EXPORT unsigned long
VpGetCompMode(void)
VpGetRoundMode(void)
{
return gfCompMode;
return gfRoundMode;
}

VP_EXPORT unsigned long
VpSetCompMode(unsigned long n)
{
unsigned long s = gfCompMode;
if(n!=VP_COMP_MODE_TRUNCATE && n!= VP_COMP_MODE_ROUNDUP && n!=VP_COMP_MODE_CEIL &&
n!=VP_COMP_MODE_FLOOR && n!= VP_COMP_MODE_EVEN) return s;
gfCompMode = n;
VpSetRoundMode(unsigned long n)
{
unsigned long s = gfRoundMode;
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_EVEN) return s;
gfRoundMode = n;
return s;
}

Expand Down Expand Up @@ -3656,18 +3652,24 @@ VpMidRound(Real *y, int f, int nf)
div = v/10;
v = v - div*10;
switch(f) {
case VP_COMP_MODE_TRUNCATE: /* Truncate/Round off */
case VP_ROUND_DOWN: /* Truncate */
break;
case VP_ROUND_UP: /* Roundup */
if(v) ++div;
break;
case VP_COMP_MODE_ROUNDUP: /* Round up */
case VP_ROUND_HALF_UP: /* Round half up */
if(v>=5) ++div;
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;
break;
case VP_COMP_MODE_FLOOR: /* floor */
case VP_ROUND_FLOOR: /* floor */
if(v && (VpGetSign(y)<0)) ++div;
break;
case VP_COMP_MODE_EVEN: /* Banker's rounding */
case VP_ROUND_EVEN: /* Banker's rounding */
if(v>5) ++div;
else if(v==5) {
if(i==(BASE_FIG-1)) {
Expand Down Expand Up @@ -3731,19 +3733,25 @@ VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
if(VpIsZero(c)) return f;

v /= BASE1;
switch(gfCompMode) {
case VP_COMP_MODE_TRUNCATE:
switch(gfRoundMode) {
case VP_ROUND_DOWN:
break;
case VP_ROUND_UP:
if(v) f = 1;
break;
case VP_COMP_MODE_ROUNDUP:
case VP_ROUND_HALF_UP:
if(v >= 5) f = 1;
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;
break;
case VP_COMP_MODE_FLOOR: /* floor */
case VP_ROUND_FLOOR: /* floor */
if(v && (VpGetSign(c)<0)) f = 1;
break;
case VP_COMP_MODE_EVEN: /* Banker's rounding */
case VP_ROUND_EVEN: /* Banker's rounding */
if(v>5) f = 1;
else if(v==5 && vPrev%2) f = 1;
break;
Expand Down Expand Up @@ -3832,6 +3840,10 @@ VpPower(Real *y, Real *x, S_INT n)
Real *w2 = NULL;

if(VpIsZero(x)) {
if(n==0) {
VpSetOne(y);
goto Exit;
}
sign = VpGetSign(x);
if(n<0) {
n = -n;
Expand Down
18 changes: 10 additions & 8 deletions ext/bigdecimal/bigdecimal.h
Expand Up @@ -52,12 +52,14 @@ extern "C" {
#define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)

/* Computation mode */
#define VP_COMP_MODE ((unsigned short)0x0100)
#define VP_COMP_MODE_TRUNCATE 0
#define VP_COMP_MODE_ROUNDUP 1
#define VP_COMP_MODE_CEIL 2
#define VP_COMP_MODE_FLOOR 3
#define VP_COMP_MODE_EVEN 4
#define VP_ROUND_MODE ((unsigned short)0x0100)
#define VP_ROUND_UP 1
#define VP_ROUND_DOWN 2
#define VP_ROUND_HALF_UP 3
#define VP_ROUND_HALF_DOWN 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_POSITIVE_ZERO 1 /* Positive zero */
Expand Down Expand Up @@ -120,8 +122,8 @@ VP_EXPORT U_LONG VpGetPrecLimit(void);
VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);

/* Computation mode */
VP_EXPORT unsigned long VpGetCompMode(void);
VP_EXPORT unsigned long VpSetCompMode(unsigned long n);
VP_EXPORT unsigned long VpGetRoundMode(void);
VP_EXPORT unsigned long VpSetRoundMode(unsigned long n);

VP_EXPORT int VpException(unsigned short f,char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v);
Expand Down

0 comments on commit 858f51d

Please sign in to comment.