00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef BIGDECIMAL_DEBUG
00018 # define BIGDECIMAL_ENABLE_VPRINT 1
00019 #endif
00020 #include "bigdecimal.h"
00021
00022 #ifndef BIGDECIMAL_DEBUG
00023 # define NDEBUG
00024 #endif
00025 #include <assert.h>
00026
00027 #include <ctype.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <math.h>
00033 #include "math.h"
00034
00035 #ifdef HAVE_IEEEFP_H
00036 #include <ieeefp.h>
00037 #endif
00038
00039
00040
00041 VALUE rb_cBigDecimal;
00042 VALUE rb_mBigMath;
00043
00044 static ID id_BigDecimal_exception_mode;
00045 static ID id_BigDecimal_rounding_mode;
00046 static ID id_BigDecimal_precision_limit;
00047
00048 static ID id_up;
00049 static ID id_down;
00050 static ID id_truncate;
00051 static ID id_half_up;
00052 static ID id_default;
00053 static ID id_half_down;
00054 static ID id_half_even;
00055 static ID id_banker;
00056 static ID id_ceiling;
00057 static ID id_ceil;
00058 static ID id_floor;
00059 static ID id_to_r;
00060 static ID id_eq;
00061
00062
00063 #define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
00064 #define PUSH(x) vStack[iStack++] = (VALUE)(x);
00065 #define SAVE(p) PUSH(p->obj);
00066 #define GUARD_OBJ(p,y) {p=y;SAVE(p);}
00067
00068 #define BASE_FIG RMPD_COMPONENT_FIGURES
00069 #define BASE RMPD_BASE
00070
00071 #define HALF_BASE (BASE/2)
00072 #define BASE1 (BASE/10)
00073
00074 #ifndef DBLE_FIG
00075 #define DBLE_FIG (DBL_DIG+1)
00076 #endif
00077
00078 #ifndef RBIGNUM_ZERO_P
00079 # define RBIGNUM_ZERO_P(x) (RBIGNUM_LEN(x) == 0 || \
00080 (RBIGNUM_DIGITS(x)[0] == 0 && \
00081 (RBIGNUM_LEN(x) == 1 || bigzero_p(x))))
00082 #endif
00083
00084 static inline int
00085 bigzero_p(VALUE x)
00086 {
00087 long i;
00088 BDIGIT *ds = RBIGNUM_DIGITS(x);
00089
00090 for (i = RBIGNUM_LEN(x) - 1; 0 <= i; i--) {
00091 if (ds[i]) return 0;
00092 }
00093 return 1;
00094 }
00095
00096 #ifndef RRATIONAL_ZERO_P
00097 # define RRATIONAL_ZERO_P(x) (FIXNUM_P(RRATIONAL(x)->num) && \
00098 FIX2LONG(RRATIONAL(x)->num) == 0)
00099 #endif
00100
00101 #ifndef RRATIONAL_NEGATIVE_P
00102 # define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
00103 #endif
00104
00105 #ifndef DECIMAL_SIZE_OF_BITS
00106 #define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
00107
00108 #endif
00109
00110 #ifdef PRIsVALUE
00111 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
00112 # define RB_OBJ_STRING(obj) (obj)
00113 #else
00114 # define PRIsVALUE "s"
00115 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
00116 # define RB_OBJ_STRING(obj) StringValueCStr(obj)
00117 #endif
00118
00119
00120
00121
00122 #define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
00123
00124
00125
00126
00127 static VALUE
00128 BigDecimal_version(VALUE self)
00129 {
00130
00131
00132
00133
00134
00135 return rb_str_new2("1.1.0");
00136 }
00137
00138
00139
00140
00141 static unsigned short VpGetException(void);
00142 static void VpSetException(unsigned short f);
00143 static void VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v);
00144 static int VpLimitRound(Real *c, size_t ixDigit);
00145 static Real *VpCopy(Real *pv, Real const* const x);
00146
00147
00148
00149
00150
00151 static void
00152 BigDecimal_delete(void *pv)
00153 {
00154 VpFree(pv);
00155 }
00156
00157 static size_t
00158 BigDecimal_memsize(const void *ptr)
00159 {
00160 const Real *pv = ptr;
00161 return pv ? (sizeof(*pv) + pv->MaxPrec * sizeof(BDIGIT)) : 0;
00162 }
00163
00164 static const rb_data_type_t BigDecimal_data_type = {
00165 "BigDecimal",
00166 {0, BigDecimal_delete, BigDecimal_memsize,},
00167 };
00168
00169 static inline int
00170 is_kind_of_BigDecimal(VALUE const v)
00171 {
00172 return rb_typeddata_is_kind_of(v, &BigDecimal_data_type);
00173 }
00174
00175 static VALUE
00176 ToValue(Real *p)
00177 {
00178 if(VpIsNaN(p)) {
00179 VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
00180 } else if(VpIsPosInf(p)) {
00181 VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
00182 } else if(VpIsNegInf(p)) {
00183 VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
00184 }
00185 return p->obj;
00186 }
00187
00188 NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
00189
00190 static void
00191 cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
00192 {
00193 VALUE str;
00194
00195 if (rb_special_const_p(v)) {
00196 str = rb_inspect(v);
00197 }
00198 else {
00199 str = rb_class_name(rb_obj_class(v));
00200 }
00201
00202 str = rb_str_cat2(rb_str_dup(str), " can't be coerced into BigDecimal");
00203 rb_exc_raise(rb_exc_new3(exc_class, str));
00204 }
00205
00206 static VALUE BigDecimal_div2(int, VALUE*, VALUE);
00207
00208 static Real*
00209 GetVpValueWithPrec(VALUE v, long prec, int must)
00210 {
00211 Real *pv;
00212 VALUE num, bg, args[2];
00213 char szD[128];
00214 VALUE orig = Qundef;
00215
00216 again:
00217 switch(TYPE(v))
00218 {
00219 case T_FLOAT:
00220 if (prec < 0) goto unable_to_coerce_without_prec;
00221 if (prec > DBL_DIG+1)goto SomeOneMayDoIt;
00222 v = rb_funcall(v, id_to_r, 0);
00223 goto again;
00224 case T_RATIONAL:
00225 if (prec < 0) goto unable_to_coerce_without_prec;
00226
00227 if (orig == Qundef ? (orig = v, 1) : orig != v) {
00228 num = RRATIONAL(v)->num;
00229 pv = GetVpValueWithPrec(num, -1, must);
00230 if (pv == NULL) goto SomeOneMayDoIt;
00231
00232 args[0] = RRATIONAL(v)->den;
00233 args[1] = LONG2NUM(prec);
00234 v = BigDecimal_div2(2, args, ToValue(pv));
00235 goto again;
00236 }
00237
00238 v = orig;
00239 goto SomeOneMayDoIt;
00240
00241 case T_DATA:
00242 if (is_kind_of_BigDecimal(v)) {
00243 pv = DATA_PTR(v);
00244 return pv;
00245 }
00246 else {
00247 goto SomeOneMayDoIt;
00248 }
00249 break;
00250
00251 case T_FIXNUM:
00252 sprintf(szD, "%ld", FIX2LONG(v));
00253 return VpCreateRbObject(VpBaseFig() * 2 + 1, szD);
00254
00255 #ifdef ENABLE_NUMERIC_STRING
00256 case T_STRING:
00257 SafeStringValue(v);
00258 return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1,
00259 RSTRING_PTR(v));
00260 #endif
00261
00262 case T_BIGNUM:
00263 bg = rb_big2str(v, 10);
00264 return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1,
00265 RSTRING_PTR(bg));
00266 default:
00267 goto SomeOneMayDoIt;
00268 }
00269
00270 SomeOneMayDoIt:
00271 if (must) {
00272 cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
00273 }
00274 return NULL;
00275
00276 unable_to_coerce_without_prec:
00277 if (must) {
00278 rb_raise(rb_eArgError,
00279 "%"PRIsVALUE" can't be coerced into BigDecimal without a precision",
00280 RB_OBJ_CLASSNAME(v));
00281 }
00282 return NULL;
00283 }
00284
00285 static Real*
00286 GetVpValue(VALUE v, int must)
00287 {
00288 return GetVpValueWithPrec(v, -1, must);
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298 static VALUE
00299 BigDecimal_double_fig(VALUE self)
00300 {
00301 return INT2FIX(VpDblFig());
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 static VALUE
00314 BigDecimal_prec(VALUE self)
00315 {
00316 ENTER(1);
00317 Real *p;
00318 VALUE obj;
00319
00320 GUARD_OBJ(p,GetVpValue(self,1));
00321 obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
00322 INT2NUM(p->MaxPrec*VpBaseFig()));
00323 return obj;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334 static VALUE
00335 BigDecimal_hash(VALUE self)
00336 {
00337 ENTER(1);
00338 Real *p;
00339 st_index_t hash;
00340
00341 GUARD_OBJ(p,GetVpValue(self,1));
00342 hash = (st_index_t)p->sign;
00343
00344 if(hash == 2 || hash == (st_index_t)-2) {
00345 hash ^= rb_memhash(p->frac, sizeof(BDIGIT)*p->Prec);
00346 hash += p->exponent;
00347 }
00348 return INT2FIX(hash);
00349 }
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 static VALUE
00364 BigDecimal_dump(int argc, VALUE *argv, VALUE self)
00365 {
00366 ENTER(5);
00367 Real *vp;
00368 char *psz;
00369 VALUE dummy;
00370 volatile VALUE dump;
00371
00372 rb_scan_args(argc, argv, "01", &dummy);
00373 GUARD_OBJ(vp,GetVpValue(self,1));
00374 dump = rb_str_new(0,VpNumOfChars(vp,"E")+50);
00375 psz = RSTRING_PTR(dump);
00376 sprintf(psz, "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
00377 VpToString(vp, psz+strlen(psz), 0, 0);
00378 rb_str_resize(dump, strlen(psz));
00379 return dump;
00380 }
00381
00382
00383
00384
00385 static VALUE
00386 BigDecimal_load(VALUE self, VALUE str)
00387 {
00388 ENTER(2);
00389 Real *pv;
00390 unsigned char *pch;
00391 unsigned char ch;
00392 unsigned long m=0;
00393
00394 SafeStringValue(str);
00395 pch = (unsigned char *)RSTRING_PTR(str);
00396
00397 while((*pch)!=(unsigned char)'\0' && (ch=*pch++)!=(unsigned char)':') {
00398 if(!ISDIGIT(ch)) {
00399 rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
00400 }
00401 m = m*10 + (unsigned long)(ch-'0');
00402 }
00403 if(m>VpBaseFig()) m -= VpBaseFig();
00404 GUARD_OBJ(pv,VpNewRbClass(m,(char *)pch,self));
00405 m /= VpBaseFig();
00406 if(m && pv->MaxPrec>m) pv->MaxPrec = m+1;
00407 return ToValue(pv);
00408 }
00409
00410 static unsigned short
00411 check_rounding_mode(VALUE const v)
00412 {
00413 unsigned short sw;
00414 ID id;
00415 switch (TYPE(v)) {
00416 case T_SYMBOL:
00417 id = SYM2ID(v);
00418 if (id == id_up)
00419 return VP_ROUND_UP;
00420 if (id == id_down || id == id_truncate)
00421 return VP_ROUND_DOWN;
00422 if (id == id_half_up || id == id_default)
00423 return VP_ROUND_HALF_UP;
00424 if (id == id_half_down)
00425 return VP_ROUND_HALF_DOWN;
00426 if (id == id_half_even || id == id_banker)
00427 return VP_ROUND_HALF_EVEN;
00428 if (id == id_ceiling || id == id_ceil)
00429 return VP_ROUND_CEIL;
00430 if (id == id_floor)
00431 return VP_ROUND_FLOOR;
00432 rb_raise(rb_eArgError, "invalid rounding mode");
00433
00434 default:
00435 break;
00436 }
00437
00438 Check_Type(v, T_FIXNUM);
00439 sw = (unsigned short)FIX2UINT(v);
00440 if (!VpIsRoundMode(sw)) {
00441 rb_raise(rb_eArgError, "invalid rounding mode");
00442 }
00443 return sw;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 static VALUE
00485 BigDecimal_mode(int argc, VALUE *argv, VALUE self)
00486 {
00487 VALUE which;
00488 VALUE val;
00489 unsigned long f,fo;
00490
00491 if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil;
00492
00493 Check_Type(which, T_FIXNUM);
00494 f = (unsigned long)FIX2INT(which);
00495
00496 if(f&VP_EXCEPTION_ALL) {
00497
00498 fo = VpGetException();
00499 if(val==Qnil) return INT2FIX(fo);
00500 if(val!=Qfalse && val!=Qtrue) {
00501 rb_raise(rb_eArgError, "second argument must be true or false");
00502 return Qnil;
00503 }
00504 if(f&VP_EXCEPTION_INFINITY) {
00505 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY):
00506 (fo&(~VP_EXCEPTION_INFINITY))));
00507 }
00508 fo = VpGetException();
00509 if(f&VP_EXCEPTION_NaN) {
00510 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
00511 (fo&(~VP_EXCEPTION_NaN))));
00512 }
00513 fo = VpGetException();
00514 if(f&VP_EXCEPTION_UNDERFLOW) {
00515 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_UNDERFLOW):
00516 (fo&(~VP_EXCEPTION_UNDERFLOW))));
00517 }
00518 fo = VpGetException();
00519 if(f&VP_EXCEPTION_ZERODIVIDE) {
00520 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_ZERODIVIDE):
00521 (fo&(~VP_EXCEPTION_ZERODIVIDE))));
00522 }
00523 fo = VpGetException();
00524 return INT2FIX(fo);
00525 }
00526 if (VP_ROUND_MODE == f) {
00527
00528 unsigned short sw;
00529 fo = VpGetRoundMode();
00530 if (NIL_P(val)) return INT2FIX(fo);
00531 sw = check_rounding_mode(val);
00532 fo = VpSetRoundMode(sw);
00533 return INT2FIX(fo);
00534 }
00535 rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
00536 return Qnil;
00537 }
00538
00539 static size_t
00540 GetAddSubPrec(Real *a, Real *b)
00541 {
00542 size_t mxs;
00543 size_t mx = a->Prec;
00544 SIGNED_VALUE d;
00545
00546 if(!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
00547 if(mx < b->Prec) mx = b->Prec;
00548 if(a->exponent!=b->exponent) {
00549 mxs = mx;
00550 d = a->exponent - b->exponent;
00551 if (d < 0) d = -d;
00552 mx = mx + (size_t)d;
00553 if (mx<mxs) {
00554 return VpException(VP_EXCEPTION_INFINITY,"Exponent overflow",0);
00555 }
00556 }
00557 return mx;
00558 }
00559
00560 static SIGNED_VALUE
00561 GetPositiveInt(VALUE v)
00562 {
00563 SIGNED_VALUE n;
00564 Check_Type(v, T_FIXNUM);
00565 n = FIX2INT(v);
00566 if (n < 0) {
00567 rb_raise(rb_eArgError, "argument must be positive");
00568 }
00569 return n;
00570 }
00571
00572 VP_EXPORT Real *
00573 VpNewRbClass(size_t mx, const char *str, VALUE klass)
00574 {
00575 Real *pv = VpAlloc(mx,str);
00576 pv->obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, pv);
00577 return pv;
00578 }
00579
00580 VP_EXPORT Real *
00581 VpCreateRbObject(size_t mx, const char *str)
00582 {
00583 Real *pv = VpAlloc(mx,str);
00584 pv->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv);
00585 return pv;
00586 }
00587
00588 #define VpAllocReal(prec) (Real *)VpMemAlloc(offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
00589 #define VpReallocReal(ptr, prec) (Real *)VpMemRealloc((ptr), offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
00590
00591 static Real *
00592 VpCopy(Real *pv, Real const* const x)
00593 {
00594 assert(x != NULL);
00595
00596 pv = VpReallocReal(pv, x->MaxPrec);
00597 pv->MaxPrec = x->MaxPrec;
00598 pv->Prec = x->Prec;
00599 pv->exponent = x->exponent;
00600 pv->sign = x->sign;
00601 pv->flag = x->flag;
00602 MEMCPY(pv->frac, x->frac, BDIGIT, pv->MaxPrec);
00603
00604 return pv;
00605 }
00606
00607
00608 static VALUE
00609 BigDecimal_IsNaN(VALUE self)
00610 {
00611 Real *p = GetVpValue(self,1);
00612 if(VpIsNaN(p)) return Qtrue;
00613 return Qfalse;
00614 }
00615
00616
00617
00618
00619 static VALUE
00620 BigDecimal_IsInfinite(VALUE self)
00621 {
00622 Real *p = GetVpValue(self,1);
00623 if(VpIsPosInf(p)) return INT2FIX(1);
00624 if(VpIsNegInf(p)) return INT2FIX(-1);
00625 return Qnil;
00626 }
00627
00628
00629 static VALUE
00630 BigDecimal_IsFinite(VALUE self)
00631 {
00632 Real *p = GetVpValue(self,1);
00633 if(VpIsNaN(p)) return Qfalse;
00634 if(VpIsInf(p)) return Qfalse;
00635 return Qtrue;
00636 }
00637
00638 static void
00639 BigDecimal_check_num(Real *p)
00640 {
00641 if(VpIsNaN(p)) {
00642 VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",1);
00643 } else if(VpIsPosInf(p)) {
00644 VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",1);
00645 } else if(VpIsNegInf(p)) {
00646 VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",1);
00647 }
00648 }
00649
00650 static VALUE BigDecimal_split(VALUE self);
00651
00652
00653
00654
00655
00656 static VALUE
00657 BigDecimal_to_i(VALUE self)
00658 {
00659 ENTER(5);
00660 ssize_t e, nf;
00661 Real *p;
00662
00663 GUARD_OBJ(p,GetVpValue(self,1));
00664 BigDecimal_check_num(p);
00665
00666 e = VpExponent10(p);
00667 if(e<=0) return INT2FIX(0);
00668 nf = VpBaseFig();
00669 if(e<=nf) {
00670 return LONG2NUM((long)(VpGetSign(p)*(BDIGIT_DBL_SIGNED)p->frac[0]));
00671 }
00672 else {
00673 VALUE a = BigDecimal_split(self);
00674 VALUE digits = RARRAY_PTR(a)[1];
00675 VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
00676 VALUE ret;
00677 ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
00678
00679 if (VpGetSign(p) < 0) {
00680 numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
00681 }
00682 if (dpower < 0) {
00683 ret = rb_funcall(numerator, rb_intern("div"), 1,
00684 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
00685 INT2FIX(-dpower)));
00686 }
00687 else
00688 ret = rb_funcall(numerator, '*', 1,
00689 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
00690 INT2FIX(dpower)));
00691 if (RB_TYPE_P(ret, T_FLOAT))
00692 rb_raise(rb_eFloatDomainError, "Infinity");
00693 return ret;
00694 }
00695 }
00696
00697
00698
00699
00700
00701 static VALUE
00702 BigDecimal_to_f(VALUE self)
00703 {
00704 ENTER(1);
00705 Real *p;
00706 double d;
00707 SIGNED_VALUE e;
00708 char *buf;
00709 volatile VALUE str;
00710
00711 GUARD_OBJ(p, GetVpValue(self, 1));
00712 if (VpVtoD(&d, &e, p) != 1)
00713 return rb_float_new(d);
00714 if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
00715 goto overflow;
00716 if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
00717 goto underflow;
00718
00719 str = rb_str_new(0, VpNumOfChars(p,"E"));
00720 buf = RSTRING_PTR(str);
00721 VpToString(p, buf, 0, 0);
00722 errno = 0;
00723 d = strtod(buf, 0);
00724 if (errno == ERANGE) {
00725 if (d == 0.0) goto underflow;
00726 if (fabs(d) >= HUGE_VAL) goto overflow;
00727 }
00728 return rb_float_new(d);
00729
00730 overflow:
00731 VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
00732 if (p->sign >= 0)
00733 return rb_float_new(VpGetDoublePosInf());
00734 else
00735 return rb_float_new(VpGetDoubleNegInf());
00736
00737 underflow:
00738 VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
00739 if (p->sign >= 0)
00740 return rb_float_new(0.0);
00741 else
00742 return rb_float_new(-0.0);
00743 }
00744
00745
00746
00747
00748 static VALUE
00749 BigDecimal_to_r(VALUE self)
00750 {
00751 Real *p;
00752 ssize_t sign, power, denomi_power;
00753 VALUE a, digits, numerator;
00754
00755 p = GetVpValue(self,1);
00756 BigDecimal_check_num(p);
00757
00758 sign = VpGetSign(p);
00759 power = VpExponent10(p);
00760 a = BigDecimal_split(self);
00761 digits = RARRAY_PTR(a)[1];
00762 denomi_power = power - RSTRING_LEN(digits);
00763 numerator = rb_funcall(digits, rb_intern("to_i"), 0);
00764
00765 if (sign < 0) {
00766 numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
00767 }
00768 if (denomi_power < 0) {
00769 return rb_Rational(numerator,
00770 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
00771 INT2FIX(-denomi_power)));
00772 }
00773 else {
00774 return rb_Rational1(rb_funcall(numerator, '*', 1,
00775 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
00776 INT2FIX(denomi_power))));
00777 }
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 static VALUE
00795 BigDecimal_coerce(VALUE self, VALUE other)
00796 {
00797 ENTER(2);
00798 VALUE obj;
00799 Real *b;
00800
00801 if (RB_TYPE_P(other, T_FLOAT)) {
00802 obj = rb_assoc_new(other, BigDecimal_to_f(self));
00803 }
00804 else {
00805 if (RB_TYPE_P(other, T_RATIONAL)) {
00806 Real* pv = DATA_PTR(self);
00807 GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
00808 }
00809 else {
00810 GUARD_OBJ(b, GetVpValue(other, 1));
00811 }
00812 obj = rb_assoc_new(b->obj, self);
00813 }
00814
00815 return obj;
00816 }
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 static VALUE
00827 BigDecimal_uplus(VALUE self)
00828 {
00829 return self;
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849 static VALUE
00850 BigDecimal_add(VALUE self, VALUE r)
00851 {
00852 ENTER(5);
00853 Real *c, *a, *b;
00854 size_t mx;
00855
00856 GUARD_OBJ(a, GetVpValue(self, 1));
00857 if (RB_TYPE_P(r, T_FLOAT)) {
00858 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
00859 }
00860 else if (RB_TYPE_P(r, T_RATIONAL)) {
00861 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
00862 }
00863 else {
00864 b = GetVpValue(r,0);
00865 }
00866
00867 if (!b) return DoSomeOne(self,r,'+');
00868 SAVE(b);
00869
00870 if (VpIsNaN(b)) return b->obj;
00871 if (VpIsNaN(a)) return a->obj;
00872
00873 mx = GetAddSubPrec(a, b);
00874 if (mx == (size_t)-1L) {
00875 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
00876 VpAddSub(c, a, b, 1);
00877 }
00878 else {
00879 GUARD_OBJ(c, VpCreateRbObject(mx * (VpBaseFig() + 1), "0"));
00880 if(!mx) {
00881 VpSetInf(c, VpGetSign(a));
00882 }
00883 else {
00884 VpAddSub(c, a, b, 1);
00885 }
00886 }
00887 return ToValue(c);
00888 }
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 static VALUE
00904 BigDecimal_sub(VALUE self, VALUE r)
00905 {
00906 ENTER(5);
00907 Real *c, *a, *b;
00908 size_t mx;
00909
00910 GUARD_OBJ(a,GetVpValue(self,1));
00911 if (RB_TYPE_P(r, T_FLOAT)) {
00912 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
00913 }
00914 else if (RB_TYPE_P(r, T_RATIONAL)) {
00915 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
00916 }
00917 else {
00918 b = GetVpValue(r,0);
00919 }
00920
00921 if(!b) return DoSomeOne(self,r,'-');
00922 SAVE(b);
00923
00924 if(VpIsNaN(b)) return b->obj;
00925 if(VpIsNaN(a)) return a->obj;
00926
00927 mx = GetAddSubPrec(a,b);
00928 if (mx == (size_t)-1L) {
00929 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
00930 VpAddSub(c, a, b, -1);
00931 } else {
00932 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
00933 if(!mx) {
00934 VpSetInf(c,VpGetSign(a));
00935 } else {
00936 VpAddSub(c, a, b, -1);
00937 }
00938 }
00939 return ToValue(c);
00940 }
00941
00942 static VALUE
00943 BigDecimalCmp(VALUE self, VALUE r,char op)
00944 {
00945 ENTER(5);
00946 SIGNED_VALUE e;
00947 Real *a, *b=0;
00948 GUARD_OBJ(a,GetVpValue(self,1));
00949 switch (TYPE(r)) {
00950 case T_DATA:
00951 if (!is_kind_of_BigDecimal(r)) break;
00952
00953 case T_FIXNUM:
00954
00955 case T_BIGNUM:
00956 GUARD_OBJ(b, GetVpValue(r,0));
00957 break;
00958
00959 case T_FLOAT:
00960 GUARD_OBJ(b, GetVpValueWithPrec(r, DBL_DIG+1, 0));
00961 break;
00962
00963 case T_RATIONAL:
00964 GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
00965 break;
00966
00967 default:
00968 break;
00969 }
00970 if (b == NULL) {
00971 ID f = 0;
00972
00973 switch (op) {
00974 case '*':
00975 return rb_num_coerce_cmp(self, r, rb_intern("<=>"));
00976
00977 case '=':
00978 return RTEST(rb_num_coerce_cmp(self, r, rb_intern("=="))) ? Qtrue : Qfalse;
00979
00980 case 'G':
00981 f = rb_intern(">=");
00982 break;
00983
00984 case 'L':
00985 f = rb_intern("<=");
00986 break;
00987
00988 case '>':
00989
00990 case '<':
00991 f = (ID)op;
00992 break;
00993
00994 default:
00995 break;
00996 }
00997 return rb_num_coerce_relop(self, r, f);
00998 }
00999 SAVE(b);
01000 e = VpComp(a, b);
01001 if (e == 999)
01002 return (op == '*') ? Qnil : Qfalse;
01003 switch (op) {
01004 case '*':
01005 return INT2FIX(e);
01006
01007 case '=':
01008 if(e==0) return Qtrue;
01009 return Qfalse;
01010
01011 case 'G':
01012 if(e>=0) return Qtrue;
01013 return Qfalse;
01014
01015 case '>':
01016 if(e> 0) return Qtrue;
01017 return Qfalse;
01018
01019 case 'L':
01020 if(e<=0) return Qtrue;
01021 return Qfalse;
01022
01023 case '<':
01024 if(e< 0) return Qtrue;
01025 return Qfalse;
01026
01027 default:
01028 break;
01029 }
01030
01031 rb_bug("Undefined operation in BigDecimalCmp()");
01032
01033 UNREACHABLE;
01034 }
01035
01036
01037 static VALUE
01038 BigDecimal_zero(VALUE self)
01039 {
01040 Real *a = GetVpValue(self,1);
01041 return VpIsZero(a) ? Qtrue : Qfalse;
01042 }
01043
01044
01045 static VALUE
01046 BigDecimal_nonzero(VALUE self)
01047 {
01048 Real *a = GetVpValue(self,1);
01049 return VpIsZero(a) ? Qnil : self;
01050 }
01051
01052
01053
01054
01055 static VALUE
01056 BigDecimal_comp(VALUE self, VALUE r)
01057 {
01058 return BigDecimalCmp(self, r, '*');
01059 }
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 static VALUE
01072 BigDecimal_eq(VALUE self, VALUE r)
01073 {
01074 return BigDecimalCmp(self, r, '=');
01075 }
01076
01077
01078
01079
01080
01081
01082
01083
01084 static VALUE
01085 BigDecimal_lt(VALUE self, VALUE r)
01086 {
01087 return BigDecimalCmp(self, r, '<');
01088 }
01089
01090
01091
01092
01093
01094
01095
01096
01097 static VALUE
01098 BigDecimal_le(VALUE self, VALUE r)
01099 {
01100 return BigDecimalCmp(self, r, 'L');
01101 }
01102
01103
01104
01105
01106
01107
01108
01109
01110 static VALUE
01111 BigDecimal_gt(VALUE self, VALUE r)
01112 {
01113 return BigDecimalCmp(self, r, '>');
01114 }
01115
01116
01117
01118
01119
01120
01121
01122
01123 static VALUE
01124 BigDecimal_ge(VALUE self, VALUE r)
01125 {
01126 return BigDecimalCmp(self, r, 'G');
01127 }
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138 static VALUE
01139 BigDecimal_neg(VALUE self)
01140 {
01141 ENTER(5);
01142 Real *c, *a;
01143 GUARD_OBJ(a,GetVpValue(self,1));
01144 GUARD_OBJ(c,VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
01145 VpAsgn(c, a, -1);
01146 return ToValue(c);
01147 }
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164 static VALUE
01165 BigDecimal_mult(VALUE self, VALUE r)
01166 {
01167 ENTER(5);
01168 Real *c, *a, *b;
01169 size_t mx;
01170
01171 GUARD_OBJ(a,GetVpValue(self,1));
01172 if (RB_TYPE_P(r, T_FLOAT)) {
01173 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
01174 }
01175 else if (RB_TYPE_P(r, T_RATIONAL)) {
01176 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
01177 }
01178 else {
01179 b = GetVpValue(r,0);
01180 }
01181
01182 if(!b) return DoSomeOne(self,r,'*');
01183 SAVE(b);
01184
01185 mx = a->Prec + b->Prec;
01186 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
01187 VpMult(c, a, b);
01188 return ToValue(c);
01189 }
01190
01191 static VALUE
01192 BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
01193
01194 {
01195 ENTER(5);
01196 Real *a, *b;
01197 size_t mx;
01198
01199 GUARD_OBJ(a,GetVpValue(self,1));
01200 if (RB_TYPE_P(r, T_FLOAT)) {
01201 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
01202 }
01203 else if (RB_TYPE_P(r, T_RATIONAL)) {
01204 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
01205 }
01206 else {
01207 b = GetVpValue(r,0);
01208 }
01209
01210 if(!b) return DoSomeOne(self,r,'/');
01211 SAVE(b);
01212
01213 *div = b;
01214 mx = a->Prec + vabs(a->exponent);
01215 if(mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
01216 mx =(mx + 1) * VpBaseFig();
01217 GUARD_OBJ((*c),VpCreateRbObject(mx, "#0"));
01218 GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
01219 VpDivd(*c, *res, a, b);
01220 return (VALUE)0;
01221 }
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242 static VALUE
01243 BigDecimal_div(VALUE self, VALUE r)
01244
01245 {
01246 ENTER(5);
01247 Real *c=NULL, *res=NULL, *div = NULL;
01248 r = BigDecimal_divide(&c, &res, &div, self, r);
01249 if(r!=(VALUE)0) return r;
01250 SAVE(c);SAVE(res);SAVE(div);
01251
01252
01253
01254
01255
01256 if(VpHasVal(div)) {
01257 VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal()*(BDIGIT_DBL)res->frac[0]/div->frac[0]));
01258 }
01259 return ToValue(c);
01260 }
01261
01262
01263
01264
01265
01266 static VALUE
01267 BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
01268 {
01269 ENTER(8);
01270 Real *c=NULL, *d=NULL, *res=NULL;
01271 Real *a, *b;
01272 size_t mx;
01273
01274 GUARD_OBJ(a,GetVpValue(self,1));
01275 if (RB_TYPE_P(r, T_FLOAT)) {
01276 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
01277 }
01278 else if (RB_TYPE_P(r, T_RATIONAL)) {
01279 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
01280 }
01281 else {
01282 b = GetVpValue(r,0);
01283 }
01284
01285 if(!b) return Qfalse;
01286 SAVE(b);
01287
01288 if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
01289 if(VpIsInf(a) && VpIsInf(b)) goto NaN;
01290 if(VpIsZero(b)) {
01291 rb_raise(rb_eZeroDivError, "divided by 0");
01292 }
01293 if(VpIsInf(a)) {
01294 GUARD_OBJ(d,VpCreateRbObject(1, "0"));
01295 VpSetInf(d, (SIGNED_VALUE)(VpGetSign(a) == VpGetSign(b) ? 1 : -1));
01296 GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
01297 *div = d;
01298 *mod = c;
01299 return Qtrue;
01300 }
01301 if(VpIsInf(b)) {
01302 GUARD_OBJ(d,VpCreateRbObject(1, "0"));
01303 *div = d;
01304 *mod = a;
01305 return Qtrue;
01306 }
01307 if(VpIsZero(a)) {
01308 GUARD_OBJ(c,VpCreateRbObject(1, "0"));
01309 GUARD_OBJ(d,VpCreateRbObject(1, "0"));
01310 *div = d;
01311 *mod = c;
01312 return Qtrue;
01313 }
01314
01315 mx = a->Prec + vabs(a->exponent);
01316 if(mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
01317 mx =(mx + 1) * VpBaseFig();
01318 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01319 GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
01320 VpDivd(c, res, a, b);
01321 mx = c->Prec *(VpBaseFig() + 1);
01322 GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
01323 VpActiveRound(d,c,VP_ROUND_DOWN,0);
01324 VpMult(res,d,b);
01325 VpAddSub(c,a,res,-1);
01326 if(!VpIsZero(c) && (VpGetSign(a)*VpGetSign(b)<0)) {
01327 VpAddSub(res,d,VpOne(),-1);
01328 GUARD_OBJ(d,VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0"));
01329 VpAddSub(d ,c,b, 1);
01330 *div = res;
01331 *mod = d;
01332 } else {
01333 *div = d;
01334 *mod = c;
01335 }
01336 return Qtrue;
01337
01338 NaN:
01339 GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
01340 GUARD_OBJ(d,VpCreateRbObject(1, "NaN"));
01341 *div = d;
01342 *mod = c;
01343 return Qtrue;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 static VALUE
01355 BigDecimal_mod(VALUE self, VALUE r)
01356 {
01357 ENTER(3);
01358 Real *div=NULL, *mod=NULL;
01359
01360 if(BigDecimal_DoDivmod(self,r,&div,&mod)) {
01361 SAVE(div); SAVE(mod);
01362 return ToValue(mod);
01363 }
01364 return DoSomeOne(self,r,'%');
01365 }
01366
01367 static VALUE
01368 BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
01369 {
01370 ENTER(10);
01371 size_t mx;
01372 Real *a=NULL, *b=NULL, *c=NULL, *res=NULL, *d=NULL, *rr=NULL, *ff=NULL;
01373 Real *f=NULL;
01374
01375 GUARD_OBJ(a,GetVpValue(self,1));
01376 if (RB_TYPE_P(r, T_FLOAT)) {
01377 b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
01378 }
01379 else if (RB_TYPE_P(r, T_RATIONAL)) {
01380 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
01381 }
01382 else {
01383 b = GetVpValue(r,0);
01384 }
01385
01386 if(!b) return DoSomeOne(self,r,rb_intern("remainder"));
01387 SAVE(b);
01388
01389 mx =(a->MaxPrec + b->MaxPrec) *VpBaseFig();
01390 GUARD_OBJ(c ,VpCreateRbObject(mx, "0"));
01391 GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
01392 GUARD_OBJ(rr ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
01393 GUARD_OBJ(ff ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
01394
01395 VpDivd(c, res, a, b);
01396
01397 mx = c->Prec *(VpBaseFig() + 1);
01398
01399 GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
01400 GUARD_OBJ(f,VpCreateRbObject(mx, "0"));
01401
01402 VpActiveRound(d,c,VP_ROUND_DOWN,0);
01403
01404 VpFrac(f, c);
01405 VpMult(rr,f,b);
01406 VpAddSub(ff,res,rr,1);
01407
01408 *dv = d;
01409 *rv = ff;
01410 return (VALUE)0;
01411 }
01412
01413
01414
01415
01416
01417 static VALUE
01418 BigDecimal_remainder(VALUE self, VALUE r)
01419 {
01420 VALUE f;
01421 Real *d,*rv=0;
01422 f = BigDecimal_divremain(self,r,&d,&rv);
01423 if(f!=(VALUE)0) return f;
01424 return ToValue(rv);
01425 }
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446 static VALUE
01447 BigDecimal_divmod(VALUE self, VALUE r)
01448 {
01449 ENTER(5);
01450 Real *div=NULL, *mod=NULL;
01451
01452 if(BigDecimal_DoDivmod(self,r,&div,&mod)) {
01453 SAVE(div); SAVE(mod);
01454 return rb_assoc_new(ToValue(div), ToValue(mod));
01455 }
01456 return DoSomeOne(self,r,rb_intern("divmod"));
01457 }
01458
01459
01460
01461
01462 static VALUE
01463 BigDecimal_div2(int argc, VALUE *argv, VALUE self)
01464 {
01465 ENTER(5);
01466 VALUE b,n;
01467 int na = rb_scan_args(argc,argv,"11",&b,&n);
01468 if(na==1) {
01469 Real *div=NULL;
01470 Real *mod;
01471 if(BigDecimal_DoDivmod(self,b,&div,&mod)) {
01472 return BigDecimal_to_i(ToValue(div));
01473 }
01474 return DoSomeOne(self,b,rb_intern("div"));
01475 } else {
01476 SIGNED_VALUE ix = GetPositiveInt(n);
01477 if (ix == 0) return BigDecimal_div(self, b);
01478 else {
01479 Real *res=NULL;
01480 Real *av=NULL, *bv=NULL, *cv=NULL;
01481 size_t mx = (ix+VpBaseFig()*2);
01482 size_t pl = VpSetPrecLimit(0);
01483
01484 GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
01485 GUARD_OBJ(av,GetVpValue(self,1));
01486 GUARD_OBJ(bv,GetVpValue(b,1));
01487 mx = av->Prec + bv->Prec + 2;
01488 if(mx <= cv->MaxPrec) mx = cv->MaxPrec+1;
01489 GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
01490 VpDivd(cv,res,av,bv);
01491 VpSetPrecLimit(pl);
01492 VpLeftRound(cv,VpGetRoundMode(),ix);
01493 return ToValue(cv);
01494 }
01495 }
01496 }
01497
01498 static VALUE
01499 BigDecimal_add2(VALUE self, VALUE b, VALUE n)
01500 {
01501 ENTER(2);
01502 Real *cv;
01503 SIGNED_VALUE mx = GetPositiveInt(n);
01504 if (mx == 0) return BigDecimal_add(self, b);
01505 else {
01506 size_t pl = VpSetPrecLimit(0);
01507 VALUE c = BigDecimal_add(self,b);
01508 VpSetPrecLimit(pl);
01509 GUARD_OBJ(cv,GetVpValue(c,1));
01510 VpLeftRound(cv,VpGetRoundMode(),mx);
01511 return ToValue(cv);
01512 }
01513 }
01514
01515 static VALUE
01516 BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
01517 {
01518 ENTER(2);
01519 Real *cv;
01520 SIGNED_VALUE mx = GetPositiveInt(n);
01521 if (mx == 0) return BigDecimal_sub(self, b);
01522 else {
01523 size_t pl = VpSetPrecLimit(0);
01524 VALUE c = BigDecimal_sub(self,b);
01525 VpSetPrecLimit(pl);
01526 GUARD_OBJ(cv,GetVpValue(c,1));
01527 VpLeftRound(cv,VpGetRoundMode(),mx);
01528 return ToValue(cv);
01529 }
01530 }
01531
01532 static VALUE
01533 BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
01534 {
01535 ENTER(2);
01536 Real *cv;
01537 SIGNED_VALUE mx = GetPositiveInt(n);
01538 if (mx == 0) return BigDecimal_mult(self, b);
01539 else {
01540 size_t pl = VpSetPrecLimit(0);
01541 VALUE c = BigDecimal_mult(self,b);
01542 VpSetPrecLimit(pl);
01543 GUARD_OBJ(cv,GetVpValue(c,1));
01544 VpLeftRound(cv,VpGetRoundMode(),mx);
01545 return ToValue(cv);
01546 }
01547 }
01548
01549
01550
01551
01552
01553
01554
01555 static VALUE
01556 BigDecimal_abs(VALUE self)
01557 {
01558 ENTER(5);
01559 Real *c, *a;
01560 size_t mx;
01561
01562 GUARD_OBJ(a,GetVpValue(self,1));
01563 mx = a->Prec *(VpBaseFig() + 1);
01564 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01565 VpAsgn(c, a, 1);
01566 VpChangeSign(c, 1);
01567 return ToValue(c);
01568 }
01569
01570
01571
01572
01573
01574
01575
01576
01577 static VALUE
01578 BigDecimal_sqrt(VALUE self, VALUE nFig)
01579 {
01580 ENTER(5);
01581 Real *c, *a;
01582 size_t mx, n;
01583
01584 GUARD_OBJ(a,GetVpValue(self,1));
01585 mx = a->Prec *(VpBaseFig() + 1);
01586
01587 n = GetPositiveInt(nFig) + VpDblFig() + 1;
01588 if(mx <= n) mx = n;
01589 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01590 VpSqrt(c, a);
01591 return ToValue(c);
01592 }
01593
01594
01595
01596 static VALUE
01597 BigDecimal_fix(VALUE self)
01598 {
01599 ENTER(5);
01600 Real *c, *a;
01601 size_t mx;
01602
01603 GUARD_OBJ(a,GetVpValue(self,1));
01604 mx = a->Prec *(VpBaseFig() + 1);
01605 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01606 VpActiveRound(c,a,VP_ROUND_DOWN,0);
01607 return ToValue(c);
01608 }
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630 static VALUE
01631 BigDecimal_round(int argc, VALUE *argv, VALUE self)
01632 {
01633 ENTER(5);
01634 Real *c, *a;
01635 int iLoc = 0;
01636 VALUE vLoc;
01637 VALUE vRound;
01638 size_t mx, pl;
01639
01640 unsigned short sw = VpGetRoundMode();
01641
01642 switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
01643 case 0:
01644 iLoc = 0;
01645 break;
01646 case 1:
01647 Check_Type(vLoc, T_FIXNUM);
01648 iLoc = FIX2INT(vLoc);
01649 break;
01650 case 2:
01651 Check_Type(vLoc, T_FIXNUM);
01652 iLoc = FIX2INT(vLoc);
01653 sw = check_rounding_mode(vRound);
01654 break;
01655 }
01656
01657 pl = VpSetPrecLimit(0);
01658 GUARD_OBJ(a,GetVpValue(self,1));
01659 mx = a->Prec *(VpBaseFig() + 1);
01660 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01661 VpSetPrecLimit(pl);
01662 VpActiveRound(c,a,sw,iLoc);
01663 if (argc == 0) {
01664 return BigDecimal_to_i(ToValue(c));
01665 }
01666 return ToValue(c);
01667 }
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686 static VALUE
01687 BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
01688 {
01689 ENTER(5);
01690 Real *c, *a;
01691 int iLoc;
01692 VALUE vLoc;
01693 size_t mx, pl = VpSetPrecLimit(0);
01694
01695 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
01696 iLoc = 0;
01697 } else {
01698 Check_Type(vLoc, T_FIXNUM);
01699 iLoc = FIX2INT(vLoc);
01700 }
01701
01702 GUARD_OBJ(a,GetVpValue(self,1));
01703 mx = a->Prec *(VpBaseFig() + 1);
01704 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01705 VpSetPrecLimit(pl);
01706 VpActiveRound(c,a,VP_ROUND_DOWN,iLoc);
01707 if (argc == 0) {
01708 return BigDecimal_to_i(ToValue(c));
01709 }
01710 return ToValue(c);
01711 }
01712
01713
01714
01715 static VALUE
01716 BigDecimal_frac(VALUE self)
01717 {
01718 ENTER(5);
01719 Real *c, *a;
01720 size_t mx;
01721
01722 GUARD_OBJ(a,GetVpValue(self,1));
01723 mx = a->Prec *(VpBaseFig() + 1);
01724 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01725 VpFrac(c, a);
01726 return ToValue(c);
01727 }
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746 static VALUE
01747 BigDecimal_floor(int argc, VALUE *argv, VALUE self)
01748 {
01749 ENTER(5);
01750 Real *c, *a;
01751 int iLoc;
01752 VALUE vLoc;
01753 size_t mx, pl = VpSetPrecLimit(0);
01754
01755 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
01756 iLoc = 0;
01757 } else {
01758 Check_Type(vLoc, T_FIXNUM);
01759 iLoc = FIX2INT(vLoc);
01760 }
01761
01762 GUARD_OBJ(a,GetVpValue(self,1));
01763 mx = a->Prec *(VpBaseFig() + 1);
01764 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01765 VpSetPrecLimit(pl);
01766 VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
01767 #ifdef BIGDECIMAL_DEBUG
01768 VPrint(stderr, "floor: c=%\n", c);
01769 #endif
01770 if (argc == 0) {
01771 return BigDecimal_to_i(ToValue(c));
01772 }
01773 return ToValue(c);
01774 }
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793 static VALUE
01794 BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
01795 {
01796 ENTER(5);
01797 Real *c, *a;
01798 int iLoc;
01799 VALUE vLoc;
01800 size_t mx, pl = VpSetPrecLimit(0);
01801
01802 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
01803 iLoc = 0;
01804 } else {
01805 Check_Type(vLoc, T_FIXNUM);
01806 iLoc = FIX2INT(vLoc);
01807 }
01808
01809 GUARD_OBJ(a,GetVpValue(self,1));
01810 mx = a->Prec *(VpBaseFig() + 1);
01811 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
01812 VpSetPrecLimit(pl);
01813 VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
01814 if (argc == 0) {
01815 return BigDecimal_to_i(ToValue(c));
01816 }
01817 return ToValue(c);
01818 }
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853 static VALUE
01854 BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
01855 {
01856 ENTER(5);
01857 int fmt = 0;
01858 int fPlus = 0;
01859 Real *vp;
01860 volatile VALUE str;
01861 char *psz;
01862 char ch;
01863 size_t nc, mc = 0;
01864 VALUE f;
01865
01866 GUARD_OBJ(vp,GetVpValue(self,1));
01867
01868 if (rb_scan_args(argc,argv,"01",&f)==1) {
01869 if (RB_TYPE_P(f, T_STRING)) {
01870 SafeStringValue(f);
01871 psz = RSTRING_PTR(f);
01872 if (*psz == ' ') {
01873 fPlus = 1;
01874 psz++;
01875 }
01876 else if (*psz == '+') {
01877 fPlus = 2;
01878 psz++;
01879 }
01880 while ((ch = *psz++) != 0) {
01881 if (ISSPACE(ch)) {
01882 continue;
01883 }
01884 if (!ISDIGIT(ch)) {
01885 if (ch == 'F' || ch == 'f') {
01886 fmt = 1;
01887 }
01888 break;
01889 }
01890 mc = mc * 10 + ch - '0';
01891 }
01892 }
01893 else {
01894 mc = (size_t)GetPositiveInt(f);
01895 }
01896 }
01897 if (fmt) {
01898 nc = VpNumOfChars(vp, "F");
01899 }
01900 else {
01901 nc = VpNumOfChars(vp, "E");
01902 }
01903 if (mc > 0) {
01904 nc += (nc + mc - 1) / mc + 1;
01905 }
01906
01907 str = rb_str_new(0, nc);
01908 psz = RSTRING_PTR(str);
01909
01910 if (fmt) {
01911 VpToFString(vp, psz, mc, fPlus);
01912 }
01913 else {
01914 VpToString (vp, psz, mc, fPlus);
01915 }
01916 rb_str_resize(str, strlen(psz));
01917 return str;
01918 }
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944 static VALUE
01945 BigDecimal_split(VALUE self)
01946 {
01947 ENTER(5);
01948 Real *vp;
01949 VALUE obj,str;
01950 ssize_t e, s;
01951 char *psz1;
01952
01953 GUARD_OBJ(vp,GetVpValue(self,1));
01954 str = rb_str_new(0, VpNumOfChars(vp,"E"));
01955 psz1 = RSTRING_PTR(str);
01956 VpSzMantissa(vp,psz1);
01957 s = 1;
01958 if(psz1[0]=='-') {
01959 size_t len = strlen(psz1+1);
01960
01961 memmove(psz1, psz1+1, len);
01962 psz1[len] = '\0';
01963 s = -1;
01964 }
01965 if(psz1[0]=='N') s=0;
01966 e = VpExponent10(vp);
01967 obj = rb_ary_new2(4);
01968 rb_ary_push(obj, INT2FIX(s));
01969 rb_ary_push(obj, str);
01970 rb_str_resize(str, strlen(psz1));
01971 rb_ary_push(obj, INT2FIX(10));
01972 rb_ary_push(obj, INT2NUM(e));
01973 return obj;
01974 }
01975
01976
01977
01978
01979
01980
01981 static VALUE
01982 BigDecimal_exponent(VALUE self)
01983 {
01984 ssize_t e = VpExponent10(GetVpValue(self, 1));
01985 return INT2NUM(e);
01986 }
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998 static VALUE
01999 BigDecimal_inspect(VALUE self)
02000 {
02001 ENTER(5);
02002 Real *vp;
02003 volatile VALUE obj;
02004 size_t nc;
02005 char *psz, *tmp;
02006
02007 GUARD_OBJ(vp,GetVpValue(self,1));
02008 nc = VpNumOfChars(vp,"E");
02009 nc +=(nc + 9) / 10;
02010
02011 obj = rb_str_new(0, nc+256);
02012 psz = RSTRING_PTR(obj);
02013 sprintf(psz,"#<BigDecimal:%"PRIxVALUE",'",self);
02014 tmp = psz + strlen(psz);
02015 VpToString(vp, tmp, 10, 0);
02016 tmp += strlen(tmp);
02017 sprintf(tmp, "',%"PRIuSIZE"(%"PRIuSIZE")>", VpPrec(vp)*VpBaseFig(), VpMaxPrec(vp)*VpBaseFig());
02018 rb_str_resize(obj, strlen(psz));
02019 return obj;
02020 }
02021
02022 static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
02023 static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
02024
02025 #define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
02026 #define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
02027
02028 inline static int
02029 is_integer(VALUE x)
02030 {
02031 return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
02032 }
02033
02034 inline static int
02035 is_negative(VALUE x)
02036 {
02037 if (FIXNUM_P(x)) {
02038 return FIX2LONG(x) < 0;
02039 }
02040 else if (RB_TYPE_P(x, T_BIGNUM)) {
02041 return RBIGNUM_NEGATIVE_P(x);
02042 }
02043 else if (RB_TYPE_P(x, T_FLOAT)) {
02044 return RFLOAT_VALUE(x) < 0.0;
02045 }
02046 return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
02047 }
02048
02049 #define is_positive(x) (!is_negative(x))
02050
02051 inline static int
02052 is_zero(VALUE x)
02053 {
02054 VALUE num;
02055
02056 switch (TYPE(x)) {
02057 case T_FIXNUM:
02058 return FIX2LONG(x) == 0;
02059
02060 case T_BIGNUM:
02061 return Qfalse;
02062
02063 case T_RATIONAL:
02064 num = RRATIONAL(x)->num;
02065 return FIXNUM_P(num) && FIX2LONG(num) == 0;
02066
02067 default:
02068 break;
02069 }
02070
02071 return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
02072 }
02073
02074 inline static int
02075 is_one(VALUE x)
02076 {
02077 VALUE num, den;
02078
02079 switch (TYPE(x)) {
02080 case T_FIXNUM:
02081 return FIX2LONG(x) == 1;
02082
02083 case T_BIGNUM:
02084 return Qfalse;
02085
02086 case T_RATIONAL:
02087 num = RRATIONAL(x)->num;
02088 den = RRATIONAL(x)->den;
02089 return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
02090 FIXNUM_P(num) && FIX2LONG(num) == 1;
02091
02092 default:
02093 break;
02094 }
02095
02096 return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
02097 }
02098
02099 inline static int
02100 is_even(VALUE x)
02101 {
02102 switch (TYPE(x)) {
02103 case T_FIXNUM:
02104 return (FIX2LONG(x) % 2) == 0;
02105
02106 case T_BIGNUM:
02107 return (RBIGNUM_DIGITS(x)[0] % 2) == 0;
02108
02109 default:
02110 break;
02111 }
02112
02113 return 0;
02114 }
02115
02116 static VALUE
02117 rmpd_power_by_big_decimal(Real const* x, Real const* exp, ssize_t const n)
02118 {
02119 VALUE log_x, multiplied, y;
02120 volatile VALUE obj = exp->obj;
02121
02122 if (VpIsZero(exp)) {
02123 return ToValue(VpCreateRbObject(n, "1"));
02124 }
02125
02126 log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
02127 multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
02128 y = BigMath_exp(multiplied, SSIZET2NUM(n));
02129 RB_GC_GUARD(obj);
02130
02131 return y;
02132 }
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144 static VALUE
02145 BigDecimal_power(int argc, VALUE*argv, VALUE self)
02146 {
02147 ENTER(5);
02148 VALUE vexp, prec;
02149 Real* exp = NULL;
02150 Real *x, *y;
02151 ssize_t mp, ma, n;
02152 SIGNED_VALUE int_exp;
02153 double d;
02154
02155 rb_scan_args(argc, argv, "11", &vexp, &prec);
02156
02157 GUARD_OBJ(x, GetVpValue(self, 1));
02158 n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
02159
02160 if (VpIsNaN(x)) {
02161 y = VpCreateRbObject(n, "0#");
02162 RB_GC_GUARD(y->obj);
02163 VpSetNaN(y);
02164 return ToValue(y);
02165 }
02166
02167 retry:
02168 switch (TYPE(vexp)) {
02169 case T_FIXNUM:
02170 break;
02171
02172 case T_BIGNUM:
02173 break;
02174
02175 case T_FLOAT:
02176 d = RFLOAT_VALUE(vexp);
02177 if (d == round(d)) {
02178 vexp = LL2NUM((LONG_LONG)round(d));
02179 goto retry;
02180 }
02181 exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1);
02182 break;
02183
02184 case T_RATIONAL:
02185 if (is_zero(RRATIONAL(vexp)->num)) {
02186 if (is_positive(vexp)) {
02187 vexp = INT2FIX(0);
02188 goto retry;
02189 }
02190 }
02191 else if (is_one(RRATIONAL(vexp)->den)) {
02192 vexp = RRATIONAL(vexp)->num;
02193 goto retry;
02194 }
02195 exp = GetVpValueWithPrec(vexp, n, 1);
02196 break;
02197
02198 case T_DATA:
02199 if (is_kind_of_BigDecimal(vexp)) {
02200 VALUE zero = INT2FIX(0);
02201 VALUE rounded = BigDecimal_round(1, &zero, vexp);
02202 if (RTEST(BigDecimal_eq(vexp, rounded))) {
02203 vexp = BigDecimal_to_i(vexp);
02204 goto retry;
02205 }
02206 exp = DATA_PTR(vexp);
02207 break;
02208 }
02209
02210 default:
02211 rb_raise(rb_eTypeError,
02212 "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
02213 RB_OBJ_CLASSNAME(vexp));
02214 }
02215
02216 if (VpIsZero(x)) {
02217 if (is_negative(vexp)) {
02218 y = VpCreateRbObject(n, "#0");
02219 RB_GC_GUARD(y->obj);
02220 if (VpGetSign(x) < 0) {
02221 if (is_integer(vexp)) {
02222 if (is_even(vexp)) {
02223
02224 VpSetPosInf(y);
02225 }
02226 else {
02227
02228 VpSetNegInf(y);
02229 }
02230 }
02231 else {
02232
02233 VpSetPosInf(y);
02234 }
02235 }
02236 else {
02237
02238 VpSetPosInf(y);
02239 }
02240 return ToValue(y);
02241 }
02242 else if (is_zero(vexp)) {
02243 return ToValue(VpCreateRbObject(n, "1"));
02244 }
02245 else {
02246 return ToValue(VpCreateRbObject(n, "0"));
02247 }
02248 }
02249
02250 if (is_zero(vexp)) {
02251 return ToValue(VpCreateRbObject(n, "1"));
02252 }
02253 else if (is_one(vexp)) {
02254 return self;
02255 }
02256
02257 if (VpIsInf(x)) {
02258 if (is_negative(vexp)) {
02259 if (VpGetSign(x) < 0) {
02260 if (is_integer(vexp)) {
02261 if (is_even(vexp)) {
02262
02263 return ToValue(VpCreateRbObject(n, "0"));
02264 }
02265 else {
02266
02267 return ToValue(VpCreateRbObject(n, "-0"));
02268 }
02269 }
02270 else {
02271
02272 return ToValue(VpCreateRbObject(n, "-0"));
02273 }
02274 }
02275 else {
02276 return ToValue(VpCreateRbObject(n, "0"));
02277 }
02278 }
02279 else {
02280 y = VpCreateRbObject(n, "0#");
02281 if (VpGetSign(x) < 0) {
02282 if (is_integer(vexp)) {
02283 if (is_even(vexp)) {
02284 VpSetPosInf(y);
02285 }
02286 else {
02287 VpSetNegInf(y);
02288 }
02289 }
02290 else {
02291
02292 rb_raise(rb_eMathDomainError,
02293 "a non-integral exponent for a negative base");
02294 }
02295 }
02296 else {
02297 VpSetPosInf(y);
02298 }
02299 return ToValue(y);
02300 }
02301 }
02302
02303 if (exp != NULL) {
02304 return rmpd_power_by_big_decimal(x, exp, n);
02305 }
02306 else if (RB_TYPE_P(vexp, T_BIGNUM)) {
02307 VALUE abs_value = BigDecimal_abs(self);
02308 if (is_one(abs_value)) {
02309 return ToValue(VpCreateRbObject(n, "1"));
02310 }
02311 else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
02312 if (is_negative(vexp)) {
02313 y = VpCreateRbObject(n, "0#");
02314 if (is_even(vexp)) {
02315 VpSetInf(y, VpGetSign(x));
02316 }
02317 else {
02318 VpSetInf(y, -VpGetSign(x));
02319 }
02320 return ToValue(y);
02321 }
02322 else if (VpGetSign(x) < 0 && is_even(vexp)) {
02323 return ToValue(VpCreateRbObject(n, "-0"));
02324 }
02325 else {
02326 return ToValue(VpCreateRbObject(n, "0"));
02327 }
02328 }
02329 else {
02330 if (is_positive(vexp)) {
02331 y = VpCreateRbObject(n, "0#");
02332 if (is_even(vexp)) {
02333 VpSetInf(y, VpGetSign(x));
02334 }
02335 else {
02336 VpSetInf(y, -VpGetSign(x));
02337 }
02338 return ToValue(y);
02339 }
02340 else if (VpGetSign(x) < 0 && is_even(vexp)) {
02341 return ToValue(VpCreateRbObject(n, "-0"));
02342 }
02343 else {
02344 return ToValue(VpCreateRbObject(n, "0"));
02345 }
02346 }
02347 }
02348
02349 int_exp = FIX2INT(vexp);
02350 ma = int_exp;
02351 if (ma < 0) ma = -ma;
02352 if (ma == 0) ma = 1;
02353
02354 if (VpIsDef(x)) {
02355 mp = x->Prec * (VpBaseFig() + 1);
02356 GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
02357 }
02358 else {
02359 GUARD_OBJ(y, VpCreateRbObject(1, "0"));
02360 }
02361 VpPower(y, x, int_exp);
02362 return ToValue(y);
02363 }
02364
02365
02366
02367
02368
02369
02370 static VALUE
02371 BigDecimal_power_op(VALUE self, VALUE exp)
02372 {
02373 return BigDecimal_power(1, &exp, self);
02374 }
02375
02376 static VALUE
02377 BigDecimal_s_allocate(VALUE klass)
02378 {
02379 return VpNewRbClass(0, NULL, klass)->obj;
02380 }
02381
02382 static Real *BigDecimal_new(int argc, VALUE *argv);
02383
02384
02385
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398
02399
02400
02401
02402 static VALUE
02403 BigDecimal_initialize(int argc, VALUE *argv, VALUE self)
02404 {
02405 ENTER(1);
02406 Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
02407 Real *x;
02408
02409 GUARD_OBJ(x, BigDecimal_new(argc, argv));
02410 if (ToValue(x)) {
02411 pv = VpCopy(pv, x);
02412 }
02413 else {
02414 VpFree(pv);
02415 pv = x;
02416 }
02417 DATA_PTR(self) = pv;
02418 pv->obj = self;
02419 return self;
02420 }
02421
02422
02423
02424
02425
02426 static VALUE
02427 BigDecimal_initialize_copy(VALUE self, VALUE other)
02428 {
02429 Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
02430 Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
02431
02432 if (self != other) {
02433 DATA_PTR(self) = VpCopy(pv, x);
02434 }
02435 return self;
02436 }
02437
02438 static Real *
02439 BigDecimal_new(int argc, VALUE *argv)
02440 {
02441 size_t mf;
02442 VALUE nFig;
02443 VALUE iniValue;
02444
02445 if (rb_scan_args(argc, argv, "11", &iniValue, &nFig) == 1) {
02446 mf = 0;
02447 }
02448 else {
02449 mf = GetPositiveInt(nFig);
02450 }
02451
02452 switch (TYPE(iniValue)) {
02453 case T_DATA:
02454 if (is_kind_of_BigDecimal(iniValue)) {
02455 return DATA_PTR(iniValue);
02456 }
02457 break;
02458
02459 case T_FIXNUM:
02460
02461 case T_BIGNUM:
02462 return GetVpValue(iniValue, 1);
02463
02464 case T_FLOAT:
02465 if (mf > DBL_DIG+1) {
02466 rb_raise(rb_eArgError, "precision too large.");
02467 }
02468
02469 case T_RATIONAL:
02470 if (NIL_P(nFig)) {
02471 rb_raise(rb_eArgError,
02472 "can't omit precision for a %"PRIsVALUE".",
02473 RB_OBJ_CLASSNAME(iniValue));
02474 }
02475 return GetVpValueWithPrec(iniValue, mf, 1);
02476
02477 case T_STRING:
02478
02479 default:
02480 break;
02481 }
02482 StringValueCStr(iniValue);
02483 return VpAlloc(mf, RSTRING_PTR(iniValue));
02484 }
02485
02486 static VALUE
02487 BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
02488 {
02489 ENTER(1);
02490 Real *pv;
02491
02492 GUARD_OBJ(pv, BigDecimal_new(argc, argv));
02493 if (ToValue(pv)) pv = VpCopy(NULL, pv);
02494 pv->obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, pv);
02495 return pv->obj;
02496 }
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510 static VALUE
02511 BigDecimal_limit(int argc, VALUE *argv, VALUE self)
02512 {
02513 VALUE nFig;
02514 VALUE nCur = INT2NUM(VpGetPrecLimit());
02515
02516 if(rb_scan_args(argc,argv,"01",&nFig)==1) {
02517 int nf;
02518 if(nFig==Qnil) return nCur;
02519 Check_Type(nFig, T_FIXNUM);
02520 nf = FIX2INT(nFig);
02521 if(nf<0) {
02522 rb_raise(rb_eArgError, "argument must be positive");
02523 }
02524 VpSetPrecLimit(nf);
02525 }
02526 return nCur;
02527 }
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545 static VALUE
02546 BigDecimal_sign(VALUE self)
02547 {
02548 int s = GetVpValue(self,1)->sign;
02549 return INT2FIX(s);
02550 }
02551
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570 static VALUE
02571 BigDecimal_save_exception_mode(VALUE self)
02572 {
02573 unsigned short const exception_mode = VpGetException();
02574 int state;
02575 VALUE ret = rb_protect(rb_yield, Qnil, &state);
02576 VpSetException(exception_mode);
02577 if (state) rb_jump_tag(state);
02578 return ret;
02579 }
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595 static VALUE
02596 BigDecimal_save_rounding_mode(VALUE self)
02597 {
02598 unsigned short const round_mode = VpGetRoundMode();
02599 int state;
02600 VALUE ret = rb_protect(rb_yield, Qnil, &state);
02601 VpSetRoundMode(round_mode);
02602 if (state) rb_jump_tag(state);
02603 return ret;
02604 }
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620 static VALUE
02621 BigDecimal_save_limit(VALUE self)
02622 {
02623 size_t const limit = VpGetPrecLimit();
02624 int state;
02625 VALUE ret = rb_protect(rb_yield, Qnil, &state);
02626 VpSetPrecLimit(limit);
02627 if (state) rb_jump_tag(state);
02628 return ret;
02629 }
02630
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641 static VALUE
02642 BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
02643 {
02644 ssize_t prec, n, i;
02645 Real* vx = NULL;
02646 VALUE one, d, x1, y, z;
02647 int negative = 0;
02648 int infinite = 0;
02649 int nan = 0;
02650 double flo;
02651
02652 prec = NUM2SSIZET(vprec);
02653 if (prec <= 0) {
02654 rb_raise(rb_eArgError, "Zero or negative precision for exp");
02655 }
02656
02657
02658
02659 switch (TYPE(x)) {
02660 case T_DATA:
02661 if (!is_kind_of_BigDecimal(x)) break;
02662 vx = DATA_PTR(x);
02663 negative = VpGetSign(vx) < 0;
02664 infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
02665 nan = VpIsNaN(vx);
02666 break;
02667
02668 case T_FIXNUM:
02669
02670 case T_BIGNUM:
02671 vx = GetVpValue(x, 0);
02672 break;
02673
02674 case T_FLOAT:
02675 flo = RFLOAT_VALUE(x);
02676 negative = flo < 0;
02677 infinite = isinf(flo);
02678 nan = isnan(flo);
02679 if (!infinite && !nan) {
02680 vx = GetVpValueWithPrec(x, DBL_DIG+1, 0);
02681 }
02682 break;
02683
02684 case T_RATIONAL:
02685 vx = GetVpValueWithPrec(x, prec, 0);
02686 break;
02687
02688 default:
02689 break;
02690 }
02691 if (infinite) {
02692 if (negative) {
02693 return ToValue(GetVpValueWithPrec(INT2NUM(0), prec, 1));
02694 }
02695 else {
02696 Real* vy;
02697 vy = VpCreateRbObject(prec, "#0");
02698 RB_GC_GUARD(vy->obj);
02699 VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
02700 return ToValue(vy);
02701 }
02702 }
02703 else if (nan) {
02704 Real* vy;
02705 vy = VpCreateRbObject(prec, "#0");
02706 RB_GC_GUARD(vy->obj);
02707 VpSetNaN(vy);
02708 return ToValue(vy);
02709 }
02710 else if (vx == NULL) {
02711 cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
02712 }
02713 x = RB_GC_GUARD(vx->obj);
02714
02715 n = prec + rmpd_double_figures();
02716 negative = VpGetSign(vx) < 0;
02717 if (negative) {
02718 VpSetSign(vx, 1);
02719 }
02720
02721 RB_GC_GUARD(one) = ToValue(VpCreateRbObject(1, "1"));
02722 RB_GC_GUARD(x1) = one;
02723 RB_GC_GUARD(y) = one;
02724 RB_GC_GUARD(d) = y;
02725 RB_GC_GUARD(z) = one;
02726 i = 0;
02727
02728 while (!VpIsZero((Real*)DATA_PTR(d))) {
02729 VALUE argv[2];
02730 SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
02731 SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
02732 ssize_t m = n - vabs(ey - ed);
02733 if (m <= 0) {
02734 break;
02735 }
02736 else if ((size_t)m < rmpd_double_figures()) {
02737 m = rmpd_double_figures();
02738 }
02739
02740 x1 = BigDecimal_mult2(x1, x, SSIZET2NUM(n));
02741 ++i;
02742 z = BigDecimal_mult(z, SSIZET2NUM(i));
02743 argv[0] = z;
02744 argv[1] = SSIZET2NUM(m);
02745 d = BigDecimal_div2(2, argv, x1);
02746 y = BigDecimal_add(y, d);
02747 }
02748
02749 if (negative) {
02750 VALUE argv[2];
02751 argv[0] = y;
02752 argv[1] = vprec;
02753 return BigDecimal_div2(2, argv, one);
02754 }
02755 else {
02756 vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
02757 return BigDecimal_round(1, &vprec, y);
02758 }
02759 }
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773 static VALUE
02774 BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
02775 {
02776 ssize_t prec, n, i;
02777 SIGNED_VALUE expo;
02778 Real* vx = NULL;
02779 VALUE argv[2], vn, one, two, w, x2, y, d;
02780 int zero = 0;
02781 int negative = 0;
02782 int infinite = 0;
02783 int nan = 0;
02784 double flo;
02785 long fix;
02786
02787 if (!is_integer(vprec)) {
02788 rb_raise(rb_eArgError, "precision must be an Integer");
02789 }
02790
02791 prec = NUM2SSIZET(vprec);
02792 if (prec <= 0) {
02793 rb_raise(rb_eArgError, "Zero or negative precision for exp");
02794 }
02795
02796
02797
02798 switch (TYPE(x)) {
02799 case T_DATA:
02800 if (!is_kind_of_BigDecimal(x)) break;
02801 vx = DATA_PTR(x);
02802 zero = VpIsZero(vx);
02803 negative = VpGetSign(vx) < 0;
02804 infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
02805 nan = VpIsNaN(vx);
02806 break;
02807
02808 case T_FIXNUM:
02809 fix = FIX2LONG(x);
02810 zero = fix == 0;
02811 negative = fix < 0;
02812 goto get_vp_value;
02813
02814 case T_BIGNUM:
02815 zero = RBIGNUM_ZERO_P(x);
02816 negative = RBIGNUM_NEGATIVE_P(x);
02817 get_vp_value:
02818 if (zero || negative) break;
02819 vx = GetVpValue(x, 0);
02820 break;
02821
02822 case T_FLOAT:
02823 flo = RFLOAT_VALUE(x);
02824 zero = flo == 0;
02825 negative = flo < 0;
02826 infinite = isinf(flo);
02827 nan = isnan(flo);
02828 if (!zero && !negative && !infinite && !nan) {
02829 vx = GetVpValueWithPrec(x, DBL_DIG+1, 1);
02830 }
02831 break;
02832
02833 case T_RATIONAL:
02834 zero = RRATIONAL_ZERO_P(x);
02835 negative = RRATIONAL_NEGATIVE_P(x);
02836 if (zero || negative) break;
02837 vx = GetVpValueWithPrec(x, prec, 1);
02838 break;
02839
02840 case T_COMPLEX:
02841 rb_raise(rb_eMathDomainError,
02842 "Complex argument for BigMath.log");
02843
02844 default:
02845 break;
02846 }
02847 if (infinite && !negative) {
02848 Real* vy;
02849 vy = VpCreateRbObject(prec, "#0");
02850 RB_GC_GUARD(vy->obj);
02851 VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
02852 return ToValue(vy);
02853 }
02854 else if (nan) {
02855 Real* vy;
02856 vy = VpCreateRbObject(prec, "#0");
02857 RB_GC_GUARD(vy->obj);
02858 VpSetNaN(vy);
02859 return ToValue(vy);
02860 }
02861 else if (zero || negative) {
02862 rb_raise(rb_eMathDomainError,
02863 "Zero or negative argument for log");
02864 }
02865 else if (vx == NULL) {
02866 cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
02867 }
02868 x = ToValue(vx);
02869
02870 RB_GC_GUARD(one) = ToValue(VpCreateRbObject(1, "1"));
02871 RB_GC_GUARD(two) = ToValue(VpCreateRbObject(1, "2"));
02872
02873 n = prec + rmpd_double_figures();
02874 RB_GC_GUARD(vn) = SSIZET2NUM(n);
02875 expo = VpExponent10(vx);
02876 if (expo < 0 || expo >= 3) {
02877 char buf[16];
02878 snprintf(buf, 16, "1E%"PRIdVALUE, -expo);
02879 x = BigDecimal_mult2(x, ToValue(VpCreateRbObject(1, buf)), vn);
02880 }
02881 else {
02882 expo = 0;
02883 }
02884 w = BigDecimal_sub(x, one);
02885 argv[0] = BigDecimal_add(x, one);
02886 argv[1] = vn;
02887 x = BigDecimal_div2(2, argv, w);
02888 RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
02889 RB_GC_GUARD(y) = x;
02890 RB_GC_GUARD(d) = y;
02891 i = 1;
02892 while (!VpIsZero((Real*)DATA_PTR(d))) {
02893 SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
02894 SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
02895 ssize_t m = n - vabs(ey - ed);
02896 if (m <= 0) {
02897 break;
02898 }
02899 else if ((size_t)m < rmpd_double_figures()) {
02900 m = rmpd_double_figures();
02901 }
02902
02903 x = BigDecimal_mult2(x2, x, vn);
02904 i += 2;
02905 argv[0] = SSIZET2NUM(i);
02906 argv[1] = SSIZET2NUM(m);
02907 d = BigDecimal_div2(2, argv, x);
02908 y = BigDecimal_add(y, d);
02909 }
02910
02911 y = BigDecimal_mult(y, two);
02912 if (expo != 0) {
02913 VALUE log10, vexpo, dy;
02914 log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
02915 vexpo = ToValue(GetVpValue(SSIZET2NUM(expo), 1));
02916 dy = BigDecimal_mult(log10, vexpo);
02917 y = BigDecimal_add(y, dy);
02918 }
02919
02920 return y;
02921 }
02922
02923
02924
02925
02926
02927
02928
02929
02930
02931
02932
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961
02962
02963
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031 void
03032 Init_bigdecimal(void)
03033 {
03034 VALUE arg;
03035
03036 id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
03037 id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode");
03038 id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit");
03039
03040
03041 VpInit(0UL);
03042
03043
03044 rb_cBigDecimal = rb_define_class("BigDecimal",rb_cNumeric);
03045 rb_define_alloc_func(rb_cBigDecimal, BigDecimal_s_allocate);
03046
03047
03048 rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
03049
03050
03051 rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
03052 rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
03053 rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
03054 rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
03055 rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);
03056
03057 rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
03058 rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
03059 rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0);
03060
03061
03062
03063
03064
03065
03066
03067
03068
03069
03070 rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
03071
03072
03073
03074
03075
03076
03077
03078 rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL));
03079
03080
03081
03082
03083
03084 rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));
03085
03086
03087
03088
03089
03090 rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY));
03091
03092
03093
03094
03095
03096 rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW));
03097
03098
03099
03100
03101
03102 rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
03103
03104
03105
03106
03107
03108 rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));
03109
03110
03111
03112
03113
03114
03115 rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));
03116
03117
03118
03119
03120 rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));
03121
03122
03123
03124
03125 rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));
03126
03127
03128
03129 rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));
03130
03131
03132
03133
03134 rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
03135
03136 rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL));
03137
03138
03139 rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));
03140
03141
03142 rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN));
03143
03144
03145 rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
03146
03147
03148 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO));
03149
03150
03151 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO",INT2FIX(VP_SIGN_NEGATIVE_ZERO));
03152
03153
03154 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE",INT2FIX(VP_SIGN_POSITIVE_FINITE));
03155
03156
03157 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE",INT2FIX(VP_SIGN_NEGATIVE_FINITE));
03158
03159
03160 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE",INT2FIX(VP_SIGN_POSITIVE_INFINITE));
03161
03162
03163 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
03164
03165 arg = rb_str_new2("+Infinity");
03166
03167 rb_define_const(rb_cBigDecimal, "INFINITY", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
03168 arg = rb_str_new2("NaN");
03169
03170 rb_define_const(rb_cBigDecimal, "NAN", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
03171
03172
03173
03174 rb_define_method(rb_cBigDecimal, "initialize", BigDecimal_initialize, -1);
03175 rb_define_method(rb_cBigDecimal, "initialize_copy", BigDecimal_initialize_copy, 1);
03176 rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
03177
03178 rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
03179 rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
03180 rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
03181 rb_define_method(rb_cBigDecimal, "div", BigDecimal_div2, -1);
03182 rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
03183 rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
03184 rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
03185 rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
03186 rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0);
03187 rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
03188 rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
03189 rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
03190 rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
03191 rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
03192 rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
03193 rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
03194 rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
03195 rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
03196 rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
03197 rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
03198 rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
03199
03200 rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
03201 rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
03202 rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
03203 rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
03204 rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
03205 rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
03206 rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
03207 rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
03208 rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
03209 rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
03210 rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
03211 rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
03212 rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
03213 rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
03214 rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
03215 rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
03216 rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
03217 rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
03218 rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
03219 rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
03220 rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
03221 rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
03222 rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
03223 rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
03224 rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0);
03225 rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
03226 rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
03227 rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
03228 rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
03229
03230
03231 rb_mBigMath = rb_define_module("BigMath");
03232 rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
03233 rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
03234
03235 id_up = rb_intern_const("up");
03236 id_down = rb_intern_const("down");
03237 id_truncate = rb_intern_const("truncate");
03238 id_half_up = rb_intern_const("half_up");
03239 id_default = rb_intern_const("default");
03240 id_half_down = rb_intern_const("half_down");
03241 id_half_even = rb_intern_const("half_even");
03242 id_banker = rb_intern_const("banker");
03243 id_ceiling = rb_intern_const("ceiling");
03244 id_ceil = rb_intern_const("ceil");
03245 id_floor = rb_intern_const("floor");
03246 id_to_r = rb_intern_const("to_r");
03247 id_eq = rb_intern_const("==");
03248 }
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259 #ifdef BIGDECIMAL_DEBUG
03260 static int gfDebug = 1;
03261 #if 0
03262 static int gfCheckVal = 1;
03263 #endif
03264 #endif
03265
03266 static Real *VpConstOne;
03267 static Real *VpPt5;
03268 #define maxnr 100UL
03269
03270
03271
03272 #define MemCmp(x,y,z) memcmp(x,y,z)
03273 #define StrCmp(x,y) strcmp(x,y)
03274
03275 static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
03276 static int AddExponent(Real *a, SIGNED_VALUE n);
03277 static BDIGIT VpAddAbs(Real *a,Real *b,Real *c);
03278 static BDIGIT VpSubAbs(Real *a,Real *b,Real *c);
03279 static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv);
03280 static int VpNmlz(Real *a);
03281 static void VpFormatSt(char *psz, size_t fFmt);
03282 static int VpRdup(Real *m, size_t ind_m);
03283
03284 #ifdef BIGDECIMAL_DEBUG
03285 static int gnAlloc=0;
03286 #endif
03287
03288 VP_EXPORT void *
03289 VpMemAlloc(size_t mb)
03290 {
03291 void *p = xmalloc(mb);
03292 if (!p) {
03293 VpException(VP_EXCEPTION_MEMORY, "failed to allocate memory", 1);
03294 }
03295 memset(p, 0, mb);
03296 #ifdef BIGDECIMAL_DEBUG
03297 gnAlloc++;
03298 #endif
03299 return p;
03300 }
03301
03302 VP_EXPORT void *
03303 VpMemRealloc(void *ptr, size_t mb)
03304 {
03305 void *p = xrealloc(ptr, mb);
03306 if (!p) {
03307 VpException(VP_EXCEPTION_MEMORY, "failed to allocate memory", 1);
03308 }
03309 return p;
03310 }
03311
03312 VP_EXPORT void
03313 VpFree(Real *pv)
03314 {
03315 if(pv != NULL) {
03316 xfree(pv);
03317 #ifdef BIGDECIMAL_DEBUG
03318 gnAlloc--;
03319 if(gnAlloc==0) {
03320 printf(" *************** All memories allocated freed ****************");
03321 getchar();
03322 }
03323 if(gnAlloc<0) {
03324 printf(" ??????????? Too many memory free calls(%d) ?????????????\n",gnAlloc);
03325 getchar();
03326 }
03327 #endif
03328 }
03329 }
03330
03331
03332
03333
03334
03335 #define rmpd_set_thread_local_exception_mode(mode) \
03336 rb_thread_local_aset( \
03337 rb_thread_current(), \
03338 id_BigDecimal_exception_mode, \
03339 INT2FIX((int)(mode)) \
03340 )
03341
03342 static unsigned short
03343 VpGetException (void)
03344 {
03345 VALUE const vmode = rb_thread_local_aref(
03346 rb_thread_current(),
03347 id_BigDecimal_exception_mode
03348 );
03349
03350 if (NIL_P(vmode)) {
03351 rmpd_set_thread_local_exception_mode(RMPD_EXCEPTION_MODE_DEFAULT);
03352 return RMPD_EXCEPTION_MODE_DEFAULT;
03353 }
03354
03355 return (unsigned short)FIX2UINT(vmode);
03356 }
03357
03358 static void
03359 VpSetException(unsigned short f)
03360 {
03361 rmpd_set_thread_local_exception_mode(f);
03362 }
03363
03364
03365
03366
03367
03368 #define rmpd_set_thread_local_precision_limit(limit) \
03369 rb_thread_local_aset( \
03370 rb_thread_current(), \
03371 id_BigDecimal_precision_limit, \
03372 SIZET2NUM(limit) \
03373 )
03374 #define RMPD_PRECISION_LIMIT_DEFAULT ((size_t)0)
03375
03376
03377 VP_EXPORT size_t
03378 VpGetPrecLimit(void)
03379 {
03380 VALUE const vlimit = rb_thread_local_aref(
03381 rb_thread_current(),
03382 id_BigDecimal_precision_limit
03383 );
03384
03385 if (NIL_P(vlimit)) {
03386 rmpd_set_thread_local_precision_limit(RMPD_PRECISION_LIMIT_DEFAULT);
03387 return RMPD_PRECISION_LIMIT_DEFAULT;
03388 }
03389
03390 return NUM2SIZET(vlimit);
03391 }
03392
03393 VP_EXPORT size_t
03394 VpSetPrecLimit(size_t n)
03395 {
03396 size_t const s = VpGetPrecLimit();
03397 rmpd_set_thread_local_precision_limit(n);
03398 return s;
03399 }
03400
03401
03402
03403
03404
03405 #define rmpd_set_thread_local_rounding_mode(mode) \
03406 rb_thread_local_aset( \
03407 rb_thread_current(), \
03408 id_BigDecimal_rounding_mode, \
03409 INT2FIX((int)(mode)) \
03410 )
03411
03412 VP_EXPORT unsigned short
03413 VpGetRoundMode(void)
03414 {
03415 VALUE const vmode = rb_thread_local_aref(
03416 rb_thread_current(),
03417 id_BigDecimal_rounding_mode
03418 );
03419
03420 if (NIL_P(vmode)) {
03421 rmpd_set_thread_local_rounding_mode(RMPD_ROUNDING_MODE_DEFAULT);
03422 return RMPD_ROUNDING_MODE_DEFAULT;
03423 }
03424
03425 return (unsigned short)FIX2INT(vmode);
03426 }
03427
03428 VP_EXPORT int
03429 VpIsRoundMode(unsigned short n)
03430 {
03431 switch (n) {
03432 case VP_ROUND_UP:
03433 case VP_ROUND_DOWN:
03434 case VP_ROUND_HALF_UP:
03435 case VP_ROUND_HALF_DOWN:
03436 case VP_ROUND_CEIL:
03437 case VP_ROUND_FLOOR:
03438 case VP_ROUND_HALF_EVEN:
03439 return 1;
03440
03441 default:
03442 return 0;
03443 }
03444 }
03445
03446 VP_EXPORT unsigned short
03447 VpSetRoundMode(unsigned short n)
03448 {
03449 if (VpIsRoundMode(n)) {
03450 rmpd_set_thread_local_rounding_mode(n);
03451 return n;
03452 }
03453
03454 return VpGetRoundMode();
03455 }
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465 volatile const double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
03466 volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
03467 static double
03468 Zero(void)
03469 {
03470 return gZero_ABCED9B1_CE73__00400511F31D;
03471 }
03472
03473 static double
03474 One(void)
03475 {
03476 return gOne_ABCED9B4_CE73__00400511F31D;
03477 }
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493 VP_EXPORT double
03494 VpGetDoubleNaN(void)
03495 {
03496 static double fNaN = 0.0;
03497 if(fNaN==0.0) fNaN = Zero()/Zero();
03498 return fNaN;
03499 }
03500
03501 VP_EXPORT double
03502 VpGetDoublePosInf(void)
03503 {
03504 static double fInf = 0.0;
03505 if(fInf==0.0) fInf = One()/Zero();
03506 return fInf;
03507 }
03508
03509 VP_EXPORT double
03510 VpGetDoubleNegInf(void)
03511 {
03512 static double fInf = 0.0;
03513 if(fInf==0.0) fInf = -(One()/Zero());
03514 return fInf;
03515 }
03516
03517 VP_EXPORT double
03518 VpGetDoubleNegZero(void)
03519 {
03520 static double nzero = 1000.0;
03521 if(nzero!=0.0) nzero = (One()/VpGetDoubleNegInf());
03522 return nzero;
03523 }
03524
03525 #if 0
03526 VP_EXPORT int
03527 VpIsNegDoubleZero(double v)
03528 {
03529 double z = VpGetDoubleNegZero();
03530 return MemCmp(&v,&z,sizeof(v))==0;
03531 }
03532 #endif
03533
03534 VP_EXPORT int
03535 VpException(unsigned short f, const char *str,int always)
03536 {
03537 VALUE exc;
03538 int fatal=0;
03539 unsigned short const exception_mode = VpGetException();
03540
03541 if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1;
03542
03543 if (always || (exception_mode & f)) {
03544 switch(f)
03545 {
03546
03547
03548
03549 case VP_EXCEPTION_ZERODIVIDE:
03550 case VP_EXCEPTION_INFINITY:
03551 case VP_EXCEPTION_NaN:
03552 case VP_EXCEPTION_UNDERFLOW:
03553 case VP_EXCEPTION_OP:
03554 exc = rb_eFloatDomainError;
03555 goto raise;
03556 case VP_EXCEPTION_MEMORY:
03557 fatal = 1;
03558 goto raise;
03559 default:
03560 fatal = 1;
03561 goto raise;
03562 }
03563 }
03564 return 0;
03565
03566 raise:
03567 if(fatal) rb_fatal("%s", str);
03568 else rb_raise(exc, "%s", str);
03569 return 0;
03570 }
03571
03572
03573
03574 static int
03575 VpIsDefOP(Real *c,Real *a,Real *b,int sw)
03576 {
03577 if(VpIsNaN(a) || VpIsNaN(b)) {
03578
03579 VpSetNaN(c);
03580 goto NaN;
03581 }
03582
03583 if(VpIsInf(a)) {
03584 if(VpIsInf(b)) {
03585 switch(sw)
03586 {
03587 case 1:
03588 if(VpGetSign(a)==VpGetSign(b)) {
03589 VpSetInf(c,VpGetSign(a));
03590 goto Inf;
03591 } else {
03592 VpSetNaN(c);
03593 goto NaN;
03594 }
03595 case 2:
03596 if(VpGetSign(a)!=VpGetSign(b)) {
03597 VpSetInf(c,VpGetSign(a));
03598 goto Inf;
03599 } else {
03600 VpSetNaN(c);
03601 goto NaN;
03602 }
03603 break;
03604 case 3:
03605 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
03606 goto Inf;
03607 break;
03608 case 4:
03609 VpSetNaN(c);
03610 goto NaN;
03611 }
03612 VpSetNaN(c);
03613 goto NaN;
03614 }
03615
03616 switch(sw)
03617 {
03618 case 1:
03619 case 2:
03620 VpSetInf(c,VpGetSign(a));
03621 break;
03622 case 3:
03623 if(VpIsZero(b)) {
03624 VpSetNaN(c);
03625 goto NaN;
03626 }
03627 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
03628 break;
03629 case 4:
03630 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
03631 }
03632 goto Inf;
03633 }
03634
03635 if(VpIsInf(b)) {
03636 switch(sw)
03637 {
03638 case 1:
03639 VpSetInf(c,VpGetSign(b));
03640 break;
03641 case 2:
03642 VpSetInf(c,-VpGetSign(b));
03643 break;
03644 case 3:
03645 if(VpIsZero(a)) {
03646 VpSetNaN(c);
03647 goto NaN;
03648 }
03649 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
03650 break;
03651 case 4:
03652 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
03653 }
03654 goto Inf;
03655 }
03656 return 1;
03657
03658 Inf:
03659 return VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
03660 NaN:
03661 return VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'",0);
03662 }
03663
03664
03665
03666
03667
03668
03669
03670
03671 VP_EXPORT size_t
03672 VpNumOfChars(Real *vp,const char *pszFmt)
03673 {
03674 SIGNED_VALUE ex;
03675 size_t nc;
03676
03677 if(vp == NULL) return BASE_FIG*2+6;
03678 if(!VpIsDef(vp)) return 32;
03679
03680 switch(*pszFmt)
03681 {
03682 case 'F':
03683 nc = BASE_FIG*(vp->Prec + 1)+2;
03684 ex = vp->exponent;
03685 if(ex < 0) {
03686 nc += BASE_FIG*(size_t)(-ex);
03687 }
03688 else {
03689 if((size_t)ex > vp->Prec) {
03690 nc += BASE_FIG*((size_t)ex - vp->Prec);
03691 }
03692 }
03693 break;
03694 case 'E':
03695 default:
03696 nc = BASE_FIG*(vp->Prec + 2)+6;
03697 }
03698 return nc;
03699 }
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715 VP_EXPORT size_t
03716 VpInit(BDIGIT BaseVal)
03717 {
03718
03719 VpGetDoubleNaN();
03720 VpGetDoublePosInf();
03721 VpGetDoubleNegInf();
03722 VpGetDoubleNegZero();
03723
03724
03725 VpConstOne = VpAlloc(1UL, "1");
03726 VpPt5 = VpAlloc(1UL, ".5");
03727
03728 #ifdef BIGDECIMAL_DEBUG
03729 gnAlloc = 0;
03730 #endif
03731
03732 #ifdef BIGDECIMAL_DEBUG
03733 if(gfDebug) {
03734 printf("VpInit: BaseVal = %lu\n", BaseVal);
03735 printf(" BASE = %lu\n", BASE);
03736 printf(" HALF_BASE = %lu\n", HALF_BASE);
03737 printf(" BASE1 = %lu\n", BASE1);
03738 printf(" BASE_FIG = %u\n", BASE_FIG);
03739 printf(" DBLE_FIG = %d\n", DBLE_FIG);
03740 }
03741 #endif
03742
03743 return rmpd_double_figures();
03744 }
03745
03746 VP_EXPORT Real *
03747 VpOne(void)
03748 {
03749 return VpConstOne;
03750 }
03751
03752
03753 static int
03754 AddExponent(Real *a, SIGNED_VALUE n)
03755 {
03756 SIGNED_VALUE e = a->exponent;
03757 SIGNED_VALUE m = e+n;
03758 SIGNED_VALUE eb, mb;
03759 if(e>0) {
03760 if(n>0) {
03761 mb = m*(SIGNED_VALUE)BASE_FIG;
03762 eb = e*(SIGNED_VALUE)BASE_FIG;
03763 if(mb<eb) goto overflow;
03764 }
03765 } else if(n<0) {
03766 mb = m*(SIGNED_VALUE)BASE_FIG;
03767 eb = e*(SIGNED_VALUE)BASE_FIG;
03768 if(mb>eb) goto underflow;
03769 }
03770 a->exponent = m;
03771 return 1;
03772
03773
03774 underflow:
03775 VpSetZero(a,VpGetSign(a));
03776 return VpException(VP_EXCEPTION_UNDERFLOW,"Exponent underflow",0);
03777
03778 overflow:
03779 VpSetInf(a,VpGetSign(a));
03780 return VpException(VP_EXCEPTION_OVERFLOW,"Exponent overflow",0);
03781 }
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791
03792
03793
03794
03795
03796 VP_EXPORT Real *
03797 VpAlloc(size_t mx, const char *szVal)
03798 {
03799 size_t i, ni, ipn, ipf, nf, ipe, ne, nalloc;
03800 char v,*psz;
03801 int sign=1;
03802 Real *vp = NULL;
03803 size_t mf = VpGetPrecLimit();
03804 VALUE buf;
03805
03806 mx = (mx + BASE_FIG - 1) / BASE_FIG + 1;
03807 if (szVal) {
03808 while (ISSPACE(*szVal)) szVal++;
03809 if (*szVal != '#') {
03810 if (mf) {
03811 mf = (mf + BASE_FIG - 1) / BASE_FIG + 2;
03812 if (mx > mf) {
03813 mx = mf;
03814 }
03815 }
03816 }
03817 else {
03818 ++szVal;
03819 }
03820 }
03821 else {
03822
03823
03824
03825 vp = VpAllocReal(mx);
03826
03827 vp->MaxPrec = mx;
03828 VpSetZero(vp,1);
03829 return vp;
03830 }
03831
03832
03833 ni = 0;
03834 buf = rb_str_tmp_new(strlen(szVal)+1);
03835 psz = RSTRING_PTR(buf);
03836 i = 0;
03837 ipn = 0;
03838 while ((psz[i]=szVal[ipn]) != 0) {
03839 if (ISDIGIT(psz[i])) ++ni;
03840 if (psz[i] == '_') {
03841 if (ni > 0) { ipn++; continue; }
03842 psz[i] = 0;
03843 break;
03844 }
03845 ++i;
03846 ++ipn;
03847 }
03848
03849 while (--i > 0) {
03850 if (ISSPACE(psz[i])) psz[i] = 0;
03851 else break;
03852 }
03853 szVal = psz;
03854
03855
03856 if (StrCmp(szVal, SZ_PINF) == 0 ||
03857 StrCmp(szVal, SZ_INF) == 0 ) {
03858 vp = VpAllocReal(1);
03859 vp->MaxPrec = 1;
03860 VpSetPosInf(vp);
03861 return vp;
03862 }
03863 if (StrCmp(szVal, SZ_NINF) == 0) {
03864 vp = VpAllocReal(1);
03865 vp->MaxPrec = 1;
03866 VpSetNegInf(vp);
03867 return vp;
03868 }
03869 if (StrCmp(szVal, SZ_NaN) == 0) {
03870 vp = VpAllocReal(1);
03871 vp->MaxPrec = 1;
03872 VpSetNaN(vp);
03873 return vp;
03874 }
03875
03876
03877 ipn = i = 0;
03878 if (szVal[i] == '-') { sign=-1; ++i; }
03879 else if (szVal[i] == '+') ++i;
03880
03881 ni = 0;
03882 while ((v = szVal[i]) != 0) {
03883 if (!ISDIGIT(v)) break;
03884 ++i;
03885 ++ni;
03886 }
03887 nf = 0;
03888 ipf = 0;
03889 ipe = 0;
03890 ne = 0;
03891 if (v) {
03892
03893 if (szVal[i] == '.') {
03894 ++i;
03895 ipf = i;
03896 while ((v = szVal[i]) != 0) {
03897 if (!ISDIGIT(v)) break;
03898 ++i;
03899 ++nf;
03900 }
03901 }
03902 ipe = 0;
03903
03904 switch (szVal[i]) {
03905 case '\0':
03906 break;
03907 case 'e': case 'E':
03908 case 'd': case 'D':
03909 ++i;
03910 ipe = i;
03911 v = szVal[i];
03912 if ((v == '-') || (v == '+')) ++i;
03913 while ((v=szVal[i]) != 0) {
03914 if (!ISDIGIT(v)) break;
03915 ++i;
03916 ++ne;
03917 }
03918 break;
03919 default:
03920 break;
03921 }
03922 }
03923 nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1;
03924
03925 if (mx <= 0) mx = 1;
03926 nalloc = Max(nalloc, mx);
03927 mx = nalloc;
03928 vp = VpAllocReal(mx);
03929
03930 vp->MaxPrec = mx;
03931 VpSetZero(vp, sign);
03932 VpCtoV(vp, &szVal[ipn], ni, &szVal[ipf], nf, &szVal[ipe], ne);
03933 rb_str_resize(buf, 0);
03934 return vp;
03935 }
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949 VP_EXPORT size_t
03950 VpAsgn(Real *c, Real *a, int isw)
03951 {
03952 size_t n;
03953 if(VpIsNaN(a)) {
03954 VpSetNaN(c);
03955 return 0;
03956 }
03957 if(VpIsInf(a)) {
03958 VpSetInf(c,isw*VpGetSign(a));
03959 return 0;
03960 }
03961
03962
03963 if(!VpIsZero(a)) {
03964 c->exponent = a->exponent;
03965 VpSetSign(c,(isw*VpGetSign(a)));
03966 n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec);
03967 c->Prec = n;
03968 memcpy(c->frac, a->frac, n * sizeof(BDIGIT));
03969
03970 if(isw!=10) {
03971
03972 if(c->Prec < a->Prec) {
03973 VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
03974 } else {
03975 VpLimitRound(c,0);
03976 }
03977 }
03978 } else {
03979
03980 VpSetZero(c,isw*VpGetSign(a));
03981 return 1;
03982 }
03983 return c->Prec*BASE_FIG;
03984 }
03985
03986
03987
03988
03989
03990
03991 VP_EXPORT size_t
03992 VpAddSub(Real *c, Real *a, Real *b, int operation)
03993 {
03994 short sw, isw;
03995 Real *a_ptr, *b_ptr;
03996 size_t n, na, nb, i;
03997 BDIGIT mrv;
03998
03999 #ifdef BIGDECIMAL_DEBUG
04000 if(gfDebug) {
04001 VPrint(stdout, "VpAddSub(enter) a=% \n", a);
04002 VPrint(stdout, " b=% \n", b);
04003 printf(" operation=%d\n", operation);
04004 }
04005 #endif
04006
04007 if(!VpIsDefOP(c,a,b,(operation>0)?1:2)) return 0;
04008
04009
04010 if(VpIsZero(a)) {
04011
04012 if(!VpIsZero(b)) {
04013 VpAsgn(c, b, operation);
04014 } else {
04015
04016 if(VpGetSign(a)<0 && operation*VpGetSign(b)<0) {
04017
04018 VpSetZero(c,-1);
04019 } else {
04020 VpSetZero(c,1);
04021 }
04022 return 1;
04023 }
04024 return c->Prec*BASE_FIG;
04025 }
04026 if(VpIsZero(b)) {
04027
04028 VpAsgn(c, a, 1);
04029 return c->Prec*BASE_FIG;
04030 }
04031
04032 if(operation < 0) sw = -1;
04033 else sw = 1;
04034
04035
04036 if(a->exponent > b->exponent) {
04037 a_ptr = a;
04038 b_ptr = b;
04039 }
04040 else if(a->exponent < b->exponent) {
04041 a_ptr = b;
04042 b_ptr = a;
04043 }
04044 else {
04045
04046
04047 na = a->Prec;
04048 nb = b->Prec;
04049 n = Min(na, nb);
04050 for(i=0;i < n; ++i) {
04051 if(a->frac[i] > b->frac[i]) {
04052 a_ptr = a;
04053 b_ptr = b;
04054 goto end_if;
04055 } else if(a->frac[i] < b->frac[i]) {
04056 a_ptr = b;
04057 b_ptr = a;
04058 goto end_if;
04059 }
04060 }
04061 if(na > nb) {
04062 a_ptr = a;
04063 b_ptr = b;
04064 goto end_if;
04065 } else if(na < nb) {
04066 a_ptr = b;
04067 b_ptr = a;
04068 goto end_if;
04069 }
04070
04071 if(VpGetSign(a) + sw *VpGetSign(b) == 0) {
04072 VpSetZero(c,1);
04073 return c->Prec*BASE_FIG;
04074 }
04075 a_ptr = a;
04076 b_ptr = b;
04077 }
04078
04079 end_if:
04080 isw = VpGetSign(a) + sw *VpGetSign(b);
04081
04082
04083
04084
04085
04086
04087
04088 if(isw) {
04089 VpSetSign(c, 1);
04090 mrv = VpAddAbs(a_ptr, b_ptr, c);
04091 VpSetSign(c, isw / 2);
04092 } else {
04093 VpSetSign(c, 1);
04094 mrv = VpSubAbs(a_ptr, b_ptr, c);
04095 if(a_ptr == a) {
04096 VpSetSign(c,VpGetSign(a));
04097 } else {
04098 VpSetSign(c,VpGetSign(a_ptr) * sw);
04099 }
04100 }
04101 VpInternalRound(c,0,(c->Prec>0)?c->frac[c->Prec-1]:0,mrv);
04102
04103 #ifdef BIGDECIMAL_DEBUG
04104 if(gfDebug) {
04105 VPrint(stdout, "VpAddSub(result) c=% \n", c);
04106 VPrint(stdout, " a=% \n", a);
04107 VPrint(stdout, " b=% \n", b);
04108 printf(" operation=%d\n", operation);
04109 }
04110 #endif
04111 return c->Prec*BASE_FIG;
04112 }
04113
04114
04115
04116
04117
04118
04119 static BDIGIT
04120 VpAddAbs(Real *a, Real *b, Real *c)
04121 {
04122 size_t word_shift;
04123 size_t ap;
04124 size_t bp;
04125 size_t cp;
04126 size_t a_pos;
04127 size_t b_pos, b_pos_with_word_shift;
04128 size_t c_pos;
04129 BDIGIT av, bv, carry, mrv;
04130
04131 #ifdef BIGDECIMAL_DEBUG
04132 if(gfDebug) {
04133 VPrint(stdout, "VpAddAbs called: a = %\n", a);
04134 VPrint(stdout, " b = %\n", b);
04135 }
04136 #endif
04137
04138 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
04139 a_pos = ap;
04140 b_pos = bp;
04141 c_pos = cp;
04142 if(word_shift==(size_t)-1L) return 0;
04143 if(b_pos == (size_t)-1L) goto Assign_a;
04144
04145 mrv = av + bv;
04146
04147
04148
04149 while(b_pos + word_shift > a_pos) {
04150 --c_pos;
04151 if(b_pos > 0) {
04152 c->frac[c_pos] = b->frac[--b_pos];
04153 } else {
04154 --word_shift;
04155 c->frac[c_pos] = 0;
04156 }
04157 }
04158
04159
04160
04161 b_pos_with_word_shift = b_pos + word_shift;
04162 while(a_pos > b_pos_with_word_shift) {
04163 c->frac[--c_pos] = a->frac[--a_pos];
04164 }
04165 carry = 0;
04166
04167
04168
04169 while(b_pos > 0) {
04170 c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
04171 if(c->frac[c_pos] >= BASE) {
04172 c->frac[c_pos] -= BASE;
04173 carry = 1;
04174 } else {
04175 carry = 0;
04176 }
04177 }
04178
04179
04180
04181 while(a_pos > 0) {
04182 c->frac[--c_pos] = a->frac[--a_pos] + carry;
04183 if(c->frac[c_pos] >= BASE) {
04184 c->frac[c_pos] -= BASE;
04185 carry = 1;
04186 } else {
04187 carry = 0;
04188 }
04189 }
04190 if(c_pos) c->frac[c_pos - 1] += carry;
04191 goto Exit;
04192
04193 Assign_a:
04194 VpAsgn(c, a, 1);
04195 mrv = 0;
04196
04197 Exit:
04198
04199 #ifdef BIGDECIMAL_DEBUG
04200 if(gfDebug) {
04201 VPrint(stdout, "VpAddAbs exit: c=% \n", c);
04202 }
04203 #endif
04204 return mrv;
04205 }
04206
04207
04208
04209
04210 static BDIGIT
04211 VpSubAbs(Real *a, Real *b, Real *c)
04212 {
04213 size_t word_shift;
04214 size_t ap;
04215 size_t bp;
04216 size_t cp;
04217 size_t a_pos;
04218 size_t b_pos, b_pos_with_word_shift;
04219 size_t c_pos;
04220 BDIGIT av, bv, borrow, mrv;
04221
04222 #ifdef BIGDECIMAL_DEBUG
04223 if(gfDebug) {
04224 VPrint(stdout, "VpSubAbs called: a = %\n", a);
04225 VPrint(stdout, " b = %\n", b);
04226 }
04227 #endif
04228
04229 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
04230 a_pos = ap;
04231 b_pos = bp;
04232 c_pos = cp;
04233 if(word_shift==(size_t)-1L) return 0;
04234 if(b_pos == (size_t)-1L) goto Assign_a;
04235
04236 if(av >= bv) {
04237 mrv = av - bv;
04238 borrow = 0;
04239 } else {
04240 mrv = 0;
04241 borrow = 1;
04242 }
04243
04244
04245
04246
04247 if(b_pos + word_shift > a_pos) {
04248 while(b_pos + word_shift > a_pos) {
04249 --c_pos;
04250 if(b_pos > 0) {
04251 c->frac[c_pos] = BASE - b->frac[--b_pos] - borrow;
04252 } else {
04253 --word_shift;
04254 c->frac[c_pos] = BASE - borrow;
04255 }
04256 borrow = 1;
04257 }
04258 }
04259
04260
04261
04262 b_pos_with_word_shift = b_pos + word_shift;
04263 while(a_pos > b_pos_with_word_shift) {
04264 c->frac[--c_pos] = a->frac[--a_pos];
04265 }
04266
04267
04268
04269 while(b_pos > 0) {
04270 --c_pos;
04271 if(a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
04272 c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
04273 borrow = 1;
04274 } else {
04275 c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
04276 borrow = 0;
04277 }
04278 }
04279
04280
04281
04282 while(a_pos > 0) {
04283 --c_pos;
04284 if(a->frac[--a_pos] < borrow) {
04285 c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
04286 borrow = 1;
04287 } else {
04288 c->frac[c_pos] = a->frac[a_pos] - borrow;
04289 borrow = 0;
04290 }
04291 }
04292 if(c_pos) c->frac[c_pos - 1] -= borrow;
04293 goto Exit;
04294
04295 Assign_a:
04296 VpAsgn(c, a, 1);
04297 mrv = 0;
04298
04299 Exit:
04300 #ifdef BIGDECIMAL_DEBUG
04301 if(gfDebug) {
04302 VPrint(stdout, "VpSubAbs exit: c=% \n", c);
04303 }
04304 #endif
04305 return mrv;
04306 }
04307
04308
04309
04310
04311
04312
04313
04314
04315
04316
04317
04318
04319
04320
04321
04322 static size_t
04323 VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv)
04324 {
04325 size_t left_word, right_word, word_shift;
04326 c->frac[0] = 0;
04327 *av = *bv = 0;
04328 word_shift =((a->exponent) -(b->exponent));
04329 left_word = b->Prec + word_shift;
04330 right_word = Max((a->Prec),left_word);
04331 left_word =(c->MaxPrec) - 1;
04332
04333
04334
04335 if(right_word > left_word) {
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345 *c_pos = right_word = left_word + 1;
04346
04347 if((a->Prec) >=(c->MaxPrec)) {
04348
04349
04350
04351
04352
04353 *a_pos = left_word;
04354 *av = a->frac[*a_pos];
04355 } else {
04356
04357
04358
04359
04360
04361 *a_pos = a->Prec;
04362 }
04363 if((b->Prec + word_shift) >= c->MaxPrec) {
04364
04365
04366
04367
04368
04369
04370 if(c->MaxPrec >=(word_shift + 1)) {
04371 *b_pos = c->MaxPrec - word_shift - 1;
04372 *bv = b->frac[*b_pos];
04373 } else {
04374 *b_pos = -1L;
04375 }
04376 } else {
04377
04378
04379
04380
04381
04382
04383 *b_pos = b->Prec;
04384 }
04385 } else {
04386
04387
04388
04389
04390
04391
04392 *b_pos = b->Prec;
04393 *a_pos = a->Prec;
04394 *c_pos = right_word + 1;
04395 }
04396 c->Prec = *c_pos;
04397 c->exponent = a->exponent;
04398 if(!AddExponent(c,1)) return (size_t)-1L;
04399 return word_shift;
04400 }
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413
04414
04415
04416
04417 VP_EXPORT size_t
04418 VpMult(Real *c, Real *a, Real *b)
04419 {
04420 size_t MxIndA, MxIndB, MxIndAB, MxIndC;
04421 size_t ind_c, i, ii, nc;
04422 size_t ind_as, ind_ae, ind_bs;
04423 BDIGIT carry;
04424 BDIGIT_DBL s;
04425 Real *w;
04426
04427 #ifdef BIGDECIMAL_DEBUG
04428 if(gfDebug) {
04429 VPrint(stdout, "VpMult(Enter): a=% \n", a);
04430 VPrint(stdout, " b=% \n", b);
04431 }
04432 #endif
04433
04434 if(!VpIsDefOP(c,a,b,3)) return 0;
04435
04436 if(VpIsZero(a) || VpIsZero(b)) {
04437
04438 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
04439 return 1;
04440 }
04441
04442 if(VpIsOne(a)) {
04443 VpAsgn(c, b, VpGetSign(a));
04444 goto Exit;
04445 }
04446 if(VpIsOne(b)) {
04447 VpAsgn(c, a, VpGetSign(b));
04448 goto Exit;
04449 }
04450 if((b->Prec) >(a->Prec)) {
04451
04452 w = a;
04453 a = b;
04454 b = w;
04455 }
04456 w = NULL;
04457 MxIndA = a->Prec - 1;
04458 MxIndB = b->Prec - 1;
04459 MxIndC = c->MaxPrec - 1;
04460 MxIndAB = a->Prec + b->Prec - 1;
04461
04462 if(MxIndC < MxIndAB) {
04463 w = c;
04464 c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0");
04465 MxIndC = MxIndAB;
04466 }
04467
04468
04469
04470 c->exponent = a->exponent;
04471 if(!AddExponent(c,b->exponent)) {
04472 if(w) VpFree(c);
04473 return 0;
04474 }
04475 VpSetSign(c,VpGetSign(a)*VpGetSign(b));
04476 carry = 0;
04477 nc = ind_c = MxIndAB;
04478 memset(c->frac, 0, (nc + 1) * sizeof(BDIGIT));
04479 c->Prec = nc + 1;
04480 for(nc = 0; nc < MxIndAB; ++nc, --ind_c) {
04481 if(nc < MxIndB) {
04482 ind_as = MxIndA - nc;
04483 ind_ae = MxIndA;
04484 ind_bs = MxIndB;
04485 } else if(nc <= MxIndA) {
04486 ind_as = MxIndA - nc;
04487 ind_ae = MxIndA -(nc - MxIndB);
04488 ind_bs = MxIndB;
04489 } else if(nc > MxIndA) {
04490 ind_as = 0;
04491 ind_ae = MxIndAB - nc - 1;
04492 ind_bs = MxIndB -(nc - MxIndA);
04493 }
04494
04495 for(i = ind_as; i <= ind_ae; ++i) {
04496 s = (BDIGIT_DBL)a->frac[i] * b->frac[ind_bs--];
04497 carry = (BDIGIT)(s / BASE);
04498 s -= (BDIGIT_DBL)carry * BASE;
04499 c->frac[ind_c] += (BDIGIT)s;
04500 if(c->frac[ind_c] >= BASE) {
04501 s = c->frac[ind_c] / BASE;
04502 carry += (BDIGIT)s;
04503 c->frac[ind_c] -= (BDIGIT)(s * BASE);
04504 }
04505 if(carry) {
04506 ii = ind_c;
04507 while(ii-- > 0) {
04508 c->frac[ii] += carry;
04509 if(c->frac[ii] >= BASE) {
04510 carry = c->frac[ii] / BASE;
04511 c->frac[ii] -= (carry * BASE);
04512 } else {
04513 break;
04514 }
04515 }
04516 }
04517 }
04518 }
04519 if(w != NULL) {
04520 VpNmlz(c);
04521 VpAsgn(w, c, 1);
04522 VpFree(c);
04523 c = w;
04524 } else {
04525 VpLimitRound(c,0);
04526 }
04527
04528 Exit:
04529 #ifdef BIGDECIMAL_DEBUG
04530 if(gfDebug) {
04531 VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
04532 VPrint(stdout, " a=% \n", a);
04533 VPrint(stdout, " b=% \n", b);
04534 }
04535 #endif
04536 return c->Prec*BASE_FIG;
04537 }
04538
04539
04540
04541
04542 VP_EXPORT size_t
04543 VpDivd(Real *c, Real *r, Real *a, Real *b)
04544 {
04545 size_t word_a, word_b, word_c, word_r;
04546 size_t i, n, ind_a, ind_b, ind_c, ind_r;
04547 size_t nLoop;
04548 BDIGIT_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
04549 BDIGIT borrow, borrow1, borrow2;
04550 BDIGIT_DBL qb;
04551
04552 #ifdef BIGDECIMAL_DEBUG
04553 if(gfDebug) {
04554 VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
04555 VPrint(stdout, " b=% \n", b);
04556 }
04557 #endif
04558
04559 VpSetNaN(r);
04560 if(!VpIsDefOP(c,a,b,4)) goto Exit;
04561 if(VpIsZero(a)&&VpIsZero(b)) {
04562 VpSetNaN(c);
04563 return VpException(VP_EXCEPTION_NaN,"(VpDivd) 0/0 not defined(NaN)",0);
04564 }
04565 if(VpIsZero(b)) {
04566 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
04567 return VpException(VP_EXCEPTION_ZERODIVIDE,"(VpDivd) Divide by zero",0);
04568 }
04569 if(VpIsZero(a)) {
04570
04571 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
04572 VpSetZero(r,VpGetSign(a)*VpGetSign(b));
04573 goto Exit;
04574 }
04575 if(VpIsOne(b)) {
04576
04577 VpAsgn(c, a, VpGetSign(b));
04578 VpSetZero(r,VpGetSign(a));
04579 goto Exit;
04580 }
04581
04582 word_a = a->Prec;
04583 word_b = b->Prec;
04584 word_c = c->MaxPrec;
04585 word_r = r->MaxPrec;
04586
04587 ind_c = 0;
04588 ind_r = 1;
04589
04590 if(word_a >= word_r) goto space_error;
04591
04592 r->frac[0] = 0;
04593 while(ind_r <= word_a) {
04594 r->frac[ind_r] = a->frac[ind_r - 1];
04595 ++ind_r;
04596 }
04597
04598 while(ind_r < word_r) r->frac[ind_r++] = 0;
04599 while(ind_c < word_c) c->frac[ind_c++] = 0;
04600
04601
04602 b1 = b1p1 = b->frac[0];
04603 if(b->Prec <= 1) {
04604 b1b2p1 = b1b2 = b1p1 * BASE;
04605 } else {
04606 b1p1 = b1 + 1;
04607 b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
04608 if(b->Prec > 2) ++b1b2p1;
04609 }
04610
04611
04612
04613 ind_c = word_r - 1;
04614 nLoop = Min(word_c,ind_c);
04615 ind_c = 1;
04616 while(ind_c < nLoop) {
04617 if(r->frac[ind_c] == 0) {
04618 ++ind_c;
04619 continue;
04620 }
04621 r1r2 = (BDIGIT_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
04622 if(r1r2 == b1b2) {
04623
04624 ind_b = 2;
04625 ind_a = ind_c + 2;
04626 while(ind_b < word_b) {
04627 if(r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
04628 if(r->frac[ind_a] > b->frac[ind_b]) break;
04629 ++ind_a;
04630 ++ind_b;
04631 }
04632
04633
04634
04635 borrow = 0;
04636 ind_b = b->Prec - 1;
04637 ind_r = ind_c + ind_b;
04638 if(ind_r >= word_r) goto space_error;
04639 n = ind_b;
04640 for(i = 0; i <= n; ++i) {
04641 if(r->frac[ind_r] < b->frac[ind_b] + borrow) {
04642 r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
04643 borrow = 1;
04644 } else {
04645 r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
04646 borrow = 0;
04647 }
04648 --ind_r;
04649 --ind_b;
04650 }
04651 ++c->frac[ind_c];
04652 goto carry;
04653 }
04654
04655
04656 if(r1r2 >= b1b2p1) {
04657 q = r1r2 / b1b2p1;
04658 c->frac[ind_c] += (BDIGIT)q;
04659 ind_r = b->Prec + ind_c - 1;
04660 goto sub_mult;
04661 }
04662
04663 div_b1p1:
04664 if(ind_c + 1 >= word_c) goto out_side;
04665 q = r1r2 / b1p1;
04666 c->frac[ind_c + 1] += (BDIGIT)q;
04667 ind_r = b->Prec + ind_c;
04668
04669 sub_mult:
04670 borrow1 = borrow2 = 0;
04671 ind_b = word_b - 1;
04672 if(ind_r >= word_r) goto space_error;
04673 n = ind_b;
04674 for(i = 0; i <= n; ++i) {
04675
04676 qb = q * b->frac[ind_b];
04677 if (qb < BASE) borrow1 = 0;
04678 else {
04679 borrow1 = (BDIGIT)(qb / BASE);
04680 qb -= (BDIGIT_DBL)borrow1 * BASE;
04681 }
04682 if(r->frac[ind_r] < qb) {
04683 r->frac[ind_r] += (BDIGIT)(BASE - qb);
04684 borrow2 = borrow2 + borrow1 + 1;
04685 } else {
04686 r->frac[ind_r] -= (BDIGIT)qb;
04687 borrow2 += borrow1;
04688 }
04689 if(borrow2) {
04690 if(r->frac[ind_r - 1] < borrow2) {
04691 r->frac[ind_r - 1] += (BASE - borrow2);
04692 borrow2 = 1;
04693 } else {
04694 r->frac[ind_r - 1] -= borrow2;
04695 borrow2 = 0;
04696 }
04697 }
04698 --ind_r;
04699 --ind_b;
04700 }
04701
04702 r->frac[ind_r] -= borrow2;
04703 carry:
04704 ind_r = ind_c;
04705 while(c->frac[ind_r] >= BASE) {
04706 c->frac[ind_r] -= BASE;
04707 --ind_r;
04708 ++c->frac[ind_r];
04709 }
04710 }
04711
04712 out_side:
04713 c->Prec = word_c;
04714 c->exponent = a->exponent;
04715 if(!AddExponent(c,2)) return 0;
04716 if(!AddExponent(c,-(b->exponent))) return 0;
04717
04718 VpSetSign(c,VpGetSign(a)*VpGetSign(b));
04719 VpNmlz(c);
04720 r->Prec = word_r;
04721 r->exponent = a->exponent;
04722 if(!AddExponent(r,1)) return 0;
04723 VpSetSign(r,VpGetSign(a));
04724 VpNmlz(r);
04725 goto Exit;
04726
04727 space_error:
04728 #ifdef BIGDECIMAL_DEBUG
04729 if(gfDebug) {
04730 printf(" word_a=%lu\n", word_a);
04731 printf(" word_b=%lu\n", word_b);
04732 printf(" word_c=%lu\n", word_c);
04733 printf(" word_r=%lu\n", word_r);
04734 printf(" ind_r =%lu\n", ind_r);
04735 }
04736 #endif
04737 rb_bug("ERROR(VpDivd): space for remainder too small.");
04738
04739 Exit:
04740 #ifdef BIGDECIMAL_DEBUG
04741 if(gfDebug) {
04742 VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
04743 VPrint(stdout, " r=% \n", r);
04744 }
04745 #endif
04746 return c->Prec*BASE_FIG;
04747 }
04748
04749
04750
04751
04752
04753 static int
04754 VpNmlz(Real *a)
04755 {
04756 size_t ind_a, i;
04757
04758 if (!VpIsDef(a)) goto NoVal;
04759 if (VpIsZero(a)) goto NoVal;
04760
04761 ind_a = a->Prec;
04762 while (ind_a--) {
04763 if (a->frac[ind_a]) {
04764 a->Prec = ind_a + 1;
04765 i = 0;
04766 while (a->frac[i] == 0) ++i;
04767 if (i) {
04768 a->Prec -= i;
04769 if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0;
04770 memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(BDIGIT));
04771 }
04772 return 1;
04773 }
04774 }
04775
04776 VpSetZero(a, VpGetSign(a));
04777 return 0;
04778
04779 NoVal:
04780 a->frac[0] = 0;
04781 a->Prec = 1;
04782 return 0;
04783 }
04784
04785
04786
04787
04788
04789
04790
04791 VP_EXPORT int
04792 VpComp(Real *a, Real *b)
04793 {
04794 int val;
04795 size_t mx, ind;
04796 int e;
04797 val = 0;
04798 if(VpIsNaN(a)||VpIsNaN(b)) return 999;
04799 if(!VpIsDef(a)) {
04800 if(!VpIsDef(b)) e = a->sign - b->sign;
04801 else e = a->sign;
04802 if(e>0) return 1;
04803 else if(e<0) return -1;
04804 else return 0;
04805 }
04806 if(!VpIsDef(b)) {
04807 e = -b->sign;
04808 if(e>0) return 1;
04809 else return -1;
04810 }
04811
04812 if(VpIsZero(a)) {
04813 if(VpIsZero(b)) return 0;
04814 val = -VpGetSign(b);
04815 goto Exit;
04816 }
04817 if(VpIsZero(b)) {
04818 val = VpGetSign(a);
04819 goto Exit;
04820 }
04821
04822
04823 if(VpGetSign(a) > VpGetSign(b)) {
04824 val = 1;
04825 goto Exit;
04826 }
04827 if(VpGetSign(a) < VpGetSign(b)) {
04828 val = -1;
04829 goto Exit;
04830 }
04831
04832
04833 if((a->exponent) >(b->exponent)) {
04834 val = VpGetSign(a);
04835 goto Exit;
04836 }
04837 if((a->exponent) <(b->exponent)) {
04838 val = -VpGetSign(b);
04839 goto Exit;
04840 }
04841
04842
04843 mx =((a->Prec) <(b->Prec)) ?(a->Prec) :(b->Prec);
04844 ind = 0;
04845 while(ind < mx) {
04846 if((a->frac[ind]) >(b->frac[ind])) {
04847 val = VpGetSign(a);
04848 goto Exit;
04849 }
04850 if((a->frac[ind]) <(b->frac[ind])) {
04851 val = -VpGetSign(b);
04852 goto Exit;
04853 }
04854 ++ind;
04855 }
04856 if((a->Prec) >(b->Prec)) {
04857 val = VpGetSign(a);
04858 } else if((a->Prec) <(b->Prec)) {
04859 val = -VpGetSign(b);
04860 }
04861
04862 Exit:
04863 if (val> 1) val = 1;
04864 else if(val<-1) val = -1;
04865
04866 #ifdef BIGDECIMAL_DEBUG
04867 if(gfDebug) {
04868 VPrint(stdout, " VpComp a=%\n", a);
04869 VPrint(stdout, " b=%\n", b);
04870 printf(" ans=%d\n", val);
04871 }
04872 #endif
04873 return (int)val;
04874 }
04875
04876 #ifdef BIGDECIMAL_ENABLE_VPRINT
04877
04878
04879
04880
04881
04882
04883
04884
04885
04886
04887 VP_EXPORT int
04888 VPrint(FILE *fp, const char *cntl_chr, Real *a)
04889 {
04890 size_t i, j, nc, nd, ZeroSup;
04891 BDIGIT m, e, nn;
04892
04893
04894 if(VpIsNaN(a)) {
04895 fprintf(fp,SZ_NaN);
04896 return 8;
04897 }
04898 if(VpIsPosInf(a)) {
04899 fprintf(fp,SZ_INF);
04900 return 8;
04901 }
04902 if(VpIsNegInf(a)) {
04903 fprintf(fp,SZ_NINF);
04904 return 9;
04905 }
04906 if(VpIsZero(a)) {
04907 fprintf(fp,"0.0");
04908 return 3;
04909 }
04910
04911 j = 0;
04912 nd = nc = 0;
04913
04914
04915 ZeroSup = 1;
04916 while(*(cntl_chr + j)) {
04917 if((*(cntl_chr + j) == '%') &&(*(cntl_chr + j + 1) != '%')) {
04918 nc = 0;
04919 if(!VpIsZero(a)) {
04920 if(VpGetSign(a) < 0) {
04921 fprintf(fp, "-");
04922 ++nc;
04923 }
04924 nc += fprintf(fp, "0.");
04925 for(i=0; i < a->Prec; ++i) {
04926 m = BASE1;
04927 e = a->frac[i];
04928 while(m) {
04929 nn = e / m;
04930 if((!ZeroSup) || nn) {
04931 nc += fprintf(fp, "%lu", (unsigned long)nn);
04932
04933
04934 ++nd;
04935 ZeroSup = 0;
04936 }
04937 if(nd >= 10) {
04938 nd = 0;
04939 nc += fprintf(fp, " ");
04940 }
04941 e = e - nn * m;
04942 m /= 10;
04943 }
04944 }
04945 nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
04946 } else {
04947 nc += fprintf(fp, "0.0");
04948 }
04949 } else {
04950 ++nc;
04951 if(*(cntl_chr + j) == '\\') {
04952 switch(*(cntl_chr + j + 1)) {
04953 case 'n':
04954 fprintf(fp, "\n");
04955 ++j;
04956 break;
04957 case 't':
04958 fprintf(fp, "\t");
04959 ++j;
04960 break;
04961 case 'b':
04962 fprintf(fp, "\n");
04963 ++j;
04964 break;
04965 default:
04966 fprintf(fp, "%c", *(cntl_chr + j));
04967 break;
04968 }
04969 } else {
04970 fprintf(fp, "%c", *(cntl_chr + j));
04971 if(*(cntl_chr + j) == '%') ++j;
04972 }
04973 }
04974 j++;
04975 }
04976 return (int)nc;
04977 }
04978 #endif
04979
04980 static void
04981 VpFormatSt(char *psz, size_t fFmt)
04982 {
04983 size_t ie, i, nf = 0;
04984 char ch;
04985
04986 if(fFmt<=0) return;
04987
04988 ie = strlen(psz);
04989 for(i = 0; i < ie; ++i) {
04990 ch = psz[i];
04991 if(!ch) break;
04992 if(ISSPACE(ch) || ch=='-' || ch=='+') continue;
04993 if(ch == '.') { nf = 0;continue;}
04994 if(ch == 'E') break;
04995 nf++;
04996 if(nf > fFmt) {
04997 memmove(psz + i + 1, psz + i, ie - i + 1);
04998 ++ie;
04999 nf = 0;
05000 psz[i] = ' ';
05001 }
05002 }
05003 }
05004
05005 VP_EXPORT ssize_t
05006 VpExponent10(Real *a)
05007 {
05008 ssize_t ex;
05009 size_t n;
05010
05011 if (!VpHasVal(a)) return 0;
05012
05013 ex = a->exponent * (ssize_t)BASE_FIG;
05014 n = BASE1;
05015 while ((a->frac[0] / n) == 0) {
05016 --ex;
05017 n /= 10;
05018 }
05019 return ex;
05020 }
05021
05022 VP_EXPORT void
05023 VpSzMantissa(Real *a,char *psz)
05024 {
05025 size_t i, n, ZeroSup;
05026 BDIGIT_DBL m, e, nn;
05027
05028 if(VpIsNaN(a)) {
05029 sprintf(psz,SZ_NaN);
05030 return;
05031 }
05032 if(VpIsPosInf(a)) {
05033 sprintf(psz,SZ_INF);
05034 return;
05035 }
05036 if(VpIsNegInf(a)) {
05037 sprintf(psz,SZ_NINF);
05038 return;
05039 }
05040
05041 ZeroSup = 1;
05042 if(!VpIsZero(a)) {
05043 if(VpGetSign(a) < 0) *psz++ = '-';
05044 n = a->Prec;
05045 for (i=0; i < n; ++i) {
05046 m = BASE1;
05047 e = a->frac[i];
05048 while (m) {
05049 nn = e / m;
05050 if((!ZeroSup) || nn) {
05051 sprintf(psz, "%lu", (unsigned long)nn);
05052 psz += strlen(psz);
05053
05054 ZeroSup = 0;
05055 }
05056 e = e - nn * m;
05057 m /= 10;
05058 }
05059 }
05060 *psz = 0;
05061 while(psz[-1]=='0') *(--psz) = 0;
05062 } else {
05063 if(VpIsPosZero(a)) sprintf(psz, "0");
05064 else sprintf(psz, "-0");
05065 }
05066 }
05067
05068 VP_EXPORT int
05069 VpToSpecialString(Real *a,char *psz,int fPlus)
05070
05071 {
05072 if(VpIsNaN(a)) {
05073 sprintf(psz,SZ_NaN);
05074 return 1;
05075 }
05076
05077 if(VpIsPosInf(a)) {
05078 if(fPlus==1) {
05079 *psz++ = ' ';
05080 } else if(fPlus==2) {
05081 *psz++ = '+';
05082 }
05083 sprintf(psz,SZ_INF);
05084 return 1;
05085 }
05086 if(VpIsNegInf(a)) {
05087 sprintf(psz,SZ_NINF);
05088 return 1;
05089 }
05090 if(VpIsZero(a)) {
05091 if(VpIsPosZero(a)) {
05092 if(fPlus==1) sprintf(psz, " 0.0");
05093 else if(fPlus==2) sprintf(psz, "+0.0");
05094 else sprintf(psz, "0.0");
05095 } else sprintf(psz, "-0.0");
05096 return 1;
05097 }
05098 return 0;
05099 }
05100
05101 VP_EXPORT void
05102 VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
05103
05104 {
05105 size_t i, n, ZeroSup;
05106 BDIGIT shift, m, e, nn;
05107 char *pszSav = psz;
05108 ssize_t ex;
05109
05110 if (VpToSpecialString(a, psz, fPlus)) return;
05111
05112 ZeroSup = 1;
05113
05114 if (VpGetSign(a) < 0) *psz++ = '-';
05115 else if (fPlus == 1) *psz++ = ' ';
05116 else if (fPlus == 2) *psz++ = '+';
05117
05118 *psz++ = '0';
05119 *psz++ = '.';
05120 n = a->Prec;
05121 for(i=0;i < n;++i) {
05122 m = BASE1;
05123 e = a->frac[i];
05124 while(m) {
05125 nn = e / m;
05126 if((!ZeroSup) || nn) {
05127 sprintf(psz, "%lu", (unsigned long)nn);
05128 psz += strlen(psz);
05129
05130 ZeroSup = 0;
05131 }
05132 e = e - nn * m;
05133 m /= 10;
05134 }
05135 }
05136 ex = a->exponent * (ssize_t)BASE_FIG;
05137 shift = BASE1;
05138 while(a->frac[0] / shift == 0) {
05139 --ex;
05140 shift /= 10;
05141 }
05142 while(psz[-1]=='0') *(--psz) = 0;
05143 sprintf(psz, "E%"PRIdSIZE, ex);
05144 if(fFmt) VpFormatSt(pszSav, fFmt);
05145 }
05146
05147 VP_EXPORT void
05148 VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
05149
05150 {
05151 size_t i, n;
05152 BDIGIT m, e, nn;
05153 char *pszSav = psz;
05154 ssize_t ex;
05155
05156 if(VpToSpecialString(a,psz,fPlus)) return;
05157
05158 if(VpGetSign(a) < 0) *psz++ = '-';
05159 else if(fPlus==1) *psz++ = ' ';
05160 else if(fPlus==2) *psz++ = '+';
05161
05162 n = a->Prec;
05163 ex = a->exponent;
05164 if(ex<=0) {
05165 *psz++ = '0';*psz++ = '.';
05166 while(ex<0) {
05167 for(i=0;i<BASE_FIG;++i) *psz++ = '0';
05168 ++ex;
05169 }
05170 ex = -1;
05171 }
05172
05173 for(i=0;i < n;++i) {
05174 --ex;
05175 if(i==0 && ex >= 0) {
05176 sprintf(psz, "%lu", (unsigned long)a->frac[i]);
05177 psz += strlen(psz);
05178 } else {
05179 m = BASE1;
05180 e = a->frac[i];
05181 while(m) {
05182 nn = e / m;
05183 *psz++ = (char)(nn + '0');
05184 e = e - nn * m;
05185 m /= 10;
05186 }
05187 }
05188 if(ex == 0) *psz++ = '.';
05189 }
05190 while(--ex>=0) {
05191 m = BASE;
05192 while(m/=10) *psz++ = '0';
05193 if(ex == 0) *psz++ = '.';
05194 }
05195 *psz = 0;
05196 while(psz[-1]=='0') *(--psz) = 0;
05197 if(psz[-1]=='.') sprintf(psz, "0");
05198 if(fFmt) VpFormatSt(pszSav, fFmt);
05199 }
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212 VP_EXPORT int
05213 VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
05214 {
05215 size_t i, j, ind_a, ma, mi, me;
05216 SIGNED_VALUE e, es, eb, ef;
05217 int sign, signe, exponent_overflow;
05218
05219
05220 e = 0;
05221 ma = a->MaxPrec;
05222 mi = ni;
05223 me = ne;
05224 signe = 1;
05225 exponent_overflow = 0;
05226 memset(a->frac, 0, ma * sizeof(BDIGIT));
05227 if (ne > 0) {
05228 i = 0;
05229 if (exp_chr[0] == '-') {
05230 signe = -1;
05231 ++i;
05232 ++me;
05233 }
05234 else if (exp_chr[0] == '+') {
05235 ++i;
05236 ++me;
05237 }
05238 while (i < me) {
05239 es = e * (SIGNED_VALUE)BASE_FIG;
05240 e = e * 10 + exp_chr[i] - '0';
05241 if (es > (SIGNED_VALUE)(e*BASE_FIG)) {
05242 exponent_overflow = 1;
05243 e = es;
05244 break;
05245 }
05246 ++i;
05247 }
05248 }
05249
05250
05251 i = 0;
05252 sign = 1;
05253 if(1 ) {
05254 if(int_chr[0] == '-') {
05255 sign = -1;
05256 ++i;
05257 ++mi;
05258 } else if(int_chr[0] == '+') {
05259 ++i;
05260 ++mi;
05261 }
05262 }
05263
05264 e = signe * e;
05265 e = e + ni;
05266
05267 if (e > 0) signe = 1;
05268 else signe = -1;
05269
05270
05271 j = 0;
05272 ef = 1;
05273 while (ef) {
05274 if (e >= 0) eb = e;
05275 else eb = -e;
05276 ef = eb / (SIGNED_VALUE)BASE_FIG;
05277 ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
05278 if (ef) {
05279 ++j;
05280 ++e;
05281 }
05282 }
05283
05284 eb = e / (SIGNED_VALUE)BASE_FIG;
05285
05286 if (exponent_overflow) {
05287 int zero = 1;
05288 for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
05289 for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
05290 if (!zero && signe > 0) {
05291 VpSetInf(a, sign);
05292 VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
05293 }
05294 else VpSetZero(a, sign);
05295 return 1;
05296 }
05297
05298 ind_a = 0;
05299 while (i < mi) {
05300 a->frac[ind_a] = 0;
05301 while ((j < BASE_FIG) && (i < mi)) {
05302 a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
05303 ++j;
05304 ++i;
05305 }
05306 if (i < mi) {
05307 ++ind_a;
05308 if (ind_a >= ma) goto over_flow;
05309 j = 0;
05310 }
05311 }
05312
05313
05314
05315 i = 0;
05316 while(i < nf) {
05317 while((j < BASE_FIG) && (i < nf)) {
05318 a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
05319 ++j;
05320 ++i;
05321 }
05322 if(i < nf) {
05323 ++ind_a;
05324 if(ind_a >= ma) goto over_flow;
05325 j = 0;
05326 }
05327 }
05328 goto Final;
05329
05330 over_flow:
05331 rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
05332
05333 Final:
05334 if (ind_a >= ma) ind_a = ma - 1;
05335 while (j < BASE_FIG) {
05336 a->frac[ind_a] = a->frac[ind_a] * 10;
05337 ++j;
05338 }
05339 a->Prec = ind_a + 1;
05340 a->exponent = eb;
05341 VpSetSign(a,sign);
05342 VpNmlz(a);
05343 return 1;
05344 }
05345
05346
05347
05348
05349
05350
05351
05352
05353
05354
05355
05356
05357
05358
05359
05360
05361 VP_EXPORT int
05362 VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
05363 {
05364 size_t ind_m, mm, fig;
05365 double div;
05366 int f = 1;
05367
05368 if(VpIsNaN(m)) {
05369 *d = VpGetDoubleNaN();
05370 *e = 0;
05371 f = -1;
05372 goto Exit;
05373 } else
05374 if(VpIsPosZero(m)) {
05375 *d = 0.0;
05376 *e = 0;
05377 f = 0;
05378 goto Exit;
05379 } else
05380 if(VpIsNegZero(m)) {
05381 *d = VpGetDoubleNegZero();
05382 *e = 0;
05383 f = 0;
05384 goto Exit;
05385 } else
05386 if(VpIsPosInf(m)) {
05387 *d = VpGetDoublePosInf();
05388 *e = 0;
05389 f = 2;
05390 goto Exit;
05391 } else
05392 if(VpIsNegInf(m)) {
05393 *d = VpGetDoubleNegInf();
05394 *e = 0;
05395 f = 2;
05396 goto Exit;
05397 }
05398
05399 fig =(DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
05400 ind_m = 0;
05401 mm = Min(fig,(m->Prec));
05402 *d = 0.0;
05403 div = 1.;
05404 while(ind_m < mm) {
05405 div /= (double)BASE;
05406 *d = *d + (double)m->frac[ind_m++] * div;
05407 }
05408 *e = m->exponent * (SIGNED_VALUE)BASE_FIG;
05409 *d *= VpGetSign(m);
05410
05411 Exit:
05412 #ifdef BIGDECIMAL_DEBUG
05413 if(gfDebug) {
05414 VPrint(stdout, " VpVtoD: m=%\n", m);
05415 printf(" d=%e * 10 **%ld\n", *d, *e);
05416 printf(" DBLE_FIG = %d\n", DBLE_FIG);
05417 }
05418 #endif
05419 return f;
05420 }
05421
05422
05423
05424
05425 VP_EXPORT void
05426 VpDtoV(Real *m, double d)
05427 {
05428 size_t ind_m, mm;
05429 SIGNED_VALUE ne;
05430 BDIGIT i;
05431 double val, val2;
05432
05433 if(isnan(d)) {
05434 VpSetNaN(m);
05435 goto Exit;
05436 }
05437 if(isinf(d)) {
05438 if(d>0.0) VpSetPosInf(m);
05439 else VpSetNegInf(m);
05440 goto Exit;
05441 }
05442
05443 if(d == 0.0) {
05444 VpSetZero(m,1);
05445 goto Exit;
05446 }
05447 val =(d > 0.) ? d :(-d);
05448 ne = 0;
05449 if(val >= 1.0) {
05450 while(val >= 1.0) {
05451 val /= (double)BASE;
05452 ++ne;
05453 }
05454 } else {
05455 val2 = 1.0 /(double)BASE;
05456 while(val < val2) {
05457 val *= (double)BASE;
05458 --ne;
05459 }
05460 }
05461
05462
05463 mm = m->MaxPrec;
05464 memset(m->frac, 0, mm * sizeof(BDIGIT));
05465 for(ind_m = 0;val > 0.0 && ind_m < mm;ind_m++) {
05466 val *= (double)BASE;
05467 i = (BDIGIT)val;
05468 val -= (double)i;
05469 m->frac[ind_m] = i;
05470 }
05471 if(ind_m >= mm) ind_m = mm - 1;
05472 VpSetSign(m, (d > 0.0) ? 1 : -1);
05473 m->Prec = ind_m + 1;
05474 m->exponent = ne;
05475
05476 VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
05477 (BDIGIT)(val*(double)BASE));
05478
05479 Exit:
05480 #ifdef BIGDECIMAL_DEBUG
05481 if(gfDebug) {
05482 printf("VpDtoV d=%30.30e\n", d);
05483 VPrint(stdout, " m=%\n", m);
05484 }
05485 #endif
05486 return;
05487 }
05488
05489
05490
05491
05492 #if 0
05493 VP_EXPORT void
05494 VpItoV(Real *m, SIGNED_VALUE ival)
05495 {
05496 size_t mm, ind_m;
05497 size_t val, v1, v2, v;
05498 int isign;
05499 SIGNED_VALUE ne;
05500
05501 if(ival == 0) {
05502 VpSetZero(m,1);
05503 goto Exit;
05504 }
05505 isign = 1;
05506 val = ival;
05507 if(ival < 0) {
05508 isign = -1;
05509 val =(size_t)(-ival);
05510 }
05511 ne = 0;
05512 ind_m = 0;
05513 mm = m->MaxPrec;
05514 while(ind_m < mm) {
05515 m->frac[ind_m] = 0;
05516 ++ind_m;
05517 }
05518 ind_m = 0;
05519 while(val > 0) {
05520 if(val) {
05521 v1 = val;
05522 v2 = 1;
05523 while(v1 >= BASE) {
05524 v1 /= BASE;
05525 v2 *= BASE;
05526 }
05527 val = val - v2 * v1;
05528 v = v1;
05529 } else {
05530 v = 0;
05531 }
05532 m->frac[ind_m] = v;
05533 ++ind_m;
05534 ++ne;
05535 }
05536 m->Prec = ind_m - 1;
05537 m->exponent = ne;
05538 VpSetSign(m,isign);
05539 VpNmlz(m);
05540
05541 Exit:
05542 #ifdef BIGDECIMAL_DEBUG
05543 if(gfDebug) {
05544 printf(" VpItoV i=%d\n", ival);
05545 VPrint(stdout, " m=%\n", m);
05546 }
05547 #endif
05548 return;
05549 }
05550 #endif
05551
05552
05553
05554
05555 VP_EXPORT int
05556 VpSqrt(Real *y, Real *x)
05557 {
05558 Real *f = NULL;
05559 Real *r = NULL;
05560 size_t y_prec;
05561 SIGNED_VALUE n, e;
05562 SIGNED_VALUE prec;
05563 ssize_t nr;
05564 double val;
05565
05566
05567 if(!VpHasVal(x)) {
05568 if(VpIsZero(x)||VpGetSign(x)>0) {
05569 VpAsgn(y,x,1);
05570 goto Exit;
05571 }
05572 VpSetNaN(y);
05573 return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(NaN or negative value)",0);
05574 goto Exit;
05575 }
05576
05577
05578 if(VpGetSign(x) < 0) {
05579 VpSetNaN(y);
05580 return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(negative value)",0);
05581 }
05582
05583
05584 if(VpIsOne(x)) {
05585 VpSetOne(y);
05586 goto Exit;
05587 }
05588
05589 n = (SIGNED_VALUE)y->MaxPrec;
05590 if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
05591
05592 f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1");
05593 r = VpAlloc((n + n) * (BASE_FIG + 2), "#1");
05594
05595 nr = 0;
05596 y_prec = y->MaxPrec;
05597
05598 prec = x->exponent - (ssize_t)y_prec;
05599 if (x->exponent > 0)
05600 ++prec;
05601 else
05602 --prec;
05603
05604 VpVtoD(&val, &e, x);
05605 e /= (SIGNED_VALUE)BASE_FIG;
05606 n = e / 2;
05607 if (e - n * 2 != 0) {
05608 val /= BASE;
05609 n = (e + 1) / 2;
05610 }
05611 VpDtoV(y, sqrt(val));
05612 y->exponent += n;
05613 n = (SIGNED_VALUE)((DBLE_FIG + BASE_FIG - 1) / BASE_FIG);
05614 y->MaxPrec = Min((size_t)n , y_prec);
05615 f->MaxPrec = y->MaxPrec + 1;
05616 n = (SIGNED_VALUE)(y_prec * BASE_FIG);
05617 if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
05618 do {
05619 y->MaxPrec *= 2;
05620 if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
05621 f->MaxPrec = y->MaxPrec;
05622 VpDivd(f, r, x, y);
05623 VpAddSub(r, f, y, -1);
05624 VpMult(f, VpPt5, r);
05625 if(VpIsZero(f)) goto converge;
05626 VpAddSub(r, f, y, 1);
05627 VpAsgn(y, r, 1);
05628 if(f->exponent <= prec) goto converge;
05629 } while(++nr < n);
05630
05631 #ifdef BIGDECIMAL_DEBUG
05632 if(gfDebug) {
05633 printf("ERROR(VpSqrt): did not converge within %ld iterations.\n",
05634 nr);
05635 }
05636 #endif
05637 y->MaxPrec = y_prec;
05638
05639 converge:
05640 VpChangeSign(y, 1);
05641 #ifdef BIGDECIMAL_DEBUG
05642 if(gfDebug) {
05643 VpMult(r, y, y);
05644 VpAddSub(f, x, r, -1);
05645 printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
05646 VPrint(stdout, " y =% \n", y);
05647 VPrint(stdout, " x =% \n", x);
05648 VPrint(stdout, " x-y*y = % \n", f);
05649 }
05650 #endif
05651 y->MaxPrec = y_prec;
05652
05653 Exit:
05654 VpFree(f);
05655 VpFree(r);
05656 return 1;
05657 }
05658
05659
05660
05661
05662
05663
05664 VP_EXPORT int
05665 VpMidRound(Real *y, unsigned short f, ssize_t nf)
05666
05667
05668
05669
05670
05671 {
05672
05673
05674
05675 int fracf, fracf_1further;
05676 ssize_t n,i,ix,ioffset, exptoadd;
05677 BDIGIT v, shifter;
05678 BDIGIT div;
05679
05680 nf += y->exponent * (ssize_t)BASE_FIG;
05681 exptoadd=0;
05682 if (nf < 0) {
05683
05684 if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
05685 VpSetZero(y,VpGetSign(y));
05686 return 0;
05687 }
05688 exptoadd = -nf;
05689 nf = 0;
05690 }
05691
05692 ix = nf / (ssize_t)BASE_FIG;
05693 if ((size_t)ix >= y->Prec) return 0;
05694 v = y->frac[ix];
05695
05696 ioffset = nf - ix*(ssize_t)BASE_FIG;
05697 n = (ssize_t)BASE_FIG - ioffset - 1;
05698 for (shifter=1,i=0; i<n; ++i) shifter *= 10;
05699
05700
05701
05702
05703
05704
05705
05706
05707
05708
05709
05710
05711
05712
05713
05714
05715
05716
05717
05718
05719
05720
05721
05722 fracf = (v % (shifter * 10) > 0);
05723 fracf_1further = ((v % shifter) > 0);
05724
05725 v /= shifter;
05726 div = v / 10;
05727 v = v - div*10;
05728
05729
05730
05731
05732
05733
05734
05735
05736
05737
05738
05739 for (i=ix+1; (size_t)i < y->Prec; i++) {
05740 if (y->frac[i] % BASE) {
05741 fracf = fracf_1further = 1;
05742 break;
05743 }
05744 }
05745
05746
05747
05748
05749
05750
05751
05752 memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(BDIGIT));
05753
05754 switch(f) {
05755 case VP_ROUND_DOWN:
05756 break;
05757 case VP_ROUND_UP:
05758 if (fracf) ++div;
05759 break;
05760 case VP_ROUND_HALF_UP:
05761 if (v>=5) ++div;
05762 break;
05763 case VP_ROUND_HALF_DOWN:
05764 if (v > 5 || (v == 5 && fracf_1further)) ++div;
05765 break;
05766 case VP_ROUND_CEIL:
05767 if (fracf && (VpGetSign(y)>0)) ++div;
05768 break;
05769 case VP_ROUND_FLOOR:
05770 if (fracf && (VpGetSign(y)<0)) ++div;
05771 break;
05772 case VP_ROUND_HALF_EVEN:
05773 if (v > 5) ++div;
05774 else if (v == 5) {
05775 if (fracf_1further) {
05776 ++div;
05777 }
05778 else {
05779 if (ioffset == 0) {
05780
05781
05782
05783
05784
05785 if (ix && (y->frac[ix-1] % 2)) ++div;
05786 }
05787 else {
05788 if (div % 2) ++div;
05789 }
05790 }
05791 }
05792 break;
05793 }
05794 for (i=0; i<=n; ++i) div *= 10;
05795 if (div>=BASE) {
05796 if(ix) {
05797 y->frac[ix] = 0;
05798 VpRdup(y,ix);
05799 } else {
05800 short s = VpGetSign(y);
05801 SIGNED_VALUE e = y->exponent;
05802 VpSetOne(y);
05803 VpSetSign(y, s);
05804 y->exponent = e+1;
05805 }
05806 } else {
05807 y->frac[ix] = div;
05808 VpNmlz(y);
05809 }
05810 if (exptoadd > 0) {
05811 y->exponent += (SIGNED_VALUE)(exptoadd/BASE_FIG);
05812 exptoadd %= (ssize_t)BASE_FIG;
05813 for(i=0;i<exptoadd;i++) {
05814 y->frac[0] *= 10;
05815 if (y->frac[0] >= BASE) {
05816 y->frac[0] /= BASE;
05817 y->exponent++;
05818 }
05819 }
05820 }
05821 return 1;
05822 }
05823
05824 VP_EXPORT int
05825 VpLeftRound(Real *y, unsigned short f, ssize_t nf)
05826
05827
05828
05829 {
05830 BDIGIT v;
05831 if (!VpHasVal(y)) return 0;
05832 v = y->frac[0];
05833 nf -= VpExponent(y)*(ssize_t)BASE_FIG;
05834 while ((v /= 10) != 0) nf--;
05835 nf += (ssize_t)BASE_FIG-1;
05836 return VpMidRound(y,f,nf);
05837 }
05838
05839 VP_EXPORT int
05840 VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
05841 {
05842
05843 if (VpAsgn(y, x, 10) <= 1) return 0;
05844 return VpMidRound(y,f,nf);
05845 }
05846
05847 static int
05848 VpLimitRound(Real *c, size_t ixDigit)
05849 {
05850 size_t ix = VpGetPrecLimit();
05851 if(!VpNmlz(c)) return -1;
05852 if(!ix) return 0;
05853 if(!ixDigit) ixDigit = c->Prec-1;
05854 if((ix+BASE_FIG-1)/BASE_FIG > ixDigit+1) return 0;
05855 return VpLeftRound(c, VpGetRoundMode(), (ssize_t)ix);
05856 }
05857
05858
05859
05860 static void
05861 VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v)
05862 {
05863 int f = 0;
05864
05865 unsigned short const rounding_mode = VpGetRoundMode();
05866
05867 if (VpLimitRound(c, ixDigit)) return;
05868 if (!v) return;
05869
05870 v /= BASE1;
05871 switch (rounding_mode) {
05872 case VP_ROUND_DOWN:
05873 break;
05874 case VP_ROUND_UP:
05875 if (v) f = 1;
05876 break;
05877 case VP_ROUND_HALF_UP:
05878 if (v >= 5) f = 1;
05879 break;
05880 case VP_ROUND_HALF_DOWN:
05881
05882
05883
05884 if (v >= 6) f = 1;
05885 break;
05886 case VP_ROUND_CEIL:
05887 if (v && (VpGetSign(c) > 0)) f = 1;
05888 break;
05889 case VP_ROUND_FLOOR:
05890 if (v && (VpGetSign(c) < 0)) f = 1;
05891 break;
05892 case VP_ROUND_HALF_EVEN:
05893
05894
05895 if (v > 5) f = 1;
05896 else if (v == 5 && vPrev % 2) f = 1;
05897 break;
05898 }
05899 if (f) {
05900 VpRdup(c, ixDigit);
05901 VpNmlz(c);
05902 }
05903 }
05904
05905
05906
05907
05908 static int
05909 VpRdup(Real *m, size_t ind_m)
05910 {
05911 BDIGIT carry;
05912
05913 if (!ind_m) ind_m = m->Prec;
05914
05915 carry = 1;
05916 while (carry > 0 && (ind_m--)) {
05917 m->frac[ind_m] += carry;
05918 if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
05919 else carry = 0;
05920 }
05921 if(carry > 0) {
05922 if (!AddExponent(m, 1)) return 0;
05923 m->Prec = m->frac[0] = 1;
05924 } else {
05925 VpNmlz(m);
05926 }
05927 return 1;
05928 }
05929
05930
05931
05932
05933 VP_EXPORT void
05934 VpFrac(Real *y, Real *x)
05935 {
05936 size_t my, ind_y, ind_x;
05937
05938 if(!VpHasVal(x)) {
05939 VpAsgn(y,x,1);
05940 goto Exit;
05941 }
05942
05943 if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) {
05944 VpSetZero(y,VpGetSign(x));
05945 goto Exit;
05946 }
05947 else if(x->exponent <= 0) {
05948 VpAsgn(y, x, 1);
05949 goto Exit;
05950 }
05951
05952
05953
05954 y->Prec = x->Prec - (size_t)x->exponent;
05955 y->Prec = Min(y->Prec, y->MaxPrec);
05956 y->exponent = 0;
05957 VpSetSign(y,VpGetSign(x));
05958 ind_y = 0;
05959 my = y->Prec;
05960 ind_x = x->exponent;
05961 while(ind_y < my) {
05962 y->frac[ind_y] = x->frac[ind_x];
05963 ++ind_y;
05964 ++ind_x;
05965 }
05966 VpNmlz(y);
05967
05968 Exit:
05969 #ifdef BIGDECIMAL_DEBUG
05970 if(gfDebug) {
05971 VPrint(stdout, "VpFrac y=%\n", y);
05972 VPrint(stdout, " x=%\n", x);
05973 }
05974 #endif
05975 return;
05976 }
05977
05978
05979
05980
05981 VP_EXPORT int
05982 VpPower(Real *y, Real *x, SIGNED_VALUE n)
05983 {
05984 size_t s, ss;
05985 ssize_t sign;
05986 Real *w1 = NULL;
05987 Real *w2 = NULL;
05988
05989 if(VpIsZero(x)) {
05990 if(n==0) {
05991 VpSetOne(y);
05992 goto Exit;
05993 }
05994 sign = VpGetSign(x);
05995 if(n<0) {
05996 n = -n;
05997 if(sign<0) sign = (n%2)?(-1):(1);
05998 VpSetInf (y,sign);
05999 } else {
06000 if(sign<0) sign = (n%2)?(-1):(1);
06001 VpSetZero(y,sign);
06002 }
06003 goto Exit;
06004 }
06005 if(VpIsNaN(x)) {
06006 VpSetNaN(y);
06007 goto Exit;
06008 }
06009 if(VpIsInf(x)) {
06010 if(n==0) {
06011 VpSetOne(y);
06012 goto Exit;
06013 }
06014 if(n>0) {
06015 VpSetInf(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
06016 goto Exit;
06017 }
06018 VpSetZero(y, (n%2==0 || VpIsPosInf(x)) ? 1 : -1);
06019 goto Exit;
06020 }
06021
06022 if((x->exponent == 1) &&(x->Prec == 1) &&(x->frac[0] == 1)) {
06023
06024 VpSetOne(y);
06025 if(VpGetSign(x) > 0) goto Exit;
06026 if((n % 2) == 0) goto Exit;
06027 VpSetSign(y, -1);
06028 goto Exit;
06029 }
06030
06031 if(n > 0) sign = 1;
06032 else if(n < 0) {
06033 sign = -1;
06034 n = -n;
06035 } else {
06036 VpSetOne(y);
06037 goto Exit;
06038 }
06039
06040
06041
06042 w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0");
06043 w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0");
06044
06045
06046 VpAsgn(y, x, 1);
06047 --n;
06048 while(n > 0) {
06049 VpAsgn(w1, x, 1);
06050 s = 1;
06051 while (ss = s, (s += s) <= (size_t)n) {
06052 VpMult(w2, w1, w1);
06053 VpAsgn(w1, w2, 1);
06054 }
06055 n -= (SIGNED_VALUE)ss;
06056 VpMult(w2, y, w1);
06057 VpAsgn(y, w2, 1);
06058 }
06059 if(sign < 0) {
06060 VpDivd(w1, w2, VpConstOne, y);
06061 VpAsgn(y, w1, 1);
06062 }
06063
06064 Exit:
06065 #ifdef BIGDECIMAL_DEBUG
06066 if(gfDebug) {
06067 VPrint(stdout, "VpPower y=%\n", y);
06068 VPrint(stdout, "VpPower x=%\n", x);
06069 printf(" n=%d\n", n);
06070 }
06071 #endif
06072 VpFree(w2);
06073 VpFree(w1);
06074 return 1;
06075 }
06076
06077 #ifdef BIGDECIMAL_DEBUG
06078 int
06079 VpVarCheck(Real * v)
06080
06081
06082
06083
06084
06085
06086
06087
06088 {
06089 size_t i;
06090
06091 if(v->MaxPrec <= 0) {
06092 printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n",
06093 v->MaxPrec);
06094 return 1;
06095 }
06096 if((v->Prec <= 0) ||((v->Prec) >(v->MaxPrec))) {
06097 printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec);
06098 printf(" Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec);
06099 return 2;
06100 }
06101 for(i = 0; i < v->Prec; ++i) {
06102 if((v->frac[i] >= BASE)) {
06103 printf("ERROR(VpVarCheck): Illegal fraction\n");
06104 printf(" Frac[%"PRIuSIZE"]=%lu\n", i, v->frac[i]);
06105 printf(" Prec. =%"PRIuSIZE"\n", v->Prec);
06106 printf(" Exp. =%"PRIdVALUE"\n", v->exponent);
06107 printf(" BASE =%lu\n", BASE);
06108 return 3;
06109 }
06110 }
06111 return 0;
06112 }
06113 #endif
06114