diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 62343830ac..f1bd1e2320 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -34,14 +34,6 @@ #include #include #include -#ifdef NT -#include -#ifdef _MSC_VER -#include -#define isnan(x) _isnan(x) -#define isinf(x) (!(_finite(x))) -#endif /* _MSC_VER */ -#endif /* defined NT */ #include "ruby.h" #include "math.h" #include "version.h" @@ -52,7 +44,7 @@ VALUE rb_cBigDecimal; #include "bigdecimal.h" -/* MACRO's to guard objects from GC by keeping it in stack */ +/* MACRO's to guard objects from GC by keeping them in stack */ #define ENTER(n) volatile VALUE vStack[n];int iStack=0 #define PUSH(x) vStack[iStack++] = (unsigned long)(x); #define SAVE(p) PUSH(p->obj); @@ -71,7 +63,9 @@ 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); +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); /* @@ -297,25 +291,32 @@ BigDecimal_load(VALUE self, VALUE str) static VALUE BigDecimal_mode(VALUE self, VALUE which, VALUE val) { - unsigned short fo = VpGetException(); - unsigned short f; + unsigned long f,fo; + + if(TYPE(which)!=T_FIXNUM) return Qnil; + f = (unsigned long)FIX2INT(which); - if(TYPE(which)!=T_FIXNUM) return INT2FIX(fo); - if(val!=Qfalse && val!=Qtrue) return INT2FIX(fo); - - f = (unsigned short)FIX2INT(which); - if(f&VP_EXCEPTION_INFINITY) { + if(f&VP_EXCEPTION_ALL) { + /* Exception mode setting */ fo = VpGetException(); - VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY): - (fo&(~VP_EXCEPTION_INFINITY)))); + if(val!=Qfalse && val!=Qtrue) return Qnil; + if(f&VP_EXCEPTION_INFINITY) { + VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY): + (fo&(~VP_EXCEPTION_INFINITY)))); + } + if(f&VP_EXCEPTION_NaN) { + VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN): + (fo&(~VP_EXCEPTION_NaN)))); + } + return INT2FIX(fo); } - if(f&VP_EXCEPTION_NaN) { - fo = VpGetException(); - VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN): - (fo&(~VP_EXCEPTION_NaN)))); + if(VP_COMP_MODE==f) { + /* Computaion mode setting */ + if(TYPE(val)!=T_FIXNUM) return Qnil; + fo = VpSetCompMode((unsigned long)FIX2INT(val)); + return INT2FIX(fo); } - fo = VpGetException(); - return INT2FIX(fo); + return Qnil; } static U_LONG @@ -380,8 +381,9 @@ static VALUE BigDecimal_IsInfinite(VALUE self) { Real *p = GetVpValue(self,1); - if(VpIsInf(p)) return Qtrue; - return Qfalse; + if(VpIsPosInf(p)) return INT2FIX(1); + if(VpIsNegInf(p)) return INT2FIX(-1); + return Qnil; } static VALUE @@ -547,7 +549,7 @@ static VALUE BigDecimal_nonzero(VALUE self) { Real *a = GetVpValue(self,1); - return VpIsZero(a) ? Qfalse : self; + return VpIsZero(a) ? Qnil : self; } static VALUE @@ -650,6 +652,7 @@ BigDecimal_mult(VALUE self, VALUE r) static VALUE BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r) +/* For c,res = self.div(r): no round operation */ { ENTER(5); Real *a, *b; @@ -669,16 +672,19 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r) static VALUE BigDecimal_div(VALUE self, VALUE r) +/* For c = self/r: with round operation */ { ENTER(5); Real *c=NULL, *res=NULL, *div = NULL; r = BigDecimal_divide(&c, &res, &div, self, r); SAVE(c);SAVE(res);SAVE(div); if(r!=(VALUE)0) return r; /* coerced by other */ - if(res->frac[0]*2>=div->frac[0]) { - /* Round up */ - VpRdup(c); - } + /* a/b = c + r/b */ + /* c xxxxx + r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE + */ + /* Round up ? */ + VpInternalRound(c,0,c->frac[c->Prec-1],(VpBaseVal()*res->frac[0])/div->frac[0]); return ToValue(c); } @@ -707,7 +713,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) VpDivd(c, res, a, b); mx = c->Prec *(VpBaseFig() + 1); GUARD_OBJ(d,VpCreateRbObject(mx, "0")); - VpRound(d,c,1,3,0); + VpActiveRound(d,c,VP_COMP_MODE_FLOOR,0); VpMult(res,d,b); VpAddSub(c,a,res,-1); *div = d; @@ -754,7 +760,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv) GUARD_OBJ(d,VpCreateRbObject(mx, "0")); GUARD_OBJ(f,VpCreateRbObject(mx, "0")); - VpRound(d,c,1,1,0); /* 1: round off */ + VpActiveRound(d,c,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */ VpFrac(f, c); VpMult(rr,f,b); @@ -813,20 +819,6 @@ BigDecimal_divmod2(VALUE self, VALUE b, VALUE n) return obj; } -static VALUE -BigDecimal_assign2(VALUE self, VALUE n, VALUE f) -{ - ENTER(5); - Real *cv; - Real *av; - U_LONG mx = (U_LONG)GetPositiveInt(n); - Check_Type(f, T_FIXNUM); - GUARD_OBJ(cv,VpCreateRbObject(mx,"0")); - GUARD_OBJ(av,GetVpValue(self,1)); - VpAsgn(cv,av,FIX2INT(f)); - return ToValue(cv); -} - static VALUE BigDecimal_add2(VALUE self, VALUE b, VALUE n) { @@ -928,7 +920,7 @@ BigDecimal_fix(VALUE self) GUARD_OBJ(a,GetVpValue(self,1)); mx = a->Prec *(VpBaseFig() + 1); GUARD_OBJ(c,VpCreateRbObject(mx, "0")); - VpRound(c,a,1,1,0); /* 1: round off */ + VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,0); /* 0: round off */ return ToValue(c); } @@ -941,19 +933,29 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) int sw; U_LONG mx; VALUE vLoc; - - if(rb_scan_args(argc,argv,"01",&vLoc)==0) { + VALUE vBanker; + int na = rb_scan_args(argc,argv,"02",&vLoc,&vBanker); + sw = VP_COMP_MODE_ROUNDUP; /* round up */ + switch(na) { + case 0: iLoc = 0; - } else { + break; + case 1: Check_Type(vLoc, T_FIXNUM); iLoc = FIX2INT(vLoc); + break; + case 2: + Check_Type(vLoc, T_FIXNUM); + iLoc = FIX2INT(vLoc); + Check_Type(vBanker, T_FIXNUM); + if(FIX2INT(vBanker)) sw = VP_COMP_MODE_EVEN; /* Banker's rounding */ + break; } - sw = 2; GUARD_OBJ(a,GetVpValue(self,1)); mx = a->Prec *(VpBaseFig() + 1); GUARD_OBJ(c,VpCreateRbObject(mx, "0")); - VpRound(c,a,sw,1,iLoc); + VpActiveRound(c,a,sw,iLoc); return ToValue(c); } @@ -973,12 +975,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self) Check_Type(vLoc, T_FIXNUM); iLoc = FIX2INT(vLoc); } - sw = 1; /* truncate */ GUARD_OBJ(a,GetVpValue(self,1)); mx = a->Prec *(VpBaseFig() + 1); GUARD_OBJ(c,VpCreateRbObject(mx, "0")); - VpRound(c,a,sw,1,iLoc); + VpActiveRound(c,a,VP_COMP_MODE_TRUNCATE,iLoc); /* 0: truncate */ return ToValue(c); } @@ -1015,7 +1016,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")); - VpRound(c,a,1,3,iLoc); + VpActiveRound(c,a,VP_COMP_MODE_FLOOR,iLoc); return ToValue(c); } @@ -1038,7 +1039,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")); - VpRound(c,a,1,2,iLoc); + VpActiveRound(c,a,VP_COMP_MODE_CEIL,iLoc); return ToValue(c); } @@ -1064,7 +1065,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self) } static VALUE -BigDecimal_to_parts(VALUE self) +BigDecimal_split(VALUE self) { ENTER(5); Real *vp; @@ -1366,8 +1367,10 @@ Init_bigdecimal(void) rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1); rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1); - /* Constants */ + /* Constants definition */ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal())); + + /* Exceptions */ rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL)); rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN)); rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY)); @@ -1375,6 +1378,14 @@ Init_bigdecimal(void) rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW)); rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE)); + /* Computation mode */ + rb_define_const(rb_cBigDecimal, "COMP_MODE",INT2FIX(VP_COMP_MODE)); + rb_define_const(rb_cBigDecimal, "COMP_MODE_TRUNCATE",INT2FIX(VP_COMP_MODE_TRUNCATE)); + rb_define_const(rb_cBigDecimal, "COMP_MODE_ROUNDUP",INT2FIX(VP_COMP_MODE_ROUNDUP)); + rb_define_const(rb_cBigDecimal, "COMP_MODE_CEIL",INT2FIX(VP_COMP_MODE_CEIL)); + rb_define_const(rb_cBigDecimal, "COMP_MODE_FLOOR",INT2FIX(VP_COMP_MODE_FLOOR)); + rb_define_const(rb_cBigDecimal, "COMP_MODE_EVEN",INT2FIX(VP_COMP_MODE_EVEN)); + /* Constants for sign value */ rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN)); rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO)); @@ -1386,7 +1397,6 @@ Init_bigdecimal(void) /* instance methods */ rb_define_method(rb_cBigDecimal, "prec", BigDecimal_prec, 0); - rb_define_method(rb_cBigDecimal, "assign", BigDecimal_assign2, 2); rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2); rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2); rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2); @@ -1394,7 +1404,7 @@ Init_bigdecimal(void) 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_i", BigDecimal_to_i, 0); - rb_define_method(rb_cBigDecimal, "to_parts", BigDecimal_to_parts, 0); + rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0); rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1); rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1); rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0); @@ -1415,6 +1425,7 @@ Init_bigdecimal(void) rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1); rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1); rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1); + rb_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1); rb_define_method(rb_cBigDecimal, "exp", BigDecimal_exp, 1); rb_define_method(rb_cBigDecimal, "sincos", BigDecimal_sincos, 1); rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1); @@ -1462,6 +1473,8 @@ static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */ #endif /* _DEBUG */ static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */ +static short gfCompMode = VP_COMP_MODE_ROUNDUP; /* Mode for general computation */ + static U_LONG BASE_FIG = 4; /* =log10(BASE) */ static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */ /* The value of BASE**2 + BASE must be represented */ @@ -1544,6 +1557,22 @@ VpSetPrecLimit(U_LONG n) return s; } +VP_EXPORT unsigned long +VpGetCompMode(void) +{ + return gfCompMode; +} + +VP_EXPORT unsigned long +VpSetCompMode(unsigned long n) +{ + unsigned long s = gfCompMode; + if(n!=VP_COMP_MODE_TRUNCATE && n!= VP_COMP_MODE_ROUNDUP && n!=VP_COMP_MODE_CEIL && + n!=VP_COMP_MODE_FLOOR && n!= VP_COMP_MODE_EVEN) return s; + gfCompMode = n; + return s; +} + /* * 0.0 & 1.0 generator * These gZero_..... and gOne_..... can be any name @@ -1552,8 +1581,8 @@ VpSetPrecLimit(U_LONG n) * (to let the compiler know they may be changed in outside * (... but not actually..)). */ -double gZero_ABCED9B1_CE73__00400511F31D = 0.0; -double gOne_ABCED9B4_CE73__00400511F31D = 1.0; +volatile double gZero_ABCED9B1_CE73__00400511F31D = 0.0; +volatile double gOne_ABCED9B4_CE73__00400511F31D = 1.0; static double Zero(void) { @@ -1969,10 +1998,10 @@ VpAlloc(U_LONG mx, char *szVal) ++i; ++ni; } - nf = 0; + nf = 0; ipf = 0; ipe = 0; - ne = 0; + ne = 0; if(v) { /* other than digit nor \0 */ if(szVal[i] == '.') { /* xxx. */ @@ -2023,11 +2052,10 @@ VpAlloc(U_LONG mx, char *szVal) * [Input] * a ... RHSV * isw ... switch for assignment. - * c = a when isw = 1 or 2 - * c = -a when isw = -1 or -1 - * when |isw|==1 - * if c->MaxPrec < a->Prec,then round up - * will not be performed. + * c = a when isw > 0 + * c = -a when isw < 0 + * if c->MaxPrec < a->Prec,then round operation + * will be performed. * [Output] * c ... LHSV */ @@ -2051,22 +2079,19 @@ VpAsgn(Real *c, Real *a, int isw) n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec); c->Prec = n; for(j=0;j < n; ++j) c->frac[j] = a->frac[j]; - if(isw < 0) isw = -isw; - if(isw == 2) { - if(a->MaxPrec>n) { - if((c->Prec < a->Prec) && - (a->frac[n] >= HALF_BASE)) VpRdup(c); /* round up/off */ - } + /* Needs round ? */ + if(c->Prec < a->Prec) { + VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]); } } else { /* The value of 'a' is zero. */ VpSetZero(c,isw*VpGetSign(a)); return 1; } - VpNmlz(c); return c->Prec*BASE_FIG; } + /* * c = a + b when operation = 1 or 2 * = a - b when operation = -1 or -2. @@ -2113,7 +2138,7 @@ VpAddSub(Real *c, Real *a, Real *b, int operation) } if(operation < 0) sw = -1; - else sw = 1; + else sw = 1; /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */ if(a->exponent > b->exponent) { @@ -2202,7 +2227,6 @@ static int VpAddAbs(Real *a, Real *b, Real *c) { U_LONG word_shift; - U_LONG round; U_LONG carry; U_LONG ap; U_LONG bp; @@ -2210,7 +2234,7 @@ VpAddAbs(Real *a, Real *b, Real *c) U_LONG a_pos; U_LONG b_pos; U_LONG c_pos; - U_LONG av, bv; + U_LONG av, bv, mrv; #ifdef _DEBUG if(gfDebug) { @@ -2226,7 +2250,7 @@ VpAddAbs(Real *a, Real *b, Real *c) if(word_shift==-1L) return 0; /* Overflow */ if(b_pos == -1L) goto Assign_a; - round =((av + bv) >= HALF_BASE) ? 1 : 0; + mrv = av + bv; /* Most right val. Used for round. */ /* Just assign the last few digits of b to c because a has no */ /* corresponding digits to be added. */ @@ -2281,8 +2305,7 @@ VpAddAbs(Real *a, Real *b, Real *c) } if(c_pos) c->frac[c_pos - 1] += carry; - if(round) VpRdup(c); /* Roundup and normalize. */ - else VpNmlz(c); /* normalize the result */ + if(!VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv)) VpNmlz(c); goto Exit; Assign_a: @@ -2305,7 +2328,7 @@ static int VpSubAbs(Real *a, Real *b, Real *c) { U_LONG word_shift; - U_LONG round; + U_LONG mrv; U_LONG borrow; U_LONG ap; U_LONG bp; @@ -2330,10 +2353,10 @@ VpSubAbs(Real *a, Real *b, Real *c) if(b_pos == -1L) goto Assign_a; if(av >= bv) { - round =((av -= bv) >= HALF_BASE) ? 1 : 0; + mrv = av - bv; borrow = 0; } else { - round = 0; + mrv = 0; borrow = 1; } @@ -2395,8 +2418,8 @@ VpSubAbs(Real *a, Real *b, Real *c) } } if(c_pos) c->frac[c_pos - 1] -= borrow; - if(round) VpRdup(c); /* Round up and normalize */ - else VpNmlz(c); /* normalize the result */ + + if(!VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv)) VpNmlz(c); goto Exit; Assign_a: @@ -2454,7 +2477,7 @@ VpSetPTR(Real *a, Real *b, Real *c, U_LONG *a_pos, U_LONG *b_pos, U_LONG *c_pos, /* * a = xxxxxxAxxx * c = xxxxxx - * a_pos = | + * a_pos = | */ *a_pos = left_word; *av = a->frac[*a_pos]; /* av is 'A' shown in above. */ @@ -2544,11 +2567,11 @@ VpMult(Real *c, Real *a, Real *b) return 1; /* 0: 1 significant digit */ } - if((a->Prec == 1) &&(a->frac[0] == 1) &&(a->exponent == 1)) { + if(VpIsOne(a)) { VpAsgn(c, b, VpGetSign(a)); goto Exit; } - if((b->Prec == 1) &&(b->frac[0] == 1) &&(b->exponent == 1)) { + if(VpIsOne(b)) { VpAsgn(c, a, VpGetSign(b)); goto Exit; } @@ -2624,7 +2647,7 @@ VpMult(Real *c, Real *a, Real *b) VpNmlz(c); /* normalize the result */ if(w != NULL) { /* free work variable */ - VpAsgn(w, c, 2); + VpAsgn(w, c, 1); VpFree(c); c = w; } @@ -2675,8 +2698,7 @@ VpDivd(Real *c, Real *r, Real *a, Real *b) VpSetZero(r,VpGetSign(a)*VpGetSign(b)); goto Exit; } - - if((b->Prec == 1) &&(b->frac[0] == 1) &&(b->exponent == 1)) { + if(VpIsOne(b)) { /* divide by one */ VpAsgn(c, a, VpGetSign(b)); VpSetZero(r,VpGetSign(a)); @@ -2980,6 +3002,7 @@ Exit: return (int)val; } +#ifdef _DEBUG /* * cntl_chr ... ASCIIZ Character, print control characters * Available control codes: @@ -3082,6 +3105,7 @@ VPrint(FILE *fp, char *cntl_chr, Real *a) } return (int)nc; } +#endif /* _DEBUG */ static void VpFormatSt(char *psz,S_INT fFmt) @@ -3468,8 +3492,9 @@ VpDtoV(Real *m, double d) } m->Prec = ind_m + 1; m->exponent = ne; - if(val*((double)((S_INT)BASE)) >=(double)((S_INT)HALF_BASE)) VpRdup(m); - VpNmlz(m); + + if(!VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0, + (U_LONG)(val*((double)((S_INT)BASE))))) VpNmlz(m); Exit: #ifdef _DEBUG @@ -3551,8 +3576,8 @@ VpSqrt(Real *y, Real *x) Real *f = NULL; Real *r = NULL; S_LONG y_prec, f_prec; - S_LONG n; - S_LONG e; + S_LONG n; + S_LONG e; S_LONG prec; S_LONG nr; double val; @@ -3650,11 +3675,12 @@ Exit: /* * - * f = 1: round, 2:ceil, 3: floor + * f = 0: Round off/Truncate, 1: round up, 2:ceil, 3: floor, 4: Banker's rounding + * nf: digit position for operation. * */ VP_EXPORT void -VpRound(Real *y, Real *x, int sw, int f, int nf) +VpActiveRound(Real *y, Real *x, int f, int nf) { int n,i,j,ix,ioffset; U_LONG v; @@ -3665,35 +3691,41 @@ VpRound(Real *y, Real *x, int sw, int f, int nf) goto Exit; } - /* First,assign whole value */ - VpAsgn(y, x, sw); + /* First,assign whole value in truncation mode */ + VpAsgn(y, x, 1); /* 1 round off,2 round up */ nf += y->exponent*((int)BASE_FIG); /* ix: x->fraq[ix] contains round position */ ix = (nf + ((int)BASE_FIG))/((int)BASE_FIG)-1; if(ix<0 || ((U_LONG)ix)>=y->Prec) goto Exit; /* Unable to round */ ioffset = nf - ix*((int)BASE_FIG); for(j=ix+1;j<(int)y->Prec;++j) y->frac[j] = 0; - VpNmlz(y); + /* VpNmlz(y); */ v = y->frac[ix]; /* drop digits after pointed digit */ n = BASE_FIG - ioffset - 1; for(i=0;i=5) { - ++div; - } + switch(f) { + case VP_COMP_MODE_TRUNCATE: /* Truncate/Round off */ + break; + case VP_COMP_MODE_ROUNDUP: /* Round up */ + if(v>=5) ++div; break; - case 2: /* ceil */ - if(v) { - if(VpGetSign(x)>0) ++div; - } + case VP_COMP_MODE_CEIL: /* ceil */ + if(v && (VpGetSign(x)>0)) ++div; break; - case 3: /* floor */ - if(v) { - if(VpGetSign(x)<0) ++div; + case VP_COMP_MODE_FLOOR: /* floor */ + if(v && (VpGetSign(x)<0)) ++div; + break; + case VP_COMP_MODE_EVEN: /* Banker's rounding */ + if(v>5) ++div; + else if(v==5) { + if(i==(BASE_FIG-1)) { + if(ix && (y->frac[ix-1]%2)) ++div; + } else { + if(div%2) ++div; + } } break; } @@ -3702,7 +3734,7 @@ VpRound(Real *y, Real *x, int sw, int f, int nf) y->frac[ix] = 0; if(ix) { VpNmlz(y); - VpRdup(y); + VpRdup(y,0); } else { VpSetOne(y); VpSetSign(y,VpGetSign(x)); @@ -3715,24 +3747,51 @@ VpRound(Real *y, Real *x, int sw, int f, int nf) Exit: #ifdef _DEBUG if(gfDebug) { - VPrint(stdout, "VpRound y=%\n", y); + VPrint(stdout, "VpActiveRound y=%\n", y); VPrint(stdout, " x=%\n", x); } #endif /*_DEBUG */ return; } +static int +VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v) +{ + int f = 0; + v /= BASE1; + switch(gfCompMode) { + case VP_COMP_MODE_TRUNCATE: + break; + case VP_COMP_MODE_ROUNDUP: + if(v >= 5) f = 1; + break; + case VP_COMP_MODE_CEIL: /* ceil */ + if(v && (VpGetSign(c)>0)) f = 1; + break; + case VP_COMP_MODE_FLOOR: /* floor */ + if(v && (VpGetSign(c)<0)) f = 1; + break; + case VP_COMP_MODE_EVEN: /* Banker's rounding */ + if(v>5) f = 1; + else if(v==5 && vPrev%2) f = 1; + break; + } + if(f) VpRdup(c,ixDigit); /* round up */ + return f; +} + /* * Rounds up m(plus one to final digit of m). */ static int -VpRdup(Real *m) +VpRdup(Real *m,U_LONG ind_m) { - U_LONG ind_m, carry; - ind_m = m->Prec; + U_LONG carry; + + if(!ind_m) ind_m = m->Prec; + carry = 1; - while(carry > 0 && ind_m) { - --ind_m; + while(carry > 0 && (ind_m--)) { m->frac[ind_m] += carry; if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE; else carry = 0; @@ -3907,8 +3966,8 @@ VpPi(Real *y) VpAddSub(r, y, f, 1); /* r = y + f */ VpAsgn(y, r, 1); /* y = r */ - VpRdup(n); /* n = n + 1 */ - VpRdup(n); /* n = n + 1 */ + VpRdup(n,0); /* n = n + 1 */ + VpRdup(n,0); /* n = n + 1 */ if(VpIsZero(f)) break; } while((f->exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) && i1exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) && i2frac[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 VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1)) #ifdef _DEBUG int VpVarCheck(Real * v); +VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a); #endif /* _DEBUG */ #if defined(__cplusplus) diff --git a/ext/bigdecimal/bigdecimal_en.html b/ext/bigdecimal/bigdecimal_en.html index b8e9768f8f..04dd83a429 100644 --- a/ext/bigdecimal/bigdecimal_en.html +++ b/ext/bigdecimal/bigdecimal_en.html @@ -2,90 +2,27 @@ @@ -99,7 +36,6 @@ Using BigDecimal class, you can obtain any number of significant digits in compu For the details about Ruby see:
@@ -126,7 +62,7 @@ NOTE:

