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

ver method added.

Spec for div changed.
add,sub,mult,div now can specify exact digits number.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4153 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shigek 2003-07-25 02:26:56 +00:00
parent cb5798876e
commit aafd6b025c
4 changed files with 226 additions and 268 deletions

View file

@ -44,7 +44,6 @@
/* #define ENABLE_NUMERIC_STRING */ /* #define ENABLE_NUMERIC_STRING */
/* #define ENABLE_TRIAL_METHOD */ /* #define ENABLE_TRIAL_METHOD */
/* #define ENABLE_BANG_METHOD */
VALUE rb_cBigDecimal; VALUE rb_cBigDecimal;
@ -56,29 +55,30 @@ VALUE rb_cBigDecimal;
#define SAVE(p) PUSH(p->obj); #define SAVE(p) PUSH(p->obj);
#define GUARD_OBJ(p,y) {p=y;SAVE(p);} #define GUARD_OBJ(p,y) {p=y;SAVE(p);}
/* ETC */
#define MemCmp(x,y,z) memcmp(x,y,z)
#define StrCmp(x,y) strcmp(x,y)
static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
static int AddExponent(Real *a,S_INT n);
static unsigned short VpGetException(void);
static void VpSetException(unsigned short f);
static int VpAddAbs(Real *a,Real *b,Real *c);
static int 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);
static int VpRdup(Real *m,U_LONG ind_m);
static int VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v);
static U_LONG SkipWhiteChar(char *szVal);
/* /*
* ================== Ruby Interface part ========================== * ================== Ruby Interface part ==========================
*/ */
static ID coerce; static ID coerce;
/*
* **** BigDecimal version ****
*/
static VALUE
BigDecimal_version(VALUE self)
{
return rb_str_new2("1.0.0");
}
/*
* VP routines used in BigDecimal part
*/
static unsigned short VpGetException(void);
static void VpSetException(unsigned short f);
static int VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v);
/*
* **** BigDecimal part ****
*/
/* Following functions borrowed from numeric.c */ /* Following functions borrowed from numeric.c */
static VALUE static VALUE
coerce_body(VALUE *x) coerce_body(VALUE *x)
@ -666,7 +666,7 @@ BigDecimal_mult(VALUE self, VALUE r)
static VALUE static VALUE
BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r) BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
/* For c,res = self.div(r): no round operation */ /* For c = self.div(r): with round operation */
{ {
ENTER(5); ENTER(5);
Real *a, *b; Real *a, *b;
@ -677,7 +677,7 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
if(!b) return DoSomeOne(self,r); if(!b) return DoSomeOne(self,r);
SAVE(b); SAVE(b);
*div = b; *div = b;
mx =(a->MaxPrec + b->MaxPrec) *VpBaseFig(); 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")); GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
VpDivd(*c, *res, a, b); VpDivd(*c, *res, a, b);
@ -814,69 +814,57 @@ BigDecimal_divmod(VALUE self, VALUE r)
} }
static VALUE static VALUE
BigDecimal_divmod2(VALUE self, VALUE b, VALUE n) BigDecimal_div2(VALUE self, VALUE b, VALUE n)
{ {
ENTER(10); ENTER(10);
VALUE obj; VALUE obj;
Real *res=NULL; Real *res=NULL;
Real *av=NULL, *bv=NULL, *cv=NULL; Real *av=NULL, *bv=NULL, *cv=NULL;
U_LONG mx = (U_LONG)GetPositiveInt(n)+VpBaseFig(); U_LONG ix = (U_LONG)GetPositiveInt(n);
U_LONG mx = (ix+VpBaseFig()*2);
obj = rb_ary_new();
GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
GUARD_OBJ(av,GetVpValue(self,1)); GUARD_OBJ(av,GetVpValue(self,1));
GUARD_OBJ(bv,GetVpValue(b,1)); GUARD_OBJ(bv,GetVpValue(b,1));
mx = cv->MaxPrec+1; mx = cv->MaxPrec+1;
GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 1)*VpBaseFig(), "#0")); GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
VpDivd(cv,res,av,bv); VpDivd(cv,res,av,bv);
obj = rb_ary_push(obj, ToValue(cv)); VpLeftRound(cv,VpGetCompMode(),ix);
obj = rb_ary_push(obj, ToValue(res)); return ToValue(cv);
return obj;
} }
static VALUE static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n) BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{ {
ENTER(5); ENTER(2);
Real *av; Real *cv;
Real *bv;
Real *cv;
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); VALUE c = BigDecimal_add(self,b);
GUARD_OBJ(av,GetVpValue(self,1)); GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(bv,GetVpValue(b,1)); VpLeftRound(cv,VpGetCompMode(),mx);
VpAddSub(cv,av,bv,1);
return ToValue(cv); return ToValue(cv);
} }
static VALUE static VALUE
BigDecimal_sub2(VALUE self, VALUE b, VALUE n) BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
{ {
ENTER(5); ENTER(2);
Real *av;
Real *bv;
Real *cv; Real *cv;
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); VALUE c = BigDecimal_sub(self,b);
GUARD_OBJ(av,GetVpValue(self,1)); GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(bv,GetVpValue(b,1)); VpLeftRound(cv,VpGetCompMode(),mx);
VpAddSub(cv,av,bv,-1);
return ToValue(cv); return ToValue(cv);
} }
static VALUE static VALUE
BigDecimal_mult2(VALUE self, VALUE b, VALUE n) BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
{ {
ENTER(5); ENTER(2);
Real *av;
Real *bv;
Real *cv; Real *cv;
U_LONG mx = (U_LONG)GetPositiveInt(n); U_LONG mx = (U_LONG)GetPositiveInt(n);
GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); VALUE c = BigDecimal_mult(self,b);
GUARD_OBJ(av,GetVpValue(self,1)); GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(bv,GetVpValue(b,1)); VpLeftRound(cv,VpGetCompMode(),mx);
VpMult(cv,av,bv);
return ToValue(cv); return ToValue(cv);
} }
@ -1119,7 +1107,6 @@ BigDecimal_inspect(VALUE self)
pszAll = ALLOCA_N(char,nc+256); pszAll = ALLOCA_N(char,nc+256);
VpToString(vp, psz1, 10); VpToString(vp, psz1, 10);
sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig()); sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
obj = rb_str_new2(pszAll); obj = rb_str_new2(pszAll);
return obj; return obj;
} }
@ -1272,102 +1259,6 @@ BigDecimal_sincos(VALUE self, VALUE nFig)
} }
#endif /* ENABLE_TRIAL_METHOD */ #endif /* ENABLE_TRIAL_METHOD */
#ifdef ENABLE_BANG_METHOD
/**** Following methods are all MUTABLE and not currently activated. ****/
static void
CheckAssign(VALUE x, VALUE y)
{
if(x==y)
rb_fatal("Bad assignment(the same object appears on both LHS and RHS).");
}
static VALUE
BigDecimal_divmod4(VALUE self, VALUE c, VALUE r, VALUE a, VALUE b)
{
ENTER(10);
U_LONG f;
Real *res=NULL;
Real *av=NULL, *bv=NULL, *cv=NULL;
CheckAssign(c,a);
CheckAssign(c,b);
CheckAssign(r,a);
CheckAssign(r,b);
CheckAssign(r,c);
GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(av,GetVpValue(a,1));
GUARD_OBJ(bv,GetVpValue(b,1));
GUARD_OBJ(res,GetVpValue(r,1));
f = VpDivd(cv,res,av,bv);
return INT2FIX(f);
}
static VALUE
BigDecimal_assign(VALUE self, VALUE c, VALUE a, VALUE f)
{
ENTER(5);
int v;
Real *av;
Real *cv;
CheckAssign(c,a);
Check_Type(f, T_FIXNUM);
GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(av,GetVpValue(a,1));
v = VpAsgn(cv,av,FIX2INT(f));
return INT2NUM(v);
}
static VALUE
BigDecimal_add3(VALUE self, VALUE c, VALUE a, VALUE b)
{
ENTER(5);
Real *av;
Real *bv;
Real *cv;
U_LONG f;
CheckAssign(c,a);
CheckAssign(c,b);
GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(av,GetVpValue(a,1));
GUARD_OBJ(bv,GetVpValue(b,1));
f = VpAddSub(cv,av,bv,1);
return INT2NUM(f);
}
static VALUE
BigDecimal_sub3(VALUE self, VALUE c, VALUE a, VALUE b)
{
ENTER(5);
Real *av;
Real *bv;
Real *cv;
U_LONG f;
CheckAssign(c,a);
CheckAssign(c,b);
GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(av,GetVpValue(a,1));
GUARD_OBJ(bv,GetVpValue(b,1));
f = VpAddSub(cv,av,bv,-1);
return INT2NUM(f);
}
static VALUE
BigDecimal_mult3(VALUE self, VALUE c, VALUE a, VALUE b)
{
ENTER(5);
Real *av;
Real *bv;
Real *cv;
U_LONG f;
CheckAssign(c,a);
CheckAssign(c,b);
GUARD_OBJ(cv,GetVpValue(c,1));
GUARD_OBJ(av,GetVpValue(a,1));
GUARD_OBJ(bv,GetVpValue(b,1));
f = VpMult(cv,av,bv);
return INT2NUM(f);
}
#endif /* ENABLE_BANG_METHOD */
void void
Init_bigdecimal(void) Init_bigdecimal(void)
{ {
@ -1381,12 +1272,13 @@ Init_bigdecimal(void)
rb_define_global_function("BigDecimal", BigDecimal_global_new, -1); rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
/* Class methods */ /* Class methods */
rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, 2);
rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1); 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, "limit", BigDecimal_limit, -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, "double_fig", BigDecimal_double_fig, 0);
rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1); rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1);
rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1); rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);
/* Constants definition */ /* Constants definition */
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal())); rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal()));
@ -1421,7 +1313,7 @@ Init_bigdecimal(void)
rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2); rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2); rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2); rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
rb_define_method(rb_cBigDecimal, "div",BigDecimal_divmod2, 2); rb_define_method(rb_cBigDecimal, "div",BigDecimal_div2, 2);
rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0); rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1); rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0); rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
@ -1474,14 +1366,6 @@ Init_bigdecimal(void)
rb_define_method(rb_cBigDecimal, "exp", BigDecimal_exp, 1); rb_define_method(rb_cBigDecimal, "exp", BigDecimal_exp, 1);
rb_define_method(rb_cBigDecimal, "sincos", BigDecimal_sincos, 1); rb_define_method(rb_cBigDecimal, "sincos", BigDecimal_sincos, 1);
#endif /* ENABLE_TRIAL_METHOD */ #endif /* ENABLE_TRIAL_METHOD */
#ifdef ENABLE_BANG_METHOD
rb_define_singleton_method(rb_cBigDecimal, "assign!", BigDecimal_assign, 3);
rb_define_singleton_method(rb_cBigDecimal, "add!", BigDecimal_add3, 3);
rb_define_singleton_method(rb_cBigDecimal, "sub!", BigDecimal_sub3, 3);
rb_define_singleton_method(rb_cBigDecimal, "mult!", BigDecimal_mult3, 3);
rb_define_singleton_method(rb_cBigDecimal, "div!",BigDecimal_divmod4, 4);
#endif /* ENABLE_BANG_METHOD */
} }
/* /*
@ -1514,6 +1398,20 @@ static Real *VpPt5; /* constant 0.5 */
static U_LONG maxnr = 100; /* Maximum iterations for calcurating sqrt. */ static U_LONG maxnr = 100; /* Maximum iterations for calcurating sqrt. */
/* used in VpSqrt() */ /* used in VpSqrt() */
/* ETC */
#define MemCmp(x,y,z) memcmp(x,y,z)
#define StrCmp(x,y) strcmp(x,y)
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 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);
static int VpRdup(Real *m,U_LONG ind_m);
static U_LONG SkipWhiteChar(char *szVal);
#ifdef _DEBUG #ifdef _DEBUG
static int gnAlloc=0; /* Memory allocation counter */ static int gnAlloc=0; /* Memory allocation counter */
#endif /* _DEBUG */ #endif /* _DEBUG */
@ -1972,8 +1870,8 @@ VpAlloc(U_LONG mx, char *szVal)
if(szVal) { if(szVal) {
if(*szVal!='#') { if(*szVal!='#') {
if(mf) { if(mf) {
mf = (mf + BASE_FIG - 1) / BASE_FIG + 1; mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
if(mx>mf) { if(mx>mf) {
mx = mf; mx = mf;
} }
} }
@ -1993,20 +1891,20 @@ VpAlloc(U_LONG mx, char *szVal)
return vp; return vp;
} }
/* Check on Inf & NaN */ /* Check on Inf & NaN */
if(StrCmp(szVal,"+Infinity")==0 || if(StrCmp(szVal,SZ_PINF)==0 ||
StrCmp(szVal, "Infinity")==0 ) { StrCmp(szVal,SZ_INF)==0 ) {
vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG)); vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
vp->MaxPrec = 1; /* set max precision */ vp->MaxPrec = 1; /* set max precision */
VpSetPosInf(vp); VpSetPosInf(vp);
return vp; return vp;
} }
if(StrCmp(szVal,"-Infinity")==0) { if(StrCmp(szVal,SZ_NINF)==0) {
vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG)); vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
vp->MaxPrec = 1; /* set max precision */ vp->MaxPrec = 1; /* set max precision */
VpSetNegInf(vp); VpSetNegInf(vp);
return vp; return vp;
} }
if(StrCmp(szVal,"NaN")==0) { if(StrCmp(szVal,SZ_NaN)==0) {
vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG)); vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
vp->MaxPrec = 1; /* set max precision */ vp->MaxPrec = 1; /* set max precision */
VpSetNaN(vp); VpSetNaN(vp);
@ -3047,15 +2945,15 @@ VPrint(FILE *fp, char *cntl_chr, Real *a)
/* Check if NaN & Inf. */ /* Check if NaN & Inf. */
if(VpIsNaN(a)) { if(VpIsNaN(a)) {
fprintf(fp,"NaN"); fprintf(fp,SZ_NaN);
return 8; return 8;
} }
if(VpIsPosInf(a)) { if(VpIsPosInf(a)) {
fprintf(fp,"Infinity"); fprintf(fp,SZ_INF);
return 8; return 8;
} }
if(VpIsNegInf(a)) { if(VpIsNegInf(a)) {
fprintf(fp,"-Infinity"); fprintf(fp,SZ_NINF);
return 9; return 9;
} }
if(VpIsZero(a)) { if(VpIsZero(a)) {
@ -3188,15 +3086,15 @@ VpSzMantissa(Real *a,char *psz)
U_LONG n, m, e, nn; U_LONG n, m, e, nn;
if(VpIsNaN(a)) { if(VpIsNaN(a)) {
sprintf(psz,"NaN"); sprintf(psz,SZ_NaN);
return; return;
} }
if(VpIsPosInf(a)) { if(VpIsPosInf(a)) {
sprintf(psz,"Infinity"); sprintf(psz,SZ_INF);
return; return;
} }
if(VpIsNegInf(a)) { if(VpIsNegInf(a)) {
sprintf(psz,"-Infinity"); sprintf(psz,SZ_NINF);
return; return;
} }
@ -3235,15 +3133,15 @@ VpToString(Real *a,char *psz,int fFmt)
S_LONG ex; S_LONG ex;
if(VpIsNaN(a)) { if(VpIsNaN(a)) {
sprintf(psz,"NaN"); sprintf(psz,SZ_NaN);
return; return;
} }
if(VpIsPosInf(a)) { if(VpIsPosInf(a)) {
sprintf(psz,"Infinity"); sprintf(psz,SZ_INF);
return; return;
} }
if(VpIsNegInf(a)) { if(VpIsNegInf(a)) {
sprintf(psz,"-Infinity"); sprintf(psz,SZ_NINF);
return; return;
} }
@ -3732,23 +3630,22 @@ Exit:
* *
*/ */
VP_EXPORT void VP_EXPORT void
VpActiveRound(Real *y, Real *x, int f, int nf) VpMidRound(Real *y, int f, int nf)
/*
* Round reletively from the decimal point.
* f: rounding mode
* nf: digit location to round from the the decimal point.
*/
{ {
int n,i,ix,ioffset; int n,i,ix,ioffset;
U_LONG v; U_LONG v;
U_LONG div; U_LONG div;
if(!VpIsDef(x)) {
VpAsgn(y,x,1);
goto Exit;
}
/* First,assign whole value in truncation mode */
VpAsgn(y, x, 1); /* 1 round off,2 round up */
nf += y->exponent*((int)BASE_FIG); nf += y->exponent*((int)BASE_FIG);
/* ix: x->fraq[ix] contains round position */ /* ix: x->fraq[ix] contains round position */
ix = (nf + ((int)BASE_FIG))/((int)BASE_FIG)-1; ix = nf/(int)BASE_FIG;
if(ix<0 || ((U_LONG)ix)>=y->Prec) goto Exit; /* Unable to round */ if(ix<0 || ((U_LONG)ix)>=y->Prec) return; /* Unable to round */
ioffset = nf - ix*((int)BASE_FIG); ioffset = nf - ix*((int)BASE_FIG);
memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG)); memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
/* VpNmlz(y); */ /* VpNmlz(y); */
@ -3765,10 +3662,10 @@ VpActiveRound(Real *y, Real *x, int f, int nf)
if(v>=5) ++div; if(v>=5) ++div;
break; break;
case VP_COMP_MODE_CEIL: /* ceil */ case VP_COMP_MODE_CEIL: /* ceil */
if(v && (VpGetSign(x)>0)) ++div; if(v && (VpGetSign(y)>0)) ++div;
break; break;
case VP_COMP_MODE_FLOOR: /* floor */ case VP_COMP_MODE_FLOOR: /* floor */
if(v && (VpGetSign(x)<0)) ++div; if(v && (VpGetSign(y)<0)) ++div;
break; break;
case VP_COMP_MODE_EVEN: /* Banker's rounding */ case VP_COMP_MODE_EVEN: /* Banker's rounding */
if(v>5) ++div; if(v>5) ++div;
@ -3789,27 +3686,50 @@ VpActiveRound(Real *y, Real *x, int f, int nf)
VpRdup(y,0); VpRdup(y,0);
} else { } else {
VpSetOne(y); VpSetOne(y);
VpSetSign(y,VpGetSign(x)); VpSetSign(y,VpGetSign(y));
} }
} else { } else {
y->frac[ix] = div; y->frac[ix] = div;
VpNmlz(y); VpNmlz(y);
} }
}
Exit: VP_EXPORT void
#ifdef _DEBUG VpLeftRound(Real *y, int f, int nf)
if(gfDebug) { /*
VPrint(stdout, "VpActiveRound y=%\n", y); * Round from the left hand side of the digits.
VPrint(stdout, " x=%\n", x); */
} {
#endif /*_DEBUG */ U_LONG v;
return;
if(!VpIsDef(y)) return; /* Unable to round */
if(VpIsZero(y)) return;
v = y->frac[0];
nf -= VpExponent(y)*BASE_FIG;
while(v=v/10) nf--;
nf += (BASE_FIG-1);
VpMidRound(y,f,nf);
}
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;
VpMidRound(y,f,nf);
} }
static int static int
VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v) VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
{ {
int f = 0; int f = 0;
if(!VpIsDef(c)) return f; /* Unable to round */
if(VpIsZero(c)) return f;
v /= BASE1; v /= BASE1;
switch(gfCompMode) { switch(gfCompMode) {
case VP_COMP_MODE_TRUNCATE: case VP_COMP_MODE_TRUNCATE:

View file

@ -20,6 +20,14 @@
extern "C" { extern "C" {
#endif #endif
/*
* NaN & Infinity
*/
#define SZ_NaN "NaN"
#define SZ_INF "Infinity"
#define SZ_PINF "+Infinity"
#define SZ_NINF "+Infinity"
/* /*
* #define VP_EXPORT other than static to let VP_ routines * #define VP_EXPORT other than static to let VP_ routines
* be called from outside of this module. * be called from outside of this module.
@ -136,6 +144,8 @@ VP_EXPORT void VpDtoV(Real *m,double d);
VP_EXPORT void VpItoV(Real *m,S_INT ival); VP_EXPORT void VpItoV(Real *m,S_INT ival);
VP_EXPORT int VpSqrt(Real *y,Real *x); VP_EXPORT int VpSqrt(Real *y,Real *x);
VP_EXPORT void VpActiveRound(Real *y,Real *x,int f,int il); 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 void VpFrac(Real *y,Real *x); VP_EXPORT void VpFrac(Real *y,Real *x);
VP_EXPORT int VpPower(Real *y,Real *x,S_INT n); VP_EXPORT int VpPower(Real *y,Real *x,S_INT n);
VP_EXPORT void VpPi(Real *y); VP_EXPORT void VpPi(Real *y);
@ -189,7 +199,7 @@ VP_EXPORT void VpSinCos(Real *psin,Real *pcos,Real *x);
#define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_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 VpSetInf(a,s) ( ((s)>0)?VpSetPosInf(a):VpSetNegInf(a) )
#define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1)) #define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
#define VpExponent(a) (a->exponent)
#ifdef _DEBUG #ifdef _DEBUG
int VpVarCheck(Real * v); int VpVarCheck(Real * v);
VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a); VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);

View file

@ -108,13 +108,13 @@ where:<BR>
s: Initial value string.<BR> s: Initial value string.<BR>
n: Maximum number of significant digits of a. n must be a Fixnum object. n: Maximum number of significant digits of a. n must be a Fixnum object.
If n is omitted or is equal to 0,then the maximum number of significant digits of a is determined from the length of s. If n is omitted or is equal to 0,then the maximum number of significant digits of a is determined from the length of s.
Actual number of digits handled in computations are usually gretaer than n.<BR>
n is useful when performing divisions like n is useful when performing divisions like
<CODE><PRE> <CODE><PRE>
BigDecimal("1") / BigDecimal("3") # => 0.3333333333 33E0 BigDecimal("1") / BigDecimal("3") # => 0.3333333333 33E0
BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0 BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
</PRE></CODE> </PRE></CODE>
but the result may differ in future version. but the resulting digits obtained may differ in future version.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>mode</B></LI><BLOCKQUOTE> <LI><B>mode</B></LI><BLOCKQUOTE>
@ -168,14 +168,17 @@ where flag must be one of:
</TABLE> </TABLE>
nil is returned if any argument is illegal.<BR> nil is returned if any argument is illegal.<BR>
The digit location for rounding operation can not be specified by mode method, The digit location for rounding operation can not be specified by mode method,
use truncate/round/ceil/floor mthods for each instance instead. use truncate/round/ceil/floor/add/sub/mult/div mthods for each instance instead.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>limit[(n)]</B></LI><BLOCKQUOTE> <LI><B>limit[(n)]</B></LI><BLOCKQUOTE>
Limits the maximum digits that the newly created BigDecimal objects can hold Limits the maximum digits that the newly created BigDecimal objects can hold
never exceed n. Returns maximum value before set. never exceed n+? (Currently,? can not be determined beforehand,but not so big).
This means the rounding operation specified by BigDecimal.mode is
performed if necessary.
limit returns maximum value before set.
Zero,the default value,means no upper limit.<BR> 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>
mf = BigDecimal::limit(n)<BR> mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE> </BLOCKQUOTE>
@ -230,31 +233,28 @@ For the resulting number of significant digits of c,see <A HREF="#PREC">Resultin
c = a.add(b,n)<BR> c = a.add(b,n)<BR>
c = a.add(b,n) performs c = a + b. c = a.add(b,n) performs c = a + b.
If n is less than the actual significant digits of a + b, If n is less than the actual significant digits of a + b,
then c is rounded properly. then c is rounded properly according to the BigDecimal.limit.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>sub</B></LI><BLOCKQUOTE> <LI><B>sub</B></LI><BLOCKQUOTE>
c = a.sub(b,n)<BR> c = a.sub(b,n)<BR>
c = a.sub(b,n) performs c = a - b. c = a.sub(b,n) performs c = a - b.
If n is less than the actual significant digits of a - b, If n is less than the actual significant digits of a - b,
then c is rounded properly. then c is rounded properly according to the BigDecimal.limit.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>mult</B></LI><BLOCKQUOTE> <LI><B>mult</B></LI><BLOCKQUOTE>
c = a.mult(b,n)<BR> c = a.mult(b,n)<BR>
c = a.mult(b,n) performs c = a * b. c = a.mult(b,n) performs c = a * b.
If n is less than the actual significant digits of a * b, If n is less than the actual significant digits of a * b,
then c is rounded properly. then c is rounded properly according to the BigDecimal.limit.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>div</B></LI><BLOCKQUOTE> <LI><B>div</B></LI><BLOCKQUOTE>
c,r = a.div(b,n)<BR> c = a.div(b,n)<BR>
c,r = a.div(b,n) performs c = a / b, r is the residue of a / b. c = a.div(b,n) performs c = a / b.
If necessary,the divide operation continues to n digits which c If n is less than the actual significant digits of a / b,
can hold. then c is rounded properly according to the BigDecimal.limit.
Unlike the divmod method,c is not always an integer.
c is never rounded,and the equation a = c*b + r is always
valid unless c is NaN or Infinity.
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>%</B></LI><BLOCKQUOTE> <LI><B>%</B></LI><BLOCKQUOTE>
@ -724,32 +724,40 @@ maximum significant digits of both side of the operator.<BR>
For example, c has more than 100 siginificant digits if c is computed as:<BR> For example, c has more than 100 siginificant digits if c is computed as:<BR>
c = 0.1+0.1*10**(-100)<br> c = 0.1+0.1*10**(-100)<br>
<BR> <BR>
As +,-,and * are always exact(no round operation is performed), As +,-,and * are always exact(no round operation is performed unless BigDecimal.limit is specified),
which means more momories are required to keep computation results. which means more momories are required to keep computation results.
But,the division such as c=1.0/3.0 will always be rounded.<BR>
Division such as c=1.0/3.0 will be rounded.<BR>
<H3>2. assign,add,sub,mult,div</H3> <H3>2. assign,add,sub,mult,div</H3>
The length of the significant digits obtained from +,-,*,/ The length of the significant digits obtained from +,-,*,/
is always defined by that of right and left side of the operator. is always defined by that of right and left side of the operator.
To specify the length of the significant digits by your self, To specify the length of the significant digits by your self,
use methos assign,add,sub,mult,div, or limit(class method). use methos assign,add,sub,mult,div.
<CODE><PRE>
BigDecimal("2").div(3,12) # 2.0/3.0 => 0.6666666666 67E0
</PRE></CODE>
</BLOCKQUOTE>
<H3>3. truncate,round,ceil,floor</H3>
Using these methods,you can specify rounding location relatively from
decimal point.
<CODE><PRE>
BigDecimal("6.66666666666666").round(12) # => 0.6666666666 667E1
</PRE></CODE>
</BLOCKQUOTE>
<H3>4. Example</H3>
Following example compute the ratio of the circumference of a circle to Following example compute the ratio of the circumference of a circle to
its dirmeter(pi=3.14159265358979....) using J.Machin's formula. its dirmeter(pi=3.14159265358979....) using J.Machin's formula.
<BR><BR> <BR><BR>
<CODE><PRE> <CODE><PRE>
#!/usr/local/bin/ruby #!/usr/local/bin/ruby
#
# pi.rb
# USAGE: ruby pi.rb n
# where n is the number of digits required.
# EX.: ruby pi.rb 1000
#
require "bigdecimal" require "bigdecimal"
# #
# Calculates 3.1415.... using J. Machin's formula. # Calculates 3.1415.... (the number of times that a circle's diameter
# will fit around the circle) using J. Machin's formula.
# #
def big_pi(sig) # sig: Number of significant figures def big_pi(sig) # sig: Number of significant figures
exp = -sig exp = -sig
@ -762,9 +770,9 @@ def big_pi(sig) # sig: Number of significant figures
k = BigDecimal::new("1") k = BigDecimal::new("1")
w = BigDecimal::new("1") w = BigDecimal::new("1")
t = BigDecimal::new("-80") t = BigDecimal::new("-80")
while (u.exponent >= exp) while (u.nonzero? && u.exponent >= exp)
t = t*m25 t = t*m25
u,r = t.div(k,sig) u = t.div(k,sig)
pi = pi + u pi = pi + u
k = k+two k = k+two
end end
@ -773,9 +781,9 @@ def big_pi(sig) # sig: Number of significant figures
k = BigDecimal::new("1") k = BigDecimal::new("1")
w = BigDecimal::new("1") w = BigDecimal::new("1")
t = BigDecimal::new("956") t = BigDecimal::new("956")
while (u.exponent >= exp ) while (u.nonzero? && u.exponent >= exp )
t,r = t.div(m57121,sig) t = t.div(m57121,sig)
u,r = t.div(k,sig) u = t.div(k,sig)
pi = pi + u pi = pi + u
k = k+two k = k+two
end end
@ -783,8 +791,12 @@ def big_pi(sig) # sig: Number of significant figures
end end
if $0 == __FILE__ if $0 == __FILE__
print "PI("+ARGV[0]+"):\n" if ARGV.size == 1
p pi(ARGV[0].to_i) print "PI("+ARGV[0]+"):\n"
p big_pi(ARGV[0].to_i)
else
print "TRY: ruby pi.rb 1000 \n"
end
end end
</PRE></CODE> </PRE></CODE>

View file

@ -92,8 +92,8 @@ c=a+b
<H3>メソッド一覧</H3> <H3>メソッド一覧</H3>
以下のメソッドが利用可能です。 以下のメソッドが利用可能です。
「有効桁数」とは BigDecimal が精度を保証する桁数です。 「有効桁数」とは BigDecimal が精度を保証する桁数です。
ぴったりではありません、若干の余裕を持って計算されます。また、 ぴったりではありません、若干の余裕を持って計算されます。
例えば32ビットのシステムでは10進で4桁毎に計算します。従って、現状では、 また、例えば32ビットのシステムでは10進で4桁毎に計算します。従って、現状では、
内部の「有効桁数」は4の倍数となっています。 内部の「有効桁数」は4の倍数となっています。
<P> <P>
以下のメソッド以外にも、(C ではない) Ruby ソースの形で 以下のメソッド以外にも、(C ではない) Ruby ソースの形で
@ -123,7 +123,6 @@ BigDecimal("1",10) / BigDecimal("3",10) # => 0.3333333333 3333333333 33333333E0
</PRE></CODE> </PRE></CODE>
ただし、個々の演算における最大有効桁数 n の取り扱いは将来のバージョンで ただし、個々の演算における最大有効桁数 n の取り扱いは将来のバージョンで
若干変更される可能性があります。 若干変更される可能性があります。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>mode</B></LI><BLOCKQUOTE> <LI><B>mode</B></LI><BLOCKQUOTE>
@ -181,15 +180,23 @@ f = BigDecimal::mode(BigDecimal::COMP_MODE,flag)
戻り値は指定前の flag の値です。 戻り値は指定前の flag の値です。
引数に正しくないものが指定された場合は nil が返ります。<BR> 引数に正しくないものが指定された場合は nil が返ります。<BR>
mode メソッドでは丸め操作の位置をユーザが指定することはできません。 mode メソッドでは丸め操作の位置をユーザが指定することはできません。
丸め操作と位置を自分で制御したい場合は truncate/round/ceil/floor といった 丸め操作と位置を自分で制御したい場合は truncate/round/ceil/floor
インスタンスメソッドを使用して下さい。 add/sub/mult といったインスタンスメソッドを使用して下さい。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>limit([n])</B></LI><BLOCKQUOTE> <LI><B>limit([n])</B></LI><BLOCKQUOTE>
生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。戻り値は 生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。
設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。 戻り値は設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。
nを指定しない場合は、現状の最大桁数が返ります。<BR> n を指定しない場合は、現状の最大桁数が返ります。<BR>
計算を続行する間に、数字の桁数が無制限に増えてしまうような場合
limit で予め桁数を制限できます。この場合 BigDecimal.mode で指定された
丸め処理が実行されます。
ただし、実際には n より若干大きい
桁数が確保されます。また、limit による桁数制限は(無制限を除いて)、
インスタンスメソッド (truncate/round/ceil/floor/add/sub/mult) より
優先されるので注意が必要です。<BR>
mf = BigDecimal::limit(n)<BR> mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>double_fig</B></LI><BLOCKQUOTE> <LI><B>double_fig</B></LI><BLOCKQUOTE>
Ruby の Float クラスが保持できる有効数字の数を返します。 Ruby の Float クラスが保持できる有効数字の数を返します。
<CODE><PRE> <CODE><PRE>
@ -240,32 +247,30 @@ c
以下のように使用します。<BR> 以下のように使用します。<BR>
c = a.add(b,n)<BR> c = a.add(b,n)<BR>
c = a + b を最大で n 桁まで計算します。 c = a + b を最大で n 桁まで計算します。
a + b の精度が n より大きいときは丸められます。 a + b の精度が n より大きいときは BigDecimal.mode で指定された方法で丸められます。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>sub</B></LI><BLOCKQUOTE> <LI><B>sub</B></LI><BLOCKQUOTE>
以下のように使用します。<BR> 以下のように使用します。<BR>
c = a.sub(b,n)<BR> c = a.sub(b,n)<BR>
c = a - b を最大で n 桁まで計算します。 c = a - b を最大で n 桁まで計算します。
a - b の精度が n より大きいときは丸められます。 a - b の精度が n より大きいときは BigDecimal.mode で指定された方法で丸められます。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>mult</B></LI><BLOCKQUOTE> <LI><B>mult</B></LI><BLOCKQUOTE>
以下のように使用します。<BR> 以下のように使用します。<BR>
c = a.mult(b,n)<BR> c = a.mult(b,n)<BR>
c = a * b を最大で n 桁まで計算します。 c = a * b を最大で n 桁まで計算します。
a * b の精度が n より大きいときは丸められます。 a * b の精度が n より大きいときは BigDecimal.mode で指定された方法で丸められます。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>div</B></LI><BLOCKQUOTE> <LI><B>div</B></LI><BLOCKQUOTE>
以下のように使用します。<BR> 以下のように使用します。<BR>
c,r = a.div(b,n)<BR> c = a.div(b,n)<BR>
c=a/b の計算をします。 r には剰余が代入されます。a/bは c = a / b を最大で n 桁まで計算します。
必要ならn 桁まで計算されます。divmod メソッド a / b の精度が n より大きいときは BigDecimal.mode で指定された方法で丸められます。
と異なり、c は整数とは限りません。
また、 c は丸められることはありません。
a = c*b + r の関係は成立します。
</BLOCKQUOTE> </BLOCKQUOTE>
<LI><B>%</B></LI><BLOCKQUOTE> <LI><B>%</B></LI><BLOCKQUOTE>
r = a%b <BR> r = a%b <BR>
a/b の余りを計算します。以下の計算と同じものです。<BR> a/b の余りを計算します。以下の計算と同じものです。<BR>
@ -708,21 +713,34 @@ c = a op b
加減算の場合は、誤差が出ないだけの精度を持つ c を生成します。例えば 加減算の場合は、誤差が出ないだけの精度を持つ c を生成します。例えば
c = 0.1+0.1*10**(-100) のような場合、c の精度は100桁以上の精度を c = 0.1+0.1*10**(-100) のような場合、c の精度は100桁以上の精度を
持つようになります。 持つようになります。
<BR> <BR><BR>
2.次に c = a op b の計算を実行します。<BR><BR> 2.次に c = a op b の計算を実行します。<BR><BR>
このように、加減算と乗算での c は必ず「誤差が出ない」だけの精度を このように、加減算と乗算での c は必ず「誤差が出ない」だけの精度を
持って生成されます。除算は(a の最大有効桁数)+(b の最大有効桁数)分の最大桁数 持って生成されます(BigDecimal.limit を指定しない場合)。
除算は(a の最大有効桁数)+(b の最大有効桁数)分の最大桁数
を持つ c が生成されますが、c = 1.0/3.0 のような計算で明らかなように、 を持つ c が生成されますが、c = 1.0/3.0 のような計算で明らかなように、
c の最大精度を超えるところで計算が打ち切られる場合があります。<BR><BR> c の最大精度を超えるところで計算が打ち切られる場合があります。<BR><BR>
いずれにせよ、c の最大精度は a や b より大きくなりますので c が必要とする いずれにせよ、c の最大精度は a や b より大きくなりますので c が必要とする
メモリー領域は大きくなることに注意して下さい。 メモリー領域は大きくなることに注意して下さい。
<BR><BR> <BR><BR>
注意:「+,-,*,/」では結果の精度(有効桁数)を自分で指定できません。 注意:「+,-,*,/」では結果の精度(有効桁数)を自分で指定できません。
精度をコントロールしたい場合は、以下の add,sub 等のメソッド 精度をコントロールしたい場合は、以下のインスタンスメソッドを使用します。<BR>
を使用します。<BR> <UL>
<LI>add,sub,mult,div</LI><BLOCKQUOTE>
これらのメソッドは先頭(最左)の数字からの桁数を指定できます。
<CODE><PRE>
BigDecimal("2").div(3,12) # 2.0/3.0 => 0.6666666666 67E0
</PRE></CODE>
</BLOCKQUOTE>
<LI>truncate,round,ceil,floor</LI><BLOCKQUOTE>
これらのメソッドは小数点からの相対位置を指定して桁数を決定します。
<CODE><PRE>
BigDecimal("6.66666666666666").round(12) # => 0.6666666666 667E1
</PRE></CODE>
</BLOCKQUOTE>
</UL>
<H3>自分で精度をコントロールしたい場合</H3> <H3>自分で精度をコントロールしたい場合</H3>
自分で精度(有効桁数)をコントロールしたい場合は assign、add、sub、mult、div 等のメソッド 自分で精度(有効桁数)をコントロールしたい場合は add、sub、mult、div 等のメソッド
が使用できます。 が使用できます。
以下の円周率を計算するプログラム例のように、 以下の円周率を計算するプログラム例のように、
求める桁数は自分で指定することができます。 求める桁数は自分で指定することができます。
@ -730,16 +748,10 @@ c = a op b
<CODE><PRE> <CODE><PRE>
#!/usr/local/bin/ruby #!/usr/local/bin/ruby
#
# pi.rb
# USAGE: ruby pi.rb n
# where n is the number of digits required.
# EX.: ruby pi.rb 1000
#
require "bigdecimal" require "bigdecimal"
# #
# Calculates 3.1415.... using J. Machin's formula. # Calculates 3.1415.... (the number of times that a circle's diameter
# will fit around the circle) using J. Machin's formula.
# #
def big_pi(sig) # sig: Number of significant figures def big_pi(sig) # sig: Number of significant figures
exp = -sig exp = -sig
@ -752,9 +764,9 @@ def big_pi(sig) # sig: Number of significant figures
k = BigDecimal::new("1") k = BigDecimal::new("1")
w = BigDecimal::new("1") w = BigDecimal::new("1")
t = BigDecimal::new("-80") t = BigDecimal::new("-80")
while (u.exponent >= exp) while (u.nonzero? && u.exponent >= exp)
t = t*m25 t = t*m25
u,r = t.div(k,sig) u = t.div(k,sig)
pi = pi + u pi = pi + u
k = k+two k = k+two
end end
@ -763,9 +775,9 @@ def big_pi(sig) # sig: Number of significant figures
k = BigDecimal::new("1") k = BigDecimal::new("1")
w = BigDecimal::new("1") w = BigDecimal::new("1")
t = BigDecimal::new("956") t = BigDecimal::new("956")
while (u.exponent >= exp ) while (u.nonzero? && u.exponent >= exp )
t,r = t.div(m57121,sig) t = t.div(m57121,sig)
u,r = t.div(k,sig) u = t.div(k,sig)
pi = pi + u pi = pi + u
k = k+two k = k+two
end end
@ -773,8 +785,12 @@ def big_pi(sig) # sig: Number of significant figures
end end
if $0 == __FILE__ if $0 == __FILE__
print "PI("+ARGV[0]+"):\n" if ARGV.size == 1
p pi(ARGV[0].to_i) print "PI("+ARGV[0]+"):\n"
p big_pi(ARGV[0].to_i)
else
print "TRY: ruby pi.rb 1000 \n"
end
end end
</PRE></CODE> </PRE></CODE>