From: Tadashi Saito Date: 2003-07-23T07:45:56+09:00 Subject: [ruby-dev:20801] [BigDecimal] Java compatible rounding This is a multi-part message in MIME format. ------=_NextPart_000_0123_01C350BE.F6DF3F20 Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit 斎藤です。 BigDecimalには、数の丸めの機能が実装されていますが、どうせなら JavaのBigDecimal互換の方がいいのではないでしょうか。 現状の「COMP_MODE」という名前ではちょっと抽象的な気もしますし、 ROUNDUPは「四捨五入」ではなく「切り上げ」という意味だと思います。 以下のパッチでは、RubyのBigDecimalにJava相当の機能を与えるため、とりあえず ・COMP_MODE* → ROUND* ・従来のROUNDUP → ROUND_HALF_UP(英語としてこちらが正しい) ・JavaのBigDecimalにあった丸めモード、  ROUND_UP(単なる切り上げ)、ROUND_HALF_DOWN の追加 ・...CEIL → ROUND_CEILING(ceilingのみ略称なのはおかしいと思ったので) という事をやっています。また、ROUND_DOWNの別名としてROUND_TRUNCATEも 定義してみました。 とりあえず、.c と .h のみのパッチを、ちょっと大きいので添付ファイルと してみました。取り込みを検討していただけますか? >小林さん -- 斎藤ただし ------=_NextPart_000_0123_01C350BE.F6DF3F20 Content-Type: application/octet-stream; name="java-compatible-rounding.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="java-compatible-rounding.patch" Index: bigdecimal.c=0A= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= RCS file: /src/ruby/ext/bigdecimal/bigdecimal.c,v=0A= retrieving revision 1.11=0A= diff -u -p -r1.11 bigdecimal.c=0A= --- bigdecimal.c 21 Jul 2003 14:49:25 -0000 1.11=0A= +++ bigdecimal.c 22 Jul 2003 16:52:38 -0000=0A= @@ -288,7 +288,7 @@ BigDecimal_mode(VALUE self, VALUE which,=0A= }=0A= return INT2FIX(fo);=0A= }=0A= - if(VP_COMP_MODE=3D=3Df) {=0A= + if(VP_ROUND=3D=3Df) {=0A= /* Computaion mode setting */=0A= if(TYPE(val)!=3DT_FIXNUM) return Qnil;=0A= fo =3D VpSetCompMode((unsigned long)FIX2INT(val));=0A= @@ -729,7 +729,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r,=0A= VpDivd(c, res, a, b);=0A= mx =3D c->Prec *(VpBaseFig() + 1);=0A= GUARD_OBJ(d,VpCreateRbObject(mx, "0"));=0A= - VpActiveRound(d,c,VP_COMP_MODE_FLOOR,0);=0A= + VpActiveRound(d,c,VP_ROUND_FLOOR,0);=0A= VpMult(res,d,b);=0A= VpAddSub(c,a,res,-1);=0A= *div =3D d;=0A= @@ -776,7 +776,7 @@ BigDecimal_divremain(VALUE self, VALUE r=0A= GUARD_OBJ(d,VpCreateRbObject(mx, "0"));=0A= GUARD_OBJ(f,VpCreateRbObject(mx, "0"));=0A= =0A= - VpActiveRound(d,c,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */=0A= + VpActiveRound(d,c,VP_ROUND_DOWN,0); /* 0: round down */=0A= =0A= VpFrac(f, c);=0A= VpMult(rr,f,b);=0A= @@ -923,7 +923,7 @@ BigDecimal_fix(VALUE self)=0A= GUARD_OBJ(a,GetVpValue(self,1));=0A= mx =3D a->Prec *(VpBaseFig() + 1);=0A= GUARD_OBJ(c,VpCreateRbObject(mx, "0"));=0A= - VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */=0A= + VpActiveRound(c,a,VP_ROUND_DOWN,0); /* 0: round down */=0A= return ToValue(c);=0A= }=0A= =0A= @@ -938,7 +938,7 @@ BigDecimal_round(int argc, VALUE *argv, =0A= VALUE vLoc;=0A= VALUE vBanker;=0A= int na =3D rb_scan_args(argc,argv,"02",&vLoc,&vBanker);=0A= - sw =3D VP_COMP_MODE_ROUNDUP; /* round up */=0A= + sw =3D VP_ROUND_HALF_UP; /* round half up */=0A= switch(na) {=0A= case 0:=0A= iLoc =3D 0;=0A= @@ -951,7 +951,7 @@ BigDecimal_round(int argc, VALUE *argv, =0A= Check_Type(vLoc, T_FIXNUM);=0A= iLoc =3D FIX2INT(vLoc);=0A= Check_Type(vBanker, T_FIXNUM);=0A= - if(FIX2INT(vBanker)) sw =3D VP_COMP_MODE_EVEN; /* Banker's = rounding */=0A= + if(FIX2INT(vBanker)) sw =3D VP_ROUND_HALF_EVEN; /* Banker's = rounding */=0A= break;=0A= }=0A= =0A= @@ -981,7 +981,7 @@ BigDecimal_truncate(int argc, VALUE *arg=0A= GUARD_OBJ(a,GetVpValue(self,1));=0A= mx =3D a->Prec *(VpBaseFig() + 1);=0A= GUARD_OBJ(c,VpCreateRbObject(mx, "0"));=0A= - VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,iLoc); /* 0: truncate */=0A= + VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */=0A= return ToValue(c);=0A= }=0A= =0A= @@ -1018,7 +1018,7 @@ BigDecimal_floor(int argc, VALUE *argv, =0A= GUARD_OBJ(a,GetVpValue(self,1));=0A= mx =3D a->Prec *(VpBaseFig() + 1);=0A= GUARD_OBJ(c,VpCreateRbObject(mx, "0"));=0A= - VpActiveRound(c,a,VP_COMP_MODE_FLOOR,iLoc);=0A= + VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);=0A= return ToValue(c);=0A= }=0A= =0A= @@ -1041,7 +1041,7 @@ BigDecimal_ceil(int argc, VALUE *argv, V=0A= GUARD_OBJ(a,GetVpValue(self,1));=0A= mx =3D a->Prec *(VpBaseFig() + 1);=0A= GUARD_OBJ(c,VpCreateRbObject(mx, "0"));=0A= - VpActiveRound(c,a,VP_COMP_MODE_CEIL,iLoc);=0A= + VpActiveRound(c,a,VP_ROUND_CEILING,iLoc);=0A= return ToValue(c);=0A= }=0A= =0A= @@ -1400,12 +1400,15 @@ Init_bigdecimal(void)=0A= rb_define_const(rb_cBigDecimal, = "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));=0A= =0A= /* Computation mode */=0A= - rb_define_const(rb_cBigDecimal, "COMP_MODE",INT2FIX(VP_COMP_MODE));=0A= - rb_define_const(rb_cBigDecimal, = "COMP_MODE_TRUNCATE",INT2FIX(VP_COMP_MODE_TRUNCATE));=0A= - rb_define_const(rb_cBigDecimal, = "COMP_MODE_ROUNDUP",INT2FIX(VP_COMP_MODE_ROUNDUP));=0A= - rb_define_const(rb_cBigDecimal, = "COMP_MODE_CEIL",INT2FIX(VP_COMP_MODE_CEIL));=0A= - rb_define_const(rb_cBigDecimal, = "COMP_MODE_FLOOR",INT2FIX(VP_COMP_MODE_FLOOR));=0A= - rb_define_const(rb_cBigDecimal, = "COMP_MODE_EVEN",INT2FIX(VP_COMP_MODE_EVEN));=0A= + rb_define_const(rb_cBigDecimal, "ROUND",INT2FIX(VP_ROUND));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_TRUNCATE",INT2FIX(VP_ROUND_DOWN));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));=0A= + rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_CEILING",INT2FIX(VP_ROUND_CEILING));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));=0A= + rb_define_const(rb_cBigDecimal, = "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));=0A= =0A= /* Constants for sign value */=0A= rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));=0A= @@ -1499,7 +1502,7 @@ static int gfCheckVal =3D 1; /* Value=0A= #endif /* _DEBUG */=0A= =0A= static U_LONG gnPrecLimit =3D 0; /* Global upper limit of the = precision newly allocated */=0A= -static short gfCompMode =3D VP_COMP_MODE_ROUNDUP; /* Mode for general = computation */=0A= +static short gfCompMode =3D VP_ROUND_HALF_UP; /* Mode for general = computation */=0A= =0A= static U_LONG BASE_FIG =3D 4; /* =3Dlog10(BASE) */=0A= static U_LONG BASE =3D 10000L; /* Base value(value must be = 10**BASE_FIG) */=0A= @@ -1593,8 +1596,9 @@ VP_EXPORT unsigned long=0A= VpSetCompMode(unsigned long n)=0A= {=0A= unsigned long s =3D gfCompMode;=0A= - if(n!=3DVP_COMP_MODE_TRUNCATE && n!=3D VP_COMP_MODE_ROUNDUP && = n!=3DVP_COMP_MODE_CEIL &&=0A= - n!=3DVP_COMP_MODE_FLOOR && n!=3D VP_COMP_MODE_EVEN) return s;=0A= + if(n!=3DVP_ROUND_DOWN && n!=3DVP_ROUND_UP && = n!=3DVP_ROUND_CEILING &&=0A= + n!=3DVP_ROUND_FLOOR && n!=3DVP_ROUND_HALF_EVEN && = n!=3DVP_ROUND_HALF_DOWN &&=0A= + n!=3DVP_ROUND_HALF_UP) return s;=0A= gfCompMode =3D n;=0A= return s;=0A= }=0A= @@ -3759,18 +3763,21 @@ VpActiveRound(Real *y, Real *x, int f, i=0A= div =3D v/10;=0A= v =3D v - div*10;=0A= switch(f) {=0A= - case VP_COMP_MODE_TRUNCATE: /* Truncate/Round off */=0A= - break;=0A= - case VP_COMP_MODE_ROUNDUP: /* Round up */=0A= + case VP_ROUND_DOWN: /* Truncate/Round down */=0A= + break;=0A= + case VP_ROUND_UP:=0A= + ++div;=0A= + break;=0A= + case VP_ROUND_HALF_UP: /* Round half up */=0A= if(v>=3D5) ++div;=0A= break;=0A= - case VP_COMP_MODE_CEIL: /* ceil */=0A= + case VP_ROUND_CEILING: /* ceil */=0A= if(v && (VpGetSign(x)>0)) ++div;=0A= break;=0A= - case VP_COMP_MODE_FLOOR: /* floor */=0A= + case VP_ROUND_FLOOR: /* floor */=0A= if(v && (VpGetSign(x)<0)) ++div;=0A= break;=0A= - case VP_COMP_MODE_EVEN: /* Banker's rounding */=0A= + case VP_ROUND_HALF_EVEN: /* Banker's rounding */=0A= if(v>5) ++div;=0A= else if(v=3D=3D5) {=0A= if(i=3D=3D(BASE_FIG-1)) {=0A= @@ -3780,6 +3787,9 @@ VpActiveRound(Real *y, Real *x, int f, i=0A= }=0A= }=0A= break;=0A= + case VP_ROUND_HALF_DOWN:=0A= + if(v>5) ++div;=0A= + break;=0A= }=0A= for(i=3D0;i<=3Dn;++i) div *=3D 10;=0A= if(div>=3DBASE) {=0A= @@ -3812,21 +3822,27 @@ VpInternalRound(Real *c,int ixDigit,U_LO=0A= int f =3D 0;=0A= v /=3D BASE1;=0A= switch(gfCompMode) {=0A= - case VP_COMP_MODE_TRUNCATE:=0A= + case VP_ROUND_DOWN:=0A= break;=0A= - case VP_COMP_MODE_ROUNDUP:=0A= + case VP_ROUND_UP:=0A= + f =3D 1;=0A= + break;=0A= + case VP_ROUND_HALF_UP:=0A= if(v >=3D 5) f =3D 1;=0A= break;=0A= - case VP_COMP_MODE_CEIL: /* ceil */=0A= + case VP_ROUND_CEILING: /* ceil */=0A= if(v && (VpGetSign(c)>0)) f =3D 1;=0A= break;=0A= - case VP_COMP_MODE_FLOOR: /* floor */=0A= + case VP_ROUND_FLOOR: /* floor */=0A= if(v && (VpGetSign(c)<0)) f =3D 1;=0A= break;=0A= - case VP_COMP_MODE_EVEN: /* Banker's rounding */=0A= + case VP_ROUND_HALF_EVEN: /* Banker's rounding */=0A= if(v>5) f =3D 1;=0A= else if(v=3D=3D5 && vPrev%2) f =3D 1;=0A= break;=0A= + case VP_ROUND_HALF_DOWN:=0A= + if(v>5) f =3D 1;=0A= + break;=0A= }=0A= if(f) VpRdup(c,ixDigit); /* round up */=0A= return f;=0A= Index: bigdecimal.h=0A= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= RCS file: /src/ruby/ext/bigdecimal/bigdecimal.h,v=0A= retrieving revision 1.5=0A= diff -u -p -r1.5 bigdecimal.h=0A= --- bigdecimal.h 18 Jul 2003 15:23:23 -0000 1.5=0A= +++ bigdecimal.h 22 Jul 2003 16:52:38 -0000=0A= @@ -44,12 +44,14 @@ extern "C" {=0A= #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)=0A= =0A= /* Computation mode */=0A= -#define VP_COMP_MODE ((unsigned short)0x0100)=0A= -#define VP_COMP_MODE_TRUNCATE 0=0A= -#define VP_COMP_MODE_ROUNDUP 1=0A= -#define VP_COMP_MODE_CEIL 2=0A= -#define VP_COMP_MODE_FLOOR 3=0A= -#define VP_COMP_MODE_EVEN 4=0A= +#define VP_ROUND ((unsigned short)0x0100)=0A= +#define VP_ROUND_DOWN 0=0A= +#define VP_ROUND_UP 1=0A= +#define VP_ROUND_CEILING 2=0A= +#define VP_ROUND_FLOOR 3=0A= +#define VP_ROUND_HALF_EVEN 4=0A= +#define VP_ROUND_HALF_DOWN 5=0A= +#define VP_ROUND_HALF_UP 6=0A= =0A= #define VP_SIGN_NaN 0 /* NaN */=0A= #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */=0A= ------=_NextPart_000_0123_01C350BE.F6DF3F20--