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