Introduction

Ruby already has builtin (variable length integer number) class Bignum. Using Bignum class,you can obtain - any integer value in magnitude. But, variable length floating number class is not yet built in. + any integer value in magnitude. But, variable length decimal number class is not yet built in. This is why I made variable length floating class BigDecimal. Feel free to send any comments or bug reports to me.
shigeo@tinyforest.gr.jp @@ -155,16 +91,80 @@ not exactly but slightly excess memories will be allocated to newly created obje In 32 bits integer system,every 4 digits(in decimal) are computed simultaneously. This means the number of significant digits in BigDecimal is always a multiple of 4. +

Class methods

    -
  • new

  • +
  • new
  • "new" method creates a new BigDecimal object.
    a=BigDecimal::new(s[,n])
    where:
    s: Initial value string.
    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. +
    -
  • double_fig

  • +
  • mode
  • +mode method controls BigDecimal computation.Following usage are defined.
    +

    [EXCEPTION control]

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

    +

    +f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    +
    +EXCEPTION_NaN controls the execution when computation results to NaN.
    +EXCEPTION_INFINITY controls the execution when computation results to Infinity(±Infinity).
    +EXCEPTION_UNDERFLOW controls the execution when computation underflows.
    +EXCEPTION_OVERFLOW controls the execution when computation overflows.
    +EXCEPTION_ZERODIVIDE controls the execution when zero-division occures.
    +EXCEPTION_ALL controls the execution for any exception defined occures.
    +If the flag is true,then the relating exception is thrown.
    +No exception is thrown when the flag is false(default) and computation +continues with the result:
    +
    +EXCEPTION_NaN results to NaN
    +EXCEPTION_INFINITY results to +Infinity or -Infinity
    +EXCEPTION_UNDERFLOW results to 0.
    +EXCEPTION_OVERFLOW results to +Infinity or -Infinity
    +EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity
    +
    +EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are + currently the same.
    +The return value of mode method is the previous value set.
    +nil is returned if any argument is wrong.
    +Suppose the return value of the mode method is f,then + f & BigDecimal::EXCEPTION_NaN !=0 means EXCEPTION_NaN is set to on. +

    +[ROUND error control]

    +Rounding operation can be controlled as: +

    +f = BigDecimal::mode(BigDecimal::COMP_MODE,flag) +
    +where flag must be one of: + + + + + + +
    COMP_MODE_TRUNCATEtruncate
    COMP_MODE_ROUNDUProundup,default
    COMP_MODE_CEILceil
    COMP_MODE_FLOORfloor
    COMP_MODE_EVENBanker's rounding
    +nil is returned if any argument is illegal.
    +The digit location for rounding operation can not be specified by mode method, +use truncate/roundup/ceil/floor mthods for each instance instead. + +
    + +
  • limit[(n)]
  • +Limits the maximum digits that the newly created BigDecimal objects can hold +never exceed n. Returns maximum value before set. +Zero,the default value,means no upper limit.
    +mf = BigDecimal::limit(n)
    +
    + +
  • double_fig
  • double_fig is a class method which returns the number of digits the Float class can have.
    @@ -180,71 +180,71 @@ double_fig is:
         v /= 10;
      }
     
    +
    -
  • prec

  • -r,m = a.prec
    -where r is the number of significant digits of a, -m is the maximum number of significant digits a can hold.
    -
    -  require "bigdecimal"
    -  a = BigDecimal.new("0.12345")
    -  p a.prec                              # ==> [8, 12]
    -  b = BigDecimal.new("0.1234500000000")
    -  p b.prec                              # ==> [8, 20]
    -  c = BigDecimal.new("0.12345",20)
    -  p c.prec                              # ==> [8, 24]
    -
    -r and m are always the multiple of log10(BigDecimal::BASE). +
  • BASE
  • +Base value used in the BigDecimal calculation. +On 32 bits integer system,the value of BASE is 10000.
    +b = BigDecimal::BASE
    +
    -
  • +

  • +
  • E
  • +e = BigDecimal::E(n)
    +where e(=2.718281828....) is the base value of natural logarithm.
    +n specifies the length of significant digits of e. + +
    +
  • PI
  • +e = BigDecimal::PI(n)
    +returns at least n digits of the ratio of the circumference of a circle to its diameter +(pi=3.14159265358979....) using J.Machin's formula.
    +
    +
