summaryrefslogtreecommitdiff
path: root/ext/bigdecimal
diff options
context:
space:
mode:
authorshigek <shigek@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-08-15 14:09:51 +0000
committershigek <shigek@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-08-15 14:09:51 +0000
commit6b0e6a7ce7757c42fbfbf244ce917cbb67fa6d50 (patch)
tree50ba13febf9b189a8d3f1930085749dfcb5bcb7e /ext/bigdecimal
parent625c1361e368f6f13f303de0310e6625d7b5296b (diff)
Bug fix: limit & div combination.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4393 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/bigdecimal')
-rw-r--r--ext/bigdecimal/bigdecimal.c78
-rw-r--r--ext/bigdecimal/bigdecimal.h6
2 files changed, 42 insertions, 42 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 2f98bfd487..85b6fd7119 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -449,12 +449,10 @@ BigDecimal_add(VALUE self, VALUE r)
ENTER(5);
Real *c, *a, *b;
U_LONG mx;
-
GUARD_OBJ(a,GetVpValue(self,1));
b = GetVpValue(r,0);
if(!b) return DoSomeOne(self,r);
SAVE(b);
-
if(VpIsNaN(b)) return b->obj;
if(VpIsNaN(a)) return a->obj;
mx = GetAddSubPrec(a,b);
@@ -626,7 +624,7 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
SAVE(b);
*div = b;
mx =(a->MaxPrec + b->MaxPrec + 1) * VpBaseFig();
- GUARD_OBJ((*c),VpCreateRbObject(mx, "0"));
+ GUARD_OBJ((*c),VpCreateRbObject(mx, "#0"));
GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
VpDivd(*c, *res, a, b);
return (VALUE)0;
@@ -646,7 +644,7 @@ BigDecimal_div(VALUE self, VALUE r)
r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
*/
/* Round */
- if(div->frac[0]) { /* frac[0] must be zero for NaN,INF,Zero */
+ if(VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
VpInternalRound(c,0,c->frac[c->Prec-1],(VpBaseVal()*res->frac[0])/div->frac[0]);
}
return ToValue(c);
@@ -1420,7 +1418,7 @@ Init_bigdecimal(void)
*
*/
#ifdef _DEBUG
-static int gfDebug = 1; /* Debug switch */
+/*static int gfDebug = 1;*/ /* Debug switch */
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
#endif /* _DEBUG */
@@ -1446,8 +1444,8 @@ static U_LONG maxnr = 100; /* Maximum iterations for calcurating sqrt. */
static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
static int AddExponent(Real *a,S_INT n);
-static int VpAddAbs(Real *a,Real *b,Real *c);
-static int VpSubAbs(Real *a,Real *b,Real *c);
+static U_LONG VpAddAbs(Real *a,Real *b,Real *c);
+static U_LONG VpSubAbs(Real *a,Real *b,Real *c);
static U_LONG VpSetPTR(Real *a,Real *b,Real *c,U_LONG *a_pos,U_LONG *b_pos,U_LONG *c_pos,U_LONG *av,U_LONG *bv);
static int VpNmlz(Real *a);
static void VpFormatSt(char *psz,S_INT fFmt);
@@ -2109,6 +2107,7 @@ VpAddSub(Real *c, Real *a, Real *b, int operation)
S_INT sw, isw;
Real *a_ptr, *b_ptr;
U_LONG n, na, nb, i;
+ U_LONG mrv;
#ifdef _DEBUG
if(gfDebug) {
@@ -2201,17 +2200,18 @@ end_if:
*/
if(isw) { /* addition */
VpSetSign(c,(S_INT)1);
- VpAddAbs(a_ptr, b_ptr, c);
+ mrv = VpAddAbs(a_ptr, b_ptr, c);
VpSetSign(c,isw / 2);
} else { /* subtraction */
VpSetSign(c,(S_INT)1);
- VpSubAbs(a_ptr, b_ptr, c);
+ mrv = VpSubAbs(a_ptr, b_ptr, c);
if(a_ptr == a) {
VpSetSign(c,VpGetSign(a));
} else {
VpSetSign(c,VpGetSign(a_ptr) * sw);
}
}
+ VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv);
#ifdef _DEBUG
if(gfDebug) {
@@ -2229,7 +2229,7 @@ end_if:
* a and b assuming abs(a)>abs(b).
* c = abs(a) + abs(b) ; where |a|>=|b|
*/
-static int
+static U_LONG
VpAddAbs(Real *a, Real *b, Real *c)
{
U_LONG word_shift;
@@ -2310,11 +2310,11 @@ VpAddAbs(Real *a, Real *b, Real *c)
}
}
if(c_pos) c->frac[c_pos - 1] += carry;
- VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv);
goto Exit;
Assign_a:
VpAsgn(c, a, 1);
+ mrv = 0;
Exit:
@@ -2323,13 +2323,13 @@ Exit:
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
}
#endif /* _DEBUG */
- return 1;
+ return mrv;
}
/*
* c = abs(a) - abs(b)
*/
-static int
+static U_LONG
VpSubAbs(Real *a, Real *b, Real *c)
{
U_LONG word_shift;
@@ -2423,11 +2423,11 @@ VpSubAbs(Real *a, Real *b, Real *c)
}
}
if(c_pos) c->frac[c_pos - 1] -= borrow;
- VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv);
goto Exit;
Assign_a:
VpAsgn(c, a, 1);
+ mrv = 0;
Exit:
#ifdef _DEBUG
@@ -2435,7 +2435,7 @@ Exit:
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
}
#endif /* _DEBUG */
- return 1;
+ return mrv;
}
/*
@@ -2885,10 +2885,9 @@ VpNmlz(Real *a)
{
U_LONG ind_a, i, j;
- if(VpIsZero(a)) {
- VpSetZero(a,VpGetSign(a));
- return 1;
- }
+ if(!VpIsDef(a)) goto NoVal;
+ if(VpIsZero(a)) goto NoVal;
+
ind_a = a->Prec;
while(ind_a--) {
if(a->frac[ind_a]) {
@@ -2912,7 +2911,12 @@ VpNmlz(Real *a)
}
/* a is zero(no non-zero digit) */
VpSetZero(a,VpGetSign(a));
- return 1;
+ return 0;
+
+NoVal:
+ a->frac[0] = 0;
+ a->Prec=1;
+ return 0;
}
/*
@@ -3760,7 +3764,7 @@ Exit:
* nf: digit position for operation.
*
*/
-VP_EXPORT void
+VP_EXPORT int
VpMidRound(Real *y, int f, int nf)
/*
* Round reletively from the decimal point.
@@ -3773,11 +3777,11 @@ VpMidRound(Real *y, int f, int nf)
U_LONG div;
nf += y->exponent*((int)BASE_FIG);
-
/* ix: x->fraq[ix] contains round position */
ix = nf/(int)BASE_FIG;
- if(ix<0 || ((U_LONG)ix)>=y->Prec) return; /* Unable to round */
+ if(ix<0 || ((U_LONG)ix)>=y->Prec) return 0; /* Unable to round */
ioffset = nf - ix*((int)BASE_FIG);
+
memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
v = y->frac[ix];
/* drop digits after pointed digit */
@@ -3829,31 +3833,30 @@ VpMidRound(Real *y, int f, int nf)
y->frac[ix] = div;
VpNmlz(y);
}
+ return 1;
}
-VP_EXPORT void
+VP_EXPORT int
VpLeftRound(Real *y, int f, int nf)
/*
* Round from the left hand side of the digits.
*/
{
U_LONG v;
-
- if(!VpHasVal(y)) return; /* Unable to round */
-
+ if(!VpHasVal(y)) return 0; /* Unable to round */
v = y->frac[0];
nf -= VpExponent(y)*BASE_FIG;
while(v=v/10) nf--;
nf += (BASE_FIG-1);
- VpMidRound(y,f,nf);
+ return VpMidRound(y,f,nf);
}
-VP_EXPORT void
+VP_EXPORT int
VpActiveRound(Real *y, Real *x, int f, int nf)
{
/* First,assign whole value in truncation mode */
- if(VpAsgn(y, x, 10)<=1) return; /* Zero,NaN,or Infinity */
- VpMidRound(y,f,nf);
+ if(VpAsgn(y, x, 10)<=1) return 0; /* Zero,NaN,or Infinity */
+ return VpMidRound(y,f,nf);
}
static int
@@ -3861,10 +3864,9 @@ VpLimitRound(Real *c,U_LONG ixDigit)
{
U_LONG ix = VpGetPrecLimit();
if(!ix) return 0;
- if(!ixDigit) ixDigit = c->Prec;
- if((ix+BASE_FIG-1)/BASE_FIG >= ixDigit) return 0;
- VpLeftRound(c,VpGetRoundMode(),ix);
- return 1;
+ if(!ixDigit) ixDigit = c->Prec-1;
+ if((ix+BASE_FIG-1)/BASE_FIG > ixDigit+1) return 0;
+ return VpLeftRound(c,VpGetRoundMode(),ix);
}
static void
@@ -3872,11 +3874,9 @@ VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
{
int f = 0;
- VpNmlz(c);
-
- if(!VpHasVal(c)) return; /* Unable to round */
-
+ if(!VpNmlz(c)) return;
if(VpLimitRound(c,ixDigit)) return;
+ if(!v) return;
v /= BASE1;
switch(gfRoundMode) {
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
index e0c1540170..1f5fef0de8 100644
--- a/ext/bigdecimal/bigdecimal.h
+++ b/ext/bigdecimal/bigdecimal.h
@@ -148,9 +148,9 @@ VP_EXPORT int VpVtoD(double *d,S_LONG *e,Real *m);
VP_EXPORT void VpDtoV(Real *m,double d);
VP_EXPORT void VpItoV(Real *m,S_INT ival);
VP_EXPORT int VpSqrt(Real *y,Real *x);
-VP_EXPORT void VpActiveRound(Real *y,Real *x,int f,int il);
-VP_EXPORT void VpMidRound(Real *y, int f, int nf);
-VP_EXPORT void VpLeftRound(Real *y, int f, int nf);
+VP_EXPORT int VpActiveRound(Real *y,Real *x,int f,int il);
+VP_EXPORT int VpMidRound(Real *y, int f, int nf);
+VP_EXPORT int VpLeftRound(Real *y, int f, int nf);
VP_EXPORT void VpFrac(Real *y,Real *x);
VP_EXPORT int VpPower(Real *y,Real *x,S_INT n);