From 0b6cf4bea8d9c676a3f344e74c55756fe6f8dd40 Mon Sep 17 00:00:00 2001 From: shigek Date: Wed, 13 Aug 2003 14:33:31 +0000 Subject: Ambiguity of BigDecimal::limit removed. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4381 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 4 ++ ext/bigdecimal/bigdecimal.c | 132 ++++++++++++++++++++++---------------- ext/bigdecimal/bigdecimal.h | 1 + ext/bigdecimal/bigdecimal_en.html | 12 ++-- ext/bigdecimal/bigdecimal_ja.html | 18 +++--- 5 files changed, 97 insertions(+), 70 deletions(-) diff --git a/ChangeLog b/ChangeLog index 775c67b3d5..920a94fb31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Wed Aug 13 23:31:00 2003 Shigeo Kobayashi + + * ext/bigdecimal.c .h .html: Ambiguity of BigDecimal::limit removed. + Wed Aug 13 19:21:34 2003 Christian Neukirchen * lib/webrick/https.rb (HTTPServer#run): should set syncing-mode diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 854756b4ee..bc0ba4c55d 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -8,26 +8,8 @@ * License or the Artistic License, as specified in the README file * of this BigDecimal distribution. * - * NOTES: - * For the notes other than listed bellow,see ruby CVS log. - * 2003-04-17 - * Bug in negative.exp(n) reported by Hitoshi Miyazaki fixed. - * 2003-03-28 - * V1.0 checked in to CVS(ruby/ext/bigdecimal). - * use rb_str2cstr() instead of STR2CSTR(). - * 2003-01-03 - * assign instead of asign(by knu),use string.h functions(by t.saito). - * 2002-12-06 - * The sqrt() bug reported by Bret Jolly fixed. - * 2002-5-6 - * The bug reported by Sako Hiroshi (ruby-list:34988) in to_i fixed. - * 2002-4-17 - * methods prec and double_fig(class method) added(S.K). - * 2002-04-04 - * Copied from BigFloat 1.1.9 and - * hash method changed according to the suggestion from Akinori MUSHA . - * All ! class methods deactivated(but not actually removed). - * to_s and to_s2 merged to one to_s[(n)]. + * NOTE: Change log in this source removed to reduce source code size. + * See rev. 1.25 if needed. * */ @@ -74,7 +56,8 @@ BigDecimal_version(VALUE self) */ static unsigned short VpGetException(void); static void VpSetException(unsigned short f); -static int VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v); +static void VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v); +static int VpLimitRound(Real *c,U_LONG ixDigit); /* * **** BigDecimal part **** @@ -229,10 +212,15 @@ BigDecimal_load(VALUE self, VALUE str) } static VALUE -BigDecimal_mode(VALUE self, VALUE which, VALUE val) +BigDecimal_mode(int argc, VALUE *argv, VALUE self) { + VALUE which; + VALUE val; + int na; unsigned long f,fo; + if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil; + Check_Type(which, T_FIXNUM); f = (unsigned long)FIX2INT(which); @@ -658,7 +646,7 @@ BigDecimal_div(VALUE self, VALUE r) r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE */ /* Round */ - if(VpIsDef(c) && (!VpIsZero(c))) { + if(div->frac[0]) { /* 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); @@ -816,12 +804,14 @@ BigDecimal_div2(int argc, VALUE *argv, VALUE self) Real *av=NULL, *bv=NULL, *cv=NULL; U_LONG ix = (U_LONG)GetPositiveInt(n); U_LONG mx = (ix+VpBaseFig()*2); + U_LONG pl = VpSetPrecLimit(0); GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); GUARD_OBJ(av,GetVpValue(self,1)); GUARD_OBJ(bv,GetVpValue(b,1)); mx = cv->MaxPrec+1; GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0")); VpDivd(cv,res,av,bv); + VpSetPrecLimit(pl); VpLeftRound(cv,VpGetRoundMode(),ix); return ToValue(cv); } @@ -833,7 +823,9 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n) ENTER(2); Real *cv; U_LONG mx = (U_LONG)GetPositiveInt(n); + U_LONG pl = VpSetPrecLimit(0); VALUE c = BigDecimal_add(self,b); + VpSetPrecLimit(pl); GUARD_OBJ(cv,GetVpValue(c,1)); VpLeftRound(cv,VpGetRoundMode(),mx); return ToValue(cv); @@ -845,7 +837,9 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n) ENTER(2); Real *cv; U_LONG mx = (U_LONG)GetPositiveInt(n); + U_LONG pl = VpSetPrecLimit(0); VALUE c = BigDecimal_sub(self,b); + VpSetPrecLimit(pl); GUARD_OBJ(cv,GetVpValue(c,1)); VpLeftRound(cv,VpGetRoundMode(),mx); return ToValue(cv); @@ -857,7 +851,9 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n) ENTER(2); Real *cv; U_LONG mx = (U_LONG)GetPositiveInt(n); + U_LONG pl = VpSetPrecLimit(0); VALUE c = BigDecimal_mult(self,b); + VpSetPrecLimit(pl); GUARD_OBJ(cv,GetVpValue(c,1)); VpLeftRound(cv,VpGetRoundMode(),mx); return ToValue(cv); @@ -919,6 +915,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) U_LONG mx; VALUE vLoc; VALUE vRound; + U_LONG pl; int sw = VpGetRoundMode(); @@ -943,9 +940,11 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) break; } + pl = VpSetPrecLimit(0); GUARD_OBJ(a,GetVpValue(self,1)); mx = a->Prec *(VpBaseFig() + 1); GUARD_OBJ(c,VpCreateRbObject(mx, "0")); + VpSetPrecLimit(pl); VpActiveRound(c,a,sw,iLoc); return ToValue(c); } @@ -958,6 +957,7 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self) int iLoc; U_LONG mx; VALUE vLoc; + U_LONG pl = VpSetPrecLimit(0); if(rb_scan_args(argc,argv,"01",&vLoc)==0) { iLoc = 0; @@ -969,6 +969,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")); + VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */ return ToValue(c); } @@ -995,6 +996,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self) U_LONG mx; int iLoc; VALUE vLoc; + U_LONG pl = VpSetPrecLimit(0); if(rb_scan_args(argc,argv,"01",&vLoc)==0) { iLoc = 0; @@ -1006,6 +1008,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")); + VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc); return ToValue(c); } @@ -1018,6 +1021,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self) U_LONG mx; int iLoc; VALUE vLoc; + U_LONG pl = VpSetPrecLimit(0); if(rb_scan_args(argc,argv,"01",&vLoc)==0) { iLoc = 0; @@ -1029,6 +1033,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")); + VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_CEIL,iLoc); return ToValue(c); } @@ -1205,8 +1210,14 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self) VALUE nCur = INT2NUM(VpGetPrecLimit()); if(rb_scan_args(argc,argv,"01",&nFig)==1) { + int nf; + if(nFig==Qnil) return nCur; Check_Type(nFig, T_FIXNUM); - VpSetPrecLimit(FIX2INT(nFig)); + nf = FIX2INT(nFig); + if(nf<0) { + rb_raise(rb_eArgError, "argument must be positive"); + } + VpSetPrecLimit(nf); } return nCur; } @@ -1298,7 +1309,7 @@ Init_bigdecimal(void) /* Class methods */ rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1); - rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, 2); + rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1); rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1); rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0); rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1); @@ -2057,7 +2068,7 @@ VpAsgn(Real *c, Real *a, int isw) return 0; } if(VpIsInf(a)) { - VpSetInf(c,isw); + VpSetInf(c,isw*VpGetSign(a)); return 0; } @@ -2069,8 +2080,13 @@ VpAsgn(Real *c, Real *a, int isw) c->Prec = n; memcpy(c->frac, a->frac, n * sizeof(U_LONG)); /* Needs round ? */ - if(c->Prec < a->Prec) { - VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]); + if(isw!=10) { + /* Not in ActiveRound */ + if(c->Prec < a->Prec) { + VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]); + } else { + VpLimitRound(c,0); + } } } else { /* The value of 'a' is zero. */ @@ -2292,8 +2308,7 @@ VpAddAbs(Real *a, Real *b, Real *c) } } if(c_pos) c->frac[c_pos - 1] += carry; - - if(!VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv)) VpNmlz(c); + VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv); goto Exit; Assign_a: @@ -2406,8 +2421,7 @@ VpSubAbs(Real *a, Real *b, Real *c) } } if(c_pos) c->frac[c_pos - 1] -= borrow; - - if(!VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv)) VpNmlz(c); + VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv); goto Exit; Assign_a: @@ -3128,8 +3142,7 @@ VpExponent10(Real *a) S_LONG ex; U_LONG n; - if(!VpIsDef(a)) return 0; - if(VpIsZero(a)) return 0; + if(!VpHasVal(a)) return 0; ex =(a->exponent) * BASE_FIG; n = BASE1; @@ -3564,8 +3577,8 @@ VpDtoV(Real *m, double d) m->Prec = ind_m + 1; m->exponent = ne; - if(!VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0, - (U_LONG)(val*((double)((S_INT)BASE))))) VpNmlz(m); + VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0, + (U_LONG)(val*((double)((S_INT)BASE)))); Exit: #ifdef _DEBUG @@ -3653,19 +3666,14 @@ VpSqrt(Real *y, Real *x) S_LONG nr; double val; - if(!VpIsDef(x)) { + if(!VpHasVal(x)) { VpAsgn(y,x,1); goto Exit; } - if(VpIsZero(x)) { - VpSetZero(y,VpGetSign(x)); - goto Exit; - } - if(VpGetSign(x) < 0) { - VpSetZero(y,VpGetSign(x)); - return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(negative valuw)",0); + VpSetNaN(y); + return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(negative value)",0); } n = (S_LONG)y->MaxPrec; @@ -3769,7 +3777,6 @@ VpMidRound(Real *y, int f, int nf) if(ix<0 || ((U_LONG)ix)>=y->Prec) return; /* Unable to round */ ioffset = nf - ix*((int)BASE_FIG); memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG)); - /* VpNmlz(y); */ v = y->frac[ix]; /* drop digits after pointed digit */ n = BASE_FIG - ioffset - 1; @@ -3830,8 +3837,7 @@ VpLeftRound(Real *y, int f, int nf) { U_LONG v; - if(!VpIsDef(y)) return; /* Unable to round */ - if(VpIsZero(y)) return; + if(!VpHasVal(y)) return; /* Unable to round */ v = y->frac[0]; nf -= VpExponent(y)*BASE_FIG; @@ -3844,19 +3850,31 @@ VP_EXPORT void VpActiveRound(Real *y, Real *x, int f, int nf) { /* First,assign whole value in truncation mode */ - VpAsgn(y, x, 1); /* 1 round off,2 round up */ - if(!VpIsDef(y)) return; /* Unable to round */ - if(VpIsZero(y)) return; + if(VpAsgn(y, x, 10)<=1) return; /* Zero,NaN,or Infinity */ VpMidRound(y,f,nf); } -static int +static int +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; +} + +static void VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v) { int f = 0; - if(!VpIsDef(c)) return f; /* Unable to round */ - if(VpIsZero(c)) return f; + VpNmlz(c); + + if(!VpHasVal(c)) return; /* Unable to round */ + + if(VpLimitRound(c,ixDigit)) return; v /= BASE1; switch(gfRoundMode) { @@ -3882,8 +3900,10 @@ VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v) else if(v==5 && vPrev%2) f = 1; break; } - if(f) VpRdup(c,ixDigit); /* round up */ - return f; + if(f) { + VpRdup(c,ixDigit); /* round up */ + VpNmlz(c); + } } /* @@ -3919,7 +3939,7 @@ VpFrac(Real *y, Real *x) { U_LONG my, ind_y, ind_x; - if(!VpIsDef(x) || VpIsZero(x)) { + if(!VpHasVal(x)) { VpAsgn(y,x,1); goto Exit; } diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h index 8230512e6a..e0c1540170 100644 --- a/ext/bigdecimal/bigdecimal.h +++ b/ext/bigdecimal/bigdecimal.h @@ -208,6 +208,7 @@ VP_EXPORT void VpSinCos(Real *psin,Real *pcos,Real *x); #define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE) #define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE) #define VpSetInf(a,s) ( ((s)>0)?VpSetPosInf(a):VpSetNegInf(a) ) +#define VpHasVal(a) (a->frac[0]) #define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1)) #define VpExponent(a) (a->exponent) #ifdef _DEBUG diff --git a/ext/bigdecimal/bigdecimal_en.html b/ext/bigdecimal/bigdecimal_en.html index c4ed6b4c01..d37d13616f 100644 --- a/ext/bigdecimal/bigdecimal_en.html +++ b/ext/bigdecimal/bigdecimal_en.html @@ -118,7 +118,10 @@ but the resulting digits obtained may differ in future version.
  • mode
  • -mode method controls BigDecimal computation.Following usage are defined.
    +f = BigDecimal.mode(s[,v])
    +mode method controls BigDecimal computation. If the second argument is not given or is nil,then the value +of current setting is returned. +Following usage are defined.

    [EXCEPTION control]

    Actions when computation results NaN or Infinity can be defined as follows.

    @@ -175,13 +178,12 @@ use truncate/round/ceil/floor/add/sub/mult/div mthods for each instance instead.

  • limit[(n)]
  • -Limits the maximum digits that the newly created BigDecimal objects can hold -never exceed n+? (Currently,? can not be determined beforehand,but not so big). +Limits the maximum digits that the newly created BigDecimal objects can hold never exceed n. This means the rounding operation specified by BigDecimal.mode is performed if necessary. -limit returns maximum value before set. +limit returns the value before set if n is nil or is not specified. Zero,the default value,means no upper limit.
    -Except for zero,the limit has more priority than instance methods such as truncate,round,ceil,floor,add,sub,mult,and div.
    +The limit has no more priority than instance methods such as truncate,round,ceil,floor,add,sub,mult,and div.
    mf = BigDecimal::limit(n)
    diff --git a/ext/bigdecimal/bigdecimal_ja.html b/ext/bigdecimal/bigdecimal_ja.html index a59d61a838..0d5516ad60 100644 --- a/ext/bigdecimal/bigdecimal_ja.html +++ b/ext/bigdecimal/bigdecimal_ja.html @@ -126,7 +126,10 @@ BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
  • mode
  • -BigDecimalの実行結果を制御します。以下の使用方法が定義されています。 +f = BigDecimal.mode(s[,v])
    +BigDecimalの実行結果を制御します。第2引数を省略、または nil を指定すると +現状の設定値が戻ります。
    +以下の使用方法が定義されています。

    [例外処理]

    計算結果が非数(NaN)やゼロによる除算になったときの処理を定義することができます。 @@ -159,8 +162,7 @@ EXCEPTION_INFINITY は今のところ同じです。
    戻り値は、設定後の値です。「値」の意味は、例えば BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば -EXCEPTION_NaNが設定されているという意味です。
    -第2引数に nil を指定すると、現状の設定値が返ります。 +EXCEPTION_NaNが設定されているという意味です。

    [丸め処理指定]

    @@ -183,20 +185,18 @@ f = BigDecimal::mode(BigDecimal::ROUND_MODE,flag) 戻り値は指定後の flag の値です。 第2引数に nil を指定すると、現状の設定値が返ります。 mode メソッドでは丸め操作の位置をユーザが指定することはできません。 -丸め操作と位置を自分で制御したい場合は truncate/round/ceil/floor や +丸め操作と位置を自分で制御したい場合は BigDecimal::limit や truncate/round/ceil/floor、 add/sub/mult/div といったインスタンスメソッドを使用して下さい。

  • limit([n])
  • 生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。 戻り値は設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。 -n を指定しない場合は、現状の最大桁数が返ります。
    +n を指定しない、または n が nil の場合は、現状の最大桁数が返ります。
    計算を続行する間に、数字の桁数が無制限に増えてしまうような場合 limit で予め桁数を制限できます。この場合 BigDecimal.mode で指定された 丸め処理が実行されます。 -ただし、実際には n より若干大きい -桁数が確保されます。また、limit による桁数制限は(無制限を除いて)、 -インスタンスメソッド (truncate/round/ceil/floor/add/sub/mult/div) より -優先されるので注意が必要です。
    +ただし、インスタンスメソッド (truncate/round/ceil/floor/add/sub/mult/div) の +桁数制限は limit より優先されます。
    mf = BigDecimal::limit(n)
    -- cgit v1.2.3