+ +

Instance methods

+
    +
  • +
  • addition(c = a + b)
    For the resulting number of significant digits of c,see Resulting number of significant digits. -
  • -

  • +
    +
  • -
  • subtraction (c = a - b) or negation (c = -a)
    For the resulting number of significant digits of c,see Resulting number of significant digits. -
  • *

  • +
    +
  • *
  • multiplication(c = a * b)
    For the resulting number of significant digits of c,see Resulting number of significant digits. -
  • /

  • +
    +
  • /
  • division(c = a / b)
    For the resulting number of significant digits of c,see Resulting number of significant digits. +
    -
  • assign

  • -c = a.assign(n,f)
    -assigns the value of a to c.
    -n is the number of significant digits of resulting c.
    -If f > 0,then a is assigned to c.
    -If f < 0,then -a is assigned to c.
    -The absolute value of f (|f|) must be 1 or 2. -If |f|=2,then proper round operation over c is performed,when the maximum -number of significant digits of c is less than current -number of significant digits of a. -If |f|=1 then extra digits are discarded when the maximum -number of significant digits of c is less than current -number of significant digits of a. - -
  • add

  • +
  • add
  • c = a.add(b,n)
    c = a.add(b,n) performs c = a + b. If n is less than the actual significant digits of a + b, then c is rounded properly. -
  • sub

  • +
    +
  • sub
  • c = a.sub(b,n)
    c = a.sub(b,n) performs c = a - b. If n is less than the actual significant digits of a - b, then c is rounded properly. -
  • mult

  • +
    +
  • mult
  • c = a.mult(b,n)
    c = a.mult(b,n) performs c = a * b. If n is less than the actual significant digits of a * b, then c is rounded properly. -
  • div

  • +
    +
  • div
  • c,r = a.div(b,n)
    c,r = a.div(b,n) performs c = a / b, r is the residue of a / b. If necessary,the divide operation continues to n digits which c @@ -253,169 +253,154 @@ 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. -
  • %

  • +
    +
  • %
  • r = a%b
    is the same as:
    r = a-((a/b).floor)*b
    -
  • fix

  • +
    +
  • fix
  • c = a.fix
    returns integer part of a.
    -
  • frac

  • +
    +
  • frac
  • c = a.frac
    returns fraction part of a.
    -
  • floor[(n)]

  • +
    +
  • floor[(n)]
  • c = a.floor
    -returns the maximum integer value (in BigDecimal) which is less than or equal to a.
    +returns the maximum integer value (in BigDecimal) which is less than or equal to a. +
    
    + c = BigDecimal("1.23456").floor  #  ==> 1
    + c = BigDecimal("-1.23456").floor #  ==> -2
    +
    + As shown in the following example,an optional integer argument (n) specifying the position -of 'floor'ed digit can be given. -If n> 0,then the (n+1)th digit counted from the decimal point in fraction part is 'floor'ed. -If n<0,then the n-th digit counted from the decimal point in integer part is 'floor'ed.
    +of the target digit can be given.
    +If n> 0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    +If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left). +
    
    + c = BigDecimal::new("1.23456").floor(4)   #  ==> 1.2345
    + c = BigDecimal::new("15.23456").floor(-1) #  ==> 10.0
    +
    -c = BigDecimal::new("1.23456")
    -d = c.floor(4) # d = 1.2345
    -c = BigDecimal::new("15.23456")
    -d = c.floor(-1) # d = 10.0
    - -
  • ceil[(n)]

  • +
    +
  • ceil[(n)]
  • c = a.ceil
    -returns the minimum integer value (in BigDecimal) which is greater than or equal to a.
    +returns the minimum integer value (in BigDecimal) which is greater than or equal to a. +
    
    + c = BigDecimal("1.23456").ceil  #  ==> 2
    + c = BigDecimal("-1.23456").ceil #  ==> -1
    +
    + As shown in the following example,an optional integer argument (n) specifying the position -of 'ceil'ed digit can be given. -If n>0,then the (n+1)th digit counted from the decimal point in fraction part is 'ceil'ed. -If n<0,then the n-th digit counted from the decimal point in integer part is 'ceil'ed.
    +of the target digit can be given.
    +If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    +If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left). +
    
    + c = BigDecimal::new("1.23456").ceil(4)   # ==> 1.2346
    + c = BigDecimal::new("15.23456").ceil(-1) # ==> 20.0
    +
    -c = BigDecimal::new("1.23456")
    -d = c.ceil(4) # d = 1.2346
    -c = BigDecimal::new("15.23456")
    -d = c.ceil(-1) # d = 20.0
    - -
  • round[(n)]

  • +
    +
  • round[(n[,b])]
  • c = a.round
    -round off a to the nearest 1.
    +round a to the nearest 1.
    +
    
    + c = BigDecimal("1.23456").round  #  ==> 1
    + c = BigDecimal("-1.23456").round #  ==> -1
    +
    + As shown in the following example,an optional integer argument (n) specifying the position -of rounded digit can be given. -If n>0,then the (n+1)th digit counted from the decimal point in fraction part is rounded. -If n<0,then the n-th digit counted from the decimal point in integer part is rounded.
    +of the target digit can be given.
    +If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    +If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left). +
    
    +c = BigDecimal::new("1.23456").round(4)   #  ==> 1.2346
    +c = BigDecimal::new("15.23456").round(-1) #  ==> 20.0
    +
    -c = BigDecimal::new("1.23456")
    -d = c.round(4) # d = 1.235
    -c = BigDecimal::new("15.23456")
    -d = c.round(-1) # d = 20.0
    +If the second optional argument b is given with the non-zero value(default is zero) then +so called Banker's rounding is performed.
    +Suppose the digit p is to be rounded,then:
    + If p<5 then p is truncated
    + If p>5 then p is rounded up
    + If p is 5 then round up operation is taken only when the left hand side digit of p is odd. +
    
    +c = BigDecimal::new("1.23456").round(3,1)   #  ==> 1.234
    +c = BigDecimal::new("1.23356").round(3,1)   #  ==> 1.234
    +
    -
  • truncate[(n)]

  • +
    +
  • truncate[(n)]
  • c = a.truncate
    truncate a to the nearest 1.
    As shown in the following example,an optional integer argument (n) specifying the position -of truncated digit can be given. -If n>0,then the (n+1)th digit counted from the decimal point in fraction part is truncated. -If n<0,then the n-th digit counted from the decimal point in integer part is truncated.
    +of the target digit can be given.
    +If n>0,then the (n+1)th digit counted from the decimal point in fraction part is processed(resulting number of fraction part digits is less than or equal to n).
    +If n<0,then the n-th digit counted from the decimal point in integer part is processed(at least n 0's are placed from the decimal point to left). -c = BigDecimal::new("1.23456")
    -d = c.truncate(4) # d = 1.2345
    -c = BigDecimal::new("15.23456")
    -d = c.truncate(-1) # d = 10.0
    +
    
    +c = BigDecimal::new("1.23456").truncate(4)   #  ==> 1.2345
    +c = BigDecimal::new("15.23456").truncate(-1) #  ==> 10.0
    +
    -
  • divmod

  • +
    +
  • divmod
  • c,r = a.divmod(b) # a = c*b + r
    returns the quotient and remainder of a/b.
    a = c * b + r is always satisfied.
    -where c is the integer sutisfying +where c is the integer satisfying c = (a/b).floor
    and,therefore r = a - c*b
    -
  • remainder

  • +
    +
  • remainder
  • r=a.remainder(b)
    returns the remainder of a/b.
    -where c is the integer sutisfying +where c is the integer satisfying c = (a/b).fix
    and,therefore: r = a - c*b
    -
  • abs

  • +
    +
  • abs
  • c = a.abs
    returns an absolute value of a.
    -
  • to_i

  • +
    +
  • to_i
  • changes a to an integer.
    i = a.to_i
    i becomes to Fixnum or Bignum. -IF a is Infinity or NaN,then i becomes to nil. +If a is Infinity or NaN,then i becomes to nil. -
  • to_s[(n)]

  • +
    +
  • to_s[(n)]
  • converts to string(results look like "0.xxxxxEn").
    s = a.to_s
    If n is given,then a space is inserted after every n digits for readability.
    s = a.to_s(n) -
  • exponent

  • +
    +
  • exponent
  • returns an integer holding exponent value of a.
    n = a.exponent
    means a = 0.xxxxxxx*10**n. -
  • to_f

  • +
    +
  • to_f
  • same as dup method. creates a new BigDecimal object having same value. +
    -
  • E

  • -e = BigDecimal::E(n)
    -where e(=2.718281828....) is the base value of natural logarithm.
    -n specifies the length of significant digits of e. - -
  • PI

  • -e = BigDecimal::PI(n)
    -returns at least n digits of the ratio of the circumference of a circle to its dirmeter -(pi=3.14159265358979....) using J.Machin's formula.
    - -
  • BASE

  • -Base value used in the BigDecimal calculation. -On 32 bit integer system,the value of BASE is 10000.
    -b = BigDecimal::BASE
    - -
  • mode

  • -mode method controls BigDecimal computation. -Following usage are defined.
    - -f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    - -EXCEPTION_NaN controls the execution once computation results to NaN. -EXCEPTION_INFINITY controls the execution once computation results to Infinity(±Infinity). -EXCEPTION_UNDERFLOW controls the execution once computation underflows. -EXCEPTION_OVERFLOW controls the execution once computation overflows. -EXCEPTION_ZERODIVIDE controls the execution once zero-division occures. -EXCEPTION_ALL controls the execution for any exception defined occures. -If the flag is true,then the relating exception is thrown. -No exception is thrown when the flag is false(default) and computation -continues with the result:
    -EXCEPTION_NaN results to NaN
    -EXCEPTION_INFINITY results to +Infinity or -Infinity
    -EXCEPTION_UNDERFLOW results to 0.
    -EXCEPTION_OVERFLOW results to +Infinity or -Infinity
    -EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity
    -EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are - currently the same.
    -The return value of mode method is the value set. -Suppose the return value of the mode method is f,then - f & BigDecimal::EXCEPTION_NaN !=0 means EXCEPTION_NaN is set to on. -If the value of the argument flag is other than nil,true nor false then -current mode status is returned. - -
  • limit[(n)]

  • -Limits the maximum digits that the newly created BigDecimal objects can hold -never exceed n. Returns maximum value before set. -Zero,the default value,means no upper limit.
    -mf = BigDecimal::limit(n)
    - -
  • sign

  • -returns the 'attribute'. + +
  • sign
  • +returns the 'attribute' of a. n = a.sign
    where the value of n means that a is:
    n = BigDecimal::SIGN_NaN(0) : a is NaN
    @@ -427,28 +412,42 @@ n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a is +Infinity
    n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a is -Infinity
    The value in () is the actual value,see (Internal structure.
    -
  • nan?

  • +
    +
  • nan?
  • a.nan? returns True when a is NaN. -
  • infinite?

  • -a.infinite? returns True when a is +∞ or -∞. +
    +
  • infinite?
  • +a.infinite? returns 1 when a is +∞,-1 when a is -∞, nil otherwise. -
  • finite?

  • -a.finite? returns True when a is neither ∞ nor NaN. +
    +
  • finite?
  • +a.finite? returns true when a is neither ∞ nor NaN. +
    -
  • to_parts

  • +
  • zero?
  • +c = a.zero?
    +returns true if a is equal to 0,otherwise returns false
    +
    +
  • nonzero?
  • +c = a.nonzero?
    +returns nil if a is 0,otherwise returns a itself.
    +
    + +
  • split
  • decomposes a BigDecimal value to 4 parts. All 4 parts are returned as an array.
    Parts consist of a sign(0 when the value is NaN,+1 for positive and -1 for negative value), a string representing fraction part,base value(always 10 currently),and an integer(Fixnum) for exponent respectively. -a=BigDecimal::new("3.14159265",10)
    -f,x,y,z = a.to_parts
    +a=BigDecimal::new("3.14159265")
    +f,x,y,z = a.split
    where f=+1,x="314159265",y=10 and z=1
    therefore,you can translate BigDecimal value to Float as:
    s = "0."+x
    b = f*(s.to_f)*(y**z)
    -
  • inspect

  • +
    +
  • inspect
  • is used for debugging output.
    p a=BigDecimal::new("3.14",10)
    should produce output like "#<0x112344:'0.314E1',4(12)%gt;". @@ -457,38 +456,44 @@ where "0x112344" is the address, and 12 is the maximum number of the significant digits the object can hold. -
  • dup

  • +
    +
  • dup
  • creates a new BigDecimal object having same value. -
  • sqrt

  • +
    +
  • sqrt
  • c = a.sqrt(n)
    computes square root value of a with significant digit number n at least.
    -
  • sincos

  • +
    +
  • sincos
  • computes and returns sine and cosine value of a with significant digit number n at least.
    sin,cos = a.sincos(n)
    Computation may return bad results unless |a|<2*3.1415..... -
  • exp

  • +
    +
  • exp
  • c = a.exp(n)
    computes the base of natural logarithm value(e=2.718281828....) powered by a with significant digit number n at least.
    -
  • power

  • +
    +
  • **
  • +c = a ** n
    +returns the value of a powered by n. +n must be an integer.
    + +
    +
  • power
  • +The same as ** method.
    c = a.power(n)
    returns the value of a powered by n(c=a**n). n must be an integer.
    -
  • zero?

  • -c = a.zero?
    -returns true if a is equal to 0,otherwise returns false
    - -
  • nonzero?

  • -c = a.nonzero?
    -returns false if a is 0,otherwise returns a itself.
    - -
  • <=>

  • +
    +
  • <=>
  • c = a <=> b
    returns 0 if a==b,1 if a > b,and returns -1 if a < b.
    +
Following methods need no explanation.
diff --git a/ext/bigdecimal/bigdecimal_ja.html b/ext/bigdecimal/bigdecimal_ja.html index efd4228d9a..56bebaa863 100644 --- a/ext/bigdecimal/bigdecimal_ja.html +++ b/ext/bigdecimal/bigdecimal_ja.html @@ -2,90 +2,30 @@ @@ -99,7 +39,6 @@ BigDecimal Ruby についての詳しい内容は以下のURLを参照してください。
@@ -160,8 +99,9 @@ c=a+b 例えば32ビットのシステムでは10進で4桁毎に計算します。従って、現状では、 内部の「有効桁数」は4の倍数となっています。 +

クラスメソッド

    -
  • new

  • +
  • new
  • 新しい BigDecimal オブジェクトを生成します。
    a=BigDecimal::new(s[,n])
    s は初期値を文字列で指定します. @@ -169,50 +109,151 @@ n n が 0 または省略されたときは、n の値は s の有効桁数とみなされます。 s の有効桁数より n が小さいときも n=0 のときと同じです。 a の最大有効桁数は n より若干大い値が採用されます。 -
  • +

  • +
    + +
  • mode
  • +BigDecimalの実行結果を制御します。以下の使用方法が定義されています。 +

    +[例外処理]

    +計算結果が非数(NaN)やゼロによる除算になったときの処理を定義することができます。 +

    +f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    +f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    +
    + +EXCEPTION_NaN は結果が NaN になったときの指定です。
    +EXCEPTION_INFINITY は結果が無限大(±Infinity)になったときの指定です。
    +EXCEPTION_UNDERFLOW は指数部がアンダーフローするときの指定です。
    +EXCEPTION_OVERFLOW は指数部がオーバーフローするときの指定です。
    +EXCEPTION_ZERODIVIDE はゼロによる割り算を実行したときの指定です。
    +EXCEPTION_ALL は、可能な全てに対して一括して設定するときに使用します。

    + +flag が true のときは、指定した状態になったときに例外を発行するようになります。
    +flag が false(デフォルト)なら、例外は発行されません。計算結果は以下のようになります。
    +
    +EXCEPTION_NaN のとき、非数(NaN)
    +EXCEPTION_INFINITY のとき、無限(+ or -Infinity)
    +EXCEPTION_UNDERFLOW のとき、ゼロ
    +EXCEPTION_OVERFLOW のとき、+Infinity か -Infinity
    +EXCEPTION_ZERODIVIDE のとき、+Infinity か -Infinity
    +
    +EXCEPTION_INFINITY、EXCEPTION_OVERFLOW、EXCEPTION_ZERODIVIDE +は今のところ同じです。
    +戻り値は、設定前の値です。「値」の意味は、例えば +BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば +EXCEPTION_NaNが設定されているという意味です。
    +引数に正しくないものが指定された場合は nil が返ります。 + +

    +[丸め処理指定]

    +計算途中の丸め操作の指定ができます。 +

    +f = BigDecimal::mode(BigDecimal::COMP_MODE,flag) +
    +の形式で指定します。
    +ここで、flag は以下の一つを指定します。 + + + + + + +
    COMP_MODE_TRUNCATE全て切り捨てます(truncate)。
    COMP_MODE_ROUNDUP四捨五入します(roundup、デフォルト)。
    COMP_MODE_CEIL数値の大きい方に繰り上げます(ceil)。
    COMP_MODE_FLOOR数値の小さい方に繰り下げます(floor)。
    COMP_MODE_EVEN四捨六入します。5の時は上位1桁が奇数の時のみ繰り上げます(Banker's rounding)。
    +戻り値は指定前の flag の値です。 +引数に正しくないものが指定された場合は nil が返ります。
    +mode メソッドでは丸め操作の位置をユーザが指定することはできません。 +丸め操作と位置を自分で制御したい場合は truncate/roundup/ceil/floor といった +インスタンスメソッドを使用して下さい。 +
    +
  • limit([n])
  • +生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。戻り値は +設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。 +nを指定しない場合は、現状の最大桁数が返ります。
    +mf = BigDecimal::limit(n)
    +
    +
  • double_fig
  • +Ruby の Float クラスが保持できる有効数字の数を返します。 +
    +  p BigDecimal::double_fig  # ==> 20 (depends on the CPU etc.)
    +
    +double_figは以下の C プログラムの結果と同じです。 +
    + double v          = 1.0;
    + int    double_fig = 0;
    + while(v + 1.0 > 1.0) {
    +    ++double_fig;
    +    v /= 10;
    + }
    +
    +
    + +
  • BASE
  • +内部で使用される基数の値です。整数が 32 ビットの処理系では10000です。
    +b = BigDecimal::BASE
    +
    + +
  • E
  • +自然対数の底e(=2.718281828....)を計算します(正直にテイラー展開で)。
    +e = BigDecimal::E(n)
    +nは必要な有効桁数を整数で指定します。 +
    +
  • PI
  • +円周率(=3.14159265358979....)を計算します(J.Machinの公式を用います)。
    +e = BigDecimal::PI(n)
    +n は必要な有効桁数を整数で指定します。 +
    +
+ +

インスタンスメソッド

+
    +
  • +
  • 加算(c = a + b)
    c の精度については「計算精度について」を参照してください。 -
  • -

  • +
    + +
  • -
  • 減算(c = a - b)、または符号反転(c = -a)
    c の精度については「計算精度について」を参照してください。 -
  • *

  • + +
    +
  • *
  • 乗算(c = a * b)
    cの精度は(aの精度)+(bの精度)程度です。
    詳しくは「計算精度について」を参照してください。 -
  • /

  • +
    +
  • /
  • 除算(c = a / b)
    c の精度については「計算精度について」を参照してください。 -
  • assign

  • -以下のように使用します。
    -c = a.assign(n,f)
    -f > 0 なら、a を c に、そのまま代入します。 -f < 0 なら、-a を c に代入します。 -f の絶対値(|f|)は1か2を指定してください。 -|f|=2 のときは、c の最大精度が a の実精度より小さいときには -丸められます。|f|=1 のときは切り捨てられます。 -n は c の有効桁数です(n 桁以上の精度を持つ c が生成されます)。 +
    -
  • add

  • +
  • add
  • 以下のように使用します。
    c = a.add(b,n)
    c = a + b を最大で n 桁まで計算します。 a + b の精度が n より大きいときは丸められます。 -
  • sub

  • +
    +
  • sub
  • 以下のように使用します。
    c = a.sub(b,n)
    c = a - b を最大で n 桁まで計算します。 a - b の精度が n より大きいときは丸められます。 -
  • mult

  • +
    +
  • mult
  • 以下のように使用します。
    c = a.mult(b,n)
    c = a * b を最大で n 桁まで計算します。 a * b の精度が n より大きいときは丸められます。 -
  • div

  • +
    +
  • div
  • 以下のように使用します。
    c,r = a.div(b,n)
    c=a/b の計算をします。 r には剰余が代入されます。a/bは @@ -220,63 +261,91 @@ c=a/b と異なり、c は整数とは限りません。 また、 c は丸められることはありません。 a = c*b + r の関係は成立します。 -
  • %

  • +
    +
  • %
  • r = a%b
    a/b の余りを計算します。以下の計算と同じものです。
    r = a-((a/b).floor)*b
    -
  • fix

  • +
    +
  • fix
  • a の小数点以下の切り捨て。
    c = a.fix -
  • frac

  • +
    +
  • frac
  • a の整数部分の切り捨て。
    c = a.frac -
  • floor

  • -a 以下の最大整数を表す値(BigDecimal 値)を返します。
    +
    + +
  • floor[(n)]
  • c = a.floor
    -以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます -(少数点以下を、最大 n 桁にします)。
    -c = BigDecimal("1.23456")
    -d = c.floor(4) # d = 1.2345 になります。
    - n が負のときは小数点以上 n 桁目を操作します。
    -c = BigDecimal("15.23456")
    -d = c.floor(-1) # d = 10.0 になります。
    +a 以下の最大整数(BigDecimal 値)を返します。 +
    
    +c = BigDecimal("1.23456").floor  #  ==> 1
    +c = BigDecimal("-1.23456").floor #  ==> -2
    +
    +以下のように引数 n を与えることもできます。
    +n>=0 なら、小数点以下 n+1 位の数字を操作します(少数点以下を、最大 n 桁にします)。
    +n が負のときは小数点以上 n 桁目を操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。
    +
    
    + c = BigDecimal::new("1.23456").floor(4)   #  ==> 1.2345
    + c = BigDecimal::new("15.23456").floor(-1) #  ==> 10.0
    +
    -
  • ceil

  • -a 以上の整数のうち、最も小さい整数を計算し、その値(BigDecimal 値)を返します。
    +
    +
  • ceil[(n)]
  • c = a.ceil
    -以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます -(少数点以下を、最大 n 桁にします)。
    -c = BigDecimal::new("1.23456")
    -d = c.ceil(4) # d = 1.2346 になります。
    - n が負のときは小数点以上 n 桁目をを操作します。
    -c = BigDecimal::new("15.23456")
    -d = c.ceil(-1) # d = 20.0 になります。
    +a 以上の整数のうち、最も小さい整数を計算し、その値(BigDecimal 値)を返します。 +
    
    +c = BigDecimal("1.23456").ceil  #  ==> 2
    +c = BigDecimal("-1.23456").ceil #  ==> -1
    +
    -
  • round

  • -小数点以下第一位の数を四捨五入して整数(BigDecimal 値)にします。
    +以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます。
    +n>=0 なら、小数点以下 n+1 位の数字を操作します(少数点以下を、最大 n 桁にします)。
    + n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。
    +
    
    + c = BigDecimal::new("1.23456").ceil(4)   # ==> 1.2346
    + c = BigDecimal::new("15.23456").ceil(-1) # ==> 20.0
    +
    + +
    +
  • round[(n[,b])]
  • c = a.round
    -以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます -(少数点以下を、最大 n 桁にします)。
    -n が正の時は、小数点以下 n+1 位の数字を四捨五入します。 -c = BigDecimal::new("1.23456")
    -d = c.round(4) # d = 1.235 になります。
    - n が負のときは小数点以上 n 桁目をを操作します。
    -c = BigDecimal::new("15.23456")
    -d = c.round(-1) # d = 20.0 になります。
    +小数点以下第一位の数を四捨五入して整数(BigDecimal 値)にします。
    +
    
    + c = BigDecimal("1.23456").round  #  ==> 1
    + c = BigDecimal("-1.23456").round #  ==> -1
    +
    -
  • truncate

  • -小数点以下の数を切り捨てて整数(BigDecimal 値)にします。
    +以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます。
    +n が正の時は、小数点以下 n+1 位の数字を四捨五入します(少数点以下を、最大 n 桁にします)。
    +n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。 +
    
    +c = BigDecimal::new("1.23456").round(4)   #  ==> 1.2346
    +c = BigDecimal::new("15.23456").round(-1) #  ==> 20.0
    +
    +2番目の引数(デフォルトは 0)にゼロ以外を指定すると、いわゆる Banker's rounding になります。
    + Banker's rounding とは、四捨五入する数字を p として、p < 5 なら切り捨て p > 5 なら切り上げ、 +p がちょうど5のときだけは切り上げ先の数字+1が偶数になるときだけ切り上げます。 +
    
    +c = BigDecimal::new("1.23456").round(3,1)   #  ==> 1.234
    +c = BigDecimal::new("1.23356").round(3,1)   #  ==> 1.234
    +
    + +
    +
  • truncate
  • c = a.truncate
    -以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます -(少数点以下を、最大 n 桁にします)。
    -n が正の時は、小数点以下 n+1 位の数字を切り捨てます。 -c = BigDecimal::new("1.23456")
    -d = c.truncate(4) # d = 1.2345 になります。
    - n が負のときは小数点以上 n 桁目をを操作します。
    -c = BigDecimal::new("15.23456")
    -d = c.truncate(-1) # d = 10.0 になります。
    +小数点以下の数を切り捨てて整数(BigDecimal 値)にします。
    +以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます。
    +n が正の時は、小数点以下 n+1 位の数字を切り捨てます(少数点以下を、最大 n 桁にします)。 +n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。
    +
    
    +c = BigDecimal::new("1.23456").truncate(4)   #  ==> 1.2345
    +c = BigDecimal::new("15.23456").truncate(-1) #  ==> 10.0
    +
    -
  • divmod

  • +
    +
  • divmod
  • 商と剰余の配列を返します。
    c,r = a.divmod(b) # a = c*b + r
    divmodメソッドは a = c * b + r となる a / b の浮動小数点型の商 c と剰余 r を @@ -284,85 +353,44 @@ divmod c = (a/b).floor
    r = a - c*b
    で計算されます。 -
  • remainder

  • +
    +
  • remainder
  • r=a.remainder(b)
    a/b の剰余 r を計算します。
    c = (a/b).fix
    r = a - c*b
    で計算されます。 -
  • abs

  • +
    +
  • abs
  • aの絶対値
    c = a.abs
    -
  • to_i

  • +
    +
  • to_i
  • 少数点以下を切り捨てて整数に変換します。
    i = a.to_i
    i は値に応じて Fixnum か Bignum になります。 a が Infinity や NaN のとき、i は nil になります。 -
  • to_f

  • +
    +
  • to_f
  • dup と全く同じです。 同じ値の BigDecimal オブジェクトを生成します。 -
  • to_s[(n)]

  • +
    +
  • to_s[(n)]
  • 文字列に変換します("0.xxxxxEn"の形になります)。
    s = a.to_s
    n が指定されたときは、仮数部分を n 桁毎に空白で区切ります。
    s = a.to_s(n) -
  • exponent

  • +
    +
  • exponent
  • 指数部を整数値で返します。 n = a.exponent
    は a の値が 0.xxxxxxx*10**n を意味します。 -
  • E

  • -自然対数の底e(=2.718281828....)を計算します(正直にテイラー展開で)。
    -e = BigDecimal::E(n)
    -nは必要な有効桁数を整数で指定します。 -
  • PI

  • -円周率(=3.14159265358979....)を計算します(J.Machinの公式を用います)。
    -e = BigDecimal::PI(n)
    -n は必要な有効桁数を整数で指定します。 -
  • BASE

  • -内部で使用される基数の値です。整数が 32 ビットの処理系では10000です。
    -b = BigDecimal::BASE
    -
  • mode

  • -BigDecimalの実行結果を制御します。以下の使用方法が定義されています。
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)
    -f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)
    +
    -EXCEPTION_NaN は結果が NaN になったときの指定です。 -EXCEPTION_INFINITY は結果が無限大(±Infinity) -になったときの指定です。 -EXCEPTION_UNDERFLOW は指数部がアンダーフローするときの指定です。 -EXCEPTION_OVERFLOW は指数部がオーバーフローするときの指定です。 -EXCEPTION_ZERODIVIDE はゼロによる割り算を実行したときの指定です。 -EXCEPTION_ALL は、可能な全てに対して一括して設定するときに -使用します。 -flag が true のときは、指定した状態になったときに例外を発行 -するようになります。 -flag が false(デフォルト)なら、例外は発行されません。計算結果は -以下のようになります。
    -EXCEPTION_NaN のとき、非数(NaN)
    -EXCEPTION_INFINITY のとき、無限(+ or -Infinity)
    -EXCEPTION_UNDERFLOW のとき、ゼロ
    -EXCEPTION_OVERFLOW のとき、+Infinity か -Infinity
    -EXCEPTION_ZERODIVIDE のとき、+Infinity か -Infinity
    -EXCEPTION_INFINITY、EXCEPTION_OVERFLOW、EXCEPTION_ZERODIVIDE -は今のところ同じです。
    -戻り値は、設定後の値です。「値」の意味は、例えば -BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば -EXCEPTION_NaNが設定されているという意味です。 -flag が nil、または、true と false 以外なら現在の設定値が返ります。 - -
  • limit([n])

  • -生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。戻り値は -設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。 -nを指定しない場合は、現状の最大桁数が返ります。
    -mf = BigDecimal::limit(n)
    -
  • sign

  • +
  • sign
  • 値の属性を返します。 n = a.sign
    としたとき n の値は a が以下のときを意味します。
    @@ -375,26 +403,40 @@ n = BigDecimal::SIGN_NEGATIVE_FINITE(-2) : a n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a は+Infinity
    n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a は-Infinity
    -
  • nan?

  • +
    +
  • nan?
  • a.nan? は a がNaNのとき真を返します。 -
  • infinite?

  • -a.infinite? は a が+∞または-∞のとき真を返します。 -
  • finite?

  • +
    +
  • infinite?
  • +a.infinite? は a が+∞のとき 1 、-∞のときは -1、それ以外のときは nil を返します。 +
    +
  • finite?
  • a.finite? は a が∞または NaN でないとき真を返します。 +
    -
  • to_parts

  • +
  • zero?
  • +a が 0 なら true になります。
    +c = a.zero? +
    +
  • nonzero?
  • +a が 0 なら nil、0 以外なら a そのものが返ります。
    +c = a.nonzero? + +
    +
  • split
  • BigDecimal 値を 0.xxxxxxx*10**n と表現したときに、符号(NaNのときは 0、それ以外は+1か-1になります)、 仮数部分の文字列("xxxxxxx")と、基数(10)、更に指数 n を配列で 返します。
    -a=BigDecimal::new("3.14159265",10)
    -f,x,y,z = a.to_parts
    +a=BigDecimal::new("3.14159265")
    +f,x,y,z = a.split
    とすると、f=+1、x="314159265"、y=10、z=1になります。
    従って、
    s = "0."+x
    b = f*(s.to_f)*(y**z)
    で Float に変換することができます。 -
  • inspect

  • +
    +
  • inspect
  • デバッグ出力に使用されます。
    p a=BigDecimal::new("3.14",10)
    とすると、[0x112344:'0.314E1',4(12)]のように出力されます。 @@ -402,47 +444,54 @@ p a=BigDecimal::new("3.14",10)
    次の4は現在の有効桁数(表示より若干大きいことがあります)、 最後はオブジェクトが取り得る最大桁数になります。 -
  • dup

  • +
    +
  • dup
  • 同じ値の BigDecimal オブジェクトを生成します。 -
  • sqrt

  • +
    +
  • sqrt
  • aの有効桁 n 桁の平方根(n の平方根ではありません)。 これまた、正直にニュートン法で計算します。
    c = a.sqrt(n)
    -
  • sincos

  • +
    +
  • sincos
  • a の有効桁 n 桁の sin と cos を同時に(テイラー展開で)計算して、 sin と cos の配列を返します。 n は必要な有効桁数です( n の sin や cos を計算するわけではありません)。
    sin,cos = a.sincos(n)
    |a|<2*3.1415....でないと正しい答えを計算できないこともあります。 -
  • exp

  • +
    +
  • exp
  • 自然対数の底e(=2.718281828....)の a 乗を計算します。
    c = a.exp(n)
    n は必要な有効桁数です。 -
  • power

  • +
    +
  • **
  • a の n 乗を計算します。nは整数。
    +c = a ** n
    +結果として c の有効桁は a の n 倍以上になるので注意。 +
    +
  • power
  • +** と同じで、a の n 乗を計算します。nは整数。
    c = a.power(n)
    結果として c の有効桁は a の n 倍以上になるので注意。 -
  • zero?

  • -a が 0 なら true になります。
    -c = a.zero?
    -
  • nonzero?

  • -a が 0 なら false、0 以外なら a そのものが返ります。
    -c = a.nonzero?
    -
  • <=>

  • +
    + +
  • <=>
  • a==b なら 0、a > b なら 1、a < b なら -1 になります。
    -c = a <=> b
    +c = a <=> b +
後は、読んで字の如くです。
    -
  • ==
  • -
  • ===
  • +
  • ==
  • +
  • ===
  • 「==」と同じですが case 文で使用されます。 -
  • !=
  • -
  • <
  • -
  • <=
  • -
  • >
  • -
  • >=
  • +
  • !=
  • +
  • <
  • +
  • <=
  • +
  • >
  • +
  • >=

coerceについて

BigDecimal オブジェクトが算術演算子の左にあるときは、BigDecimal オブジェクトが