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