* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / ext / bigdecimal / bigdecimal.c
blob213d9ea1493ff24b8d3bae9182321e663d5976c4
1 /*
3 * Ruby BigDecimal(Variable decimal precision) extension library.
5 * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file
9 * of this BigDecimal distribution.
11 * NOTE: Change log in this source removed to reduce source code size.
12 * See rev. 1.25 if needed.
16 #include "ruby/ruby.h"
17 #include <ctype.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <float.h>
23 #include <math.h>
24 #include "math.h"
26 #ifdef HAVE_IEEEFP_H
27 #include <ieeefp.h>
28 #endif
30 /* #define ENABLE_NUMERIC_STRING */
32 VALUE rb_cBigDecimal;
34 #include "bigdecimal.h"
36 /* MACRO's to guard objects from GC by keeping them in stack */
37 #define ENTER(n) volatile VALUE vStack[n];int iStack=0
38 #define PUSH(x) vStack[iStack++] = (unsigned long)(x);
39 #define SAVE(p) PUSH(p->obj);
40 #define GUARD_OBJ(p,y) {p=y;SAVE(p);}
43 * ================== Ruby Interface part ==========================
45 #define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
47 #if 0
48 /* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
50 * Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
51 * You may distribute under the terms of either the GNU General Public
52 * License or the Artistic License, as specified in the README file
53 * of the BigDecimal distribution.
55 * Documented by mathew <meta@pobox.com>.
57 * = Introduction
59 * Ruby provides built-in support for arbitrary precision integer arithmetic.
60 * For example:
62 * 42**13 -> 1265437718438866624512
64 * BigDecimal provides similar support for very large or very accurate floating
65 * point numbers.
67 * Decimal arithmetic is also useful for general calculation, because it
68 * provides the correct answers people expect--whereas normal binary floating
69 * point arithmetic often introduces subtle errors because of the conversion
70 * between base 10 and base 2. For example, try:
72 * sum = 0
73 * for i in (1..10000)
74 * sum = sum + 0.0001
75 * end
76 * print sum
78 * and contrast with the output from:
80 * require 'bigdecimal'
82 * sum = BigDecimal.new("0")
83 * for i in (1..10000)
84 * sum = sum + BigDecimal.new("0.0001")
85 * end
86 * print sum
88 * Similarly:
90 * (BigDecimal.new("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") -> true
92 * (1.2 - 1.0) == 0.2 -> false
94 * = Special features of accurate decimal arithmetic
96 * Because BigDecimal is more accurate than normal binary floating point
97 * arithmetic, it requires some special values.
99 * == Infinity
101 * BigDecimal sometimes needs to return infinity, for example if you divide
102 * a value by zero.
104 * BigDecimal.new("1.0") / BigDecimal.new("0.0") -> infinity
106 * BigDecimal.new("-1.0") / BigDecimal.new("0.0") -> -infinity
108 * You can represent infinite numbers to BigDecimal using the strings
109 * 'Infinity', '+Infinity' and '-Infinity' (case-sensitive)
111 * == Not a Number
113 * When a computation results in an undefined value, the special value NaN
114 * (for 'not a number') is returned.
116 * Example:
118 * BigDecimal.new("0.0") / BigDecimal.new("0.0") -> NaN
120 * You can also create undefined values. NaN is never considered to be the
121 * same as any other value, even NaN itself:
123 * n = BigDecimal.new('NaN')
125 * n == 0.0 -> nil
127 * n == n -> nil
129 * == Positive and negative zero
131 * If a computation results in a value which is too small to be represented as
132 * a BigDecimal within the currently specified limits of precision, zero must
133 * be returned.
135 * If the value which is too small to be represented is negative, a BigDecimal
136 * value of negative zero is returned. If the value is positive, a value of
137 * positive zero is returned.
139 * BigDecimal.new("1.0") / BigDecimal.new("-Infinity") -> -0.0
141 * BigDecimal.new("1.0") / BigDecimal.new("Infinity") -> 0.0
143 * (See BigDecimal.mode for how to specify limits of precision.)
145 * Note that -0.0 and 0.0 are considered to be the same for the purposes of
146 * comparison.
148 * Note also that in mathematics, there is no particular concept of negative
149 * or positive zero; true mathematical zero has no sign.
151 void
152 Init_BigDecimal()
154 /* This is a #if-ed out function to fool Rdoc into documenting the class. */
155 /* The real init function is Init_bigdecimal() further down. */
157 #endif
160 * Returns the BigDecimal version number.
162 * Ruby 1.8.0 returns 1.0.0.
163 * Ruby 1.8.1 thru 1.8.3 return 1.0.1.
165 static VALUE
166 BigDecimal_version(VALUE self)
169 * 1.0.0: Ruby 1.8.0
170 * 1.0.1: Ruby 1.8.1
172 return rb_str_new2("1.0.1");
176 * VP routines used in BigDecimal part
178 static unsigned short VpGetException(void);
179 static void VpSetException(unsigned short f);
180 static void VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v);
181 static int VpLimitRound(Real *c,U_LONG ixDigit);
184 * **** BigDecimal part ****
187 static void
188 BigDecimal_delete(Real *pv)
190 VpFree(pv);
193 static VALUE
194 ToValue(Real *p)
196 if(VpIsNaN(p)) {
197 VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
198 } else if(VpIsPosInf(p)) {
199 VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
200 } else if(VpIsNegInf(p)) {
201 VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
203 return p->obj;
206 static Real *
207 GetVpValue(VALUE v, int must)
209 Real *pv;
210 VALUE bg;
211 char szD[128];
213 switch(TYPE(v))
215 case T_DATA:
216 if(RDATA(v)->dfree ==(void *) BigDecimal_delete) {
217 Data_Get_Struct(v, Real, pv);
218 return pv;
219 } else {
220 goto SomeOneMayDoIt;
222 break;
223 case T_FIXNUM:
224 sprintf(szD, "%ld", FIX2LONG(v));
225 return VpCreateRbObject(VpBaseFig() * 2 + 1, szD);
227 #ifdef ENABLE_NUMERIC_STRING
228 case T_STRING:
229 SafeStringValue(v);
230 return VpCreateRbObject(strlen(RSTRING_PTR(v)) + VpBaseFig() + 1,
231 RSTRING_PTR(v));
232 #endif /* ENABLE_NUMERIC_STRING */
234 case T_BIGNUM:
235 bg = rb_big2str(v, 10);
236 return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1,
237 RSTRING_PTR(bg));
238 default:
239 goto SomeOneMayDoIt;
242 SomeOneMayDoIt:
243 if(must) {
244 rb_raise(rb_eTypeError, "%s can't be coerced into BigDecimal",
245 rb_special_const_p(v)?
246 RSTRING_PTR(rb_inspect(v)):
247 rb_obj_classname(v)
250 return NULL; /* NULL means to coerce */
253 /* call-seq:
254 * BigDecimal.double_fig
256 * The BigDecimal.double_fig class method returns the number of digits a
257 * Float number is allowed to have. The result depends upon the CPU and OS
258 * in use.
260 static VALUE
261 BigDecimal_double_fig(VALUE self)
263 return INT2FIX(VpDblFig());
266 /* call-seq:
267 * precs
269 * Returns an Array of two Integer values.
271 * The first value is the current number of significant digits in the
272 * BigDecimal. The second value is the maximum number of significant digits
273 * for the BigDecimal.
275 static VALUE
276 BigDecimal_prec(VALUE self)
278 ENTER(1);
279 Real *p;
280 VALUE obj;
282 GUARD_OBJ(p,GetVpValue(self,1));
283 obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
284 INT2NUM(p->MaxPrec*VpBaseFig()));
285 return obj;
288 static VALUE
289 BigDecimal_hash(VALUE self)
291 ENTER(1);
292 Real *p;
293 U_LONG hash,i;
295 GUARD_OBJ(p,GetVpValue(self,1));
296 hash = (U_LONG)p->sign;
297 /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
298 if(hash==2) {
299 for(i = 0; i < p->Prec;i++) {
300 hash = 31 * hash + p->frac[i];
301 hash ^= p->frac[i];
303 hash += p->exponent;
305 return INT2FIX(hash);
308 static VALUE
309 BigDecimal_dump(int argc, VALUE *argv, VALUE self)
311 ENTER(5);
312 char sz[50];
313 Real *vp;
314 char *psz;
315 VALUE dummy;
316 rb_scan_args(argc, argv, "01", &dummy);
317 GUARD_OBJ(vp,GetVpValue(self,1));
318 sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
319 psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
320 sprintf(psz,"%s",sz);
321 VpToString(vp, psz+strlen(psz), 0, 0);
322 return rb_str_new2(psz);
326 * Internal method used to provide marshalling support. See the Marshal module.
328 static VALUE
329 BigDecimal_load(VALUE self, VALUE str)
331 ENTER(2);
332 Real *pv;
333 unsigned char *pch;
334 unsigned char ch;
335 unsigned long m=0;
337 SafeStringValue(str);
338 pch = (unsigned char *)RSTRING_PTR(str);
339 /* First get max prec */
340 while((*pch)!=(unsigned char)'\0' && (ch=*pch++)!=(unsigned char)':') {
341 if(!ISDIGIT(ch)) {
342 rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
344 m = m*10 + (unsigned long)(ch-'0');
346 if(m>VpBaseFig()) m -= VpBaseFig();
347 GUARD_OBJ(pv,VpNewRbClass(m,(char *)pch,self));
348 m /= VpBaseFig();
349 if(m && pv->MaxPrec>m) pv->MaxPrec = m+1;
350 return ToValue(pv);
353 /* call-seq:
354 * BigDecimal.mode(mode, value)
356 * Controls handling of arithmetic exceptions and rounding. If no value
357 * is supplied, the current value is returned.
359 * Six values of the mode parameter control the handling of arithmetic
360 * exceptions:
362 * BigDecimal::EXCEPTION_NaN
363 * BigDecimal::EXCEPTION_INFINITY
364 * BigDecimal::EXCEPTION_UNDERFLOW
365 * BigDecimal::EXCEPTION_OVERFLOW
366 * BigDecimal::EXCEPTION_ZERODIVIDE
367 * BigDecimal::EXCEPTION_ALL
369 * For each mode parameter above, if the value set is false, computation
370 * continues after an arithmetic exception of the appropriate type.
371 * When computation continues, results are as follows:
373 * EXCEPTION_NaN:: NaN
374 * EXCEPTION_INFINITY:: +infinity or -infinity
375 * EXCEPTION_UNDERFLOW:: 0
376 * EXCEPTION_OVERFLOW:: +infinity or -infinity
377 * EXCEPTION_ZERODIVIDE:: +infinity or -infinity
379 * One value of the mode parameter controls the rounding of numeric values:
380 * BigDecimal::ROUND_MODE. The values it can take are:
382 * ROUND_UP:: round away from zero
383 * ROUND_DOWN:: round towards zero (truncate)
384 * ROUND_HALF_UP:: round up if the appropriate digit >= 5, otherwise truncate (default)
385 * ROUND_HALF_DOWN:: round up if the appropriate digit >= 6, otherwise truncate
386 * ROUND_HALF_EVEN:: round towards the even neighbor (Banker's rounding)
387 * ROUND_CEILING:: round towards positive infinity (ceil)
388 * ROUND_FLOOR:: round towards negative infinity (floor)
391 static VALUE
392 BigDecimal_mode(int argc, VALUE *argv, VALUE self)
394 VALUE which;
395 VALUE val;
396 unsigned long f,fo;
398 if(rb_scan_args(argc,argv,"11",&which,&val)==1) val = Qnil;
400 Check_Type(which, T_FIXNUM);
401 f = (unsigned long)FIX2INT(which);
403 if(f&VP_EXCEPTION_ALL) {
404 /* Exception mode setting */
405 fo = VpGetException();
406 if(val==Qnil) return INT2FIX(fo);
407 if(val!=Qfalse && val!=Qtrue) {
408 rb_raise(rb_eTypeError, "second argument must be true or false");
409 return Qnil; /* Not reached */
411 if(f&VP_EXCEPTION_INFINITY) {
412 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_INFINITY):
413 (fo&(~VP_EXCEPTION_INFINITY))));
415 if(f&VP_EXCEPTION_NaN) {
416 VpSetException((unsigned short)((val==Qtrue)?(fo|VP_EXCEPTION_NaN):
417 (fo&(~VP_EXCEPTION_NaN))));
419 fo = VpGetException();
420 return INT2FIX(fo);
422 if(VP_ROUND_MODE==f) {
423 /* Rounding mode setting */
424 fo = VpGetRoundMode();
425 if(val==Qnil) return INT2FIX(fo);
426 Check_Type(val, T_FIXNUM);
427 if(!VpIsRoundMode(FIX2INT(val))) {
428 rb_raise(rb_eTypeError, "invalid rounding mode");
429 return Qnil;
431 fo = VpSetRoundMode((unsigned long)FIX2INT(val));
432 return INT2FIX(fo);
434 rb_raise(rb_eTypeError, "first argument for BigDecimal#mode invalid");
435 return Qnil;
438 static U_LONG
439 GetAddSubPrec(Real *a, Real *b)
441 U_LONG mxs;
442 U_LONG mx = a->Prec;
443 S_INT d;
445 if(!VpIsDef(a) || !VpIsDef(b)) return (-1L);
446 if(mx < b->Prec) mx = b->Prec;
447 if(a->exponent!=b->exponent) {
448 mxs = mx;
449 d = a->exponent - b->exponent;
450 if(d<0) d = -d;
451 mx = mx+(U_LONG)d;
452 if(mx<mxs) {
453 return VpException(VP_EXCEPTION_INFINITY,"Exponent overflow",0);
456 return mx;
459 static S_INT
460 GetPositiveInt(VALUE v)
462 S_INT n;
463 Check_Type(v, T_FIXNUM);
464 n = FIX2INT(v);
465 if(n < 0) {
466 rb_raise(rb_eArgError, "argument must be positive");
468 return n;
471 VP_EXPORT Real *
472 VpNewRbClass(U_LONG mx, char *str, VALUE klass)
474 Real *pv = VpAlloc(mx,str);
475 pv->obj = (VALUE)Data_Wrap_Struct(klass, 0, BigDecimal_delete, pv);
476 return pv;
479 VP_EXPORT Real *
480 VpCreateRbObject(U_LONG mx, const char *str)
482 Real *pv = VpAlloc(mx,str);
483 pv->obj = (VALUE)Data_Wrap_Struct(rb_cBigDecimal, 0, BigDecimal_delete, pv);
484 return pv;
487 /* Returns True if the value is Not a Number */
488 static VALUE
489 BigDecimal_IsNaN(VALUE self)
491 Real *p = GetVpValue(self,1);
492 if(VpIsNaN(p)) return Qtrue;
493 return Qfalse;
496 /* Returns True if the value is infinite */
497 static VALUE
498 BigDecimal_IsInfinite(VALUE self)
500 Real *p = GetVpValue(self,1);
501 if(VpIsPosInf(p)) return INT2FIX(1);
502 if(VpIsNegInf(p)) return INT2FIX(-1);
503 return Qnil;
506 /* Returns True if the value is finite (not NaN or infinite) */
507 static VALUE
508 BigDecimal_IsFinite(VALUE self)
510 Real *p = GetVpValue(self,1);
511 if(VpIsNaN(p)) return Qfalse;
512 if(VpIsInf(p)) return Qfalse;
513 return Qtrue;
516 /* Returns the value as an integer (Fixnum or Bignum).
518 * If the BigNumber is infinity or NaN, returns nil.
520 static VALUE
521 BigDecimal_to_i(VALUE self)
523 ENTER(5);
524 int e,n,i,nf;
525 U_LONG v,b,j;
526 char *psz,*pch;
527 Real *p;
529 GUARD_OBJ(p,GetVpValue(self,1));
531 /* Infinity or NaN not converted. */
532 if(VpIsNaN(p)) {
533 VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
534 return Qnil;
535 } else if(VpIsPosInf(p)) {
536 VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
537 return Qnil;
538 } else if(VpIsNegInf(p)) {
539 VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
540 return Qnil;
543 e = VpExponent10(p);
544 if(e<=0) return INT2FIX(0);
545 nf = VpBaseFig();
546 if(e<=nf) {
547 e = VpGetSign(p)*p->frac[0];
548 return INT2FIX(e);
550 psz = ALLOCA_N(char,(unsigned int)(e+nf+2));
552 n = (e+nf-1)/nf;
553 pch = psz;
554 if(VpGetSign(p)<0) *pch++ = '-';
555 for(i=0;i<n;++i) {
556 b = VpBaseVal()/10;
557 if(i>=(int)p->Prec) {
558 while(b) {
559 *pch++ = '0';
560 b /= 10;
562 continue;
564 v = p->frac[i];
565 while(b) {
566 j = v/b;
567 *pch++ = (char)(j + '0');
568 v -= j*b;
569 b /= 10;
572 *pch++ = 0;
573 return rb_cstr2inum(psz,10);
576 static VALUE
577 BigDecimal_induced_from(VALUE self, VALUE x)
579 Real *p = GetVpValue(x,1);
580 return p->obj;
583 /* Returns a new Float object having approximately the same value as the
584 * BigDecimal number. Normal accuracy limits and built-in errors of binary
585 * Float arithmetic apply.
587 static VALUE
588 BigDecimal_to_f(VALUE self)
590 ENTER(1);
591 Real *p;
592 double d;
593 S_LONG e;
594 char *buf;
596 GUARD_OBJ(p,GetVpValue(self,1));
597 if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
598 buf = ALLOCA_N(char,(unsigned int)VpNumOfChars(p,"E"));
599 VpToString(p, buf, 0, 0);
600 errno = 0;
601 d = strtod(buf, 0);
602 if(errno == ERANGE) {
603 VpException(VP_EXCEPTION_OVERFLOW,"BigDecimal to Float conversion",0);
604 if(d>0.0) return rb_float_new(DBL_MAX);
605 else return rb_float_new(-DBL_MAX);
607 return rb_float_new(d);
610 /* The coerce method provides support for Ruby type coercion. It is not
611 * enabled by default.
613 * This means that binary operations like + * / or - can often be performed
614 * on a BigDecimal and an object of another type, if the other object can
615 * be coerced into a BigDecimal value.
617 * e.g.
618 * a = BigDecimal.new("1.0")
619 * b = a / 2.0 -> 0.5
621 * Note that coercing a String to a BigDecimal is not supported by default;
622 * it requires a special compile-time option when building Ruby.
624 static VALUE
625 BigDecimal_coerce(VALUE self, VALUE other)
627 ENTER(2);
628 VALUE obj;
629 Real *b;
630 if(TYPE(other) == T_FLOAT) {
631 obj = rb_assoc_new(other, BigDecimal_to_f(self));
632 } else {
633 GUARD_OBJ(b,GetVpValue(other,1));
634 obj = rb_assoc_new(b->obj, self);
636 return obj;
639 static VALUE
640 BigDecimal_uplus(VALUE self)
642 return self;
645 /* call-seq:
646 * add(value, digits)
648 * Add the specified value.
650 * e.g.
651 * c = a.add(b,n)
652 * c = a + b
654 * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
656 static VALUE
657 BigDecimal_add(VALUE self, VALUE r)
659 ENTER(5);
660 Real *c, *a, *b;
661 U_LONG mx;
662 GUARD_OBJ(a,GetVpValue(self,1));
663 b = GetVpValue(r,0);
664 if(!b) return DoSomeOne(self,r,'+');
665 SAVE(b);
666 if(VpIsNaN(b)) return b->obj;
667 if(VpIsNaN(a)) return a->obj;
668 mx = GetAddSubPrec(a,b);
669 if(mx==(-1L)) {
670 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
671 VpAddSub(c, a, b, 1);
672 } else {
673 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
674 if(!mx) {
675 VpSetInf(c,VpGetSign(a));
676 } else {
677 VpAddSub(c, a, b, 1);
680 return ToValue(c);
683 /* call-seq:
684 * sub(value, digits)
686 * Subtract the specified value.
688 * e.g.
689 * c = a.sub(b,n)
690 * c = a - b
692 * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
694 static VALUE
695 BigDecimal_sub(VALUE self, VALUE r)
697 ENTER(5);
698 Real *c, *a, *b;
699 U_LONG mx;
701 GUARD_OBJ(a,GetVpValue(self,1));
702 b = GetVpValue(r,0);
703 if(!b) return DoSomeOne(self,r,'-');
704 SAVE(b);
706 if(VpIsNaN(b)) return b->obj;
707 if(VpIsNaN(a)) return a->obj;
709 mx = GetAddSubPrec(a,b);
710 if(mx==(-1L)) {
711 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
712 VpAddSub(c, a, b, -1);
713 } else {
714 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
715 if(!mx) {
716 VpSetInf(c,VpGetSign(a));
717 } else {
718 VpAddSub(c, a, b, -1);
721 return ToValue(c);
724 static VALUE
725 BigDecimalCmp(VALUE self, VALUE r,char op)
727 ENTER(5);
728 S_INT e;
729 Real *a, *b;
730 GUARD_OBJ(a,GetVpValue(self,1));
731 b = GetVpValue(r,0);
732 if(!b) {
733 ID f = 0;
735 switch(op)
737 case '*': f = rb_intern("<=>");break;
738 case '=': f = rb_intern("=="); break;
739 case '!': f = rb_intern("!="); break;
740 case 'G': f = rb_intern(">="); break;
741 case 'L': f = rb_intern("<="); break;
742 case '>': case '<': f = (ID)op; break;
744 return rb_num_coerce_cmp(self,r,f);
746 SAVE(b);
747 e = VpComp(a, b);
748 if(e==999) return Qnil;
749 switch(op)
751 case '*': return INT2FIX(e); /* any op */
752 case '=': if(e==0) return Qtrue ; return Qfalse;
753 case '!': if(e!=0) return Qtrue ; return Qfalse;
754 case 'G': if(e>=0) return Qtrue ; return Qfalse;
755 case '>': if(e> 0) return Qtrue ; return Qfalse;
756 case 'L': if(e<=0) return Qtrue ; return Qfalse;
757 case '<': if(e< 0) return Qtrue ; return Qfalse;
759 rb_bug("Undefined operation in BigDecimalCmp()");
762 /* Returns True if the value is zero. */
763 static VALUE
764 BigDecimal_zero(VALUE self)
766 Real *a = GetVpValue(self,1);
767 return VpIsZero(a) ? Qtrue : Qfalse;
770 /* Returns True if the value is non-zero. */
771 static VALUE
772 BigDecimal_nonzero(VALUE self)
774 Real *a = GetVpValue(self,1);
775 return VpIsZero(a) ? Qnil : self;
778 /* The comparison operator.
779 * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
781 static VALUE
782 BigDecimal_comp(VALUE self, VALUE r)
784 return BigDecimalCmp(self, r, '*');
788 * Tests for value equality; returns true if the values are equal.
790 * The == and === operators and the eql? method have the same implementation
791 * for BigDecimal.
793 * Values may be coerced to perform the comparison:
795 * BigDecimal.new('1.0') == 1.0 -> true
797 static VALUE
798 BigDecimal_eq(VALUE self, VALUE r)
800 return BigDecimalCmp(self, r, '=');
803 /* call-seq:
804 * a < b
806 * Returns true if a is less than b. Values may be coerced to perform the
807 * comparison (see ==, coerce).
809 static VALUE
810 BigDecimal_lt(VALUE self, VALUE r)
812 return BigDecimalCmp(self, r, '<');
815 /* call-seq:
816 * a <= b
818 * Returns true if a is less than or equal to b. Values may be coerced to
819 * perform the comparison (see ==, coerce).
821 static VALUE
822 BigDecimal_le(VALUE self, VALUE r)
824 return BigDecimalCmp(self, r, 'L');
827 /* call-seq:
828 * a > b
830 * Returns true if a is greater than b. Values may be coerced to
831 * perform the comparison (see ==, coerce).
833 static VALUE
834 BigDecimal_gt(VALUE self, VALUE r)
836 return BigDecimalCmp(self, r, '>');
839 /* call-seq:
840 * a >= b
842 * Returns true if a is greater than or equal to b. Values may be coerced to
843 * perform the comparison (see ==, coerce)
845 static VALUE
846 BigDecimal_ge(VALUE self, VALUE r)
848 return BigDecimalCmp(self, r, 'G');
851 static VALUE
852 BigDecimal_neg(VALUE self)
854 ENTER(5);
855 Real *c, *a;
856 GUARD_OBJ(a,GetVpValue(self,1));
857 GUARD_OBJ(c,VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
858 VpAsgn(c, a, -1);
859 return ToValue(c);
862 /* call-seq:
863 * mult(value, digits)
865 * Multiply by the specified value.
867 * e.g.
868 * c = a.mult(b,n)
869 * c = a * b
871 * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
873 static VALUE
874 BigDecimal_mult(VALUE self, VALUE r)
876 ENTER(5);
877 Real *c, *a, *b;
878 U_LONG mx;
880 GUARD_OBJ(a,GetVpValue(self,1));
881 b = GetVpValue(r,0);
882 if(!b) return DoSomeOne(self,r,'*');
883 SAVE(b);
885 mx = a->Prec + b->Prec;
886 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
887 VpMult(c, a, b);
888 return ToValue(c);
891 static VALUE
892 BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
893 /* For c = self.div(r): with round operation */
895 ENTER(5);
896 Real *a, *b;
897 U_LONG mx;
899 GUARD_OBJ(a,GetVpValue(self,1));
900 b = GetVpValue(r,0);
901 if(!b) return DoSomeOne(self,r,'/');
902 SAVE(b);
903 *div = b;
904 mx =(a->MaxPrec + b->MaxPrec + 1) * VpBaseFig();
905 GUARD_OBJ((*c),VpCreateRbObject(mx, "#0"));
906 GUARD_OBJ((*res),VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
907 VpDivd(*c, *res, a, b);
908 return (VALUE)0;
911 /* call-seq:
912 * div(value, digits)
913 * quo(value)
915 * Divide by the specified value.
917 * e.g.
918 * c = a.div(b,n)
920 * digits:: If specified and less than the number of significant digits of the result, the result is rounded to that number of digits, according to BigDecimal.mode.
922 * If digits is 0, the result is the same as the / operator. If not, the
923 * result is an integer BigDecimal, by analogy with Float#div.
925 * The alias quo is provided since div(value, 0) is the same as computing
926 * the quotient; see divmod.
928 static VALUE
929 BigDecimal_div(VALUE self, VALUE r)
930 /* For c = self/r: with round operation */
932 ENTER(5);
933 Real *c=NULL, *res=NULL, *div = NULL;
934 r = BigDecimal_divide(&c, &res, &div, self, r);
935 if(r!=(VALUE)0) return r; /* coerced by other */
936 SAVE(c);SAVE(res);SAVE(div);
937 /* a/b = c + r/b */
938 /* c xxxxx
939 r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
941 /* Round */
942 if(VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
943 VpInternalRound(c,0,c->frac[c->Prec-1],(VpBaseVal()*res->frac[0])/div->frac[0]);
945 return ToValue(c);
949 * %: mod = a%b = a - (a.to_f/b).floor * b
950 * div = (a.to_f/b).floor
952 static VALUE
953 BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
955 ENTER(8);
956 Real *c=NULL, *d=NULL, *res=NULL;
957 Real *a, *b;
958 U_LONG mx;
960 GUARD_OBJ(a,GetVpValue(self,1));
961 b = GetVpValue(r,0);
962 if(!b) return DoSomeOne(self,r,rb_intern("divmod"));
963 SAVE(b);
965 if(VpIsNaN(a) || VpIsNaN(b)) goto NaN;
966 if(VpIsInf(a) || VpIsInf(b)) goto NaN;
967 if(VpIsZero(b)) goto NaN;
968 if(VpIsZero(a)) {
969 GUARD_OBJ(c,VpCreateRbObject(1, "0"));
970 GUARD_OBJ(d,VpCreateRbObject(1, "0"));
971 *div = d;
972 *mod = c;
973 return (VALUE)0;
976 mx = a->Prec;
977 if(mx<b->Prec) mx = b->Prec;
978 mx =(mx + 1) * VpBaseFig();
979 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
980 GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
981 VpDivd(c, res, a, b);
982 mx = c->Prec *(VpBaseFig() + 1);
983 GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
984 VpActiveRound(d,c,VP_ROUND_DOWN,0);
985 VpMult(res,d,b);
986 VpAddSub(c,a,res,-1);
987 if(!VpIsZero(c) && (VpGetSign(a)*VpGetSign(b)<0)) {
988 VpAddSub(res,d,VpOne(),-1);
989 VpAddSub(d ,c,b, 1);
990 *div = res;
991 *mod = d;
992 } else {
993 *div = d;
994 *mod = c;
996 return (VALUE)0;
998 NaN:
999 GUARD_OBJ(c,VpCreateRbObject(1, "NaN"));
1000 GUARD_OBJ(d,VpCreateRbObject(1, "NaN"));
1001 *div = d;
1002 *mod = c;
1003 return (VALUE)0;
1006 /* call-seq:
1007 * a % b
1008 * a.modulo(b)
1010 * Returns the modulus from dividing by b. See divmod.
1012 static VALUE
1013 BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
1015 ENTER(3);
1016 VALUE obj;
1017 Real *div=NULL, *mod=NULL;
1019 obj = BigDecimal_DoDivmod(self,r,&div,&mod);
1020 if(obj!=(VALUE)0) return obj;
1021 SAVE(div);SAVE(mod);
1022 return ToValue(mod);
1025 static VALUE
1026 BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1028 ENTER(10);
1029 U_LONG mx;
1030 Real *a=NULL, *b=NULL, *c=NULL, *res=NULL, *d=NULL, *rr=NULL, *ff=NULL;
1031 Real *f=NULL;
1033 GUARD_OBJ(a,GetVpValue(self,1));
1034 b = GetVpValue(r,0);
1035 if(!b) return DoSomeOne(self,r,rb_intern("remainder"));
1036 SAVE(b);
1038 mx =(a->MaxPrec + b->MaxPrec) *VpBaseFig();
1039 GUARD_OBJ(c ,VpCreateRbObject(mx, "0"));
1040 GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
1041 GUARD_OBJ(rr ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
1042 GUARD_OBJ(ff ,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
1044 VpDivd(c, res, a, b);
1046 mx = c->Prec *(VpBaseFig() + 1);
1048 GUARD_OBJ(d,VpCreateRbObject(mx, "0"));
1049 GUARD_OBJ(f,VpCreateRbObject(mx, "0"));
1051 VpActiveRound(d,c,VP_ROUND_DOWN,0); /* 0: round off */
1053 VpFrac(f, c);
1054 VpMult(rr,f,b);
1055 VpAddSub(ff,res,rr,1);
1057 *dv = d;
1058 *rv = ff;
1059 return (VALUE)0;
1062 /* Returns the remainder from dividing by the value.
1064 * If the values divided are of the same sign, the remainder is the same as
1065 * the modulus (see divmod).
1067 * Otherwise, the remainder is the modulus minus the value divided by.
1069 static VALUE
1070 BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
1072 VALUE f;
1073 Real *d,*rv=0;
1074 f = BigDecimal_divremain(self,r,&d,&rv);
1075 if(f!=(VALUE)0) return f;
1076 return ToValue(rv);
1079 /* Divides by the specified value, and returns the quotient and modulus
1080 * as BigDecimal numbers. The quotient is rounded towards negative infinity.
1082 * For example:
1084 * require 'bigdecimal'
1086 * a = BigDecimal.new("42")
1087 * b = BigDecimal.new("9")
1089 * q,m = a.divmod(b)
1091 * c = q * b + m
1093 * a == c -> true
1095 * The quotient q is (a/b).floor, and the modulus is the amount that must be
1096 * added to q * b to get a.
1098 static VALUE
1099 BigDecimal_divmod(VALUE self, VALUE r)
1101 ENTER(5);
1102 VALUE obj;
1103 Real *div=NULL, *mod=NULL;
1105 obj = BigDecimal_DoDivmod(self,r,&div,&mod);
1106 if(obj!=(VALUE)0) return obj;
1107 SAVE(div);SAVE(mod);
1108 obj = rb_assoc_new(ToValue(div), ToValue(mod));
1109 return obj;
1112 static VALUE
1113 BigDecimal_div2(int argc, VALUE *argv, VALUE self)
1115 ENTER(5);
1116 VALUE b,n;
1117 int na = rb_scan_args(argc,argv,"11",&b,&n);
1118 if(na==1) { /* div in Float sense */
1119 VALUE obj;
1120 Real *div=NULL;
1121 Real *mod;
1122 obj = BigDecimal_DoDivmod(self,b,&div,&mod);
1123 if(obj!=(VALUE)0) return obj;
1124 return ToValue(div);
1125 } else { /* div in BigDecimal sense */
1126 U_LONG ix = (U_LONG)GetPositiveInt(n);
1127 if(ix==0) return BigDecimal_div(self,b);
1128 else {
1129 Real *res=NULL;
1130 Real *av=NULL, *bv=NULL, *cv=NULL;
1131 U_LONG mx = (ix+VpBaseFig()*2);
1132 U_LONG pl = VpSetPrecLimit(0);
1134 GUARD_OBJ(cv,VpCreateRbObject(mx,"0"));
1135 GUARD_OBJ(av,GetVpValue(self,1));
1136 GUARD_OBJ(bv,GetVpValue(b,1));
1137 mx = av->Prec + bv->Prec + 2;
1138 if(mx <= cv->MaxPrec) mx = cv->MaxPrec+1;
1139 GUARD_OBJ(res,VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
1140 VpDivd(cv,res,av,bv);
1141 VpSetPrecLimit(pl);
1142 VpLeftRound(cv,VpGetRoundMode(),ix);
1143 return ToValue(cv);
1148 static VALUE
1149 BigDecimal_add2(VALUE self, VALUE b, VALUE n)
1151 ENTER(2);
1152 Real *cv;
1153 U_LONG mx = (U_LONG)GetPositiveInt(n);
1154 if(mx==0) return BigDecimal_add(self,b);
1155 else {
1156 U_LONG pl = VpSetPrecLimit(0);
1157 VALUE c = BigDecimal_add(self,b);
1158 VpSetPrecLimit(pl);
1159 GUARD_OBJ(cv,GetVpValue(c,1));
1160 VpLeftRound(cv,VpGetRoundMode(),mx);
1161 return ToValue(cv);
1165 static VALUE
1166 BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
1168 ENTER(2);
1169 Real *cv;
1170 U_LONG mx = (U_LONG)GetPositiveInt(n);
1171 if(mx==0) return BigDecimal_sub(self,b);
1172 else {
1173 U_LONG pl = VpSetPrecLimit(0);
1174 VALUE c = BigDecimal_sub(self,b);
1175 VpSetPrecLimit(pl);
1176 GUARD_OBJ(cv,GetVpValue(c,1));
1177 VpLeftRound(cv,VpGetRoundMode(),mx);
1178 return ToValue(cv);
1182 static VALUE
1183 BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
1185 ENTER(2);
1186 Real *cv;
1187 U_LONG mx = (U_LONG)GetPositiveInt(n);
1188 if(mx==0) return BigDecimal_mult(self,b);
1189 else {
1190 U_LONG pl = VpSetPrecLimit(0);
1191 VALUE c = BigDecimal_mult(self,b);
1192 VpSetPrecLimit(pl);
1193 GUARD_OBJ(cv,GetVpValue(c,1));
1194 VpLeftRound(cv,VpGetRoundMode(),mx);
1195 return ToValue(cv);
1199 /* Returns the absolute value.
1201 * BigDecimal('5').abs -> 5
1203 * BigDecimal('-3').abs -> 3
1205 static VALUE
1206 BigDecimal_abs(VALUE self)
1208 ENTER(5);
1209 Real *c, *a;
1210 U_LONG mx;
1212 GUARD_OBJ(a,GetVpValue(self,1));
1213 mx = a->Prec *(VpBaseFig() + 1);
1214 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1215 VpAsgn(c, a, 1);
1216 VpChangeSign(c,(S_INT)1);
1217 return ToValue(c);
1220 /* call-seq:
1221 * sqrt(n)
1223 * Returns the square root of the value.
1225 * If n is specified, returns at least that many significant digits.
1227 static VALUE
1228 BigDecimal_sqrt(VALUE self, VALUE nFig)
1230 ENTER(5);
1231 Real *c, *a;
1232 S_INT mx, n;
1234 GUARD_OBJ(a,GetVpValue(self,1));
1235 mx = a->Prec *(VpBaseFig() + 1);
1237 n = GetPositiveInt(nFig) + VpDblFig() + 1;
1238 if(mx <= n) mx = n;
1239 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1240 VpSqrt(c, a);
1241 return ToValue(c);
1244 /* Return the integer part of the number.
1246 static VALUE
1247 BigDecimal_fix(VALUE self)
1249 ENTER(5);
1250 Real *c, *a;
1251 U_LONG mx;
1253 GUARD_OBJ(a,GetVpValue(self,1));
1254 mx = a->Prec *(VpBaseFig() + 1);
1255 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1256 VpActiveRound(c,a,VP_ROUND_DOWN,0); /* 0: round off */
1257 return ToValue(c);
1260 /* call-seq:
1261 * round(n,mode)
1263 * Round to the nearest 1 (by default), returning the result as a BigDecimal.
1265 * BigDecimal('3.14159').round -> 3
1267 * BigDecimal('8.7').round -> 9
1269 * If n is specified and positive, the fractional part of the result has no
1270 * more than that many digits.
1272 * If n is specified and negative, at least that many digits to the left of the
1273 * decimal point will be 0 in the result.
1275 * BigDecimal('3.14159').round(3) -> 3.142
1277 * BigDecimal('13345.234').round(-2) -> 13300.0
1279 * The value of the optional mode argument can be used to determine how
1280 * rounding is performed; see BigDecimal.mode.
1282 static VALUE
1283 BigDecimal_round(int argc, VALUE *argv, VALUE self)
1285 ENTER(5);
1286 Real *c, *a;
1287 int iLoc = 0;
1288 U_LONG mx;
1289 VALUE vLoc;
1290 VALUE vRound;
1291 U_LONG pl;
1293 int sw = VpGetRoundMode();
1295 int na = rb_scan_args(argc,argv,"02",&vLoc,&vRound);
1296 switch(na) {
1297 case 0:
1298 iLoc = 0;
1299 break;
1300 case 1:
1301 Check_Type(vLoc, T_FIXNUM);
1302 iLoc = FIX2INT(vLoc);
1303 break;
1304 case 2:
1305 Check_Type(vLoc, T_FIXNUM);
1306 iLoc = FIX2INT(vLoc);
1307 Check_Type(vRound, T_FIXNUM);
1308 sw = FIX2INT(vRound);
1309 if(!VpIsRoundMode(sw)) {
1310 rb_raise(rb_eTypeError, "invalid rounding mode");
1311 return Qnil;
1313 break;
1316 pl = VpSetPrecLimit(0);
1317 GUARD_OBJ(a,GetVpValue(self,1));
1318 mx = a->Prec *(VpBaseFig() + 1);
1319 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1320 VpSetPrecLimit(pl);
1321 VpActiveRound(c,a,sw,iLoc);
1322 return ToValue(c);
1325 /* call-seq:
1326 * truncate(n)
1328 * Truncate to the nearest 1, returning the result as a BigDecimal.
1330 * BigDecimal('3.14159').truncate -> 3
1332 * BigDecimal('8.7').truncate -> 8
1334 * If n is specified and positive, the fractional part of the result has no
1335 * more than that many digits.
1337 * If n is specified and negative, at least that many digits to the left of the
1338 * decimal point will be 0 in the result.
1340 * BigDecimal('3.14159').truncate(3) -> 3.141
1342 * BigDecimal('13345.234').truncate(-2) -> 13300.0
1344 static VALUE
1345 BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
1347 ENTER(5);
1348 Real *c, *a;
1349 int iLoc;
1350 U_LONG mx;
1351 VALUE vLoc;
1352 U_LONG pl = VpSetPrecLimit(0);
1354 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
1355 iLoc = 0;
1356 } else {
1357 Check_Type(vLoc, T_FIXNUM);
1358 iLoc = FIX2INT(vLoc);
1361 GUARD_OBJ(a,GetVpValue(self,1));
1362 mx = a->Prec *(VpBaseFig() + 1);
1363 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1364 VpSetPrecLimit(pl);
1365 VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */
1366 return ToValue(c);
1369 /* Return the fractional part of the number.
1371 static VALUE
1372 BigDecimal_frac(VALUE self)
1374 ENTER(5);
1375 Real *c, *a;
1376 U_LONG mx;
1378 GUARD_OBJ(a,GetVpValue(self,1));
1379 mx = a->Prec *(VpBaseFig() + 1);
1380 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1381 VpFrac(c, a);
1382 return ToValue(c);
1385 /* call-seq:
1386 * floor(n)
1388 * Return the largest integer less than or equal to the value, as a BigDecimal.
1390 * BigDecimal('3.14159').floor -> 3
1392 * BigDecimal('-9.1').floor -> -10
1394 * If n is specified and positive, the fractional part of the result has no
1395 * more than that many digits.
1397 * If n is specified and negative, at least that
1398 * many digits to the left of the decimal point will be 0 in the result.
1400 * BigDecimal('3.14159').floor(3) -> 3.141
1402 * BigDecimal('13345.234').floor(-2) -> 13300.0
1404 static VALUE
1405 BigDecimal_floor(int argc, VALUE *argv, VALUE self)
1407 ENTER(5);
1408 Real *c, *a;
1409 U_LONG mx;
1410 int iLoc;
1411 VALUE vLoc;
1412 U_LONG pl = VpSetPrecLimit(0);
1414 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
1415 iLoc = 0;
1416 } else {
1417 Check_Type(vLoc, T_FIXNUM);
1418 iLoc = FIX2INT(vLoc);
1421 GUARD_OBJ(a,GetVpValue(self,1));
1422 mx = a->Prec *(VpBaseFig() + 1);
1423 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1424 VpSetPrecLimit(pl);
1425 VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc);
1426 return ToValue(c);
1429 /* call-seq:
1430 * ceil(n)
1432 * Return the smallest integer greater than or equal to the value, as a BigDecimal.
1434 * BigDecimal('3.14159').ceil -> 4
1436 * BigDecimal('-9.1').ceil -> -9
1438 * If n is specified and positive, the fractional part of the result has no
1439 * more than that many digits.
1441 * If n is specified and negative, at least that
1442 * many digits to the left of the decimal point will be 0 in the result.
1444 * BigDecimal('3.14159').ceil(3) -> 3.142
1446 * BigDecimal('13345.234').ceil(-2) -> 13400.0
1448 static VALUE
1449 BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
1451 ENTER(5);
1452 Real *c, *a;
1453 U_LONG mx;
1454 int iLoc;
1455 VALUE vLoc;
1456 U_LONG pl = VpSetPrecLimit(0);
1458 if(rb_scan_args(argc,argv,"01",&vLoc)==0) {
1459 iLoc = 0;
1460 } else {
1461 Check_Type(vLoc, T_FIXNUM);
1462 iLoc = FIX2INT(vLoc);
1465 GUARD_OBJ(a,GetVpValue(self,1));
1466 mx = a->Prec *(VpBaseFig() + 1);
1467 GUARD_OBJ(c,VpCreateRbObject(mx, "0"));
1468 VpSetPrecLimit(pl);
1469 VpActiveRound(c,a,VP_ROUND_CEIL,iLoc);
1470 return ToValue(c);
1473 /* call-seq:
1474 * to_s(s)
1476 * Converts the value to a string.
1478 * The default format looks like 0.xxxxEnn.
1480 * The optional parameter s consists of either an integer; or an optional '+'
1481 * or ' ', followed by an optional number, followed by an optional 'E' or 'F'.
1483 * If there is a '+' at the start of s, positive values are returned with
1484 * a leading '+'.
1486 * A space at the start of s returns positive values with a leading space.
1488 * If s contains a number, a space is inserted after each group of that many
1489 * fractional digits.
1491 * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
1493 * If s ends with an 'F', conventional floating point notation is used.
1495 * Examples:
1497 * BigDecimal.new('-123.45678901234567890').to_s('5F') -> '-123.45678 90123 45678 9'
1499 * BigDecimal.new('123.45678901234567890').to_s('+8F') -> '+123.45678901 23456789'
1501 * BigDecimal.new('123.45678901234567890').to_s(' F') -> ' 123.4567890123456789'
1503 static VALUE
1504 BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
1506 ENTER(5);
1507 int fmt=0; /* 0:E format */
1508 int fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
1509 Real *vp;
1510 char *psz;
1511 char ch;
1512 U_LONG nc;
1513 S_INT mc = 0;
1514 VALUE f;
1516 GUARD_OBJ(vp,GetVpValue(self,1));
1518 if(rb_scan_args(argc,argv,"01",&f)==1) {
1519 if(TYPE(f)==T_STRING) {
1520 SafeStringValue(f);
1521 psz = RSTRING_PTR(f);
1522 if(*psz==' ') {
1523 fPlus = 1; psz++;
1524 } else if(*psz=='+') {
1525 fPlus = 2; psz++;
1527 while((ch=*psz++)!=0) {
1528 if(ISSPACE(ch)) continue;
1529 if(!ISDIGIT(ch)) {
1530 if(ch=='F' || ch=='f') fmt = 1; /* F format */
1531 break;
1533 mc = mc * 10 + ch - '0';
1535 } else {
1536 mc = GetPositiveInt(f);
1539 if(fmt) {
1540 nc = VpNumOfChars(vp,"F");
1541 } else {
1542 nc = VpNumOfChars(vp,"E");
1544 if(mc>0) nc += (nc + mc - 1) / mc + 1;
1546 psz = ALLOCA_N(char,(unsigned int)nc);
1548 if(fmt) {
1549 VpToFString(vp, psz, mc, fPlus);
1550 } else {
1551 VpToString (vp, psz, mc, fPlus);
1553 return rb_str_new2(psz);
1556 /* Splits a BigDecimal number into four parts, returned as an array of values.
1558 * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
1559 * if the BigDecimal is Not a Number.
1561 * The second value is a string representing the significant digits of the
1562 * BigDecimal, with no leading zeros.
1564 * The third value is the base used for arithmetic (currently always 10) as an
1565 * Integer.
1567 * The fourth value is an Integer exponent.
1569 * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
1570 * string of significant digits with no leading zeros, and n is the exponent.
1572 * From these values, you can translate a BigDecimal to a float as follows:
1574 * sign, significant_digits, base, exponent = a.split
1575 * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
1577 * (Note that the to_f method is provided as a more convenient way to translate
1578 * a BigDecimal to a Float.)
1580 static VALUE
1581 BigDecimal_split(VALUE self)
1583 ENTER(5);
1584 Real *vp;
1585 VALUE obj,obj1;
1586 S_LONG e;
1587 S_LONG s;
1588 char *psz1;
1590 GUARD_OBJ(vp,GetVpValue(self,1));
1591 psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
1592 VpSzMantissa(vp,psz1);
1593 s = 1;
1594 if(psz1[0]=='-') {
1595 s = -1; ++psz1;
1597 if(psz1[0]=='N') s=0; /* NaN */
1598 e = VpExponent10(vp);
1599 obj1 = rb_str_new2(psz1);
1600 obj = rb_ary_new2(4);
1601 rb_ary_push(obj, INT2FIX(s));
1602 rb_ary_push(obj, obj1);
1603 rb_ary_push(obj, INT2FIX(10));
1604 rb_ary_push(obj, INT2NUM(e));
1605 return obj;
1608 /* Returns the exponent of the BigDecimal number, as an Integer.
1610 * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
1611 * of digits with no leading zeros, then n is the exponent.
1613 static VALUE
1614 BigDecimal_exponent(VALUE self)
1616 S_LONG e = VpExponent10(GetVpValue(self,1));
1617 return INT2NUM(e);
1620 /* Returns debugging information about the value as a string of comma-separated
1621 * values in angle brackets with a leading #:
1623 * BigDecimal.new("1234.5678").inspect ->
1624 * "#<BigDecimal:b7ea1130,'0.12345678E4',8(12)>"
1626 * The first part is the address, the second is the value as a string, and
1627 * the final part ss(mm) is the current number of significant digits and the
1628 * maximum number of significant digits, respectively.
1630 static VALUE
1631 BigDecimal_inspect(VALUE self)
1633 ENTER(5);
1634 Real *vp;
1635 VALUE obj;
1636 unsigned int nc;
1637 char *psz1;
1638 char *pszAll;
1640 GUARD_OBJ(vp,GetVpValue(self,1));
1641 nc = VpNumOfChars(vp,"E");
1642 nc +=(nc + 9) / 10;
1644 psz1 = ALLOCA_N(char,nc);
1645 pszAll = ALLOCA_N(char,nc+256);
1646 VpToString(vp, psz1, 10, 0);
1647 sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
1648 obj = rb_str_new2(pszAll);
1649 return obj;
1652 /* call-seq:
1653 * power(n)
1655 * Returns the value raised to the power of n. Note that n must be an Integer.
1657 * Also available as the operator **
1659 static VALUE
1660 BigDecimal_power(VALUE self, VALUE p)
1662 ENTER(5);
1663 Real *x, *y;
1664 S_LONG mp, ma, n;
1666 Check_Type(p, T_FIXNUM);
1667 n = FIX2INT(p);
1668 ma = n;
1669 if(ma < 0) ma = -ma;
1670 if(ma == 0) ma = 1;
1672 GUARD_OBJ(x,GetVpValue(self,1));
1673 if(VpIsDef(x)) {
1674 mp = x->Prec *(VpBaseFig() + 1);
1675 GUARD_OBJ(y,VpCreateRbObject(mp *(ma + 1), "0"));
1676 } else {
1677 GUARD_OBJ(y,VpCreateRbObject(1, "0"));
1679 VpPower(y, x, n);
1680 return ToValue(y);
1683 static VALUE
1684 BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
1686 ENTER(5);
1687 Real *pv;
1688 S_LONG mf;
1689 VALUE nFig;
1690 VALUE iniValue;
1692 if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
1693 mf = 0;
1694 } else {
1695 mf = GetPositiveInt(nFig);
1697 SafeStringValue(iniValue);
1698 GUARD_OBJ(pv,VpCreateRbObject(mf, RSTRING_PTR(iniValue)));
1699 return ToValue(pv);
1702 /* call-seq:
1703 * new(initial, digits)
1705 * Create a new BigDecimal object.
1707 * initial:: The initial value, as a String. Spaces are ignored, unrecognized characters terminate the value.
1709 * digits:: The number of significant digits, as a Fixnum. If omitted or 0, the number of significant digits is determined from the initial value.
1711 * The actual number of significant digits used in computation is usually
1712 * larger than the specified number.
1714 static VALUE
1715 BigDecimal_new(int argc, VALUE *argv, VALUE self)
1717 ENTER(5);
1718 Real *pv;
1719 S_LONG mf;
1720 VALUE nFig;
1721 VALUE iniValue;
1723 if(rb_scan_args(argc,argv,"11",&iniValue,&nFig)==1) {
1724 mf = 0;
1725 } else {
1726 mf = GetPositiveInt(nFig);
1728 SafeStringValue(iniValue);
1729 GUARD_OBJ(pv,VpNewRbClass(mf, RSTRING_PTR(iniValue),self));
1730 return ToValue(pv);
1733 /* call-seq:
1734 * BigDecimal.limit(digits)
1736 * Limit the number of significant digits in newly created BigDecimal
1737 * numbers to the specified value. Rounding is performed as necessary,
1738 * as specified by BigDecimal.mode.
1740 * A limit of 0, the default, means no upper limit.
1742 * The limit specified by this method takes priority over any limit
1743 * specified to instance methods such as ceil, floor, truncate, or round.
1745 static VALUE
1746 BigDecimal_limit(int argc, VALUE *argv, VALUE self)
1748 VALUE nFig;
1749 VALUE nCur = INT2NUM(VpGetPrecLimit());
1751 if(rb_scan_args(argc,argv,"01",&nFig)==1) {
1752 int nf;
1753 if(nFig==Qnil) return nCur;
1754 Check_Type(nFig, T_FIXNUM);
1755 nf = FIX2INT(nFig);
1756 if(nf<0) {
1757 rb_raise(rb_eArgError, "argument must be positive");
1759 VpSetPrecLimit(nf);
1761 return nCur;
1764 /* Returns the sign of the value.
1766 * Returns a positive value if > 0, a negative value if < 0, and a
1767 * zero if == 0.
1769 * The specific value returned indicates the type and sign of the BigDecimal,
1770 * as follows:
1772 * BigDecimal::SIGN_NaN:: value is Not a Number
1773 * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0
1774 * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0
1775 * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +infinity
1776 * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -infinity
1777 * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive
1778 * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
1780 static VALUE
1781 BigDecimal_sign(VALUE self)
1782 { /* sign */
1783 int s = GetVpValue(self,1)->sign;
1784 return INT2FIX(s);
1787 void
1788 Init_bigdecimal(void)
1790 /* Initialize VP routines */
1791 VpInit((U_LONG)0);
1793 /* Class and method registration */
1794 rb_cBigDecimal = rb_define_class("BigDecimal",rb_cNumeric);
1796 /* Global function */
1797 rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
1799 /* Class methods */
1800 rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_new, -1);
1801 rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
1802 rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
1803 rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
1804 rb_define_singleton_method(rb_cBigDecimal, "induced_from",BigDecimal_induced_from, 1);
1805 rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
1806 rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);
1808 /* Constants definition */
1811 * Base value used in internal calculations. On a 32 bit system, BASE
1812 * is 10000, indicating that calculation is done in groups of 4 digits.
1813 * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
1814 * guarantee that two groups could always be multiplied together without
1815 * overflow.)
1817 rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((S_INT)VpBaseVal()));
1819 /* Exceptions */
1822 * 0xff: Determines whether overflow, underflow or zero divide result in
1823 * an exception being thrown. See BigDecimal.mode.
1825 rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL",INT2FIX(VP_EXCEPTION_ALL));
1828 * 0x02: Determines what happens when the result of a computation is not a
1829 * number (NaN). See BigDecimal.mode.
1831 rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN",INT2FIX(VP_EXCEPTION_NaN));
1834 * 0x01: Determines what happens when the result of a computation is
1835 * infinity. See BigDecimal.mode.
1837 rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY",INT2FIX(VP_EXCEPTION_INFINITY));
1840 * 0x04: Determines what happens when the result of a computation is an
1841 * underflow (a result too small to be represented). See BigDecimal.mode.
1843 rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW",INT2FIX(VP_EXCEPTION_UNDERFLOW));
1846 * 0x01: Determines what happens when the result of a computation is an
1847 * overflow (a result too large to be represented). See BigDecimal.mode.
1849 rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW",INT2FIX(VP_EXCEPTION_OVERFLOW));
1852 * 0x01: Determines what happens when a division by zero is performed.
1853 * See BigDecimal.mode.
1855 rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE",INT2FIX(VP_EXCEPTION_ZERODIVIDE));
1858 * 0x100: Determines what happens when a result must be rounded in order to
1859 * fit in the appropriate number of significant digits. See
1860 * BigDecimal.mode.
1862 rb_define_const(rb_cBigDecimal, "ROUND_MODE",INT2FIX(VP_ROUND_MODE));
1864 /* 1: Indicates that values should be rounded away from zero. See
1865 * BigDecimal.mode.
1867 rb_define_const(rb_cBigDecimal, "ROUND_UP",INT2FIX(VP_ROUND_UP));
1869 /* 2: Indicates that values should be rounded towards zero. See
1870 * BigDecimal.mode.
1872 rb_define_const(rb_cBigDecimal, "ROUND_DOWN",INT2FIX(VP_ROUND_DOWN));
1874 /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
1875 * See BigDecimal.mode. */
1876 rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP",INT2FIX(VP_ROUND_HALF_UP));
1878 /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
1879 * See BigDecimal.mode.
1881 rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN",INT2FIX(VP_ROUND_HALF_DOWN));
1882 /* 5: Round towards +infinity. See BigDecimal.mode. */
1883 rb_define_const(rb_cBigDecimal, "ROUND_CEILING",INT2FIX(VP_ROUND_CEIL));
1885 /* 6: Round towards -infinity. See BigDecimal.mode. */
1886 rb_define_const(rb_cBigDecimal, "ROUND_FLOOR",INT2FIX(VP_ROUND_FLOOR));
1888 /* 7: Round towards the even neighbor. See BigDecimal.mode. */
1889 rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN",INT2FIX(VP_ROUND_HALF_EVEN));
1891 /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
1892 rb_define_const(rb_cBigDecimal, "SIGN_NaN",INT2FIX(VP_SIGN_NaN));
1894 /* 1: Indicates that a value is +0. See BigDecimal.sign. */
1895 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO",INT2FIX(VP_SIGN_POSITIVE_ZERO));
1897 /* -1: Indicates that a value is -0. See BigDecimal.sign. */
1898 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO",INT2FIX(VP_SIGN_NEGATIVE_ZERO));
1900 /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
1901 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE",INT2FIX(VP_SIGN_POSITIVE_FINITE));
1903 /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
1904 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE",INT2FIX(VP_SIGN_NEGATIVE_FINITE));
1906 /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
1907 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE",INT2FIX(VP_SIGN_POSITIVE_INFINITE));
1909 /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
1910 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE",INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
1912 /* instance methods */
1913 rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
1915 rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
1916 rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
1917 rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
1918 rb_define_method(rb_cBigDecimal, "div",BigDecimal_div2, -1);
1919 rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
1920 rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
1921 rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
1922 rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
1923 rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
1924 rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
1925 rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
1926 rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
1927 rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
1928 rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
1929 rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
1930 rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
1931 rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
1932 rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
1933 rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
1934 rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
1935 /* rb_define_method(rb_cBigDecimal, "dup", BigDecimal_dup, 0); */
1936 rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
1937 rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
1938 rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
1939 rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
1940 rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
1941 rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
1942 rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
1943 rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
1944 rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, 1);
1945 rb_define_method(rb_cBigDecimal, "**", BigDecimal_power, 1);
1946 rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
1947 rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
1948 rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
1949 rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
1950 rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
1951 rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
1952 rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
1953 rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
1954 rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
1955 rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
1956 rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
1957 rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
1958 rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
1959 rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
1960 rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0);
1961 rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
1962 rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
1963 rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
1964 rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
1969 * ============================================================================
1971 * vp_ routines begin from here.
1973 * ============================================================================
1976 #ifdef _DEBUG
1977 /*static int gfDebug = 1;*/ /* Debug switch */
1978 static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
1979 #endif /* _DEBUG */
1981 static U_LONG gnPrecLimit = 0; /* Global upper limit of the precision newly allocated */
1982 static U_LONG gfRoundMode = VP_ROUND_HALF_UP; /* Mode for general rounding operation */
1984 #ifndef BASE_FIG
1985 static U_LONG BASE_FIG = 4; /* =log10(BASE) */
1986 static U_LONG BASE = 10000L; /* Base value(value must be 10**BASE_FIG) */
1987 /* The value of BASE**2 + BASE must be represented */
1988 /* within one U_LONG. */
1989 static U_LONG HALF_BASE = 5000L;/* =BASE/2 */
1990 static U_LONG BASE1 = 1000L; /* =BASE/10 */
1991 #else
1992 #ifndef BASE
1993 #error BASE_FIG is defined but BASE is not
1994 #endif
1995 #define HALF_BASE (BASE/2)
1996 #define BASE1 (BASE/10)
1997 #endif
1998 #ifndef DBLE_FIG
1999 #define DBLE_FIG (DBL_DIG+1) /* figure of double */
2000 #endif
2002 static Real *VpConstOne; /* constant 1.0 */
2003 static Real *VpPt5; /* constant 0.5 */
2004 #define maxnr 100UL /* Maximum iterations for calcurating sqrt. */
2005 /* used in VpSqrt() */
2007 /* ETC */
2008 #define MemCmp(x,y,z) memcmp(x,y,z)
2009 #define StrCmp(x,y) strcmp(x,y)
2011 static int VpIsDefOP(Real *c,Real *a,Real *b,int sw);
2012 static int AddExponent(Real *a,S_INT n);
2013 static U_LONG VpAddAbs(Real *a,Real *b,Real *c);
2014 static U_LONG VpSubAbs(Real *a,Real *b,Real *c);
2015 static U_LONG VpSetPTR(Real *a,Real *b,Real *c,U_LONG *a_pos,U_LONG *b_pos,U_LONG *c_pos,U_LONG *av,U_LONG *bv);
2016 static int VpNmlz(Real *a);
2017 static void VpFormatSt(char *psz,S_INT fFmt);
2018 static int VpRdup(Real *m,U_LONG ind_m);
2020 #ifdef _DEBUG
2021 static int gnAlloc=0; /* Memory allocation counter */
2022 #endif /* _DEBUG */
2024 VP_EXPORT void *
2025 VpMemAlloc(U_LONG mb)
2027 void *p = xmalloc((unsigned int)mb);
2028 if(!p) {
2029 VpException(VP_EXCEPTION_MEMORY,"failed to allocate memory",1);
2031 memset(p,0,mb);
2032 #ifdef _DEBUG
2033 gnAlloc++; /* Count allocation call */
2034 #endif /* _DEBUG */
2035 return p;
2038 VP_EXPORT void
2039 VpFree(Real *pv)
2041 if(pv != NULL) {
2042 xfree(pv);
2043 #ifdef _DEBUG
2044 gnAlloc--; /* Decrement allocation count */
2045 if(gnAlloc==0) {
2046 printf(" *************** All memories allocated freed ****************");
2047 getchar();
2049 if(gnAlloc<0) {
2050 printf(" ??????????? Too many memory free calls(%d) ?????????????\n",gnAlloc);
2051 getchar();
2053 #endif /* _DEBUG */
2058 * EXCEPTION Handling.
2060 static unsigned short gfDoException = 0; /* Exception flag */
2062 static unsigned short
2063 VpGetException (void)
2065 return gfDoException;
2068 static void
2069 VpSetException(unsigned short f)
2071 gfDoException = f;
2074 /* These 2 functions added at v1.1.7 */
2075 VP_EXPORT U_LONG
2076 VpGetPrecLimit(void)
2078 return gnPrecLimit;
2081 VP_EXPORT U_LONG
2082 VpSetPrecLimit(U_LONG n)
2084 U_LONG s = gnPrecLimit;
2085 gnPrecLimit = n;
2086 return s;
2089 VP_EXPORT unsigned long
2090 VpGetRoundMode(void)
2092 return gfRoundMode;
2095 VP_EXPORT int
2096 VpIsRoundMode(unsigned long n)
2098 if(n==VP_ROUND_UP || n==VP_ROUND_DOWN ||
2099 n==VP_ROUND_HALF_UP || n==VP_ROUND_HALF_DOWN ||
2100 n==VP_ROUND_CEIL || n==VP_ROUND_FLOOR ||
2101 n==VP_ROUND_HALF_EVEN
2102 ) return 1;
2103 return 0;
2106 VP_EXPORT unsigned long
2107 VpSetRoundMode(unsigned long n)
2109 if(VpIsRoundMode(n)) gfRoundMode = n;
2110 return gfRoundMode;
2114 * 0.0 & 1.0 generator
2115 * These gZero_..... and gOne_..... can be any name
2116 * referenced from nowhere except Zero() and One().
2117 * gZero_..... and gOne_..... must have global scope
2118 * (to let the compiler know they may be changed in outside
2119 * (... but not actually..)).
2121 volatile const double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
2122 volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
2123 static double
2124 Zero(void)
2126 return gZero_ABCED9B1_CE73__00400511F31D;
2129 static double
2130 One(void)
2132 return gOne_ABCED9B4_CE73__00400511F31D;
2135 VP_EXPORT U_LONG
2136 VpBaseFig(void)
2138 return BASE_FIG;
2141 VP_EXPORT U_LONG
2142 VpDblFig(void)
2144 return DBLE_FIG;
2147 VP_EXPORT U_LONG
2148 VpBaseVal(void)
2150 return BASE;
2154 ----------------------------------------------------------------
2155 Value of sign in Real structure is reserved for future use.
2156 short sign;
2157 ==0 : NaN
2158 1 : Positive zero
2159 -1 : Negative zero
2160 2 : Positive number
2161 -2 : Negative number
2162 3 : Positive infinite number
2163 -3 : Negative infinite number
2164 ----------------------------------------------------------------
2167 VP_EXPORT double
2168 VpGetDoubleNaN(void) /* Returns the value of NaN */
2170 static double fNaN = 0.0;
2171 if(fNaN==0.0) fNaN = Zero()/Zero();
2172 return fNaN;
2175 VP_EXPORT double
2176 VpGetDoublePosInf(void) /* Returns the value of +Infinity */
2178 static double fInf = 0.0;
2179 if(fInf==0.0) fInf = One()/Zero();
2180 return fInf;
2183 VP_EXPORT double
2184 VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
2186 static double fInf = 0.0;
2187 if(fInf==0.0) fInf = -(One()/Zero());
2188 return fInf;
2191 VP_EXPORT double
2192 VpGetDoubleNegZero(void) /* Returns the value of -0 */
2194 static double nzero = 1000.0;
2195 if(nzero!=0.0) nzero = (One()/VpGetDoubleNegInf());
2196 return nzero;
2199 #if 0 /* unused */
2200 VP_EXPORT int
2201 VpIsNegDoubleZero(double v)
2203 double z = VpGetDoubleNegZero();
2204 return MemCmp(&v,&z,sizeof(v))==0;
2206 #endif
2208 VP_EXPORT int
2209 VpException(unsigned short f, const char *str,int always)
2211 VALUE exc;
2212 int fatal=0;
2214 if(f==VP_EXCEPTION_OP || f==VP_EXCEPTION_MEMORY) always = 1;
2216 if(always||(gfDoException&f)) {
2217 switch(f)
2220 case VP_EXCEPTION_ZERODIVIDE:
2221 case VP_EXCEPTION_OVERFLOW:
2223 case VP_EXCEPTION_INFINITY:
2224 exc = rb_eFloatDomainError;
2225 goto raise;
2226 case VP_EXCEPTION_NaN:
2227 exc = rb_eFloatDomainError;
2228 goto raise;
2229 case VP_EXCEPTION_UNDERFLOW:
2230 exc = rb_eFloatDomainError;
2231 goto raise;
2232 case VP_EXCEPTION_OP:
2233 exc = rb_eFloatDomainError;
2234 goto raise;
2235 case VP_EXCEPTION_MEMORY:
2236 fatal = 1;
2237 goto raise;
2238 default:
2239 fatal = 1;
2240 goto raise;
2243 return 0; /* 0 Means VpException() raised no exception */
2245 raise:
2246 if(fatal) rb_fatal("%s", str);
2247 else rb_raise(exc, "%s", str);
2248 return 0;
2251 /* Throw exception or returns 0,when resulting c is Inf or NaN */
2252 /* sw=1:+ 2:- 3:* 4:/ */
2253 static int
2254 VpIsDefOP(Real *c,Real *a,Real *b,int sw)
2256 if(VpIsNaN(a) || VpIsNaN(b)) {
2257 /* at least a or b is NaN */
2258 VpSetNaN(c);
2259 goto NaN;
2262 if(VpIsInf(a)) {
2263 if(VpIsInf(b)) {
2264 switch(sw)
2266 case 1: /* + */
2267 if(VpGetSign(a)==VpGetSign(b)) {
2268 VpSetInf(c,VpGetSign(a));
2269 goto Inf;
2270 } else {
2271 VpSetNaN(c);
2272 goto NaN;
2274 case 2: /* - */
2275 if(VpGetSign(a)!=VpGetSign(b)) {
2276 VpSetInf(c,VpGetSign(a));
2277 goto Inf;
2278 } else {
2279 VpSetNaN(c);
2280 goto NaN;
2282 break;
2283 case 3: /* * */
2284 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
2285 goto Inf;
2286 break;
2287 case 4: /* / */
2288 VpSetNaN(c);
2289 goto NaN;
2291 VpSetNaN(c);
2292 goto NaN;
2294 /* Inf op Finite */
2295 switch(sw)
2297 case 1: /* + */
2298 case 2: /* - */
2299 VpSetInf(c,VpGetSign(a));
2300 break;
2301 case 3: /* * */
2302 if(VpIsZero(b)) {
2303 VpSetNaN(c);
2304 goto NaN;
2306 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
2307 break;
2308 case 4: /* / */
2309 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
2311 goto Inf;
2314 if(VpIsInf(b)) {
2315 switch(sw)
2317 case 1: /* + */
2318 VpSetInf(c,VpGetSign(b));
2319 break;
2320 case 2: /* - */
2321 VpSetInf(c,-VpGetSign(b));
2322 break;
2323 case 3: /* * */
2324 if(VpIsZero(a)) {
2325 VpSetNaN(c);
2326 goto NaN;
2328 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
2329 break;
2330 case 4: /* / */
2331 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
2333 goto Inf;
2335 return 1; /* Results OK */
2337 Inf:
2338 return VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
2339 NaN:
2340 return VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'",0);
2344 ----------------------------------------------------------------
2348 * returns number of chars needed to represent vp in specified format.
2350 VP_EXPORT U_LONG
2351 VpNumOfChars(Real *vp,const char *pszFmt)
2353 S_INT ex;
2354 U_LONG nc;
2356 if(vp == NULL) return BASE_FIG*2+6;
2357 if(!VpIsDef(vp)) return 32; /* not sure,may be OK */
2359 switch(*pszFmt)
2361 case 'F':
2362 nc = BASE_FIG*(vp->Prec + 1)+2;
2363 ex = vp->exponent;
2364 if(ex<0) {
2365 nc += BASE_FIG*(-ex);
2366 } else {
2367 if(ex > (S_INT)vp->Prec) {
2368 nc += BASE_FIG*(ex - (S_INT)vp->Prec);
2371 break;
2372 case 'E':
2373 default:
2374 nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
2376 return nc;
2380 * Initializer for Vp routines and constants used.
2381 * [Input]
2382 * BaseVal: Base value(assigned to BASE) for Vp calculation.
2383 * It must be the form BaseVal=10**n.(n=1,2,3,...)
2384 * If Base <= 0L,then the BASE will be calcurated so
2385 * that BASE is as large as possible satisfying the
2386 * relation MaxVal <= BASE*(BASE+1). Where the value
2387 * MaxVal is the largest value which can be represented
2388 * by one U_LONG word(LONG) in the computer used.
2390 * [Returns]
2391 * DBLE_FIG ... OK
2393 VP_EXPORT U_LONG
2394 VpInit(U_LONG BaseVal)
2396 /* Setup +/- Inf NaN -0 */
2397 VpGetDoubleNaN();
2398 VpGetDoublePosInf();
2399 VpGetDoubleNegInf();
2400 VpGetDoubleNegZero();
2402 #ifndef BASE_FIG
2403 if(BaseVal <= 0) {
2404 U_LONG w;
2405 /* Base <= 0, then determine Base by calcuration. */
2406 BASE = 1;
2407 while(
2408 (BASE > 0) &&
2409 ((w = BASE *(BASE + 1)) > BASE) &&((w / BASE) ==(BASE + 1))
2411 BaseVal = BASE;
2412 BASE = BaseVal * 10L;
2415 /* Set Base Values */
2416 BASE = BaseVal;
2417 HALF_BASE = BASE / 2;
2418 BASE1 = BASE / 10;
2419 BASE_FIG = 0;
2420 while(BaseVal /= 10) ++BASE_FIG;
2421 #endif
2423 /* Allocates Vp constants. */
2424 VpConstOne = VpAlloc((U_LONG)1, "1");
2425 VpPt5 = VpAlloc((U_LONG)1, ".5");
2427 #ifdef _DEBUG
2428 gnAlloc = 0;
2429 #endif /* _DEBUG */
2431 #ifdef _DEBUG
2432 if(gfDebug) {
2433 printf("VpInit: BaseVal = %lu\n", BaseVal);
2434 printf(" BASE = %lu\n", BASE);
2435 printf(" HALF_BASE = %lu\n", HALF_BASE);
2436 printf(" BASE1 = %lu\n", BASE1);
2437 printf(" BASE_FIG = %lu\n", BASE_FIG);
2438 printf(" DBLE_FIG = %lu\n", DBLE_FIG);
2440 #endif /* _DEBUG */
2442 return DBLE_FIG;
2445 VP_EXPORT Real *
2446 VpOne(void)
2448 return VpConstOne;
2451 /* If exponent overflows,then raise exception or returns 0 */
2452 static int
2453 AddExponent(Real *a,S_INT n)
2455 S_INT e = a->exponent;
2456 S_INT m = e+n;
2457 S_INT eb,mb;
2458 if(e>0) {
2459 if(n>0) {
2460 mb = m*BASE_FIG;
2461 eb = e*BASE_FIG;
2462 if(mb<eb) goto overflow;
2464 } else if(n<0) {
2465 mb = m*BASE_FIG;
2466 eb = e*BASE_FIG;
2467 if(mb>eb) goto underflow;
2469 a->exponent = m;
2470 return 1;
2472 /* Overflow/Underflow ==> Raise exception or returns 0 */
2473 underflow:
2474 VpSetZero(a,VpGetSign(a));
2475 return VpException(VP_EXCEPTION_UNDERFLOW,"Exponent underflow",0);
2477 overflow:
2478 VpSetInf(a,VpGetSign(a));
2479 return VpException(VP_EXCEPTION_OVERFLOW,"Exponent overflow",0);
2483 * Allocates variable.
2484 * [Input]
2485 * mx ... allocation unit, if zero then mx is determined by szVal.
2486 * The mx is the number of effective digits can to be stored.
2487 * szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
2488 * If szVal[0]=='#' then Max. Prec. will not be considered(1.1.7),
2489 * full precision specified by szVal is allocated.
2491 * [Returns]
2492 * Pointer to the newly allocated variable, or
2493 * NULL be returned if memory allocation is failed,or any error.
2495 VP_EXPORT Real *
2496 VpAlloc(U_LONG mx, const char *szVal)
2498 U_LONG i, ni, ipn, ipf, nf, ipe, ne, nalloc;
2499 char v,*psz;
2500 int sign=1;
2501 Real *vp = NULL;
2502 U_LONG mf = VpGetPrecLimit();
2504 mx = (mx + BASE_FIG - 1) / BASE_FIG + 1; /* Determine allocation unit. */
2505 if(szVal) {
2506 while(ISSPACE(*szVal)) szVal++;
2507 if(*szVal!='#') {
2508 if(mf) {
2509 mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
2510 if(mx>mf) {
2511 mx = mf;
2514 } else {
2515 ++szVal;
2517 } else {
2518 /* necessary to be able to store */
2519 /* at least mx digits. */
2520 /* szVal==NULL ==> allocate zero value. */
2521 vp = (Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
2522 /* xmalloc() alway returns(or throw interruption) */
2523 vp->MaxPrec = mx; /* set max precision */
2524 VpSetZero(vp,1); /* initialize vp to zero. */
2525 return vp;
2528 /* Skip all '_' after digit: 2006-6-30 */
2529 ni = 0;
2530 psz = ALLOCA_N(char,strlen(szVal)+1);
2531 i = 0;
2532 ipn = 0;
2533 while((psz[i]=szVal[ipn])!=0) {
2534 if(ISDIGIT(psz[i])) ++ni;
2535 if(psz[i]=='_') {
2536 if(ni>0) {ipn++;continue;}
2537 psz[i]=0;
2538 break;
2540 ++i; ++ipn;
2542 /* Skip trailing spaces */
2543 while((--i)>0) {
2544 if(ISSPACE(psz[i])) psz[i] = 0;
2545 else break;
2547 szVal = psz;
2549 /* Check on Inf & NaN */
2550 if(StrCmp(szVal,SZ_PINF)==0 ||
2551 StrCmp(szVal,SZ_INF)==0 ) {
2552 vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
2553 vp->MaxPrec = 1; /* set max precision */
2554 VpSetPosInf(vp);
2555 return vp;
2557 if(StrCmp(szVal,SZ_NINF)==0) {
2558 vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
2559 vp->MaxPrec = 1; /* set max precision */
2560 VpSetNegInf(vp);
2561 return vp;
2563 if(StrCmp(szVal,SZ_NaN)==0) {
2564 vp = (Real *) VpMemAlloc(sizeof(Real) + sizeof(U_LONG));
2565 vp->MaxPrec = 1; /* set max precision */
2566 VpSetNaN(vp);
2567 return vp;
2570 /* check on number szVal[] */
2571 ipn = i = 0;
2572 if (szVal[i] == '-') {sign=-1;++i;}
2573 else if(szVal[i] == '+') ++i;
2574 /* Skip digits */
2575 ni = 0; /* digits in mantissa */
2576 while((v = szVal[i]) != 0) {
2577 if(!ISDIGIT(v)) break;
2578 ++i;
2579 ++ni;
2581 nf = 0;
2582 ipf = 0;
2583 ipe = 0;
2584 ne = 0;
2585 if(v) {
2586 /* other than digit nor \0 */
2587 if(szVal[i] == '.') { /* xxx. */
2588 ++i;
2589 ipf = i;
2590 while((v = szVal[i]) != 0) { /* get fraction part. */
2591 if(!ISDIGIT(v)) break;
2592 ++i;
2593 ++nf;
2596 ipe = 0; /* Exponent */
2598 switch(szVal[i]) {
2599 case '\0': break;
2600 case 'e':
2601 case 'E':
2602 case 'd':
2603 case 'D':
2604 ++i;
2605 ipe = i;
2606 v = szVal[i];
2607 if((v == '-') ||(v == '+')) ++i;
2608 while((v=szVal[i])!=0) {
2609 if(!ISDIGIT(v)) break;
2610 ++i;
2611 ++ne;
2613 break;
2614 default:
2615 break;
2618 nalloc =(ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
2619 /* units for szVal[] */
2620 if(mx <= 0) mx = 1;
2621 nalloc = Max(nalloc, mx);
2622 mx = nalloc;
2623 vp =(Real *) VpMemAlloc(sizeof(Real) + mx * sizeof(U_LONG));
2624 /* xmalloc() alway returns(or throw interruption) */
2625 vp->MaxPrec = mx; /* set max precision */
2626 VpSetZero(vp,sign);
2627 VpCtoV(vp, &(szVal[ipn]), ni, &(szVal[ipf]), nf, &(szVal[ipe]), ne);
2628 return vp;
2632 * Assignment(c=a).
2633 * [Input]
2634 * a ... RHSV
2635 * isw ... switch for assignment.
2636 * c = a when isw > 0
2637 * c = -a when isw < 0
2638 * if c->MaxPrec < a->Prec,then round operation
2639 * will be performed.
2640 * [Output]
2641 * c ... LHSV
2643 VP_EXPORT int
2644 VpAsgn(Real *c, Real *a, int isw)
2646 U_LONG n;
2647 if(VpIsNaN(a)) {
2648 VpSetNaN(c);
2649 return 0;
2651 if(VpIsInf(a)) {
2652 VpSetInf(c,isw*VpGetSign(a));
2653 return 0;
2656 /* check if the RHS is zero */
2657 if(!VpIsZero(a)) {
2658 c->exponent = a->exponent; /* store exponent */
2659 VpSetSign(c,(isw*VpGetSign(a))); /* set sign */
2660 n =(a->Prec < c->MaxPrec) ?(a->Prec) :(c->MaxPrec);
2661 c->Prec = n;
2662 memcpy(c->frac, a->frac, n * sizeof(U_LONG));
2663 /* Needs round ? */
2664 if(isw!=10) {
2665 /* Not in ActiveRound */
2666 if(c->Prec < a->Prec) {
2667 VpInternalRound(c,n,(n>0)?a->frac[n-1]:0,a->frac[n]);
2668 } else {
2669 VpLimitRound(c,0);
2672 } else {
2673 /* The value of 'a' is zero. */
2674 VpSetZero(c,isw*VpGetSign(a));
2675 return 1;
2677 return c->Prec*BASE_FIG;
2681 * c = a + b when operation = 1 or 2
2682 * = a - b when operation = -1 or -2.
2683 * Returns number of significant digits of c
2685 VP_EXPORT int
2686 VpAddSub(Real *c, Real *a, Real *b, int operation)
2688 S_INT sw, isw;
2689 Real *a_ptr, *b_ptr;
2690 U_LONG n, na, nb, i;
2691 U_LONG mrv;
2693 #ifdef _DEBUG
2694 if(gfDebug) {
2695 VPrint(stdout, "VpAddSub(enter) a=% \n", a);
2696 VPrint(stdout, " b=% \n", b);
2697 printf(" operation=%d\n", operation);
2699 #endif /* _DEBUG */
2701 if(!VpIsDefOP(c,a,b,(operation>0)?1:2)) return 0; /* No significant digits */
2703 /* check if a or b is zero */
2704 if(VpIsZero(a)) {
2705 /* a is zero,then assign b to c */
2706 if(!VpIsZero(b)) {
2707 VpAsgn(c, b, operation);
2708 } else {
2709 /* Both a and b are zero. */
2710 if(VpGetSign(a)<0 && operation*VpGetSign(b)<0) {
2711 /* -0 -0 */
2712 VpSetZero(c,-1);
2713 } else {
2714 VpSetZero(c,1);
2716 return 1; /* 0: 1 significant digits */
2718 return c->Prec*BASE_FIG;
2720 if(VpIsZero(b)) {
2721 /* b is zero,then assign a to c. */
2722 VpAsgn(c, a, 1);
2723 return c->Prec*BASE_FIG;
2726 if(operation < 0) sw = -1;
2727 else sw = 1;
2729 /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
2730 if(a->exponent > b->exponent) {
2731 a_ptr = a;
2732 b_ptr = b;
2733 } /* |a|>|b| */
2734 else if(a->exponent < b->exponent) {
2735 a_ptr = b;
2736 b_ptr = a;
2737 } /* |a|<|b| */
2738 else {
2739 /* Exponent part of a and b is the same,then compare fraction */
2740 /* part */
2741 na = a->Prec;
2742 nb = b->Prec;
2743 n = Min(na, nb);
2744 for(i=0;i < n; ++i) {
2745 if(a->frac[i] > b->frac[i]) {
2746 a_ptr = a;
2747 b_ptr = b;
2748 goto end_if;
2749 } else if(a->frac[i] < b->frac[i]) {
2750 a_ptr = b;
2751 b_ptr = a;
2752 goto end_if;
2755 if(na > nb) {
2756 a_ptr = a;
2757 b_ptr = b;
2758 goto end_if;
2759 } else if(na < nb) {
2760 a_ptr = b;
2761 b_ptr = a;
2762 goto end_if;
2764 /* |a| == |b| */
2765 if(VpGetSign(a) + sw *VpGetSign(b) == 0) {
2766 VpSetZero(c,1); /* abs(a)=abs(b) and operation = '-' */
2767 return c->Prec*BASE_FIG;
2769 a_ptr = a;
2770 b_ptr = b;
2773 end_if:
2774 isw = VpGetSign(a) + sw *VpGetSign(b);
2776 * isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1)
2777 * = 2 ...( 1)+( 1),( 1)-(-1)
2778 * =-2 ...(-1)+(-1),(-1)-( 1)
2779 * If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|)
2780 * else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
2782 if(isw) { /* addition */
2783 VpSetSign(c,(S_INT)1);
2784 mrv = VpAddAbs(a_ptr, b_ptr, c);
2785 VpSetSign(c,isw / 2);
2786 } else { /* subtraction */
2787 VpSetSign(c,(S_INT)1);
2788 mrv = VpSubAbs(a_ptr, b_ptr, c);
2789 if(a_ptr == a) {
2790 VpSetSign(c,VpGetSign(a));
2791 } else {
2792 VpSetSign(c,VpGetSign(a_ptr) * sw);
2795 VpInternalRound(c,0,(c->Prec>0)?c->frac[c->Prec-1]:0,mrv);
2797 #ifdef _DEBUG
2798 if(gfDebug) {
2799 VPrint(stdout, "VpAddSub(result) c=% \n", c);
2800 VPrint(stdout, " a=% \n", a);
2801 VPrint(stdout, " b=% \n", b);
2802 printf(" operation=%d\n", operation);
2804 #endif /* _DEBUG */
2805 return c->Prec*BASE_FIG;
2809 * Addition of two variable precisional variables
2810 * a and b assuming abs(a)>abs(b).
2811 * c = abs(a) + abs(b) ; where |a|>=|b|
2813 static U_LONG
2814 VpAddAbs(Real *a, Real *b, Real *c)
2816 U_LONG word_shift;
2817 U_LONG carry;
2818 U_LONG ap;
2819 U_LONG bp;
2820 U_LONG cp;
2821 U_LONG a_pos;
2822 U_LONG b_pos;
2823 U_LONG c_pos;
2824 U_LONG av, bv, mrv;
2826 #ifdef _DEBUG
2827 if(gfDebug) {
2828 VPrint(stdout, "VpAddAbs called: a = %\n", a);
2829 VPrint(stdout, " b = %\n", b);
2831 #endif /* _DEBUG */
2833 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
2834 a_pos = ap;
2835 b_pos = bp;
2836 c_pos = cp;
2837 if(word_shift==-1L) return 0; /* Overflow */
2838 if(b_pos == -1L) goto Assign_a;
2840 mrv = av + bv; /* Most right val. Used for round. */
2842 /* Just assign the last few digits of b to c because a has no */
2843 /* corresponding digits to be added. */
2844 while(b_pos + word_shift > a_pos) {
2845 --c_pos;
2846 if(b_pos > 0) {
2847 c->frac[c_pos] = b->frac[--b_pos];
2848 } else {
2849 --word_shift;
2850 c->frac[c_pos] = 0;
2854 /* Just assign the last few digits of a to c because b has no */
2855 /* corresponding digits to be added. */
2856 bv = b_pos + word_shift;
2857 while(a_pos > bv) {
2858 c->frac[--c_pos] = a->frac[--a_pos];
2860 carry = 0; /* set first carry be zero */
2862 /* Now perform addition until every digits of b will be */
2863 /* exhausted. */
2864 while(b_pos > 0) {
2865 c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
2866 if(c->frac[c_pos] >= BASE) {
2867 c->frac[c_pos] -= BASE;
2868 carry = 1;
2869 } else {
2870 carry = 0;
2874 /* Just assign the first few digits of a with considering */
2875 /* the carry obtained so far because b has been exhausted. */
2876 while(a_pos > 0) {
2877 c->frac[--c_pos] = a->frac[--a_pos] + carry;
2878 if(c->frac[c_pos] >= BASE) {
2879 c->frac[c_pos] -= BASE;
2880 carry = 1;
2881 } else {
2882 carry = 0;
2885 if(c_pos) c->frac[c_pos - 1] += carry;
2886 goto Exit;
2888 Assign_a:
2889 VpAsgn(c, a, 1);
2890 mrv = 0;
2892 Exit:
2894 #ifdef _DEBUG
2895 if(gfDebug) {
2896 VPrint(stdout, "VpAddAbs exit: c=% \n", c);
2898 #endif /* _DEBUG */
2899 return mrv;
2903 * c = abs(a) - abs(b)
2905 static U_LONG
2906 VpSubAbs(Real *a, Real *b, Real *c)
2908 U_LONG word_shift;
2909 U_LONG mrv;
2910 U_LONG borrow;
2911 U_LONG ap;
2912 U_LONG bp;
2913 U_LONG cp;
2914 U_LONG a_pos;
2915 U_LONG b_pos;
2916 U_LONG c_pos;
2917 U_LONG av, bv;
2919 #ifdef _DEBUG
2920 if(gfDebug) {
2921 VPrint(stdout, "VpSubAbs called: a = %\n", a);
2922 VPrint(stdout, " b = %\n", b);
2924 #endif /* _DEBUG */
2926 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
2927 a_pos = ap;
2928 b_pos = bp;
2929 c_pos = cp;
2930 if(word_shift==-1L) return 0; /* Overflow */
2931 if(b_pos == -1L) goto Assign_a;
2933 if(av >= bv) {
2934 mrv = av - bv;
2935 borrow = 0;
2936 } else {
2937 mrv = 0;
2938 borrow = 1;
2941 /* Just assign the values which are the BASE subtracted by */
2942 /* each of the last few digits of the b because the a has no */
2943 /* corresponding digits to be subtracted. */
2944 if(b_pos + word_shift > a_pos) {
2945 while(b_pos + word_shift > a_pos) {
2946 --c_pos;
2947 if(b_pos > 0) {
2948 c->frac[c_pos] = BASE - b->frac[--b_pos] - borrow;
2949 } else {
2950 --word_shift;
2951 c->frac[c_pos] = BASE - borrow;
2953 borrow = 1;
2956 /* Just assign the last few digits of a to c because b has no */
2957 /* corresponding digits to subtract. */
2959 bv = b_pos + word_shift;
2960 while(a_pos > bv) {
2961 c->frac[--c_pos] = a->frac[--a_pos];
2964 /* Now perform subtraction until every digits of b will be */
2965 /* exhausted. */
2966 while(b_pos > 0) {
2967 --c_pos;
2968 if(a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
2969 c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
2970 borrow = 1;
2971 } else {
2972 c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
2973 borrow = 0;
2977 /* Just assign the first few digits of a with considering */
2978 /* the borrow obtained so far because b has been exhausted. */
2979 while(a_pos > 0) {
2980 --c_pos;
2981 if(a->frac[--a_pos] < borrow) {
2982 c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
2983 borrow = 1;
2984 } else {
2985 c->frac[c_pos] = a->frac[a_pos] - borrow;
2986 borrow = 0;
2989 if(c_pos) c->frac[c_pos - 1] -= borrow;
2990 goto Exit;
2992 Assign_a:
2993 VpAsgn(c, a, 1);
2994 mrv = 0;
2996 Exit:
2997 #ifdef _DEBUG
2998 if(gfDebug) {
2999 VPrint(stdout, "VpSubAbs exit: c=% \n", c);
3001 #endif /* _DEBUG */
3002 return mrv;
3006 * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant
3007 * digit of c(In case of addition).
3008 * ------------------------- figure of output -----------------------------------
3009 * a = xxxxxxxxxxx
3010 * b = xxxxxxxxxx
3011 * c =xxxxxxxxxxxxxxx
3012 * word_shift = | |
3013 * right_word = | | (Total digits in RHSV)
3014 * left_word = | | (Total digits in LHSV)
3015 * a_pos = |
3016 * b_pos = |
3017 * c_pos = |
3019 static U_LONG
3020 VpSetPTR(Real *a, Real *b, Real *c, U_LONG *a_pos, U_LONG *b_pos, U_LONG *c_pos, U_LONG *av, U_LONG *bv)
3022 U_LONG left_word, right_word, word_shift;
3023 c->frac[0] = 0;
3024 *av = *bv = 0;
3025 word_shift =((a->exponent) -(b->exponent));
3026 left_word = b->Prec + word_shift;
3027 right_word = Max((a->Prec),left_word);
3028 left_word =(c->MaxPrec) - 1; /* -1 ... prepare for round up */
3030 * check if 'round' is needed.
3032 if(right_word > left_word) { /* round ? */
3033 /*---------------------------------
3034 * Actual size of a = xxxxxxAxx
3035 * Actual size of b = xxxBxxxxx
3036 * Max. size of c = xxxxxx
3037 * Round off = |-----|
3038 * c_pos = |
3039 * right_word = |
3040 * a_pos = |
3042 *c_pos = right_word = left_word + 1; /* Set resulting precision */
3043 /* be equal to that of c */
3044 if((a->Prec) >=(c->MaxPrec)) {
3046 * a = xxxxxxAxxx
3047 * c = xxxxxx
3048 * a_pos = |
3050 *a_pos = left_word;
3051 *av = a->frac[*a_pos]; /* av is 'A' shown in above. */
3052 } else {
3054 * a = xxxxxxx
3055 * c = xxxxxxxxxx
3056 * a_pos = |
3058 *a_pos = a->Prec;
3060 if((b->Prec + word_shift) >= c->MaxPrec) {
3062 * a = xxxxxxxxx
3063 * b = xxxxxxxBxxx
3064 * c = xxxxxxxxxxx
3065 * b_pos = |
3067 if(c->MaxPrec >=(word_shift + 1)) {
3068 *b_pos = c->MaxPrec - word_shift - 1;
3069 *bv = b->frac[*b_pos];
3070 } else {
3071 *b_pos = -1L;
3073 } else {
3075 * a = xxxxxxxxxxxxxxxx
3076 * b = xxxxxx
3077 * c = xxxxxxxxxxxxx
3078 * b_pos = |
3080 *b_pos = b->Prec;
3082 } else { /* The MaxPrec of c - 1 > The Prec of a + b */
3084 * a = xxxxxxx
3085 * b = xxxxxx
3086 * c = xxxxxxxxxxx
3087 * c_pos = |
3089 *b_pos = b->Prec;
3090 *a_pos = a->Prec;
3091 *c_pos = right_word + 1;
3093 c->Prec = *c_pos;
3094 c->exponent = a->exponent;
3095 if(!AddExponent(c,(S_LONG)1)) return (-1L);
3096 return word_shift;
3100 * Return number og significant digits
3101 * c = a * b , Where a = a0a1a2 ... an
3102 * b = b0b1b2 ... bm
3103 * c = c0c1c2 ... cl
3104 * a0 a1 ... an * bm
3105 * a0 a1 ... an * bm-1
3106 * . . .
3107 * . . .
3108 * a0 a1 .... an * b0
3109 * +_____________________________
3110 * c0 c1 c2 ...... cl
3111 * nc <---|
3112 * MaxAB |--------------------|
3114 VP_EXPORT int
3115 VpMult(Real *c, Real *a, Real *b)
3117 U_LONG MxIndA, MxIndB, MxIndAB, MxIndC;
3118 U_LONG ind_c, i, ii, nc;
3119 U_LONG ind_as, ind_ae, ind_bs, ind_be;
3120 U_LONG Carry, s;
3121 Real *w;
3123 #ifdef _DEBUG
3124 if(gfDebug) {
3125 VPrint(stdout, "VpMult(Enter): a=% \n", a);
3126 VPrint(stdout, " b=% \n", b);
3128 #endif /* _DEBUG */
3130 if(!VpIsDefOP(c,a,b,3)) return 0; /* No significant digit */
3132 if(VpIsZero(a) || VpIsZero(b)) {
3133 /* at least a or b is zero */
3134 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
3135 return 1; /* 0: 1 significant digit */
3138 if(VpIsOne(a)) {
3139 VpAsgn(c, b, VpGetSign(a));
3140 goto Exit;
3142 if(VpIsOne(b)) {
3143 VpAsgn(c, a, VpGetSign(b));
3144 goto Exit;
3146 if((b->Prec) >(a->Prec)) {
3147 /* Adjust so that digits(a)>digits(b) */
3148 w = a;
3149 a = b;
3150 b = w;
3152 w = NULL;
3153 MxIndA = a->Prec - 1;
3154 MxIndB = b->Prec - 1;
3155 MxIndC = c->MaxPrec - 1;
3156 MxIndAB = a->Prec + b->Prec - 1;
3158 if(MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
3159 w = c;
3160 c = VpAlloc((U_LONG)((MxIndAB + 1) * BASE_FIG), "#0");
3161 MxIndC = MxIndAB;
3164 /* set LHSV c info */
3166 c->exponent = a->exponent; /* set exponent */
3167 if(!AddExponent(c,b->exponent)) {
3168 VpFree(c);
3169 return 0;
3171 VpSetSign(c,VpGetSign(a)*VpGetSign(b)); /* set sign */
3172 Carry = 0;
3173 nc = ind_c = MxIndAB;
3174 memset(c->frac, 0, (nc + 1) * sizeof(U_LONG)); /* Initialize c */
3175 c->Prec = nc + 1; /* set precision */
3176 for(nc = 0; nc < MxIndAB; ++nc, --ind_c) {
3177 if(nc < MxIndB) { /* The left triangle of the Fig. */
3178 ind_as = MxIndA - nc;
3179 ind_ae = MxIndA;
3180 ind_bs = MxIndB;
3181 ind_be = MxIndB - nc;
3182 } else if(nc <= MxIndA) { /* The middle rectangular of the Fig. */
3183 ind_as = MxIndA - nc;
3184 ind_ae = MxIndA -(nc - MxIndB);
3185 ind_bs = MxIndB;
3186 ind_be = 0;
3187 } else if(nc > MxIndA) { /* The right triangle of the Fig. */
3188 ind_as = 0;
3189 ind_ae = MxIndAB - nc - 1;
3190 ind_bs = MxIndB -(nc - MxIndA);
3191 ind_be = 0;
3194 for(i = ind_as; i <= ind_ae; ++i) {
3195 s =((a->frac[i]) *(b->frac[ind_bs--]));
3196 Carry = s / BASE;
3197 s = s -(Carry * BASE);
3198 c->frac[ind_c] += s;
3199 if(c->frac[ind_c] >= BASE) {
3200 s = c->frac[ind_c] / BASE;
3201 Carry += s;
3202 c->frac[ind_c] -= (s * BASE);
3204 if(Carry) {
3205 ii = ind_c;
3206 while((--ii) >= 0) {
3207 c->frac[ii] += Carry;
3208 if(c->frac[ii] >= BASE) {
3209 Carry = c->frac[ii] / BASE;
3210 c->frac[ii] -=(Carry * BASE);
3211 } else {
3212 break;
3218 if(w != NULL) { /* free work variable */
3219 VpNmlz(c);
3220 VpAsgn(w, c, 1);
3221 VpFree(c);
3222 c = w;
3223 } else {
3224 VpLimitRound(c,0);
3227 Exit:
3228 #ifdef _DEBUG
3229 if(gfDebug) {
3230 VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
3231 VPrint(stdout, " a=% \n", a);
3232 VPrint(stdout, " b=% \n", b);
3234 #endif /*_DEBUG */
3235 return c->Prec*BASE_FIG;
3239 * c = a / b, remainder = r
3241 VP_EXPORT int
3242 VpDivd(Real *c, Real *r, Real *a, Real *b)
3244 U_LONG word_a, word_b, word_c, word_r;
3245 U_LONG i, n, ind_a, ind_b, ind_c, ind_r;
3246 U_LONG nLoop;
3247 U_LONG q, b1, b1p1, b1b2, b1b2p1, r1r2;
3248 U_LONG borrow, borrow1, borrow2, qb;
3250 #ifdef _DEBUG
3251 if(gfDebug) {
3252 VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
3253 VPrint(stdout, " b=% \n", b);
3255 #endif /*_DEBUG */
3257 VpSetNaN(r);
3258 if(!VpIsDefOP(c,a,b,4)) goto Exit;
3259 if(VpIsZero(a)&&VpIsZero(b)) {
3260 VpSetNaN(c);
3261 return VpException(VP_EXCEPTION_NaN,"(VpDivd) 0/0 not defined(NaN)",0);
3263 if(VpIsZero(b)) {
3264 VpSetInf(c,VpGetSign(a)*VpGetSign(b));
3265 return VpException(VP_EXCEPTION_ZERODIVIDE,"(VpDivd) Divide by zero",0);
3267 if(VpIsZero(a)) {
3268 /* numerator a is zero */
3269 VpSetZero(c,VpGetSign(a)*VpGetSign(b));
3270 VpSetZero(r,VpGetSign(a)*VpGetSign(b));
3271 goto Exit;
3273 if(VpIsOne(b)) {
3274 /* divide by one */
3275 VpAsgn(c, a, VpGetSign(b));
3276 VpSetZero(r,VpGetSign(a));
3277 goto Exit;
3280 word_a = a->Prec;
3281 word_b = b->Prec;
3282 word_c = c->MaxPrec;
3283 word_r = r->MaxPrec;
3285 ind_c = 0;
3286 ind_r = 1;
3288 if(word_a >= word_r) goto space_error;
3290 r->frac[0] = 0;
3291 while(ind_r <= word_a) {
3292 r->frac[ind_r] = a->frac[ind_r - 1];
3293 ++ind_r;
3296 while(ind_r < word_r) r->frac[ind_r++] = 0;
3297 while(ind_c < word_c) c->frac[ind_c++] = 0;
3299 /* initial procedure */
3300 b1 = b1p1 = b->frac[0];
3301 if(b->Prec <= 1) {
3302 b1b2p1 = b1b2 = b1p1 * BASE;
3303 } else {
3304 b1p1 = b1 + 1;
3305 b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
3306 if(b->Prec > 2) ++b1b2p1;
3309 /* */
3310 /* loop start */
3311 ind_c = word_r - 1;
3312 nLoop = Min(word_c,ind_c);
3313 ind_c = 1;
3314 while(ind_c < nLoop) {
3315 if(r->frac[ind_c] == 0) {
3316 ++ind_c;
3317 continue;
3319 r1r2 = r->frac[ind_c] * BASE + r->frac[ind_c + 1];
3320 if(r1r2 == b1b2) {
3321 /* The first two word digits is the same */
3322 ind_b = 2;
3323 ind_a = ind_c + 2;
3324 while(ind_b < word_b) {
3325 if(r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
3326 if(r->frac[ind_a] > b->frac[ind_b]) break;
3327 ++ind_a;
3328 ++ind_b;
3330 /* The first few word digits of r and b is the same and */
3331 /* the first different word digit of w is greater than that */
3332 /* of b, so quotinet is 1 and just subtract b from r. */
3333 borrow = 0; /* quotient=1, then just r-b */
3334 ind_b = b->Prec - 1;
3335 ind_r = ind_c + ind_b;
3336 if(ind_r >= word_r) goto space_error;
3337 n = ind_b;
3338 for(i = 0; i <= n; ++i) {
3339 if(r->frac[ind_r] < b->frac[ind_b] + borrow) {
3340 r->frac[ind_r] +=(BASE -(b->frac[ind_b] + borrow));
3341 borrow = 1;
3342 } else {
3343 r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
3344 borrow = 0;
3346 --ind_r;
3347 --ind_b;
3349 ++(c->frac[ind_c]);
3350 goto carry;
3352 /* The first two word digits is not the same, */
3353 /* then compare magnitude, and divide actually. */
3354 if(r1r2 >= b1b2p1) {
3355 q = r1r2 / b1b2p1;
3356 c->frac[ind_c] += q;
3357 ind_r = b->Prec + ind_c - 1;
3358 goto sub_mult;
3361 div_b1p1:
3362 if(ind_c + 1 >= word_c) goto out_side;
3363 q = r1r2 / b1p1;
3364 c->frac[ind_c + 1] += q;
3365 ind_r = b->Prec + ind_c;
3367 sub_mult:
3368 borrow1 = borrow2 = 0;
3369 ind_b = word_b - 1;
3370 if(ind_r >= word_r) goto space_error;
3371 n = ind_b;
3372 for(i = 0; i <= n; ++i) {
3373 /* now, perform r = r - q * b */
3374 qb = q *(b->frac[ind_b]);
3375 if(qb < BASE) borrow1 = 0;
3376 else {
3377 borrow1 = qb / BASE;
3378 qb = qb - borrow1 * BASE;
3380 if(r->frac[ind_r] < qb) {
3381 r->frac[ind_r] +=(BASE - qb);
3382 borrow2 = borrow2 + borrow1 + 1;
3383 } else {
3384 r->frac[ind_r] -= qb;
3385 borrow2 += borrow1;
3387 if(borrow2) {
3388 if(r->frac[ind_r - 1] < borrow2) {
3389 r->frac[ind_r - 1] +=(BASE - borrow2);
3390 borrow2 = 1;
3391 } else {
3392 r->frac[ind_r - 1] -= borrow2;
3393 borrow2 = 0;
3396 --ind_r;
3397 --ind_b;
3400 r->frac[ind_r] -= borrow2;
3401 carry:
3402 ind_r = ind_c;
3403 while(c->frac[ind_r] >= BASE) {
3404 c->frac[ind_r] -= BASE;
3405 --ind_r;
3406 ++(c->frac[ind_r]);
3409 /* End of operation, now final arrangement */
3410 out_side:
3411 c->Prec = word_c;
3412 c->exponent = a->exponent;
3413 if(!AddExponent(c,(S_LONG)2)) return 0;
3414 if(!AddExponent(c,-(b->exponent))) return 0;
3416 VpSetSign(c,VpGetSign(a)*VpGetSign(b));
3417 VpNmlz(c); /* normalize c */
3418 r->Prec = word_r;
3419 r->exponent = a->exponent;
3420 if(!AddExponent(r,(S_LONG)1)) return 0;
3421 VpSetSign(r,VpGetSign(a));
3422 VpNmlz(r); /* normalize r(remainder) */
3423 goto Exit;
3425 space_error:
3426 #ifdef _DEBUG
3427 if(gfDebug) {
3428 printf(" word_a=%lu\n", word_a);
3429 printf(" word_b=%lu\n", word_b);
3430 printf(" word_c=%lu\n", word_c);
3431 printf(" word_r=%lu\n", word_r);
3432 printf(" ind_r =%lu\n", ind_r);
3434 #endif /* _DEBUG */
3435 rb_bug("ERROR(VpDivd): space for remainder too small.");
3437 Exit:
3438 #ifdef _DEBUG
3439 if(gfDebug) {
3440 VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
3441 VPrint(stdout, " r=% \n", r);
3443 #endif /* _DEBUG */
3444 return c->Prec*BASE_FIG;
3448 * Input a = 00000xxxxxxxx En(5 preceeding zeros)
3449 * Output a = xxxxxxxx En-5
3451 static int
3452 VpNmlz(Real *a)
3454 U_LONG ind_a, i;
3456 if(!VpIsDef(a)) goto NoVal;
3457 if(VpIsZero(a)) goto NoVal;
3459 ind_a = a->Prec;
3460 while(ind_a--) {
3461 if(a->frac[ind_a]) {
3462 a->Prec = ind_a + 1;
3463 i = 0;
3464 while(a->frac[i] == 0) ++i; /* skip the first few zeros */
3465 if(i) {
3466 a->Prec -= i;
3467 if(!AddExponent(a,-((S_INT)i))) return 0;
3468 memmove(&(a->frac[0]),&(a->frac[i]),(a->Prec)*sizeof(U_LONG));
3470 return 1;
3473 /* a is zero(no non-zero digit) */
3474 VpSetZero(a,VpGetSign(a));
3475 return 0;
3477 NoVal:
3478 a->frac[0] = 0;
3479 a->Prec=1;
3480 return 0;
3484 * VpComp = 0 ... if a=b,
3485 * Pos ... a>b,
3486 * Neg ... a<b.
3487 * 999 ... result undefined(NaN)
3489 VP_EXPORT int
3490 VpComp(Real *a, Real *b)
3492 int val;
3493 U_LONG mx, ind;
3494 int e;
3495 val = 0;
3496 if(VpIsNaN(a)||VpIsNaN(b)) return 999;
3497 if(!VpIsDef(a)) {
3498 if(!VpIsDef(b)) e = a->sign - b->sign;
3499 else e = a->sign;
3500 if(e>0) return 1;
3501 else if(e<0) return -1;
3502 else return 0;
3504 if(!VpIsDef(b)) {
3505 e = -b->sign;
3506 if(e>0) return 1;
3507 else return -1;
3509 /* Zero check */
3510 if(VpIsZero(a)) {
3511 if(VpIsZero(b)) return 0; /* both zero */
3512 val = -VpGetSign(b);
3513 goto Exit;
3515 if(VpIsZero(b)) {
3516 val = VpGetSign(a);
3517 goto Exit;
3520 /* compare sign */
3521 if(VpGetSign(a) > VpGetSign(b)) {
3522 val = 1; /* a>b */
3523 goto Exit;
3525 if(VpGetSign(a) < VpGetSign(b)) {
3526 val = -1; /* a<b */
3527 goto Exit;
3530 /* a and b have same sign, && signe!=0,then compare exponent */
3531 if((a->exponent) >(b->exponent)) {
3532 val = VpGetSign(a);
3533 goto Exit;
3535 if((a->exponent) <(b->exponent)) {
3536 val = -VpGetSign(b);
3537 goto Exit;
3540 /* a and b have same exponent, then compare significand. */
3541 mx =((a->Prec) <(b->Prec)) ?(a->Prec) :(b->Prec);
3542 ind = 0;
3543 while(ind < mx) {
3544 if((a->frac[ind]) >(b->frac[ind])) {
3545 val = VpGetSign(a);
3546 goto Exit;
3548 if((a->frac[ind]) <(b->frac[ind])) {
3549 val = -VpGetSign(b);
3550 goto Exit;
3552 ++ind;
3554 if((a->Prec) >(b->Prec)) {
3555 val = VpGetSign(a);
3556 } else if((a->Prec) <(b->Prec)) {
3557 val = -VpGetSign(b);
3560 Exit:
3561 if (val> 1) val = 1;
3562 else if(val<-1) val = -1;
3564 #ifdef _DEBUG
3565 if(gfDebug) {
3566 VPrint(stdout, " VpComp a=%\n", a);
3567 VPrint(stdout, " b=%\n", b);
3568 printf(" ans=%d\n", val);
3570 #endif /* _DEBUG */
3571 return (int)val;
3574 #ifdef _DEBUG
3576 * cntl_chr ... ASCIIZ Character, print control characters
3577 * Available control codes:
3578 * % ... VP variable. To print '%', use '%%'.
3579 * \n ... new line
3580 * \b ... backspace
3581 * ... tab
3582 * Note: % must must not appear more than once
3583 * a ... VP variable to be printed
3585 VP_EXPORT int
3586 VPrint(FILE *fp, char *cntl_chr, Real *a)
3588 U_LONG i, j, nc, nd, ZeroSup;
3589 U_LONG n, m, e, nn;
3591 /* Check if NaN & Inf. */
3592 if(VpIsNaN(a)) {
3593 fprintf(fp,SZ_NaN);
3594 return 8;
3596 if(VpIsPosInf(a)) {
3597 fprintf(fp,SZ_INF);
3598 return 8;
3600 if(VpIsNegInf(a)) {
3601 fprintf(fp,SZ_NINF);
3602 return 9;
3604 if(VpIsZero(a)) {
3605 fprintf(fp,"0.0");
3606 return 3;
3609 j = 0;
3610 nd = nc = 0; /* nd : number of digits in fraction part(every 10 digits, */
3611 /* nd<=10). */
3612 /* nc : number of caracters printed */
3613 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
3614 while(*(cntl_chr + j)) {
3615 if((*(cntl_chr + j) == '%') &&(*(cntl_chr + j + 1) != '%')) {
3616 nc = 0;
3617 if(!VpIsZero(a)) {
3618 if(VpGetSign(a) < 0) {
3619 fprintf(fp, "-");
3620 ++nc;
3622 nc += fprintf(fp, "0.");
3623 n = a->Prec;
3624 for(i=0;i < n;++i) {
3625 m = BASE1;
3626 e = a->frac[i];
3627 while(m) {
3628 nn = e / m;
3629 if((!ZeroSup) || nn) {
3630 nc += fprintf(fp, "%lu", nn); /* The reading zero(s) */
3631 /* as 0.00xx will not */
3632 /* be printed. */
3633 ++nd;
3634 ZeroSup = 0; /* Set to print succeeding zeros */
3636 if(nd >= 10) { /* print ' ' after every 10 digits */
3637 nd = 0;
3638 nc += fprintf(fp, " ");
3640 e = e - nn * m;
3641 m /= 10;
3644 nc += fprintf(fp, "E%ld", VpExponent10(a));
3645 } else {
3646 nc += fprintf(fp, "0.0");
3648 } else {
3649 ++nc;
3650 if(*(cntl_chr + j) == '\\') {
3651 switch(*(cntl_chr + j + 1)) {
3652 case 'n':
3653 fprintf(fp, "\n");
3654 ++j;
3655 break;
3656 case 't':
3657 fprintf(fp, "\t");
3658 ++j;
3659 break;
3660 case 'b':
3661 fprintf(fp, "\n");
3662 ++j;
3663 break;
3664 default:
3665 fprintf(fp, "%c", *(cntl_chr + j));
3666 break;
3668 } else {
3669 fprintf(fp, "%c", *(cntl_chr + j));
3670 if(*(cntl_chr + j) == '%') ++j;
3673 j++;
3675 return (int)nc;
3677 #endif /* _DEBUG */
3679 static void
3680 VpFormatSt(char *psz,S_INT fFmt)
3682 U_LONG ie;
3683 U_LONG i;
3684 S_INT nf = 0;
3685 char ch;
3687 if(fFmt<=0) return;
3689 ie = strlen(psz);
3690 for(i = 0; i < ie; ++i) {
3691 ch = psz[i];
3692 if(!ch) break;
3693 if(ISSPACE(ch) || ch=='-' || ch=='+') continue;
3694 if(ch == '.') { nf = 0;continue;}
3695 if(ch == 'E') break;
3696 nf++;
3697 if(nf > fFmt) {
3698 memmove(psz + i + 1, psz + i, ie - i + 1);
3699 ++ie;
3700 nf = 0;
3701 psz[i] = ' ';
3706 VP_EXPORT S_LONG
3707 VpExponent10(Real *a)
3709 S_LONG ex;
3710 U_LONG n;
3712 if(!VpHasVal(a)) return 0;
3714 ex =(a->exponent) * BASE_FIG;
3715 n = BASE1;
3716 while((a->frac[0] / n) == 0) {
3717 --ex;
3718 n /= 10;
3720 return ex;
3723 VP_EXPORT void
3724 VpSzMantissa(Real *a,char *psz)
3726 U_LONG i, ZeroSup;
3727 U_LONG n, m, e, nn;
3729 if(VpIsNaN(a)) {
3730 sprintf(psz,SZ_NaN);
3731 return;
3733 if(VpIsPosInf(a)) {
3734 sprintf(psz,SZ_INF);
3735 return;
3737 if(VpIsNegInf(a)) {
3738 sprintf(psz,SZ_NINF);
3739 return;
3742 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
3743 if(!VpIsZero(a)) {
3744 if(VpGetSign(a) < 0) *psz++ = '-';
3745 n = a->Prec;
3746 for(i=0;i < n;++i) {
3747 m = BASE1;
3748 e = a->frac[i];
3749 while(m) {
3750 nn = e / m;
3751 if((!ZeroSup) || nn) {
3752 sprintf(psz, "%lu", nn); /* The reading zero(s) */
3753 psz += strlen(psz);
3754 /* as 0.00xx will be ignored. */
3755 ZeroSup = 0; /* Set to print succeeding zeros */
3757 e = e - nn * m;
3758 m /= 10;
3761 *psz = 0;
3762 while(psz[-1]=='0') *(--psz) = 0;
3763 } else {
3764 if(VpIsPosZero(a)) sprintf(psz, "0");
3765 else sprintf(psz, "-0");
3769 VP_EXPORT int
3770 VpToSpecialString(Real *a,char *psz,int fPlus)
3771 /* fPlus =0:default, =1: set ' ' before digits , =2: set '+' before digits. */
3773 if(VpIsNaN(a)) {
3774 sprintf(psz,SZ_NaN);
3775 return 1;
3778 if(VpIsPosInf(a)) {
3779 if(fPlus==1) {
3780 *psz++ = ' ';
3781 } else if(fPlus==2) {
3782 *psz++ = '+';
3784 sprintf(psz,SZ_INF);
3785 return 1;
3787 if(VpIsNegInf(a)) {
3788 sprintf(psz,SZ_NINF);
3789 return 1;
3791 if(VpIsZero(a)) {
3792 if(VpIsPosZero(a)) {
3793 if(fPlus==1) sprintf(psz, " 0.0");
3794 else if(fPlus==2) sprintf(psz, "+0.0");
3795 else sprintf(psz, "0.0");
3796 } else sprintf(psz, "-0.0");
3797 return 1;
3799 return 0;
3802 VP_EXPORT void
3803 VpToString(Real *a,char *psz,int fFmt,int fPlus)
3804 /* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
3806 U_LONG i, ZeroSup;
3807 U_LONG n, m, e, nn;
3808 char *pszSav = psz;
3809 S_LONG ex;
3811 if(VpToSpecialString(a,psz,fPlus)) return;
3813 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
3815 if(VpGetSign(a) < 0) *psz++ = '-';
3816 else if(fPlus==1) *psz++ = ' ';
3817 else if(fPlus==2) *psz++ = '+';
3819 *psz++ = '0';
3820 *psz++ = '.';
3821 n = a->Prec;
3822 for(i=0;i < n;++i) {
3823 m = BASE1;
3824 e = a->frac[i];
3825 while(m) {
3826 nn = e / m;
3827 if((!ZeroSup) || nn) {
3828 sprintf(psz, "%lu", nn); /* The reading zero(s) */
3829 psz += strlen(psz);
3830 /* as 0.00xx will be ignored. */
3831 ZeroSup = 0; /* Set to print succeeding zeros */
3833 e = e - nn * m;
3834 m /= 10;
3837 ex =(a->exponent) * BASE_FIG;
3838 n = BASE1;
3839 while((a->frac[0] / n) == 0) {
3840 --ex;
3841 n /= 10;
3843 while(psz[-1]=='0') *(--psz) = 0;
3844 sprintf(psz, "E%ld", ex);
3845 if(fFmt) VpFormatSt(pszSav, fFmt);
3848 VP_EXPORT void
3849 VpToFString(Real *a,char *psz,int fFmt,int fPlus)
3850 /* fPlus =0:default,=1: set ' ' before digits ,set '+' before digits. */
3852 U_LONG i;
3853 U_LONG n, m, e, nn;
3854 char *pszSav = psz;
3855 S_LONG ex;
3857 if(VpToSpecialString(a,psz,fPlus)) return;
3859 if(VpGetSign(a) < 0) *psz++ = '-';
3860 else if(fPlus==1) *psz++ = ' ';
3861 else if(fPlus==2) *psz++ = '+';
3863 n = a->Prec;
3864 ex = a->exponent;
3865 if(ex<=0) {
3866 *psz++ = '0';*psz++ = '.';
3867 while(ex<0) {
3868 for(i=0;i<BASE_FIG;++i) *psz++ = '0';
3869 ++ex;
3871 ex = -1;
3874 for(i=0;i < n;++i) {
3875 --ex;
3876 if(i==0 && ex >= 0) {
3877 sprintf(psz, "%lu", a->frac[i]);
3878 psz += strlen(psz);
3879 } else {
3880 m = BASE1;
3881 e = a->frac[i];
3882 while(m) {
3883 nn = e / m;
3884 *psz++ = (char)(nn + '0');
3885 e = e - nn * m;
3886 m /= 10;
3889 if(ex == 0) *psz++ = '.';
3891 while(--ex>=0) {
3892 m = BASE;
3893 while(m/=10) *psz++ = '0';
3894 if(ex == 0) *psz++ = '.';
3896 *psz = 0;
3897 while(psz[-1]=='0') *(--psz) = 0;
3898 if(psz[-1]=='.') sprintf(psz, "0");
3899 if(fFmt) VpFormatSt(pszSav, fFmt);
3903 * [Output]
3904 * a[] ... variable to be assigned the value.
3905 * [Input]
3906 * int_chr[] ... integer part(may include '+/-').
3907 * ni ... number of characters in int_chr[],not including '+/-'.
3908 * frac[] ... fraction part.
3909 * nf ... number of characters in frac[].
3910 * exp_chr[] ... exponent part(including '+/-').
3911 * ne ... number of characters in exp_chr[],not including '+/-'.
3913 VP_EXPORT int
3914 VpCtoV(Real *a, const char *int_chr, U_LONG ni, const char *frac, U_LONG nf, const char *exp_chr, U_LONG ne)
3916 U_LONG i, j, ind_a, ma, mi, me;
3917 U_LONG loc;
3918 S_INT e,es, eb, ef;
3919 S_INT sign, signe;
3920 /* get exponent part */
3921 e = 0;
3922 ma = a->MaxPrec;
3923 mi = ni;
3924 me = ne;
3925 signe = 1;
3926 memset(a->frac, 0, ma * sizeof(U_LONG));
3927 if(ne > 0) {
3928 i = 0;
3929 if(exp_chr[0] == '-') {
3930 signe = -1;
3931 ++i;
3932 ++me;
3933 } else if(exp_chr[0] == '+') {
3934 ++i;
3935 ++me;
3937 while(i < me) {
3938 es = e*((S_INT)BASE_FIG);
3939 e = e * 10 + exp_chr[i] - '0';
3940 if(es>e*((S_INT)BASE_FIG)) {
3941 return VpException(VP_EXCEPTION_INFINITY,"exponent overflow",0);
3943 ++i;
3947 /* get integer part */
3948 i = 0;
3949 sign = 1;
3950 if(ni >= 0) {
3951 if(int_chr[0] == '-') {
3952 sign = -1;
3953 ++i;
3954 ++mi;
3955 } else if(int_chr[0] == '+') {
3956 ++i;
3957 ++mi;
3961 e = signe * e; /* e: The value of exponent part. */
3962 e = e + ni; /* set actual exponent size. */
3964 if(e > 0) signe = 1;
3965 else signe = -1;
3967 /* Adjust the exponent so that it is the multiple of BASE_FIG. */
3968 j = 0;
3969 ef = 1;
3970 while(ef) {
3971 if(e>=0) eb = e;
3972 else eb = -e;
3973 ef = eb / ((S_INT)BASE_FIG);
3974 ef = eb - ef * ((S_INT)BASE_FIG);
3975 if(ef) {
3976 ++j; /* Means to add one more preceeding zero */
3977 ++e;
3981 eb = e / ((S_INT)BASE_FIG);
3983 ind_a = 0;
3984 while(i < mi) {
3985 a->frac[ind_a] = 0;
3986 while((j < (U_LONG)BASE_FIG) &&(i < mi)) {
3987 a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
3988 ++j;
3989 ++i;
3991 if(i < mi) {
3992 ++ind_a;
3993 if(ind_a >= ma) goto over_flow;
3994 j = 0;
3997 loc = 1;
3999 /* get fraction part */
4001 i = 0;
4002 while(i < nf) {
4003 while((j < (U_LONG)BASE_FIG) &&(i < nf)) {
4004 a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
4005 ++j;
4006 ++i;
4008 if(i < nf) {
4009 ++ind_a;
4010 if(ind_a >= ma) goto over_flow;
4011 j = 0;
4014 goto Final;
4016 over_flow:
4017 rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
4019 Final:
4020 if(ind_a >= ma) ind_a = ma - 1;
4021 while(j < (U_LONG)BASE_FIG) {
4022 a->frac[ind_a] = a->frac[ind_a] * 10;
4023 ++j;
4025 a->Prec = ind_a + 1;
4026 a->exponent = eb;
4027 VpSetSign(a,sign);
4028 VpNmlz(a);
4029 return 1;
4033 * [Input]
4034 * *m ... Real
4035 * [Output]
4036 * *d ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
4037 * *e ... U_LONG,exponent of m.
4038 * DBLE_FIG ... Number of digits in a double variable.
4040 * m -> d*10**e, 0<d<BASE
4041 * [Returns]
4042 * 0 ... Zero
4043 * 1 ... Normal
4044 * 2 ... Infinity
4045 * -1 ... NaN
4047 VP_EXPORT int
4048 VpVtoD(double *d, S_LONG *e, Real *m)
4050 U_LONG ind_m, mm, fig;
4051 double div;
4052 int f = 1;
4054 if(VpIsNaN(m)) {
4055 *d = VpGetDoubleNaN();
4056 *e = 0;
4057 f = -1; /* NaN */
4058 goto Exit;
4059 } else
4060 if(VpIsPosZero(m)) {
4061 *d = 0.0;
4062 *e = 0;
4063 f = 0;
4064 goto Exit;
4065 } else
4066 if(VpIsNegZero(m)) {
4067 *d = VpGetDoubleNegZero();
4068 *e = 0;
4069 f = 0;
4070 goto Exit;
4071 } else
4072 if(VpIsPosInf(m)) {
4073 *d = VpGetDoublePosInf();
4074 *e = 0;
4075 f = 2;
4076 goto Exit;
4077 } else
4078 if(VpIsNegInf(m)) {
4079 *d = VpGetDoubleNegInf();
4080 *e = 0;
4081 f = 2;
4082 goto Exit;
4084 /* Normal number */
4085 fig =(DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
4086 ind_m = 0;
4087 mm = Min(fig,(m->Prec));
4088 *d = 0.0;
4089 div = 1.;
4090 while(ind_m < mm) {
4091 div /=(double)((S_INT)BASE);
4092 *d = *d +((double) ((S_INT)m->frac[ind_m++])) * div;
4094 *e = m->exponent * ((S_INT)BASE_FIG);
4095 *d *= VpGetSign(m);
4097 Exit:
4098 #ifdef _DEBUG
4099 if(gfDebug) {
4100 VPrint(stdout, " VpVtoD: m=%\n", m);
4101 printf(" d=%e * 10 **%ld\n", *d, *e);
4102 printf(" DBLE_FIG = %ld\n", DBLE_FIG);
4104 #endif /*_DEBUG */
4105 return f;
4109 * m <- d
4111 VP_EXPORT void
4112 VpDtoV(Real *m, double d)
4114 U_LONG i, ind_m, mm;
4115 U_LONG ne;
4116 double val, val2;
4118 if(isnan(d)) {
4119 VpSetNaN(m);
4120 goto Exit;
4122 if(isinf(d)) {
4123 if(d>0.0) VpSetPosInf(m);
4124 else VpSetNegInf(m);
4125 goto Exit;
4128 if(d == 0.0) {
4129 VpSetZero(m,1);
4130 goto Exit;
4132 val =(d > 0.) ? d :(-d);
4133 ne = 0;
4134 if(val >= 1.0) {
4135 while(val >= 1.0) {
4136 val /=(double)((S_INT)BASE);
4137 ++ne;
4139 } else {
4140 val2 = 1.0 /(double)((S_INT)BASE);
4141 while(val < val2) {
4142 val *=(double)((S_INT)BASE);
4143 --ne;
4146 /* Now val = 0.xxxxx*BASE**ne */
4148 mm = m->MaxPrec;
4149 memset(m->frac, 0, mm * sizeof(U_LONG));
4150 for(ind_m = 0;val > 0.0 && ind_m < mm;ind_m++) {
4151 val *=(double)((S_INT)BASE);
4152 i =(U_LONG) val;
4153 val -=(double)((S_INT)i);
4154 m->frac[ind_m] = i;
4156 if(ind_m >= mm) ind_m = mm - 1;
4157 if(d > 0.0) {
4158 VpSetSign(m, (S_INT)1);
4159 } else {
4160 VpSetSign(m,-(S_INT)1);
4162 m->Prec = ind_m + 1;
4163 m->exponent = ne;
4165 VpInternalRound(m,0,(m->Prec>0)?m->frac[m->Prec-1]:0,
4166 (U_LONG)(val*((double)((S_INT)BASE))));
4168 Exit:
4169 #ifdef _DEBUG
4170 if(gfDebug) {
4171 printf("VpDtoV d=%30.30e\n", d);
4172 VPrint(stdout, " m=%\n", m);
4174 #endif /* _DEBUG */
4175 return;
4179 * m <- ival
4181 #if 0 /* unused */
4182 VP_EXPORT void
4183 VpItoV(Real *m, S_INT ival)
4185 U_LONG mm, ind_m;
4186 U_LONG val, v1, v2, v;
4187 int isign;
4188 S_INT ne;
4190 if(ival == 0) {
4191 VpSetZero(m,1);
4192 goto Exit;
4194 isign = 1;
4195 val = ival;
4196 if(ival < 0) {
4197 isign = -1;
4198 val =(U_LONG)(-ival);
4200 ne = 0;
4201 ind_m = 0;
4202 mm = m->MaxPrec;
4203 while(ind_m < mm) {
4204 m->frac[ind_m] = 0;
4205 ++ind_m;
4207 ind_m = 0;
4208 while(val > 0) {
4209 if(val) {
4210 v1 = val;
4211 v2 = 1;
4212 while(v1 >= BASE) {
4213 v1 /= BASE;
4214 v2 *= BASE;
4216 val = val - v2 * v1;
4217 v = v1;
4218 } else {
4219 v = 0;
4221 m->frac[ind_m] = v;
4222 ++ind_m;
4223 ++ne;
4225 m->Prec = ind_m - 1;
4226 m->exponent = ne;
4227 VpSetSign(m,isign);
4228 VpNmlz(m);
4230 Exit:
4231 #ifdef _DEBUG
4232 if(gfDebug) {
4233 printf(" VpItoV i=%d\n", ival);
4234 VPrint(stdout, " m=%\n", m);
4236 #endif /* _DEBUG */
4237 return;
4239 #endif
4242 * y = SQRT(x), y*y - x =>0
4244 VP_EXPORT int
4245 VpSqrt(Real *y, Real *x)
4247 Real *f = NULL;
4248 Real *r = NULL;
4249 S_LONG y_prec, f_prec;
4250 S_LONG n;
4251 S_LONG e;
4252 S_LONG prec;
4253 S_LONG nr;
4254 double val;
4256 /* Zero, NaN or Infinity ? */
4257 if(!VpHasVal(x)) {
4258 if(VpIsZero(x)||VpGetSign(x)>0) {
4259 VpAsgn(y,x,1);
4260 goto Exit;
4262 VpSetNaN(y);
4263 return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(NaN or negative value)",0);
4264 goto Exit;
4267 /* Negative ? */
4268 if(VpGetSign(x) < 0) {
4269 VpSetNaN(y);
4270 return VpException(VP_EXCEPTION_OP,"(VpSqrt) SQRT(negative value)",0);
4273 /* One ? */
4274 if(VpIsOne(x)) {
4275 VpSetOne(y);
4276 goto Exit;
4279 n = (S_LONG)y->MaxPrec;
4280 if((S_LONG)x->MaxPrec > n) n = (S_LONG)x->MaxPrec;
4281 /* allocate temporally variables */
4282 f = VpAlloc(y->MaxPrec *(BASE_FIG + 2), "#1");
4283 r = VpAlloc((n + n) *(BASE_FIG + 2), "#1");
4285 nr = 0;
4286 y_prec = (S_LONG)y->MaxPrec;
4287 f_prec = (S_LONG)f->MaxPrec;
4289 prec = x->exponent;
4290 if(prec > 0) ++prec;
4291 else --prec;
4292 prec = prec - (S_LONG)y->MaxPrec;
4293 VpVtoD(&val, &e, x); /* val <- x */
4294 e /= ((S_LONG)BASE_FIG);
4295 n = e / 2;
4296 if(e - n * 2 != 0) {
4297 val /=(double)((S_INT)BASE);
4298 n =(e + 1) / 2;
4300 VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
4301 y->exponent += n;
4302 n = (DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
4303 y->MaxPrec = (U_LONG)Min(n , y_prec);
4304 f->MaxPrec = y->MaxPrec + 1;
4305 n = y_prec*((S_LONG)BASE_FIG);
4306 if((U_LONG)n<maxnr) n = (U_LONG)maxnr;
4307 do {
4308 y->MaxPrec *= 2;
4309 if(y->MaxPrec > (U_LONG)y_prec) y->MaxPrec = (U_LONG)y_prec;
4310 f->MaxPrec = y->MaxPrec;
4311 VpDivd(f, r, x, y); /* f = x/y */
4312 VpAddSub(r, f, y, -1); /* r = f - y */
4313 VpMult(f, VpPt5, r); /* f = 0.5*r */
4314 if(VpIsZero(f)) goto converge;
4315 VpAddSub(r, f, y, 1); /* r = y + f */
4316 VpAsgn(y, r, 1); /* y = r */
4317 if(f->exponent <= prec) goto converge;
4318 } while(++nr < n);
4319 /* */
4320 #ifdef _DEBUG
4321 if(gfDebug) {
4322 printf("ERROR(VpSqrt): did not converge within %ld iterations.\n",
4323 nr);
4325 #endif /* _DEBUG */
4326 y->MaxPrec = y_prec;
4328 converge:
4329 VpChangeSign(y,(S_INT)1);
4330 #ifdef _DEBUG
4331 if(gfDebug) {
4332 VpMult(r, y, y);
4333 VpAddSub(f, x, r, -1);
4334 printf("VpSqrt: iterations = %lu\n", nr);
4335 VPrint(stdout, " y =% \n", y);
4336 VPrint(stdout, " x =% \n", x);
4337 VPrint(stdout, " x-y*y = % \n", f);
4339 #endif /* _DEBUG */
4340 y->MaxPrec = y_prec;
4342 Exit:
4343 VpFree(f);
4344 VpFree(r);
4345 return 1;
4350 * nf: digit position for operation.
4353 VP_EXPORT int
4354 VpMidRound(Real *y, int f, int nf)
4356 * Round reletively from the decimal point.
4357 * f: rounding mode
4358 * nf: digit location to round from the the decimal point.
4361 /* fracf: any positive digit under rounding position? */
4362 /* exptoadd: number of digits needed to compensate negative nf */
4363 int n,i,ix,ioffset,fracf,exptoadd;
4364 U_LONG v,shifter;
4365 U_LONG div;
4367 nf += y->exponent*((int)BASE_FIG);
4368 exptoadd=0;
4369 if (nf < 0) {
4370 /* rounding position too left(large). */
4371 if((f!=VP_ROUND_CEIL) && (f!=VP_ROUND_FLOOR)) {
4372 VpSetZero(y,VpGetSign(y)); /* truncate everything */
4373 return 0;
4375 exptoadd = -nf;
4376 nf = 0;
4379 /* ix: x->fraq[ix] contains round position */
4380 ix = nf/(int)BASE_FIG;
4381 if(((U_LONG)ix)>=y->Prec) return 0; /* rounding position too right(small). */
4382 ioffset = nf - ix*((int)BASE_FIG);
4384 v = y->frac[ix];
4386 /* drop digits after pointed digit */
4387 n = BASE_FIG - ioffset - 1;
4388 for(shifter=1,i=0;i<n;++i) shifter *= 10;
4389 fracf = (v%(shifter*10) > 0);
4390 v /= shifter;
4391 div = v/10;
4392 v = v - div*10;
4393 if (fracf == 0) {
4394 for(i=ix+1;i<y->Prec;i++) {
4395 if (y->frac[i]%BASE) {
4396 fracf = 1;
4397 break;
4401 memset(y->frac+ix+1, 0, (y->Prec - (ix+1)) * sizeof(U_LONG));
4402 switch(f) {
4403 case VP_ROUND_DOWN: /* Truncate */
4404 break;
4405 case VP_ROUND_UP: /* Roundup */
4406 if(fracf) ++div;
4407 break;
4408 case VP_ROUND_HALF_UP: /* Round half up */
4409 if(v>=5) ++div;
4410 break;
4411 case VP_ROUND_HALF_DOWN: /* Round half down */
4412 if(v>=6) ++div;
4413 break;
4414 case VP_ROUND_CEIL: /* ceil */
4415 if(fracf && (VpGetSign(y)>0)) ++div;
4416 break;
4417 case VP_ROUND_FLOOR: /* floor */
4418 if(fracf && (VpGetSign(y)<0)) ++div;
4419 break;
4420 case VP_ROUND_HALF_EVEN: /* Banker's rounding */
4421 if(v>5) ++div;
4422 else if(v==5) {
4423 if((U_LONG)i==(BASE_FIG-1)) {
4424 if(ix && (y->frac[ix-1]%2)) ++div;
4425 } else {
4426 if(div%2) ++div;
4429 break;
4431 for(i=0;i<=n;++i) div *= 10;
4432 if(div>=BASE) {
4433 if(ix) {
4434 y->frac[ix] = 0;
4435 VpRdup(y,ix);
4436 } else {
4437 S_INT s = VpGetSign(y);
4438 int e = y->exponent;
4439 VpSetOne(y);
4440 VpSetSign(y,s);
4441 y->exponent = e+1;
4443 } else {
4444 y->frac[ix] = div;
4445 VpNmlz(y);
4447 if (exptoadd > 0) {
4448 y->exponent += exptoadd/BASE_FIG;
4449 exptoadd %= BASE_FIG;
4450 for(i=0;i<exptoadd;i++) {
4451 y->frac[0] *= 10;
4452 if (y->frac[0] >= BASE) {
4453 y->frac[0] /= BASE;
4454 y->exponent++;
4458 return 1;
4461 VP_EXPORT int
4462 VpLeftRound(Real *y, int f, int nf)
4464 * Round from the left hand side of the digits.
4467 U_LONG v;
4468 if(!VpHasVal(y)) return 0; /* Unable to round */
4469 v = y->frac[0];
4470 nf -= VpExponent(y)*BASE_FIG;
4471 while((v /= 10) != 0) nf--;
4472 nf += (BASE_FIG-1);
4473 return VpMidRound(y,f,nf);
4476 VP_EXPORT int
4477 VpActiveRound(Real *y, Real *x, int f, int nf)
4479 /* First,assign whole value in truncation mode */
4480 if(VpAsgn(y, x, 10)<=1) return 0; /* Zero,NaN,or Infinity */
4481 return VpMidRound(y,f,nf);
4484 static int
4485 VpLimitRound(Real *c,U_LONG ixDigit)
4487 U_LONG ix = VpGetPrecLimit();
4488 if(!VpNmlz(c)) return -1;
4489 if(!ix) return 0;
4490 if(!ixDigit) ixDigit = c->Prec-1;
4491 if((ix+BASE_FIG-1)/BASE_FIG > ixDigit+1) return 0;
4492 return VpLeftRound(c,VpGetRoundMode(),ix);
4495 static void
4496 VpInternalRound(Real *c,int ixDigit,U_LONG vPrev,U_LONG v)
4498 int f = 0;
4500 if(VpLimitRound(c,ixDigit)) return;
4501 if(!v) return;
4503 v /= BASE1;
4504 switch(gfRoundMode) {
4505 case VP_ROUND_DOWN:
4506 break;
4507 case VP_ROUND_UP:
4508 if(v) f = 1;
4509 break;
4510 case VP_ROUND_HALF_UP:
4511 if(v >= 5) f = 1;
4512 break;
4513 case VP_ROUND_HALF_DOWN:
4514 if(v >= 6) f = 1;
4515 break;
4516 case VP_ROUND_CEIL: /* ceil */
4517 if(v && (VpGetSign(c)>0)) f = 1;
4518 break;
4519 case VP_ROUND_FLOOR: /* floor */
4520 if(v && (VpGetSign(c)<0)) f = 1;
4521 break;
4522 case VP_ROUND_HALF_EVEN: /* Banker's rounding */
4523 if(v>5) f = 1;
4524 else if(v==5 && vPrev%2) f = 1;
4525 break;
4527 if(f) {
4528 VpRdup(c,ixDigit); /* round up */
4529 VpNmlz(c);
4534 * Rounds up m(plus one to final digit of m).
4536 static int
4537 VpRdup(Real *m,U_LONG ind_m)
4539 U_LONG carry;
4541 if(!ind_m) ind_m = m->Prec;
4543 carry = 1;
4544 while(carry > 0 && (ind_m--)) {
4545 m->frac[ind_m] += carry;
4546 if(m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
4547 else carry = 0;
4549 if(carry > 0) { /* Overflow,count exponent and set fraction part be 1 */
4550 if(!AddExponent(m,(S_LONG)1)) return 0;
4551 m->Prec = m->frac[0] = 1;
4552 } else {
4553 VpNmlz(m);
4555 return 1;
4559 * y = x - fix(x)
4561 VP_EXPORT void
4562 VpFrac(Real *y, Real *x)
4564 U_LONG my, ind_y, ind_x;
4566 if(!VpHasVal(x)) {
4567 VpAsgn(y,x,1);
4568 goto Exit;
4571 if(x->exponent > 0 && (U_LONG)x->exponent >= x->Prec) {
4572 VpSetZero(y,VpGetSign(x));
4573 goto Exit;
4574 } else if(x->exponent <= 0) {
4575 VpAsgn(y, x, 1);
4576 goto Exit;
4579 y->Prec = x->Prec -(U_LONG) x->exponent;
4580 y->Prec = Min(y->Prec, y->MaxPrec);
4581 y->exponent = 0;
4582 VpSetSign(y,VpGetSign(x));
4583 ind_y = 0;
4584 my = y->Prec;
4585 ind_x = x->exponent;
4586 while(ind_y < my) {
4587 y->frac[ind_y] = x->frac[ind_x];
4588 ++ind_y;
4589 ++ind_x;
4591 VpNmlz(y);
4593 Exit:
4594 #ifdef _DEBUG
4595 if(gfDebug) {
4596 VPrint(stdout, "VpFrac y=%\n", y);
4597 VPrint(stdout, " x=%\n", x);
4599 #endif /* _DEBUG */
4600 return;
4604 * y = x ** n
4606 VP_EXPORT int
4607 VpPower(Real *y, Real *x, S_INT n)
4609 U_LONG s, ss;
4610 S_LONG sign;
4611 Real *w1 = NULL;
4612 Real *w2 = NULL;
4614 if(VpIsZero(x)) {
4615 if(n==0) {
4616 VpSetOne(y);
4617 goto Exit;
4619 sign = VpGetSign(x);
4620 if(n<0) {
4621 n = -n;
4622 if(sign<0) sign = (n%2)?(-1):(1);
4623 VpSetInf (y,sign);
4624 } else {
4625 if(sign<0) sign = (n%2)?(-1):(1);
4626 VpSetZero(y,sign);
4628 goto Exit;
4630 if(!VpIsDef(x)) {
4631 VpSetNaN(y); /* Not sure !!! */
4632 goto Exit;
4635 if((x->exponent == 1) &&(x->Prec == 1) &&(x->frac[0] == 1)) {
4636 /* abs(x) = 1 */
4637 VpSetOne(y);
4638 if(VpGetSign(x) > 0) goto Exit;
4639 if((n % 2) == 0) goto Exit;
4640 VpSetSign(y,-(S_INT)1);
4641 goto Exit;
4644 if(n > 0) sign = 1;
4645 else if(n < 0) {
4646 sign = -1;
4647 n = -n;
4648 } else {
4649 VpSetOne(y);
4650 goto Exit;
4653 /* Allocate working variables */
4655 w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0");
4656 w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0");
4657 /* calculation start */
4659 VpAsgn(y, x, 1);
4660 --n;
4661 while(n > 0) {
4662 VpAsgn(w1, x, 1);
4663 s = 1;
4664 loop1: ss = s;
4665 s += s;
4666 if(s >(U_LONG) n) goto out_loop1;
4667 VpMult(w2, w1, w1);
4668 VpAsgn(w1, w2, 1);
4669 goto loop1;
4670 out_loop1:
4671 n -= ss;
4672 VpMult(w2, y, w1);
4673 VpAsgn(y, w2, 1);
4675 if(sign < 0) {
4676 VpDivd(w1, w2, VpConstOne, y);
4677 VpAsgn(y, w1, 1);
4680 Exit:
4681 #ifdef _DEBUG
4682 if(gfDebug) {
4683 VPrint(stdout, "VpPower y=%\n", y);
4684 VPrint(stdout, "VpPower x=%\n", x);
4685 printf(" n=%d\n", n);
4687 #endif /* _DEBUG */
4688 VpFree(w2);
4689 VpFree(w1);
4690 return 1;
4693 #ifdef _DEBUG
4695 VpVarCheck(Real * v)
4697 * Checks the validity of the Real variable v.
4698 * [Input]
4699 * v ... Real *, variable to be checked.
4700 * [Returns]
4701 * 0 ... correct v.
4702 * other ... error
4705 U_LONG i;
4707 if(v->MaxPrec <= 0) {
4708 printf("ERROR(VpVarCheck): Illegal Max. Precision(=%lu)\n",
4709 v->MaxPrec);
4710 return 1;
4712 if((v->Prec <= 0) ||((v->Prec) >(v->MaxPrec))) {
4713 printf("ERROR(VpVarCheck): Illegal Precision(=%lu)\n", v->Prec);
4714 printf(" Max. Prec.=%lu\n", v->MaxPrec);
4715 return 2;
4717 for(i = 0; i < v->Prec; ++i) {
4718 if((v->frac[i] >= BASE)) {
4719 printf("ERROR(VpVarCheck): Illegal fraction\n");
4720 printf(" Frac[%ld]=%lu\n", i, v->frac[i]);
4721 printf(" Prec. =%lu\n", v->Prec);
4722 printf(" Exp. =%d\n", v->exponent);
4723 printf(" BASE =%lu\n", BASE);
4724 return 3;
4727 return 0;
4729 #endif /* _DEBUG */