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

1.From Tadashi Saito's advice

to_parts changed to split,assign removed, ** added,bugs in infinite? & nozero? fixed.
2.Rounding functionalities added
  mode now accepts rounding mode.
  round accepts second argument for Bankers' rounding.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4008 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shigek 2003-06-27 04:38:57 +00:00
parent 7e91b4b546
commit d3ce235bab
4 changed files with 735 additions and 609 deletions

View file

@ -34,14 +34,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef NT
#include <malloc.h>
#ifdef _MSC_VER
#include <float.h>
#define isnan(x) _isnan(x)
#define isinf(x) (!(_finite(x)))
#endif /* _MSC_VER */
#endif /* defined NT */
#include "ruby.h" #include "ruby.h"
#include "math.h" #include "math.h"
#include "version.h" #include "version.h"
@ -52,7 +44,7 @@ VALUE rb_cBigDecimal;
#include "bigdecimal.h" #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 ENTER(n) volatile VALUE vStack[n];int iStack=0
#define PUSH(x) vStack[iStack++] = (unsigned long)(x); #define PUSH(x) vStack[iStack++] = (unsigned long)(x);
#define SAVE(p) PUSH(p->obj); #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 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 int VpNmlz(Real *a);
static void VpFormatSt(char *psz,S_INT fFmt); 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); static U_LONG SkipWhiteChar(char *szVal);
/* /*
@ -297,25 +291,32 @@ BigDecimal_load(VALUE self, VALUE str)
static VALUE static VALUE
BigDecimal_mode(VALUE self, VALUE which, VALUE val) BigDecimal_mode(VALUE self, VALUE which, VALUE val)
{ {
unsigned short fo = VpGetException(); unsigned long f,fo;
unsigned short f;
if(TYPE(which)!=T_FIXNUM) return Qnil;
f = (unsigned long)FIX2INT(which);
if(TYPE(which)!=T_FIXNUM) return INT2FIX(fo); if(f&VP_EXCEPTION_ALL) {
if(val!=Qfalse && val!=Qtrue) return INT2FIX(fo); /* Exception mode setting */
f = (unsigned short)FIX2INT(which);
if(f&VP_EXCEPTION_INFINITY) {
fo = VpGetException(); fo = VpGetException();
VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY): if(val!=Qfalse && val!=Qtrue) return Qnil;
(fo&(~VP_EXCEPTION_INFINITY)))); 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) { if(VP_COMP_MODE==f) {
fo = VpGetException(); /* Computaion mode setting */
VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN): if(TYPE(val)!=T_FIXNUM) return Qnil;
(fo&(~VP_EXCEPTION_NaN)))); fo = VpSetCompMode((unsigned long)FIX2INT(val));
return INT2FIX(fo);
} }
fo = VpGetException(); return Qnil;
return INT2FIX(fo);
} }
static U_LONG static U_LONG
@ -380,8 +381,9 @@ static VALUE
BigDecimal_IsInfinite(VALUE self) BigDecimal_IsInfinite(VALUE self)
{ {
Real *p = GetVpValue(self,1); Real *p = GetVpValue(self,1);
if(VpIsInf(p)) return Qtrue; if(VpIsPosInf(p)) return INT2FIX(1);
return Qfalse; if(VpIsNegInf(p)) return INT2FIX(-1);
return Qnil;
} }
static VALUE static VALUE
@ -547,7 +549,7 @@ static VALUE
BigDecimal_nonzero(VALUE self) BigDecimal_nonzero(VALUE self)
{ {
Real *a = GetVpValue(self,1); Real *a = GetVpValue(self,1);
return VpIsZero(a) ? Qfalse : self; return VpIsZero(a) ? Qnil : self;
} }
static VALUE static VALUE
@ -650,6 +652,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 */
{ {
ENTER(5); ENTER(5);
Real *a, *b; Real *a, *b;
@ -669,16 +672,19 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
static VALUE static VALUE
BigDecimal_div(VALUE self, VALUE r) BigDecimal_div(VALUE self, VALUE r)
/* For c = self/r: with round operation */
{ {
ENTER(5); ENTER(5);
Real *c=NULL, *res=NULL, *div = NULL; Real *c=NULL, *res=NULL, *div = NULL;
r = BigDecimal_divide(&c, &res, &div, self, r); r = BigDecimal_divide(&c, &res, &div, self, r);
SAVE(c);SAVE(res);SAVE(div); SAVE(c);SAVE(res);SAVE(div);
if(r!=(VALUE)0) return r; /* coerced by other */ if(r!=(VALUE)0) return r; /* coerced by other */
if(res->frac[0]*2>=div->frac[0]) { /* a/b = c + r/b */
/* Round up */ /* c xxxxx
VpRdup(c); 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); return ToValue(c);
} }
@ -707,7 +713,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
VpDivd(c, res, a, b); VpDivd(c, res, a, b);
mx = c->Prec *(VpBaseFig() + 1); mx = c->Prec *(VpBaseFig() + 1);
GUARD_OBJ(d,VpCreateRbObject(mx, "0")); GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
VpRound(d,c,1,3,0); VpActiveRound(d,c,VP_COMP_MODE_FLOOR,0);
VpMult(res,d,b); VpMult(res,d,b);
VpAddSub(c,a,res,-1); VpAddSub(c,a,res,-1);
*div = d; *div = d;
@ -754,7 +760,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
GUARD_OBJ(d,VpCreateRbObject(mx, "0")); GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
GUARD_OBJ(f,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); VpFrac(f, c);
VpMult(rr,f,b); VpMult(rr,f,b);
@ -813,20 +819,6 @@ BigDecimal_divmod2(VALUE self, VALUE b, VALUE n)
return obj; 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 static VALUE
BigDecimal_add2(VALUE self, VALUE b, VALUE n) BigDecimal_add2(VALUE self, VALUE b, VALUE n)
{ {
@ -928,7 +920,7 @@ BigDecimal_fix(VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); 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); return ToValue(c);
} }
@ -941,19 +933,29 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
int sw; int sw;
U_LONG mx; U_LONG mx;
VALUE vLoc; VALUE vLoc;
VALUE vBanker;
if(rb_scan_args(argc,argv,"01",&vLoc)==0) { int na = rb_scan_args(argc,argv,"02",&vLoc,&vBanker);
sw = VP_COMP_MODE_ROUNDUP; /* round up */
switch(na) {
case 0:
iLoc = 0; iLoc = 0;
} else { break;
case 1:
Check_Type(vLoc, T_FIXNUM); Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc); 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)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpRound(c,a,sw,1,iLoc); VpActiveRound(c,a,sw,iLoc);
return ToValue(c); return ToValue(c);
} }
@ -973,12 +975,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
Check_Type(vLoc, T_FIXNUM); Check_Type(vLoc, T_FIXNUM);
iLoc = FIX2INT(vLoc); iLoc = FIX2INT(vLoc);
} }
sw = 1; /* truncate */
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); 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); return ToValue(c);
} }
@ -1015,7 +1016,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpRound(c,a,1,3,iLoc); VpActiveRound(c,a,VP_COMP_MODE_FLOOR,iLoc);
return ToValue(c); return ToValue(c);
} }
@ -1038,7 +1039,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(a,GetVpValue(self,1)); GUARD_OBJ(a,GetVpValue(self,1));
mx = a->Prec *(VpBaseFig() + 1); mx = a->Prec *(VpBaseFig() + 1);
GUARD_OBJ(c,VpCreateRbObject(mx, "0")); GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
VpRound(c,a,1,2,iLoc); VpActiveRound(c,a,VP_COMP_MODE_CEIL,iLoc);
return ToValue(c); return ToValue(c);
} }
@ -1064,7 +1065,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
} }
static VALUE static VALUE
BigDecimal_to_parts(VALUE self) BigDecimal_split(VALUE self)
{ {
ENTER(5); ENTER(5);
Real *vp; 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, "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);
/* Constants */ /* Constants definition */
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal())); 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_ALL",INT2FIX(VP_EXCEPTION_ALL));
rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN)); rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));
rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY)); 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_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE)); 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 */ /* Constants for sign value */
rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN)); rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO)); rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO));
@ -1386,7 +1397,6 @@ Init_bigdecimal(void)
/* instance methods */ /* instance methods */
rb_define_method(rb_cBigDecimal, "prec", BigDecimal_prec, 0); 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, "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);
@ -1394,7 +1404,7 @@ Init_bigdecimal(void)
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);
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_add, 1);
rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1); rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0); 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, "floor", BigDecimal_floor, -1);
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1); rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 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, "exp", BigDecimal_exp, 1);
rb_define_method(rb_cBigDecimal, "sincos", BigDecimal_sincos, 1); rb_define_method(rb_cBigDecimal, "sincos", BigDecimal_sincos, 1);
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1); rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
@ -1462,6 +1473,8 @@ static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
#endif /* _DEBUG */ #endif /* _DEBUG */
static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */ 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_FIG = 4; /* =log10(BASE) */
static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */ static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */
/* The value of BASE**2 + BASE must be represented */ /* The value of BASE**2 + BASE must be represented */
@ -1544,6 +1557,22 @@ VpSetPrecLimit(U_LONG n)
return s; 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 * 0.0 & 1.0 generator
* These gZero_..... and gOne_..... can be any name * 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 * (to let the compiler know they may be changed in outside
* (... but not actually..)). * (... but not actually..)).
*/ */
double gZero_ABCED9B1_CE73__00400511F31D = 0.0; volatile double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
double gOne_ABCED9B4_CE73__00400511F31D = 1.0; volatile double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
static double static double
Zero(void) Zero(void)
{ {
@ -1969,10 +1998,10 @@ VpAlloc(U_LONG mx, char *szVal)
++i; ++i;
++ni; ++ni;
} }
nf = 0; nf = 0;
ipf = 0; ipf = 0;
ipe = 0; ipe = 0;
ne = 0; ne = 0;
if(v) { if(v) {
/* other than digit nor \0 */ /* other than digit nor \0 */
if(szVal[i] == '.') { /* xxx. */ if(szVal[i] == '.') { /* xxx. */
@ -2023,11 +2052,10 @@ VpAlloc(U_LONG mx, char *szVal)
* [Input] * [Input]
* a ... RHSV * a ... RHSV
* isw ... switch for assignment. * isw ... switch for assignment.
* c = a when isw = 1 or 2 * c = a when isw > 0
* c = -a when isw = -1 or -1 * c = -a when isw < 0
* when |isw|==1 * if c->MaxPrec < a->Prec,then round operation
* if c->MaxPrec < a->Prec,then round up * will be performed.
* will not be performed.
* [Output] * [Output]
* c ... LHSV * c ... LHSV
*/ */
@ -2051,22 +2079,19 @@ VpAsgn(Real *c, Real *a, int isw)
n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec); n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec);
c->Prec = n; c->Prec = n;
for(j=0;j < n; ++j) c->frac[j] = a->frac[j]; for(j=0;j < n; ++j) c->frac[j] = a->frac[j];
if(isw < 0) isw = -isw; /* Needs round ? */
if(isw == 2) { if(c->Prec < a->Prec) {
if(a->MaxPrec>n) { VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
if((c->Prec < a->Prec) &&
(a->frac[n] >= HALF_BASE)) VpRdup(c); /* round up/off */
}
} }
} else { } else {
/* The value of 'a' is zero. */ /* The value of 'a' is zero. */
VpSetZero(c,isw*VpGetSign(a)); VpSetZero(c,isw*VpGetSign(a));
return 1; return 1;
} }
VpNmlz(c);
return c->Prec*BASE_FIG; return c->Prec*BASE_FIG;
} }
/* /*
* c = a + b when operation = 1 or 2 * c = a + b when operation = 1 or 2
* = 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; if(operation < 0) sw = -1;
else sw = 1; else sw = 1;
/* compare absolute value. As a result,|a_ptr|>=|b_ptr| */ /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
if(a->exponent > b->exponent) { if(a->exponent > b->exponent) {
@ -2202,7 +2227,6 @@ static int
VpAddAbs(Real *a, Real *b, Real *c) VpAddAbs(Real *a, Real *b, Real *c)
{ {
U_LONG word_shift; U_LONG word_shift;
U_LONG round;
U_LONG carry; U_LONG carry;
U_LONG ap; U_LONG ap;
U_LONG bp; U_LONG bp;
@ -2210,7 +2234,7 @@ VpAddAbs(Real *a, Real *b, Real *c)
U_LONG a_pos; U_LONG a_pos;
U_LONG b_pos; U_LONG b_pos;
U_LONG c_pos; U_LONG c_pos;
U_LONG av, bv; U_LONG av, bv, mrv;
#ifdef _DEBUG #ifdef _DEBUG
if(gfDebug) { if(gfDebug) {
@ -2226,7 +2250,7 @@ VpAddAbs(Real *a, Real *b, Real *c)
if(word_shift==-1L) return 0; /* Overflow */ if(word_shift==-1L) return 0; /* Overflow */
if(b_pos == -1L) goto Assign_a; 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 */ /* Just assign the last few digits of b to c because a has no */
/* corresponding digits to be added. */ /* 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(c_pos) c->frac[c_pos - 1] += carry;
if(round) VpRdup(c); /* Roundup and normalize. */ if(!VpInternalRound(c,0,(c->Prec>0)?a->frac[c->Prec-1]:0,mrv)) VpNmlz(c);
else VpNmlz(c); /* normalize the result */
goto Exit; goto Exit;
Assign_a: Assign_a:
@ -2305,7 +2328,7 @@ static int
VpSubAbs(Real *a, Real *b, Real *c) VpSubAbs(Real *a, Real *b, Real *c)
{ {
U_LONG word_shift; U_LONG word_shift;
U_LONG round; U_LONG mrv;
U_LONG borrow; U_LONG borrow;
U_LONG ap; U_LONG ap;
U_LONG bp; U_LONG bp;
@ -2330,10 +2353,10 @@ VpSubAbs(Real *a, Real *b, Real *c)
if(b_pos == -1L) goto Assign_a; if(b_pos == -1L) goto Assign_a;
if(av >= bv) { if(av >= bv) {
round =((av -= bv) >= HALF_BASE) ? 1 : 0; mrv = av - bv;
borrow = 0; borrow = 0;
} else { } else {
round = 0; mrv = 0;
borrow = 1; borrow = 1;
} }
@ -2395,8 +2418,8 @@ VpSubAbs(Real *a, Real *b, Real *c)
} }
} }
if(c_pos) c->frac[c_pos - 1] -= borrow; 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; goto Exit;
Assign_a: 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 * a = xxxxxxAxxx
* c = xxxxxx * c = xxxxxx
* a_pos = | * a_pos = |
*/ */
*a_pos = left_word; *a_pos = left_word;
*av = a->frac[*a_pos]; /* av is 'A' shown in above. */ *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 */ 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)); VpAsgn(c, b, VpGetSign(a));
goto Exit; goto Exit;
} }
if((b->Prec == 1) &&(b->frac[0] == 1) &&(b->exponent == 1)) { if(VpIsOne(b)) {
VpAsgn(c, a, VpGetSign(b)); VpAsgn(c, a, VpGetSign(b));
goto Exit; goto Exit;
} }
@ -2624,7 +2647,7 @@ VpMult(Real *c, Real *a, Real *b)
VpNmlz(c); /* normalize the result */ VpNmlz(c); /* normalize the result */
if(w != NULL) { /* free work variable */ if(w != NULL) { /* free work variable */
VpAsgn(w, c, 2); VpAsgn(w, c, 1);
VpFree(c); VpFree(c);
c = w; c = w;
} }
@ -2675,8 +2698,7 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
VpSetZero(r,VpGetSign(a)*VpGetSign(b)); VpSetZero(r,VpGetSign(a)*VpGetSign(b));
goto Exit; goto Exit;
} }
if(VpIsOne(b)) {
if((b->Prec == 1) &&(b->frac[0] == 1) &&(b->exponent == 1)) {
/* divide by one */ /* divide by one */
VpAsgn(c, a, VpGetSign(b)); VpAsgn(c, a, VpGetSign(b));
VpSetZero(r,VpGetSign(a)); VpSetZero(r,VpGetSign(a));
@ -2980,6 +3002,7 @@ Exit:
return (int)val; return (int)val;
} }
#ifdef _DEBUG
/* /*
* cntl_chr ... ASCIIZ Character, print control characters * cntl_chr ... ASCIIZ Character, print control characters
* Available control codes: * Available control codes:
@ -3082,6 +3105,7 @@ VPrint(FILE *fp, char *cntl_chr, Real *a)
} }
return (int)nc; return (int)nc;
} }
#endif /* _DEBUG */
static void static void
VpFormatSt(char *psz,S_INT fFmt) VpFormatSt(char *psz,S_INT fFmt)
@ -3468,8 +3492,9 @@ VpDtoV(Real *m, double d)
} }
m->Prec = ind_m + 1; m->Prec = ind_m + 1;
m->exponent = ne; 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: Exit:
#ifdef _DEBUG #ifdef _DEBUG
@ -3551,8 +3576,8 @@ VpSqrt(Real *y, Real *x)
Real *f = NULL; Real *f = NULL;
Real *r = NULL; Real *r = NULL;
S_LONG y_prec, f_prec; S_LONG y_prec, f_prec;
S_LONG n; S_LONG n;
S_LONG e; S_LONG e;
S_LONG prec; S_LONG prec;
S_LONG nr; S_LONG nr;
double val; 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 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; int n,i,j,ix,ioffset;
U_LONG v; U_LONG v;
@ -3665,35 +3691,41 @@ VpRound(Real *y, Real *x, int sw, int f, int nf)
goto Exit; goto Exit;
} }
/* First,assign whole value */ /* First,assign whole value in truncation mode */
VpAsgn(y, x, sw); 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))/((int)BASE_FIG)-1;
if(ix<0 || ((U_LONG)ix)>=y->Prec) goto Exit; /* Unable to round */ if(ix<0 || ((U_LONG)ix)>=y->Prec) goto Exit; /* Unable to round */
ioffset = nf - ix*((int)BASE_FIG); ioffset = nf - ix*((int)BASE_FIG);
for(j=ix+1;j<(int)y->Prec;++j) y->frac[j] = 0; for(j=ix+1;j<(int)y->Prec;++j) y->frac[j] = 0;
VpNmlz(y); /* VpNmlz(y); */
v = y->frac[ix]; v = y->frac[ix];
/* drop digits after pointed digit */ /* drop digits after pointed digit */
n = BASE_FIG - ioffset - 1; n = BASE_FIG - ioffset - 1;
for(i=0;i<n;++i) v /= 10; for(i=0;i<n;++i) v /= 10;
div = v/10; div = v/10;
v = v - div*10; v = v - div*10;
switch(f){ switch(f) {
case 1: /* Round */ case VP_COMP_MODE_TRUNCATE: /* Truncate/Round off */
if(sw==2 && v>=5) { break;
++div; case VP_COMP_MODE_ROUNDUP: /* Round up */
} if(v>=5) ++div;
break; break;
case 2: /* ceil */ case VP_COMP_MODE_CEIL: /* ceil */
if(v) { if(v && (VpGetSign(x)>0)) ++div;
if(VpGetSign(x)>0) ++div;
}
break; break;
case 3: /* floor */ case VP_COMP_MODE_FLOOR: /* floor */
if(v) { if(v && (VpGetSign(x)<0)) ++div;
if(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; break;
} }
@ -3702,7 +3734,7 @@ VpRound(Real *y, Real *x, int sw, int f, int nf)
y->frac[ix] = 0; y->frac[ix] = 0;
if(ix) { if(ix) {
VpNmlz(y); VpNmlz(y);
VpRdup(y); VpRdup(y,0);
} else { } else {
VpSetOne(y); VpSetOne(y);
VpSetSign(y,VpGetSign(x)); VpSetSign(y,VpGetSign(x));
@ -3715,24 +3747,51 @@ VpRound(Real *y, Real *x, int sw, int f, int nf)
Exit: Exit:
#ifdef _DEBUG #ifdef _DEBUG
if(gfDebug) { if(gfDebug) {
VPrint(stdout, "VpRound y=%\n", y); VPrint(stdout, "VpActiveRound y=%\n", y);
VPrint(stdout, " x=%\n", x); VPrint(stdout, " x=%\n", x);
} }
#endif /*_DEBUG */ #endif /*_DEBUG */
return; 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). * Rounds up m(plus one to final digit of m).
*/ */
static int static int
VpRdup(Real *m) VpRdup(Real *m,U_LONG ind_m)
{ {
U_LONG ind_m, carry; U_LONG carry;
ind_m = m->Prec;
if(!ind_m) ind_m = m->Prec;
carry = 1; carry = 1;
while(carry > 0 && ind_m) { while(carry > 0 && (ind_m--)) {
--ind_m;
m->frac[ind_m] += carry; m->frac[ind_m] += carry;
if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE; if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
else carry = 0; else carry = 0;
@ -3907,8 +3966,8 @@ VpPi(Real *y)
VpAddSub(r, y, f, 1); /* r = y + f */ VpAddSub(r, y, f, 1); /* r = y + f */
VpAsgn(y, r, 1); /* y = r */ VpAsgn(y, r, 1); /* y = r */
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
if(VpIsZero(f)) break; if(VpIsZero(f)) break;
} while((f->exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) && } while((f->exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) &&
i1<nc i1<nc
@ -3926,8 +3985,8 @@ VpPi(Real *y)
VpAddSub(r, y, f, 1); /* r = y + f */ VpAddSub(r, y, f, 1); /* r = y + f */
VpAsgn(y, r, 1); /* y = r */ VpAsgn(y, r, 1); /* y = r */
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
if(VpIsZero(f)) break; if(VpIsZero(f)) break;
} while((f->exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) && } while((f->exponent > 0 || ((U_LONG)(-(f->exponent)) < y->MaxPrec)) &&
i2<nc i2<nc
@ -3972,11 +4031,11 @@ VpExp1(Real *y)
add = VpAlloc(p, "#1"); /* add = 1 */ add = VpAlloc(p, "#1"); /* add = 1 */
VpSetOne(y); /* y = 1 */ VpSetOne(y); /* y = 1 */
VpRdup(y); /* y = y + 1 */ VpRdup(y,0); /* y = y + 1 */
i = 0; i = 0;
do { do {
++i; ++i;
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
VpDivd(f, r, add, n); /* f = add/n(=1/n!) */ VpDivd(f, r, add, n); /* f = add/n(=1/n!) */
VpAsgn(add, f, 1); /* add = 1/n! */ VpAsgn(add, f, 1); /* add = 1/n! */
VpAddSub(r, y, f, 1); VpAddSub(r, y, f, 1);
@ -4041,7 +4100,7 @@ VpExp(Real *y, Real *x)
i = 0; i = 0;
do { do {
++i; ++i;
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
VpDivd(div, r, x, n); /* div = x/n */ VpDivd(div, r, x, n); /* div = x/n */
VpMult(c, z, div); /* c = x/(n-1)! * x/n */ VpMult(c, z, div); /* c = x/(n-1)! * x/n */
VpAsgn(z, c, 1); /* z = x*n/n! */ VpAsgn(z, c, 1); /* z = x*n/n! */
@ -4117,7 +4176,7 @@ VpSinCos(Real *psin,Real *pcos,Real *x)
i = 0; i = 0;
do { do {
++i; ++i;
VpRdup(n); /* n = n + 1 */ VpRdup(n,0); /* n = n + 1 */
VpDivd(div, r, x, n); /* div = x/n */ VpDivd(div, r, x, n); /* div = x/n */
VpMult(c, z, div); /* c = x/(n-1)! * x/n */ VpMult(c, z, div); /* c = x/(n-1)! * x/n */
VpAsgn(z, c, 1); /* z = x*n/n! */ VpAsgn(z, c, 1); /* z = x*n/n! */

View file

@ -32,7 +32,7 @@ extern "C" {
#define S_INT int #define S_INT int
/* Exception codes */ /* Exception codes */
#define VP_EXCEPTION_ALL ((unsigned short)0xFFFF) #define VP_EXCEPTION_ALL ((unsigned short)0x00FF)
#define VP_EXCEPTION_INFINITY ((unsigned short)0x0001) #define VP_EXCEPTION_INFINITY ((unsigned short)0x0001)
#define VP_EXCEPTION_NaN ((unsigned short)0x0002) #define VP_EXCEPTION_NaN ((unsigned short)0x0002)
#define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004) #define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004)
@ -43,6 +43,14 @@ extern "C" {
#define VP_EXCEPTION_OP ((unsigned short)0x0020) #define VP_EXCEPTION_OP ((unsigned short)0x0020)
#define VP_EXCEPTION_MEMORY ((unsigned short)0x0040) #define VP_EXCEPTION_MEMORY ((unsigned short)0x0040)
/* Computation mode */
#define VP_COMP_MODE ((unsigned short)0x0100)
#define VP_COMP_MODE_TRUNCATE 0
#define VP_COMP_MODE_ROUNDUP 1
#define VP_COMP_MODE_CEIL 2
#define VP_COMP_MODE_FLOOR 3
#define VP_COMP_MODE_EVEN 4
#define VP_SIGN_NaN 0 /* NaN */ #define VP_SIGN_NaN 0 /* NaN */
#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */ #define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
#define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */ #define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
@ -103,6 +111,10 @@ VP_EXPORT double VpGetDoubleNegZero(void);
VP_EXPORT U_LONG VpGetPrecLimit(void); VP_EXPORT U_LONG VpGetPrecLimit(void);
VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n); VP_EXPORT U_LONG VpSetPrecLimit(U_LONG n);
/* Computation mode */
VP_EXPORT unsigned long VpGetCompMode(void);
VP_EXPORT unsigned long VpSetCompMode(unsigned long n);
VP_EXPORT int VpException(unsigned short f,char *str,int always); VP_EXPORT int VpException(unsigned short f,char *str,int always);
VP_EXPORT int VpIsNegDoubleZero(double v); VP_EXPORT int VpIsNegDoubleZero(double v);
VP_EXPORT U_LONG VpNumOfChars(Real *vp); VP_EXPORT U_LONG VpNumOfChars(Real *vp);
@ -123,14 +135,13 @@ VP_EXPORT void VpVtoD(double *d,S_LONG *e,Real *m);
VP_EXPORT void VpDtoV(Real *m,double d); 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 VpRound(Real *y,Real *x,int sw,int f,int il); VP_EXPORT void VpActiveRound(Real *y,Real *x,int f,int il);
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);
VP_EXPORT void VpExp1(Real *y); VP_EXPORT void VpExp1(Real *y);
VP_EXPORT void VpExp(Real *y,Real *x); VP_EXPORT void VpExp(Real *y,Real *x);
VP_EXPORT void VpSinCos(Real *psin,Real *pcos,Real *x); VP_EXPORT void VpSinCos(Real *psin,Real *pcos,Real *x);
VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);
/* /*
* ------------------ * ------------------
@ -177,9 +188,11 @@ VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);
#define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE) #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 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))
#ifdef _DEBUG #ifdef _DEBUG
int VpVarCheck(Real * v); int VpVarCheck(Real * v);
VP_EXPORT int VPrint(FILE *fp,char *cntl_chr,Real *a);
#endif /* _DEBUG */ #endif /* _DEBUG */
#if defined(__cplusplus) #if defined(__cplusplus)

View file

@ -2,90 +2,27 @@
<HEAD> <HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html"> <META HTTP-EQUIV="Content-Type" CONTENT="text/html">
<style type="text/css"><!-- <style type="text/css"><!--
body { body { color: #3f0f0f; background: #fefeff; margin-left: 2em; margin-right: 2em;}
color: #3f0f0f; h1 { color: #ffffff; background-color: #3939AD; border-color: #FF00FF; width: 100%; border-style: solid;
background: #fefeff; border-top-width: 0.1em; border-bottom-width: 0.1em; border-right: none; border-left: none;
margin-left: 2em; margin-right: 2em; padding: 0.1em; font-weight: bold; font-size: 160%; text-align: center;}
} h2 { color: #00007f; background-color: #e7e7ff; border-color: #000094; width: 100%; border-style: solid; border-le ft: none; border-right: none; border-top-width: 0.1em; border-bottom-width: 0.1em; padding: 0.1em;
h1 { font-weight: bold; font-size: 110%;
color: #ffffff;
background-color: #3939AD;
border-color: #FF00FF;
width: 100%;
border-style: solid;
border-top-width: 0.1em;
border-bottom-width: 0.1em;
border-right: none;
border-left: none;
padding: 0.1em;
font-weight: bold;
font-size: 160%;
text-align: center;
}
h2 {
color: #00007f;
background-color: #e7e7ff;
border-color: #000094;
width: 100%;
border-style: solid;
border-left: none;
border-right: none;
border-top-width: 0.1em;
border-bottom-width: 0.1em;
padding: 0.1em;
font-weight: bold;
font-size: 110%;
}
h3 {
color: #00007f;
padding: 0.2em;
font-size: 110%;
}
h4, h5 {
color: #000000;
padding: 0.2em;
font-size: 100%;
}
table {
margin-top: 0.2em; margin-bottom: 0.2em;
margin-left: 2em; margin-right: 2em;
}
caption {
color: #7f0000;
font-weight: bold;
}
th {
background: #e7e7ff;
padding-left: 0.2em; padding-right: 0.2em;
}
td {
background: #f3f7ff;
padding-left: 0.2em; padding-right: 0.2em;
}
code {
color: #0000df;
}
dt {
margin-top: 0.2em;
}
li {
margin-top: 0.2em;
} }
h3 { color: #00007f; padding: 0.2em; font-size: 110%;}
h4, h5 { color: #000000; padding: 0.2em; font-size: 100%;}
table { margin-top: 0.2em; margin-bottom: 0.2em; margin-left: 2em; margin-right: 2em;}
caption { color: #7f0000; font-weight: bold;}
th { background: #e7e7ff; padding-left: 0.2em; padding-right: 0.2em;}
td { background: #f3f7ff; padding-left: 0.2em; padding-right: 0.2em;}
code { color: #0000df;}
dt { margin-top: 0.2em;}
li { margin-top: 0.2em;}
pre pre
{ { BACKGROUND-COLOR: #d0d0d0; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none;
BACKGROUND-COLOR: #d0d0d0; BORDER-RIGHT: medium none; BORDER-TOP: medium none; LINE-HEIGHT: 100%; MARGIN: 12px 12px 12px 12px;
BORDER-BOTTOM: medium none; PADDING-BOTTOM: 12px; PADDING-LEFT: 12px; PADDING-RIGHT: 12px; PADDING-TOP: 12px;
BORDER-LEFT: medium none; WHITE-SPACE: pre; WIDTH: 100%
BORDER-RIGHT: medium none;
BORDER-TOP: medium none;
LINE-HEIGHT: 100%;
MARGIN: 12px 12px 12px 12px;
PADDING-BOTTOM: 12px;
PADDING-LEFT: 12px;
PADDING-RIGHT: 12px;
PADDING-TOP: 12px;
WHITE-SPACE: pre;
WIDTH: 100%
} }
--></style> --></style>
@ -99,7 +36,6 @@ Using BigDecimal class, you can obtain any number of significant digits in compu
For the details about Ruby see:<BR> For the details about Ruby see:<BR>
<UL> <UL>
<LI><A HREF="http://www.ruby-lang.org/en/">http://www.ruby-lang.org/en/</A>:Official Ruby page(English).</LI> <LI><A HREF="http://www.ruby-lang.org/en/">http://www.ruby-lang.org/en/</A>:Official Ruby page(English).</LI>
<LI><A HREF="http://ruby.freak.ne.jp/">http://ruby.freak.ne.jp/</A>:Ruby informations(Japanese).</LI>
<LI><A HREF="http://kahori.com/ruby/ring/">http://kahori.com/ruby/ring/</A>:Mutually linked pages relating to Ruby(Japanese). <LI><A HREF="http://kahori.com/ruby/ring/">http://kahori.com/ruby/ring/</A>:Mutually linked pages relating to Ruby(Japanese).
</LI> </LI>
</UL> </UL>
@ -126,7 +62,7 @@ NOTE:<BR>
<A NAME="#INTRO"> <A NAME="#INTRO">
<H2>Introduction</H2> <H2>Introduction</H2>
Ruby already has builtin (variable length integer number) class Bignum. Using Bignum class,you can obtain 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. This is why I made variable length floating class BigDecimal.
Feel free to send any comments or bug reports to me. Feel free to send any comments or bug reports to me.
<A HREF="mailto:shigeo@tinyforest.gr.jp">shigeo@tinyforest.gr.jp</A> <A HREF="mailto:shigeo@tinyforest.gr.jp">shigeo@tinyforest.gr.jp</A>
@ -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. 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. This means the number of significant digits in BigDecimal is always a multiple of 4.
<H4><U>Class methods</U></H4>
<UL> <UL>
<LI><B>new</B></LI><BR> <LI><B>new</B></LI><BLOCKQUOTE>
"new" method creates a new BigDecimal object.<BR> "new" method creates a new BigDecimal object.<BR>
a=BigDecimal::new(s[,n])<BR> a=BigDecimal::new(s[,n])<BR>
where:<BR> 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.
</BLOCKQUOTE>
<LI><B>double_fig</B></LI><BR> <LI><B>mode</B></LI><BLOCKQUOTE>
mode method controls BigDecimal computation.Following usage are defined.<BR>
<P><B>[EXCEPTION control]</B><P>
Actions when computation results NaN or Infinity can be defined as follows.
<P>
<BLOCKQUOTE>
f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)<BR>
</BLOCKQUOTE>
EXCEPTION_NaN controls the execution when computation results to NaN.<BR>
EXCEPTION_INFINITY controls the execution when computation results to Infinity(<28>}Infinity).<BR>
EXCEPTION_UNDERFLOW controls the execution when computation underflows.<BR>
EXCEPTION_OVERFLOW controls the execution when computation overflows.<BR>
EXCEPTION_ZERODIVIDE controls the execution when zero-division occures.<BR>
EXCEPTION_ALL controls the execution for any exception defined occures.<BR>
If the flag is true,then the relating exception is thrown.<BR>
No exception is thrown when the flag is false(default) and computation
continues with the result:<BR>
<BLOCKQUOTE>
EXCEPTION_NaN results to NaN<BR>
EXCEPTION_INFINITY results to +Infinity or -Infinity<BR>
EXCEPTION_UNDERFLOW results to 0.<BR>
EXCEPTION_OVERFLOW results to +Infinity or -Infinity<BR>
EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity<BR>
</BLOCKQUOTE>
EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are
currently the same.<BR>
The return value of mode method is the previous value set.<BR>
nil is returned if any argument is wrong.<BR>
Suppose the return value of the mode method is f,then
f &amp; BigDecimal::EXCEPTION_NaN !=0 means EXCEPTION_NaN is set to on.
<P>
<B>[ROUND error control]</B><P>
Rounding operation can be controlled as:
<BLOCKQUOTE>
f = BigDecimal::mode(BigDecimal::COMP_MODE,flag)
</BLOCKQUOTE>
where flag must be one of:
<TABLE>
<TR><TD>COMP_MODE_TRUNCATE</TD><TD>truncate</TD></TR>
<TR><TD>COMP_MODE_ROUNDUP</TD><TD>roundup,default</TD></TR>
<TR><TD>COMP_MODE_CEIL</TD><TD>ceil</TD></TR>
<TR><TD>COMP_MODE_FLOOR</TD><TD>floor</TD></TR>
<TR><TD>COMP_MODE_EVEN</TD><TD>Banker's rounding</TD></TR>
</TABLE>
nil is returned if any argument is illegal.<BR>
The digit location for rounding operation can not be specified by mode method,
use truncate/roundup/ceil/floor 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. Returns maximum value before set.
Zero,the default value,means no upper limit.<BR>
mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE>
<LI><B>double_fig</B></LI><BLOCKQUOTE>
double_fig is a class method which returns the number of digits double_fig is a class method which returns the number of digits
the Float class can have. the Float class can have.
<CODE><PRE> <CODE><PRE>
@ -180,71 +180,71 @@ double_fig is:
v /= 10; v /= 10;
} }
</PRE></CODE> </PRE></CODE>
</BLOCKQUOTE>
<LI><B>prec</B></LI><BR> <LI><B>BASE</B></LI><BLOCKQUOTE>
r,m = a.prec<BR> Base value used in the BigDecimal calculation.
where r is the number of significant digits of a, On 32 bits integer system,the value of BASE is 10000.<BR>
m is the maximum number of significant digits a can hold.<br> b = BigDecimal::BASE<BR>
<CODE><PRE> </BLOCKQUOTE>
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]
</PRE></CODE>
r and m are always the multiple of log10(BigDecimal::BASE).
<LI><B>+</B></LI><BR> <LI><B>E</B></LI><BLOCKQUOTE>
e = BigDecimal::E(n)<BR>
where e(=2.718281828....) is the base value of natural logarithm.<BR>
n specifies the length of significant digits of e.
</BLOCKQUOTE>
<LI><B>PI</B></LI><BLOCKQUOTE>
e = BigDecimal::PI(n)<BR>
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.<BR>
</BLOCKQUOTE>
</UL>
<H4><U>Instance methods</U></H4>
<UL>
<LI><B>+</B></LI><BLOCKQUOTE>
addition(c = a + b)<BR> addition(c = a + b)<BR>
For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>. For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>.
<LI><B>-</B></LI><BR> </BLOCKQUOTE>
<LI><B>-</B></LI><BLOCKQUOTE>
subtraction (c = a - b) or negation (c = -a)<BR> subtraction (c = a - b) or negation (c = -a)<BR>
For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>. For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>.
<LI><B>*</B></LI><BR> </BLOCKQUOTE>
<LI><B>*</B></LI><BLOCKQUOTE>
multiplication(c = a * b)<BR> multiplication(c = a * b)<BR>
For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>. For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>.
<LI><B>/</B></LI><BR> </BLOCKQUOTE>
<LI><B>/</B></LI><BLOCKQUOTE>
division(c = a / b)<BR> division(c = a / b)<BR>
For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>. For the resulting number of significant digits of c,see <A HREF="#PREC">Resulting number of significant digits</A>.
</BLOCKQUOTE>
<LI><B>assign</B></LI><BR> <LI><B>add</B></LI><BLOCKQUOTE>
c = a.assign(n,f)<BR>
assigns the value of a to c.<BR>
n is the number of significant digits of resulting c.<BR>
If f > 0,then a is assigned to c.<BR>
If f < 0,then -a is assigned to c.<BR>
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.
<LI><B>add</B></LI><BR>
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.
<LI><B>sub</B></LI><BR> </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.
<LI><B>mult</B></LI><BR> </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.
<LI><B>div</B></LI><BR> </BLOCKQUOTE>
<LI><B>div</B></LI><BLOCKQUOTE>
c,r = a.div(b,n)<BR> c,r = a.div(b,n)<BR>
c,r = a.div(b,n) performs c = a / b, r is the residue of a / b. 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 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 c is never rounded,and the equation a = c*b + r is always
valid unless c is NaN or Infinity. valid unless c is NaN or Infinity.
<LI><B>%</B></LI><BR> </BLOCKQUOTE>
<LI><B>%</B></LI><BLOCKQUOTE>
r = a%b <BR> r = a%b <BR>
is the same as:<BR> is the same as:<BR>
r = a-((a/b).floor)*b<BR> r = a-((a/b).floor)*b<BR>
<LI><B>fix</B></LI><BR> </BLOCKQUOTE>
<LI><B>fix</B></LI><BLOCKQUOTE>
c = a.fix<BR> c = a.fix<BR>
returns integer part of a.<BR> returns integer part of a.<BR>
<LI><B>frac</B></LI><BR> </BLOCKQUOTE>
<LI><B>frac</B></LI><BLOCKQUOTE>
c = a.frac<BR> c = a.frac<BR>
returns fraction part of a.<BR> returns fraction part of a.<BR>
<LI><B>floor[(n)]</B></LI><BR> </BLOCKQUOTE>
<LI><B>floor[(n)]</B></LI><BLOCKQUOTE>
c = a.floor<BR> c = a.floor<BR>
returns the maximum integer value (in BigDecimal) which is less than or equal to a.<BR> returns the maximum integer value (in BigDecimal) which is less than or equal to a.
<PRE><CODE>
c = BigDecimal("1.23456").floor # ==> 1
c = BigDecimal("-1.23456").floor # ==> -2
</CODE></PRE>
As shown in the following example,an optional integer argument (n) specifying the position As shown in the following example,an optional integer argument (n) specifying the position
of 'floor'ed digit can be given. of the target digit can be given.<BR>
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+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).<BR>
If n<0,then the n-th digit counted from the decimal point in integer part is 'floor'ed.<BR> 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).
<PRE><CODE>
c = BigDecimal::new("1.23456").floor(4) # ==> 1.2345
c = BigDecimal::new("15.23456").floor(-1) # ==> 10.0
</CODE></PRE>
c = BigDecimal::new("1.23456")<BR> </BLOCKQUOTE>
d = c.floor(4) # d = 1.2345<BR> <LI><B>ceil[(n)]</B></LI><BLOCKQUOTE>
c = BigDecimal::new("15.23456")<BR>
d = c.floor(-1) # d = 10.0<BR>
<LI><B>ceil[(n)]</B></LI><BR>
c = a.ceil<BR> c = a.ceil<BR>
returns the minimum integer value (in BigDecimal) which is greater than or equal to a.<BR> returns the minimum integer value (in BigDecimal) which is greater than or equal to a.
<PRE><CODE>
c = BigDecimal("1.23456").ceil # ==> 2
c = BigDecimal("-1.23456").ceil # ==> -1
</CODE></PRE>
As shown in the following example,an optional integer argument (n) specifying the position As shown in the following example,an optional integer argument (n) specifying the position
of 'ceil'ed digit can be given. of the target digit can be given.<BR>
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+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).<BR>
If n<0,then the n-th digit counted from the decimal point in integer part is 'ceil'ed.<BR> 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).
<PRE><CODE>
c = BigDecimal::new("1.23456").ceil(4) # ==> 1.2346
c = BigDecimal::new("15.23456").ceil(-1) # ==> 20.0
</CODE></PRE>
c = BigDecimal::new("1.23456")<BR> </BLOCKQUOTE>
d = c.ceil(4) # d = 1.2346<BR> <LI><B>round[(n[,b])]</B></LI><BLOCKQUOTE>
c = BigDecimal::new("15.23456")<BR>
d = c.ceil(-1) # d = 20.0<BR>
<LI><B>round[(n)]</B></LI><BR>
c = a.round<BR> c = a.round<BR>
round off a to the nearest 1<>D<BR> round a to the nearest 1<>D<BR>
<PRE><CODE>
c = BigDecimal("1.23456").round # ==> 1
c = BigDecimal("-1.23456").round # ==> -1
</CODE></PRE>
As shown in the following example,an optional integer argument (n) specifying the position As shown in the following example,an optional integer argument (n) specifying the position
of rounded digit can be given. of the target digit can be given.<BR>
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+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).<BR>
If n<0,then the n-th digit counted from the decimal point in integer part is rounded.<BR> 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).
<PRE><CODE>
c = BigDecimal::new("1.23456").round(4) # ==> 1.2346
c = BigDecimal::new("15.23456").round(-1) # ==> 20.0
</CODE></PRE>
c = BigDecimal::new("1.23456")<BR> If the second optional argument b is given with the non-zero value(default is zero) then
d = c.round(4) # d = 1.235 <BR> so called Banker's rounding is performed.<BR>
c = BigDecimal::new("15.23456")<BR> Suppose the digit p is to be rounded,then:<BR>
d = c.round(-1) # d = 20.0<BR> If p<5 then p is truncated<BR>
If p>5 then p is rounded up<BR>
If p is 5 then round up operation is taken only when the left hand side digit of p is odd.
<PRE><CODE>
c = BigDecimal::new("1.23456").round(3,1) # ==> 1.234
c = BigDecimal::new("1.23356").round(3,1) # ==> 1.234
</CODE></PRE>
<LI><B>truncate[(n)]</B></LI><BR> </BLOCKQUOTE>
<LI><B>truncate[(n)]</B></LI><BLOCKQUOTE>
c = a.truncate<BR> c = a.truncate<BR>
truncate a to the nearest 1<>D<BR> truncate a to the nearest 1<>D<BR>
As shown in the following example,an optional integer argument (n) specifying the position As shown in the following example,an optional integer argument (n) specifying the position
of truncated digit can be given. of the target digit can be given.<BR>
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+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).<BR>
If n<0,then the n-th digit counted from the decimal point in integer part is truncated.<BR> 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")<BR> <PRE><CODE>
d = c.truncate(4) # d = 1.2345<BR> c = BigDecimal::new("1.23456").truncate(4) # ==> 1.2345
c = BigDecimal::new("15.23456")<BR> c = BigDecimal::new("15.23456").truncate(-1) # ==> 10.0
d = c.truncate(-1) # d = 10.0<BR> </CODE></PRE>
<LI><B>divmod</B></LI><BR> </BLOCKQUOTE>
<LI><B>divmod</B></LI><BLOCKQUOTE>
c,r = a.divmod(b) # a = c*b + r<BR> c,r = a.divmod(b) # a = c*b + r<BR>
returns the quotient and remainder of a/b.<BR> returns the quotient and remainder of a/b.<BR>
a = c * b + r is always satisfied.<BR> a = c * b + r is always satisfied.<BR>
where c is the integer sutisfying where c is the integer satisfying
c = (a/b).floor <BR> c = (a/b).floor <BR>
and,therefore and,therefore
r = a - c*b<BR> r = a - c*b<BR>
<LI><B>remainder</B></LI><BR> </BLOCKQUOTE>
<LI><B>remainder</B></LI><BLOCKQUOTE>
r=a.remainder(b)<BR> r=a.remainder(b)<BR>
returns the remainder of a/b.<BR> returns the remainder of a/b.<BR>
where c is the integer sutisfying where c is the integer satisfying
c = (a/b).fix <BR> c = (a/b).fix <BR>
and,therefore: and,therefore:
r = a - c*b<BR> r = a - c*b<BR>
<LI><B>abs</B></LI><BR> </BLOCKQUOTE>
<LI><B>abs</B></LI><BLOCKQUOTE>
c = a.abs<BR> c = a.abs<BR>
returns an absolute value of a.<BR> returns an absolute value of a.<BR>
<LI><B>to_i</B></LI><BR> </BLOCKQUOTE>
<LI><B>to_i</B></LI><BLOCKQUOTE>
changes a to an integer.<BR> changes a to an integer.<BR>
i = a.to_i<BR> i = a.to_i<BR>
i becomes to Fixnum or Bignum. 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.
<LI><B>to_s[(n)]</B></LI><BR> </BLOCKQUOTE>
<LI><B>to_s[(n)]</B></LI><BLOCKQUOTE>
converts to string(results look like "0.xxxxxEn").<BR> converts to string(results look like "0.xxxxxEn").<BR>
s = a.to_s<BR> s = a.to_s<BR>
If n is given,then a space is inserted after every n digits for readability.<BR> If n is given,then a space is inserted after every n digits for readability.<BR>
s = a.to_s(n) s = a.to_s(n)
<LI><B>exponent</B></LI><BR> </BLOCKQUOTE>
<LI><B>exponent</B></LI><BLOCKQUOTE>
returns an integer holding exponent value of a.<BR> returns an integer holding exponent value of a.<BR>
n = a.exponent <BR> n = a.exponent <BR>
means a = 0.xxxxxxx*10**n. means a = 0.xxxxxxx*10**n.
<LI><B>to_f</B></LI><BR> </BLOCKQUOTE>
<LI><B>to_f</B></LI><BLOCKQUOTE>
same as dup method. same as dup method.
creates a new BigDecimal object having same value. creates a new BigDecimal object having same value.
</BLOCKQUOTE>
<LI><B>E</B></LI><BR> </BLOCKQUOTE>
e = BigDecimal::E(n)<BR> <LI><B>sign</B></LI><BLOCKQUOTE>
where e(=2.718281828....) is the base value of natural logarithm.<BR> returns the 'attribute' of a.
n specifies the length of significant digits of e.
<LI><B>PI</B></LI><BR>
e = BigDecimal::PI(n)<BR>
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.<BR>
<LI><B>BASE</B></LI><BR>
Base value used in the BigDecimal calculation.
On 32 bit integer system,the value of BASE is 10000.<BR>
b = BigDecimal::BASE<BR>
<LI><B>mode</B></LI><BR>
mode method controls BigDecimal computation.
Following usage are defined.<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)<BR>
EXCEPTION_NaN controls the execution once computation results to NaN.
EXCEPTION_INFINITY controls the execution once computation results to Infinity(<28>}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:<BR>
EXCEPTION_NaN results to NaN<BR>
EXCEPTION_INFINITY results to +Infinity or -Infinity<BR>
EXCEPTION_UNDERFLOW results to 0.<BR>
EXCEPTION_OVERFLOW results to +Infinity or -Infinity<BR>
EXCEPTION_ZERODIVIDE results to +Infinity or -Infinity<BR>
EXCEPTION_INFINITY,EXCEPTION_OVERFLOW, and EXCEPTION_ZERODIVIDE are
currently the same.<BR>
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.
<LI><B>limit[(n)]</B></LI><BR>
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.<BR>
mf = BigDecimal::limit(n)<BR>
<LI><B>sign</B></LI><BR>
returns the 'attribute'.
n = a.sign <BR> n = a.sign <BR>
where the value of n means that a is:<BR> where the value of n means that a is:<BR>
n = BigDecimal::SIGN_NaN(0) : a is NaN<BR> n = BigDecimal::SIGN_NaN(0) : a is NaN<BR>
@ -427,28 +412,42 @@ n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a is +Infinity<BR>
n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a is -Infinity<BR> n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a is -Infinity<BR>
The value in () is the actual value,see (<A HREF="#STRUCT">Internal structure</A>.<BR> The value in () is the actual value,see (<A HREF="#STRUCT">Internal structure</A>.<BR>
<LI><B>nan?</B></LI><BR> </BLOCKQUOTE>
<LI><B>nan?</B></LI><BLOCKQUOTE>
a.nan? returns True when a is NaN. a.nan? returns True when a is NaN.
<LI><B>infinite?</B></LI><BR> </BLOCKQUOTE>
a.infinite? returns True when a is +<2B>‡ or -<2D>‡. <LI><B>infinite?</B></LI><BLOCKQUOTE>
a.infinite? returns 1 when a is +<2B>‡,-1 when a is -<2D>‡, nil otherwise.
<LI><B>finite?</B></LI><BR> </BLOCKQUOTE>
a.finite? returns True when a is neither <20>‡ nor NaN. <LI><B>finite?</B></LI><BLOCKQUOTE>
a.finite? returns true when a is neither <20>‡ nor NaN.
</BLOCKQUOTE>
<LI><B>to_parts</B></LI><BR> <LI><B>zero?</B></LI><BLOCKQUOTE>
c = a.zero?<BR>
returns true if a is equal to 0,otherwise returns false<BR>
</BLOCKQUOTE>
<LI><B>nonzero?</B></LI><BLOCKQUOTE>
c = a.nonzero?<BR>
returns nil if a is 0,otherwise returns a itself.<BR>
</BLOCKQUOTE>
<LI><B>split</B></LI><BLOCKQUOTE>
decomposes a BigDecimal value to 4 parts. decomposes a BigDecimal value to 4 parts.
All 4 parts are returned as an array.<BR> All 4 parts are returned as an array.<BR>
Parts consist of a sign(0 when the value is NaN,+1 for positive and 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. -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)<BR> a=BigDecimal::new("3.14159265")<BR>
f,x,y,z = a.to_parts<BR> f,x,y,z = a.split<BR>
where f=+1,x="314159265",y=10 and z=1<BR> where f=+1,x="314159265",y=10 and z=1<BR>
therefore,you can translate BigDecimal value to Float as:<BR> therefore,you can translate BigDecimal value to Float as:<BR>
s = "0."+x<BR> s = "0."+x<BR>
b = f*(s.to_f)*(y**z)<BR> b = f*(s.to_f)*(y**z)<BR>
<LI><B>inspect</B></LI><BR> </BLOCKQUOTE>
<LI><B>inspect</B></LI><BLOCKQUOTE>
is used for debugging output.<BR> is used for debugging output.<BR>
p a=BigDecimal::new("3.14",10)<BR> p a=BigDecimal::new("3.14",10)<BR>
should produce output like "#&lt;0x112344:'0.314E1',4(12)%gt;". should produce output like "#&lt;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 and 12 is the maximum number of the significant digits
the object can hold. the object can hold.
<LI><B>dup</B></LI><BR> </BLOCKQUOTE>
<LI><B>dup</B></LI><BLOCKQUOTE>
creates a new BigDecimal object having same value. creates a new BigDecimal object having same value.
<LI><B>sqrt</B></LI><BR> </BLOCKQUOTE>
<LI><B>sqrt</B></LI><BLOCKQUOTE>
c = a.sqrt(n)<BR> c = a.sqrt(n)<BR>
computes square root value of a with significant digit number n at least.<BR> computes square root value of a with significant digit number n at least.<BR>
<LI><B>sincos</B></LI><BR> </BLOCKQUOTE>
<LI><B>sincos</B></LI><BLOCKQUOTE>
computes and returns sine and cosine value of a with significant digit number n at least.<BR> computes and returns sine and cosine value of a with significant digit number n at least.<BR>
sin,cos = a.sincos(n)<BR> sin,cos = a.sincos(n)<BR>
Computation may return bad results unless |a|<2*3.1415..... Computation may return bad results unless |a|<2*3.1415.....
<LI><B>exp</B></LI><BR> </BLOCKQUOTE>
<LI><B>exp</B></LI><BLOCKQUOTE>
c = a.exp(n)<BR> c = a.exp(n)<BR>
computes the base of natural logarithm value(e=2.718281828....) powered by a computes the base of natural logarithm value(e=2.718281828....) powered by a
with significant digit number n at least.<BR> with significant digit number n at least.<BR>
<LI><B>power</B></LI><BR> </BLOCKQUOTE>
<LI><B>**</B></LI><BLOCKQUOTE>
c = a ** n<BR>
returns the value of a powered by n.
n must be an integer.<BR>
</BLOCKQUOTE>
<LI><B>power</B></LI><BLOCKQUOTE>
The same as ** method.<BR>
c = a.power(n)<BR> c = a.power(n)<BR>
returns the value of a powered by n(c=a**n). returns the value of a powered by n(c=a**n).
n must be an integer.<BR> n must be an integer.<BR>
<LI><B>zero?</B></LI><BR> </BLOCKQUOTE>
c = a.zero?<BR> <LI><B>&lt;=&gt;</B></LI><BLOCKQUOTE>
returns true if a is equal to 0,otherwise returns false<BR>
<LI><B>nonzero?</B></LI><BR>
c = a.nonzero?<BR>
returns false if a is 0,otherwise returns a itself.<BR>
<LI><B>&lt;=&gt;</B></LI><BR>
c = a &lt;=&gt; b <BR> c = a &lt;=&gt; b <BR>
returns 0 if a==b,1 if a &gt b,and returns -1 if a &lt b.<BR> returns 0 if a==b,1 if a &gt b,and returns -1 if a &lt b.<BR>
</BLOCKQUOTE>
</UL> </UL>
Following methods need no explanation.<BR> Following methods need no explanation.<BR>

View file

@ -2,90 +2,30 @@
<HEAD> <HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS"> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=Shift_JIS">
<style type="text/css"><!-- <style type="text/css"><!--
body { body { color: #3f0f0f; background: #fefeff; margin-left: 2em; margin-right: 2em;}
color: #3f0f0f; h1 { color: #ffffff; background-color: #3939AD; border-color: #FF00FF; width: 100%;
background: #fefeff; border-style: solid; border-top-width: 0.1em; border-bottom-width: 0.1em; border-right: none;
margin-left: 2em; margin-right: 2em; border-left: none; padding: 0.1em; font-weight: bold; font-size: 160%; text-align: center;
} }
h1 { h2 { color: #00007f; background-color: #e7e7ff; border-color: #000094; width: 100%;
color: #ffffff; border-style: solid; border-left: none; border-right: none; border-top-width: 0.1em; border-bottom-width: 0.1em;
background-color: #3939AD;
border-color: #FF00FF;
width: 100%;
border-style: solid;
border-top-width: 0.1em;
border-bottom-width: 0.1em;
border-right: none;
border-left: none;
padding: 0.1em; padding: 0.1em;
font-weight: bold; font-weight: bold; font-size: 110%;
font-size: 160%;
text-align: center;
}
h2 {
color: #00007f;
background-color: #e7e7ff;
border-color: #000094;
width: 100%;
border-style: solid;
border-left: none;
border-right: none;
border-top-width: 0.1em;
border-bottom-width: 0.1em;
padding: 0.1em;
font-weight: bold;
font-size: 110%;
}
h3 {
color: #00007f;
padding: 0.2em;
font-size: 110%;
}
h4, h5 {
color: #000000;
padding: 0.2em;
font-size: 100%;
}
table {
margin-top: 0.2em; margin-bottom: 0.2em;
margin-left: 2em; margin-right: 2em;
}
caption {
color: #7f0000;
font-weight: bold;
}
th {
background: #e7e7ff;
padding-left: 0.2em; padding-right: 0.2em;
}
td {
background: #f3f7ff;
padding-left: 0.2em; padding-right: 0.2em;
}
code {
color: #0000df;
}
dt {
margin-top: 0.2em;
}
li {
margin-top: 0.2em;
} }
h3 { color: #00007f; padding: 0.2em; font-size: 110%;}
h4, h5 { color: #000000; padding: 0.2em; font-size: 100%;}
table { margin-top: 0.2em; margin-bottom: 0.2em; margin-left: 2em; margin-right: 2em;}
caption { color: #7f0000; font-weight: bold;}
th { background: #e7e7ff; padding-left: 0.2em; padding-right: 0.2em;}
td { background: #f3f7ff; padding-left: 0.2em; padding-right: 0.2em;}
code { color: #0000df;}
dt { margin-top: 0.2em;}
li { margin-top: 0.2em;}
pre pre
{ { BACKGROUND-COLOR: #d0d0d0; BORDER-BOTTOM: medium none; BORDER-LEFT: medium none;
BACKGROUND-COLOR: #d0d0d0; BORDER-RIGHT: medium none; BORDER-TOP: medium none; LINE-HEIGHT: 100%; MARGIN: 12px 12px 12px 12px;
BORDER-BOTTOM: medium none; PADDING-BOTTOM: 12px; PADDING-LEFT: 12px; PADDING-RIGHT: 12px; PADDING-TOP: 12px;
BORDER-LEFT: medium none; WHITE-SPACE: pre; WIDTH: 100%
BORDER-RIGHT: medium none;
BORDER-TOP: medium none;
LINE-HEIGHT: 100%;
MARGIN: 12px 12px 12px 12px;
PADDING-BOTTOM: 12px;
PADDING-LEFT: 12px;
PADDING-RIGHT: 12px;
PADDING-TOP: 12px;
WHITE-SPACE: pre;
WIDTH: 100%
} }
--></style> --></style>
@ -99,7 +39,6 @@ BigDecimal
Ruby についての詳しい内容は以下のURLを参照してください。 Ruby についての詳しい内容は以下のURLを参照してください。
<UL> <UL>
<LI><A HREF="http://www.ruby-lang.org/ja/">http://www.ruby-lang.org/ja/</A>Ruby公式ページ</LI> <LI><A HREF="http://www.ruby-lang.org/ja/">http://www.ruby-lang.org/ja/</A>Ruby公式ページ</LI>
<LI><A HREF="http://ruby.freak.ne.jp/">http://ruby.freak.ne.jp/</A>Rubyに関する情報ページ</LI>
<LI><A HREF="http://kahori.com/ruby/ring/">http://kahori.com/ruby/ring/</A>Rubyに関するページを辿れます</LI> <LI><A HREF="http://kahori.com/ruby/ring/">http://kahori.com/ruby/ring/</A>Rubyに関するページを辿れます</LI>
</UL> </UL>
<hr> <hr>
@ -160,8 +99,9 @@ c=a+b
例えば32ビットのシステムでは10進で4桁毎に計算します。従って、現状では、 例えば32ビットのシステムでは10進で4桁毎に計算します。従って、現状では、
内部の「有効桁数」は4の倍数となっています。 内部の「有効桁数」は4の倍数となっています。
<H4><U>クラスメソッド</U></H4>
<UL> <UL>
<LI>new</LI><BR> <LI><B>new</B></LI><BLOCKQUOTE>
新しい BigDecimal オブジェクトを生成します。<BR> 新しい BigDecimal オブジェクトを生成します。<BR>
a=BigDecimal::new(s[,n])<BR> a=BigDecimal::new(s[,n])<BR>
s は初期値を文字列で指定します. s は初期値を文字列で指定します.
@ -169,50 +109,151 @@ n
n が 0 または省略されたときは、n の値は s の有効桁数とみなされます。 n が 0 または省略されたときは、n の値は s の有効桁数とみなされます。
s の有効桁数より n が小さいときも n=0 のときと同じです。 s の有効桁数より n が小さいときも n=0 のときと同じです。
a の最大有効桁数は n より若干大い値が採用されます。 a の最大有効桁数は n より若干大い値が採用されます。
<LI>+</LI><BR> </BLOCKQUOTE>
<LI><B>mode</B></LI><BLOCKQUOTE>
BigDecimalの実行結果を制御します。以下の使用方法が定義されています。
<P>
<B>[例外処理]</B><P>
計算結果が非数(NaN)やゼロによる除算になったときの処理を定義することができます。
<BLOCKQUOTE>
f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)<BR>
</BLOCKQUOTE>
EXCEPTION_NaN は結果が NaN になったときの指定です。<BR>
EXCEPTION_INFINITY は結果が無限大(±Infinity)になったときの指定です。<BR>
EXCEPTION_UNDERFLOW は指数部がアンダーフローするときの指定です。<BR>
EXCEPTION_OVERFLOW は指数部がオーバーフローするときの指定です。<BR>
EXCEPTION_ZERODIVIDE はゼロによる割り算を実行したときの指定です。<BR>
EXCEPTION_ALL は、可能な全てに対して一括して設定するときに使用します。<BR><BR>
flag が true のときは、指定した状態になったときに例外を発行するようになります。<BR>
flag が falseデフォルトなら、例外は発行されません。計算結果は以下のようになります。<BR>
<BLOCKQUOTE>
EXCEPTION_NaN のとき、非数(NaN)<BR>
EXCEPTION_INFINITY のとき、無限(+ or -Infinity)<BR>
EXCEPTION_UNDERFLOW のとき、ゼロ<BR>
EXCEPTION_OVERFLOW のとき、+Infinity か -Infinity<BR>
EXCEPTION_ZERODIVIDE のとき、+Infinity か -Infinity<BR>
</BLOCKQUOTE>
EXCEPTION_INFINITY、EXCEPTION_OVERFLOW、EXCEPTION_ZERODIVIDE
は今のところ同じです。<BR>
戻り値は、設定前の値です。「値」の意味は、例えば
BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば
EXCEPTION_NaNが設定されているという意味です。<BR>
引数に正しくないものが指定された場合は nil が返ります。
<P>
<B>[丸め処理指定]</B><P>
計算途中の丸め操作の指定ができます。
<BLOCKQUOTE>
f = BigDecimal::mode(BigDecimal::COMP_MODE,flag)
</BLOCKQUOTE>
の形式で指定します。<BR>
ここで、flag は以下の一つを指定します。
<TABLE>
<TR><TD>COMP_MODE_TRUNCATE</TD><TD>全て切り捨てます(truncate)。</TD></TR>
<TR><TD>COMP_MODE_ROUNDUP</TD><TD>四捨五入します(roundup、デフォルト)。</TD></TR>
<TR><TD>COMP_MODE_CEIL</TD><TD>数値の大きい方に繰り上げます(ceil)。</TD></TR>
<TR><TD>COMP_MODE_FLOOR</TD><TD>数値の小さい方に繰り下げます(floor)。</TD></TR>
<TR><TD>COMP_MODE_EVEN</TD><TD>四捨六入します。5の時は上位1桁が奇数の時のみ繰り上げます(Banker's rounding)。</TD></TR>
</TABLE>
戻り値は指定前の flag の値です。
引数に正しくないものが指定された場合は nil が返ります。<BR>
mode メソッドでは丸め操作の位置をユーザが指定することはできません。
丸め操作と位置を自分で制御したい場合は truncate/roundup/ceil/floor といった
インスタンスメソッドを使用して下さい。
</BLOCKQUOTE>
<LI><B>limit([n])</B></LI><BLOCKQUOTE>
生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。戻り値は
設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。
nを指定しない場合は、現状の最大桁数が返ります。<BR>
mf = BigDecimal::limit(n)<BR>
</BLOCKQUOTE>
<LI><B>double_fig</B></LI><BLOCKQUOTE>
Ruby の Float クラスが保持できる有効数字の数を返します。
<CODE><PRE>
p BigDecimal::double_fig # ==> 20 (depends on the CPU etc.)
</PRE></CODE>
double_figは以下の C プログラムの結果と同じです。
<CODE><PRE>
double v = 1.0;
int double_fig = 0;
while(v + 1.0 > 1.0) {
++double_fig;
v /= 10;
}
</PRE></CODE>
</BLOCKQUOTE>
<LI><B>BASE</B></LI><BLOCKQUOTE>
内部で使用される基数の値です。整数が 32 ビットの処理系では10000です。<BR>
b = BigDecimal::BASE<BR>
</BLOCKQUOTE>
<LI><B>E</B></LI><BLOCKQUOTE>
自然対数の底e(=2.718281828....)を計算します(正直にテイラー展開で)。<BR>
e = BigDecimal::E(n)<BR>
nは必要な有効桁数を整数で指定します。
</BLOCKQUOTE>
<LI><B>PI</B></LI><BLOCKQUOTE>
円周率(=3.14159265358979....)を計算しますJMachinの公式を用います<BR>
e = BigDecimal::PI(n)<BR>
n は必要な有効桁数を整数で指定します。
</BLOCKQUOTE>
</UL>
<H4><U>インスタンスメソッド</U></H4>
<UL>
<LI><B>+</B></LI><BLOCKQUOTE>
加算c = a + b<BR> 加算c = a + b<BR>
c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。 c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。
<LI>-</LI><BR> </BLOCKQUOTE>
<LI><B>-</B></LI><BLOCKQUOTE>
減算c = a - b、または符号反転c = -a<BR> 減算c = a - b、または符号反転c = -a<BR>
c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。 c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。
<LI>*</LI><BR>
</BLOCKQUOTE>
<LI><B>*</B></LI><BLOCKQUOTE>
乗算(c = a * b)<BR> 乗算(c = a * b)<BR>
cの精度は(aの精度)+(bの精度)程度です。<br> cの精度は(aの精度)+(bの精度)程度です。<br>
詳しくは「<A HREF="#PREC">計算精度について</A>」を参照してください。 詳しくは「<A HREF="#PREC">計算精度について</A>」を参照してください。
<LI>/</LI><BR> </BLOCKQUOTE>
<LI><B>/</B></LI><BLOCKQUOTE>
除算(c = a / b)<BR> 除算(c = a / b)<BR>
c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。 c の精度については「<A HREF="#PREC">計算精度について</A>」を参照してください。
<LI>assign</LI><BR> </BLOCKQUOTE>
以下のように使用します。<BR>
c = a.assign(n,f)<BR>
f > 0 なら、a を c に、そのまま代入します。
f < 0 なら-a c に代入します
f の絶対値(|f|)は1か2を指定してください。
|f|=2 のときは、c の最大精度が a の実精度より小さいときには
丸められます。|f|=1 のときは切り捨てられます。
n は c の有効桁数ですn 桁以上の精度を持つ c が生成されます)。
<LI>add</LI><BR> <LI><B>add</B></LI><BLOCKQUOTE>
以下のように使用します。<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 より大きいときは丸められます。
<LI>sub</LI><BR> </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 より大きいときは丸められます。
<LI>mult</LI><BR> </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 より大きいときは丸められます。
<LI>div</LI><BR> </BLOCKQUOTE>
<LI><B>div</B></LI><BLOCKQUOTE>
以下のように使用します。<BR> 以下のように使用します。<BR>
c,r = a.div(b,n)<BR> c,r = a.div(b,n)<BR>
c=a/b の計算をします。 r には剰余が代入されます。a/bは c=a/b の計算をします。 r には剰余が代入されます。a/bは
@ -220,63 +261,91 @@ c=a/b
と異なり、c は整数とは限りません。 と異なり、c は整数とは限りません。
また、 c は丸められることはありません。 また、 c は丸められることはありません。
a = c*b + r の関係は成立します。 a = c*b + r の関係は成立します。
<LI>%</LI><BR> </BLOCKQUOTE>
<LI><B>%</B></LI><BLOCKQUOTE>
r = a%b <BR> r = a%b <BR>
a/b の余りを計算します。以下の計算と同じものです。<BR> a/b の余りを計算します。以下の計算と同じものです。<BR>
r = a-((a/b).floor)*b<BR> r = a-((a/b).floor)*b<BR>
<LI>fix</LI><BR> </BLOCKQUOTE>
<LI><B>fix</B></LI><BLOCKQUOTE>
a の小数点以下の切り捨て。<BR> a の小数点以下の切り捨て。<BR>
c = a.fix c = a.fix
<LI>frac</LI><BR> </BLOCKQUOTE>
<LI><B>frac</B></LI><BLOCKQUOTE>
a の整数部分の切り捨て。<BR> a の整数部分の切り捨て。<BR>
c = a.frac c = a.frac
<LI>floor</LI><BR> </BLOCKQUOTE>
a 以下の最大整数を表す値BigDecimal 値)を返します。<BR>
<LI><B>floor[(n)]</B></LI><BLOCKQUOTE>
c = a.floor<BR> c = a.floor<BR>
以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます a 以下の最大整数BigDecimal 値)を返します。
(少数点以下を、最大 n 桁にします)。<BR> <PRE><CODE>
c = BigDecimal("1.23456")<BR> c = BigDecimal("1.23456").floor # ==> 1
d = c.floor(4) # d = 1.2345 になります。<BR> c = BigDecimal("-1.23456").floor # ==> -2
n が負のときは小数点以上 n 桁目を操作します。<BR> </CODE></PRE>
c = BigDecimal("15.23456")<BR> 以下のように引数 n を与えることもできます。<BR>
d = c.floor(-1) # d = 10.0 になります。<BR> n>=0 なら、小数点以下 n+1 位の数字を操作します(少数点以下を、最大 n 桁にします)。<BR>
n が負のときは小数点以上 n 桁目を操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。<BR>
<PRE><CODE>
c = BigDecimal::new("1.23456").floor(4) # ==> 1.2345
c = BigDecimal::new("15.23456").floor(-1) # ==> 10.0
</CODE></PRE>
<LI>ceil</LI><BR> </BLOCKQUOTE>
a 以上の整数のうち、最も小さい整数を計算し、その値BigDecimal 値)を返します。<BR> <LI><B>ceil[(n)]</B></LI><BLOCKQUOTE>
c = a.ceil<BR> c = a.ceil<BR>
以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます a 以上の整数のうち、最も小さい整数を計算し、その値BigDecimal 値)を返します。
(少数点以下を、最大 n 桁にします)。<BR> <PRE><CODE>
c = BigDecimal::new("1.23456")<BR> c = BigDecimal("1.23456").ceil # ==> 2
d = c.ceil(4) # d = 1.2346 になります。<BR> c = BigDecimal("-1.23456").ceil # ==> -1
n が負のときは小数点以上 n 桁目をを操作します。<BR> </CODE></PRE>
c = BigDecimal::new("15.23456")<BR>
d = c.ceil(-1) # d = 20.0 になります。<BR>
<LI>round</LI><BR> 以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます。<BR>
小数点以下第一位の数を四捨五入して整数BigDecimal 値)にします。<BR> n>=0 なら、小数点以下 n+1 位の数字を操作します(少数点以下を、最大 n 桁にします)。<BR>
n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。<BR>
<PRE><CODE>
c = BigDecimal::new("1.23456").ceil(4) # ==> 1.2346
c = BigDecimal::new("15.23456").ceil(-1) # ==> 20.0
</CODE></PRE>
</BLOCKQUOTE>
<LI><B>round[(n[,b])]</B></LI><BLOCKQUOTE>
c = a.round<BR> c = a.round<BR>
以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます 小数点以下第一位の数を四捨五入して整数BigDecimal 値)にします。<BR>
(少数点以下を、最大 n 桁にします)。<BR> <PRE><CODE>
n が正の時は、小数点以下 n+1 位の数字を四捨五入します。 c = BigDecimal("1.23456").round # ==> 1
c = BigDecimal::new("1.23456")<BR> c = BigDecimal("-1.23456").round # ==> -1
d = c.round(4) # d = 1.235 になります。<BR> </CODE></PRE>
n が負のときは小数点以上 n 桁目をを操作します。<BR>
c = BigDecimal::new("15.23456")<BR>
d = c.round(-1) # d = 20.0 になります。<BR>
<LI>truncate</LI><BR> 以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます。<BR>
小数点以下の数を切り捨てて整数BigDecimal 値)にします。<BR> n が正の時は、小数点以下 n+1 位の数字を四捨五入します(少数点以下を、最大 n 桁にします)。<BR>
n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。
<PRE><CODE>
c = BigDecimal::new("1.23456").round(4) # ==> 1.2346
c = BigDecimal::new("15.23456").round(-1) # ==> 20.0
</CODE></PRE>
2番目の引数(デフォルトは 0にゼロ以外を指定すると、いわゆる Banker's rounding になります。<BR>
Banker's rounding とは、四捨五入する数字を p として、p &lt; 5 なら切り捨て p &gt; 5 なら切り上げ、
p がちょうど5のときだけは切り上げ先の数字+1が偶数になるときだけ切り上げます。
<PRE><CODE>
c = BigDecimal::new("1.23456").round(3,1) # ==> 1.234
c = BigDecimal::new("1.23356").round(3,1) # ==> 1.234
</CODE></PRE>
</BLOCKQUOTE>
<LI><B>truncate</B></LI><BLOCKQUOTE>
c = a.truncate<BR> c = a.truncate<BR>
以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます 小数点以下の数を切り捨てて整数BigDecimal 値)にします。<BR>
(少数点以下を、最大 n 桁にします)。<BR> 以下のように引数を与えて、小数点以下 n+1 位の数字を操作することもできます<BR>
n が正の時は、小数点以下 n+1 位の数字を切り捨てます。 n が正の時は、小数点以下 n+1 位の数字を切り捨てます(少数点以下を、最大 n 桁にします)
c = BigDecimal::new("1.23456")<BR> n が負のときは小数点以上 n 桁目をを操作します(小数点位置から左に少なくとも n 個の 0 が並びます)。<BR>
d = c.truncate(4) # d = 1.2345 になります。<BR> <PRE><CODE>
n が負のときは小数点以上 n 桁目をを操作します。<BR> c = BigDecimal::new("1.23456").truncate(4) # ==> 1.2345
c = BigDecimal::new("15.23456")<BR> c = BigDecimal::new("15.23456").truncate(-1) # ==> 10.0
d = c.truncate(-1) # d = 10.0 になります。<BR> </CODE></PRE>
<LI>divmod</LI><BR> </BLOCKQUOTE>
<LI><B>divmod</B></LI><BLOCKQUOTE>
商と剰余の配列を返します。<BR> 商と剰余の配列を返します。<BR>
c,r = a.divmod(b) # a = c*b + r<BR> c,r = a.divmod(b) # a = c*b + r<BR>
divmodメソッドは a = c * b + r となる a / b の浮動小数点型の商 c と剰余 r を divmodメソッドは a = c * b + r となる a / b の浮動小数点型の商 c と剰余 r を
@ -284,85 +353,44 @@ divmod
c = (a/b).floor <BR> c = (a/b).floor <BR>
r = a - c*b<BR> r = a - c*b<BR>
で計算されます。 で計算されます。
<LI>remainder</LI><BR> </BLOCKQUOTE>
<LI><B>remainder</B></LI><BLOCKQUOTE>
r=a.remainder(b)<BR> r=a.remainder(b)<BR>
a/b の剰余 r を計算します。<BR> a/b の剰余 r を計算します。<BR>
c = (a/b).fix <BR> c = (a/b).fix <BR>
r = a - c*b<BR> r = a - c*b<BR>
で計算されます。 で計算されます。
<LI>abs</LI><BR> </BLOCKQUOTE>
<LI><B>abs</B></LI><BLOCKQUOTE>
aの絶対値<BR> aの絶対値<BR>
c = a.abs<BR> c = a.abs<BR>
<LI>to_i</LI><BR> </BLOCKQUOTE>
<LI><B>to_i</B></LI><BLOCKQUOTE>
少数点以下を切り捨てて整数に変換します。<BR> 少数点以下を切り捨てて整数に変換します。<BR>
i = a.to_i<BR> i = a.to_i<BR>
i は値に応じて Fixnum か Bignum になります。 i は値に応じて Fixnum か Bignum になります。
a が Infinity や NaN のとき、i は nil になります。 a が Infinity や NaN のとき、i は nil になります。
<LI>to_f</LI><BR> </BLOCKQUOTE>
<LI><B>to_f</B></LI><BLOCKQUOTE>
dup と全く同じです。 dup と全く同じです。
同じ値の BigDecimal オブジェクトを生成します。 同じ値の BigDecimal オブジェクトを生成します。
<LI>to_s[(n)]</LI><BR> </BLOCKQUOTE>
<LI><B>to_s[(n)]</B></LI><BLOCKQUOTE>
文字列に変換します("0.xxxxxEn"の形になります)。<BR> 文字列に変換します("0.xxxxxEn"の形になります)。<BR>
s = a.to_s<BR> s = a.to_s<BR>
n が指定されたときは、仮数部分を n 桁毎に空白で区切ります。<BR> n が指定されたときは、仮数部分を n 桁毎に空白で区切ります。<BR>
s = a.to_s(n) s = a.to_s(n)
<LI>exponent</LI><BR> </BLOCKQUOTE>
<LI><B>exponent</B></LI><BLOCKQUOTE>
指数部を整数値で返します。 指数部を整数値で返します。
n = a.exponent <BR> n = a.exponent <BR>
は a の値が 0.xxxxxxx*10**n を意味します。 は a の値が 0.xxxxxxx*10**n を意味します。
<LI>E</LI><BR> </BLOCKQUOTE>
自然対数の底e(=2.718281828....)を計算します(正直にテイラー展開で)。<BR>
e = BigDecimal::E(n)<BR>
nは必要な有効桁数を整数で指定します。
<LI>PI</LI><BR>
円周率(=3.14159265358979....)を計算しますJMachinの公式を用います<BR>
e = BigDecimal::PI(n)<BR>
n は必要な有効桁数を整数で指定します。
<LI>BASE</LI><BR>
内部で使用される基数の値です。整数が 32 ビットの処理系では10000です。<BR>
b = BigDecimal::BASE<BR>
<LI>mode</LI><BR>
BigDecimalの実行結果を制御します。以下の使用方法が定義されています。<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_NaN,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_INFINITY,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_UNDERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_OVERFLOW,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ZERODIVIDE,flag)<BR>
f = BigDecimal::mode(BigDecimal::EXCEPTION_ALL,flag)<BR>
EXCEPTION_NaN は結果が NaN になったときの指定です。 <LI><B>sign</B></LI><BLOCKQUOTE>
EXCEPTION_INFINITY は結果が無限大(±Infinity)
になったときの指定です。
EXCEPTION_UNDERFLOW は指数部がアンダーフローするときの指定です。
EXCEPTION_OVERFLOW は指数部がオーバーフローするときの指定です。
EXCEPTION_ZERODIVIDE はゼロによる割り算を実行したときの指定です。
EXCEPTION_ALL は、可能な全てに対して一括して設定するときに
使用します。
flag が true のときは、指定した状態になったときに例外を発行
するようになります。
flag が falseデフォルトなら、例外は発行されません。計算結果は
以下のようになります。<BR>
EXCEPTION_NaN のとき、非数(NaN)<BR>
EXCEPTION_INFINITY のとき、無限(+ or -Infinity)<BR>
EXCEPTION_UNDERFLOW のとき、ゼロ<BR>
EXCEPTION_OVERFLOW のとき、+Infinity か -Infinity<BR>
EXCEPTION_ZERODIVIDE のとき、+Infinity か -Infinity<BR>
EXCEPTION_INFINITY、EXCEPTION_OVERFLOW、EXCEPTION_ZERODIVIDE
は今のところ同じです。<BR>
戻り値は、設定後の値です。「値」の意味は、例えば
BigDecimal::EXCEPTION_NaNと「値」の & が ゼロ以外ならば
EXCEPTION_NaNが設定されているという意味です。
flag が nil、または、true と false 以外なら現在の設定値が返ります。
<LI>limit([n])</LI><BR>
生成されるBigDecimalオブジェクトの最大桁数をn桁に制限します。戻り値は
設定する前の値です。設定値のデフォルト値は0で、桁数無制限という意味です。
nを指定しない場合は、現状の最大桁数が返ります。<BR>
mf = BigDecimal::limit(n)<BR>
<LI>sign</LI><BR>
値の属性を返します。 値の属性を返します。
n = a.sign <BR> n = a.sign <BR>
としたとき n の値は a が以下のときを意味します。<BR> としたとき n の値は a が以下のときを意味します。<BR>
@ -375,26 +403,40 @@ n = BigDecimal::SIGN_NEGATIVE_FINITE(-2) : a
n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a は+Infinity<BR> n = BigDecimal::SIGN_POSITIVE_INFINITE(3) : a は+Infinity<BR>
n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a は-Infinity<BR> n = BigDecimal::SIGN_NEGATIVE_INFINITE(-3) : a は-Infinity<BR>
<LI>nan?</LI><BR> </BLOCKQUOTE>
<LI><B>nan?</B></LI><BLOCKQUOTE>
a.nan? は a がNaNのとき真を返します。 a.nan? は a がNaNのとき真を返します。
<LI>infinite?</LI><BR> </BLOCKQUOTE>
a.infinite? は a が+∞または-∞のとき真を返します。 <LI><B>infinite?</B></LI><BLOCKQUOTE>
<LI>finite?</LI><BR> a.infinite? は a が+∞のとき 1 、-∞のときは -1、それ以外のときは nil を返します。
</BLOCKQUOTE>
<LI><B>finite?</B></LI><BLOCKQUOTE>
a.finite? は a が∞または NaN でないとき真を返します。 a.finite? は a が∞または NaN でないとき真を返します。
</BLOCKQUOTE>
<LI>to_parts</LI><BR> <LI><B>zero?</B></LI><BLOCKQUOTE>
a が 0 なら true になります。<BR>
c = a.zero?
</BLOCKQUOTE>
<LI><B>nonzero?</B></LI><BLOCKQUOTE>
a が 0 なら nil、0 以外なら a そのものが返ります。<BR>
c = a.nonzero?
</BLOCKQUOTE>
<LI><B>split</B></LI><BLOCKQUOTE>
BigDecimal 値を 0.xxxxxxx*10**n と表現したときに、符号NaNのときは BigDecimal 値を 0.xxxxxxx*10**n と表現したときに、符号NaNのときは
0、それ以外は+1か-1になります 0、それ以外は+1か-1になります
仮数部分の文字列("xxxxxxx"と、基数10、更に指数 n を配列で 仮数部分の文字列("xxxxxxx"と、基数10、更に指数 n を配列で
返します。<BR> 返します。<BR>
a=BigDecimal::new("3.14159265",10)<BR> a=BigDecimal::new("3.14159265")<BR>
f,x,y,z = a.to_parts<BR> f,x,y,z = a.split<BR>
とすると、f=+1、x="314159265"、y=10、z=1になります。<BR> とすると、f=+1、x="314159265"、y=10、z=1になります。<BR>
従って、<BR> 従って、<BR>
s = "0."+x<BR> s = "0."+x<BR>
b = f*(s.to_f)*(y**z)<BR> b = f*(s.to_f)*(y**z)<BR>
で Float に変換することができます。 で Float に変換することができます。
<LI>inspect</LI><BR> </BLOCKQUOTE>
<LI><B>inspect</B></LI><BLOCKQUOTE>
デバッグ出力に使用されます。<BR> デバッグ出力に使用されます。<BR>
p a=BigDecimal::new("3.14",10)<BR> p a=BigDecimal::new("3.14",10)<BR>
とすると、[0x112344:'0.314E1',4(12)]のように出力されます。 とすると、[0x112344:'0.314E1',4(12)]のように出力されます。
@ -402,47 +444,54 @@ p a=BigDecimal::new("3.14",10)<BR>
次の4は現在の有効桁数(表示より若干大きいことがあります)、 次の4は現在の有効桁数(表示より若干大きいことがあります)、
最後はオブジェクトが取り得る最大桁数になります。 最後はオブジェクトが取り得る最大桁数になります。
<LI>dup</LI><BR> </BLOCKQUOTE>
<LI><B>dup</B></LI><BLOCKQUOTE>
同じ値の BigDecimal オブジェクトを生成します。 同じ値の BigDecimal オブジェクトを生成します。
<LI>sqrt</LI><BR> </BLOCKQUOTE>
<LI><B>sqrt</B></LI><BLOCKQUOTE>
aの有効桁 n 桁の平方根n の平方根ではありません)。 aの有効桁 n 桁の平方根n の平方根ではありません)。
これまた、正直にニュートン法で計算します。<BR> これまた、正直にニュートン法で計算します。<BR>
c = a.sqrt(n)<BR> c = a.sqrt(n)<BR>
<LI>sincos</LI><BR> </BLOCKQUOTE>
<LI><B>sincos</B></LI><BLOCKQUOTE>
a の有効桁 n 桁の sin と cos を同時に(テイラー展開で)計算して、 a の有効桁 n 桁の sin と cos を同時に(テイラー展開で)計算して、
sin と cos の配列を返します。 sin と cos の配列を返します。
n は必要な有効桁数です( n の sin や cos を計算するわけではありません)。 n は必要な有効桁数です( n の sin や cos を計算するわけではありません)。
<BR> <BR>
sin,cos = a.sincos(n)<BR> sin,cos = a.sincos(n)<BR>
|a|<2*3.1415....でないと正しい答えを計算できないこともあります |a|<2*3.1415....でないと正しい答えを計算できないこともあります
<LI>exp</LI><BR> </BLOCKQUOTE>
<LI><B>exp</B></LI><BLOCKQUOTE>
自然対数の底e(=2.718281828....)の a 乗を計算します。<BR> 自然対数の底e(=2.718281828....)の a 乗を計算します。<BR>
c = a.exp(n)<BR> c = a.exp(n)<BR>
n は必要な有効桁数です。 n は必要な有効桁数です。
<LI>power</LI><BR> </BLOCKQUOTE>
<LI><B>**</B></LI><BLOCKQUOTE>
a の n 乗を計算します。nは整数。<BR> a の n 乗を計算します。nは整数。<BR>
c = a ** n<BR>
結果として c の有効桁は a の n 倍以上になるので注意。
</BLOCKQUOTE>
<LI><B>power</B></LI><BLOCKQUOTE>
** と同じで、a の n 乗を計算します。nは整数。<BR>
c = a.power(n)<BR> c = a.power(n)<BR>
結果として c の有効桁は a の n 倍以上になるので注意。 結果として c の有効桁は a の n 倍以上になるので注意。
<LI>zero?</LI><BR> </BLOCKQUOTE>
a が 0 なら true になります。<BR>
c = a.zero?<BR> <LI><B>&lt=&gt</B></LI><BLOCKQUOTE>
<LI>nonzero?</LI><BR>
a が 0 なら false、0 以外なら a そのものが返ります。<BR>
c = a.nonzero?<BR>
<LI>&lt=&gt</LI><BR>
a==b なら 0、a &gt b なら 1、a &lt b なら -1 になります。<BR> a==b なら 0、a &gt b なら 1、a &lt b なら -1 になります。<BR>
c = a &lt=&gt b <BR> c = a &lt=&gt b
</BLOCKQUOTE>
</UL> </UL>
後は、読んで字の如くです。<BR> 後は、読んで字の如くです。<BR>
<UL> <UL>
<LI>==</LI> <LI><B>==</B></LI>
<LI>===</LI> <LI><B>===</B></LI>
「==」と同じですが case 文で使用されます。 「==」と同じですが case 文で使用されます。
<LI>!=</LI> <LI><B>!=</B></LI>
<LI>&lt</LI> <LI><B>&lt</B></LI>
<LI>&lt=</LI> <LI><B>&lt=</B></LI>
<LI>&gt</LI> <LI><B>&gt</B></LI>
<LI>&gt=</LI> <LI><B>&gt=</B></LI>
</UL> </UL>
<H3>coerceについて</H3> <H3>coerceについて</H3>
BigDecimal オブジェクトが算術演算子の左にあるときは、BigDecimal オブジェクトが BigDecimal オブジェクトが算術演算子の左にあるときは、BigDecimal オブジェクトが