* ext/bigdecimal/bigdecimal.c: patch from "NATORI Shin"

(u-tokyo.ac.jp) applied to fix rounding bug.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9179 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2005-09-16 07:22:49 +00:00
Родитель e0166cd8f6
Коммит 56d82da97c
2 изменённых файлов: 43 добавлений и 8 удалений

Просмотреть файл

@ -1834,6 +1834,11 @@ Sat Jun 25 11:37:00 2005 NARUSE, Yui <naruse@ruby-lang.org>
conv, {eucjp, shiftjis, utf8}?
* ext/nkf/lib/kconv.rb: add aliases Kconv.to_* and String#to_*
Fri Jun 24 17:00:00 2005 Shigeo Kobayashi <shigeo@tinyforest.jp>
* ext/bigdecimal/bigdecimal.c: patch from "NATORI Shin"
(u-tokyo.ac.jp) applied to fix rounding bug.
Fri Jun 24 13:17:45 2005 akira yamada <akira@ruby-lang.org>
* lib/uri/common.rb, lib/uri/generic.rb: fixed typo in documents and

Просмотреть файл

@ -3723,28 +3723,45 @@ VpMidRound(Real *y, int f, int nf)
* nf: digit location to round from the the decimal point.
*/
{
int n,i,ix,ioffset;
U_LONG v;
/* fracf: any positive digit under rounding position? */
/* exptoadd: number of digits needed to compensate negative nf */
int n,i,ix,ioffset,fracf,exptoadd;
U_LONG v,shifter;
U_LONG div;
nf += y->exponent*((int)BASE_FIG);
exptoadd=0;
if (nf < 0) {
exptoadd = -nf;
nf = 0;
}
/* ix: x->fraq[ix] contains round position */
ix = nf/(int)BASE_FIG;
if(ix<0 || ((U_LONG)ix)>=y->Prec) return 0; /* Unable to round */
if(((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 */
n = BASE_FIG - ioffset - 1;
for(i=0;i<n;++i) v /= 10;
for(shifter=1,i=0;i<n;++i) shifter *= 10;
fracf = (v%(shifter*10) > 0);
v /= shifter;
div = v/10;
v = v - div*10;
if (fracf == 0) {
for(i=ix+1;i<y->Prec;i++) {
if (y->frac[i]%BASE) {
fracf = 1;
break;
}
}
}
memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
switch(f) {
case VP_ROUND_DOWN: /* Truncate */
break;
case VP_ROUND_UP: /* Roundup */
if(v) ++div;
if(fracf) ++div;
break;
case VP_ROUND_HALF_UP: /* Round half up */
if(v>=5) ++div;
@ -3753,10 +3770,10 @@ VpMidRound(Real *y, int f, int nf)
if(v>=6) ++div;
break;
case VP_ROUND_CEIL: /* ceil */
if(v && (VpGetSign(y)>0)) ++div;
if(fracf && (VpGetSign(y)>0)) ++div;
break;
case VP_ROUND_FLOOR: /* floor */
if(v && (VpGetSign(y)<0)) ++div;
if(fracf && (VpGetSign(y)<0)) ++div;
break;
case VP_ROUND_HALF_EVEN: /* Banker's rounding */
if(v>5) ++div;
@ -3776,13 +3793,26 @@ VpMidRound(Real *y, int f, int nf)
VpRdup(y,ix);
} else {
S_INT s = VpGetSign(y);
int e = y->exponent;
VpSetOne(y);
VpSetSign(y,s);
y->exponent = e+1;
}
} else {
y->frac[ix] = div;
VpNmlz(y);
}
if (exptoadd > 0) {
y->exponent += exptoadd/BASE_FIG;
exptoadd %= BASE_FIG;
for(i=0;i<exptoadd;i++) {
y->frac[0] *= 10;
if (y->frac[0] >= BASE) {
y->frac[0] /= BASE;
y->exponent++;
}
}
}
return 1;
}