summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorshigek <shigek@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-07-26 13:04:57 +0000
committershigek <shigek@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-07-26 13:04:57 +0000
commit472efdfeb41af1b2b5376af3f5a5e870f02b7374 (patch)
tree1cd021ce4fcc966968924504193d0e78689c5ea9 /ext
parent92aee059e87f97b8ea0a56a85196109005702ffe (diff)
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
Diffstat (limited to 'ext')
-rw-r--r--ext/bigdecimal/bigdecimal.c110
-rw-r--r--ext/bigdecimal/bigdecimal.h18
2 files changed, 71 insertions, 57 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index d11e8fa5b9..a5d29660fb 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -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;
@@ -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;
@@ -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);
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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;
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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);
}
@@ -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));
@@ -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) */
@@ -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;
}
@@ -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)) {
@@ -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;
@@ -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;
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
index 9341c6dc42..62c89dce50 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -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 */
@@ -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);