1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Ambiguity of BigDecimal::limit removed.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4381 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shigek 2003-08-13 14:33:31 +00:00
parent 3d7147bcea
commit 0b6cf4bea8
5 changed files with 97 additions and 70 deletions

View file

@ -1,3 +1,7 @@
Wed Aug 13 23:31:00 2003 Shigeo Kobayashi <shigek@ruby-lang.org>
* ext/bigdecimal.c .h .html: Ambiguity of BigDecimal::limit removed.
Wed Aug 13 19:21:34 2003 Christian Neukirchen <chneukirchen@yahoo.de>
* lib/webrick/https.rb (HTTPServer#run): should set syncing-mode

View file

@ -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 <knu@iDaemons.org>.
* 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;
}

View file

@ -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

View file

@ -118,7 +118,10 @@ but the resulting digits obtained may differ in future version.
</BLOCKQUOTE>
<LI><B>mode</B></LI><BLOCKQUOTE>
mode method controls BigDecimal computation.Following usage are defined.<BR>
f = BigDecimal.mode(s[,v])<BR>
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.<BR>
<P><B>[EXCEPTION control]</B><P>
Actions when computation results NaN or Infinity can be defined as follows.
<P>
@ -175,13 +178,12 @@ use truncate/round/ceil/floor/add/sub/mult/div mthods for each instance instead.
</BLOCKQUOTE>
<LI><B>limit[(n)]</B></LI><BLOCKQUOTE>
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.<BR>
Except for zero,the limit has more priority than instance methods such as truncate,round,ceil,floor,add,sub,mult,and div. <BR>
The limit has no more priority than instance methods such as truncate,round,ceil,floor,add,sub,mult,and div. <BR>
mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE>

View file

@ -126,7 +126,10 @@ BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
</BLOCKQUOTE>
<LI><B>mode</B></LI><BLOCKQUOTE>
BigDecimalの実行結果を制御します。以下の使用方法が定義されています。
f = BigDecimal.mode(s[,v])<BR>
BigDecimalの実行結果を制御します。第引数を省略、または nil を指定すると
現状の設定値が戻ります。<BR>
以下の使用方法が定義されています。
<P>
<B>[例外処理]</B><P>
計算結果が非数(NaN)やゼロによる除算になったときの処理を定義することができます。
@ -159,8 +162,7 @@ EXCEPTION_INFINITY
は今のところ同じです。<BR>
戻り値は、設定後の値です。「値」の意味は、例えば
BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば
EXCEPTION_NaNが設定されているという意味です。<BR>
第2引数に nil を指定すると、現状の設定値が返ります。
EXCEPTION_NaNが設定されているという意味です。
<P>
<B>[丸め処理指定]</B><P>
@ -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 といったインスタンスメソッドを使用して下さい。
</BLOCKQUOTE>
<LI><B>limit([n])</B></LI><BLOCKQUOTE>
生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。
戻り値は設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。
n を指定しない場合は、現状の最大桁数が返ります。<BR>
n を指定しない、または n が nil の場合は、現状の最大桁数が返ります。<BR>
計算を続行する間に、数字の桁数が無制限に増えてしまうような場合
limit で予め桁数を制限できます。この場合 BigDecimal.mode で指定された
丸め処理が実行されます。
ただし、実際には n より若干大きい
桁数が確保されます。また、limit による桁数制限は(無制限を除いて)、
インスタンスメソッド (truncate/round/ceil/floor/add/sub/mult/div) より
優先されるので注意が必要です。<BR>
ただし、インスタンスメソッド (truncate/round/ceil/floor/add/sub/mult/div) の
桁数制限は limit より優先されます。<BR>
mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE>