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