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"
30 /* #define ENABLE_NUMERIC_STRING */
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)
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>.
59 * Ruby provides built-in support for arbitrary precision integer arithmetic.
62 * 42**13 -> 1265437718438866624512
64 * BigDecimal provides similar support for very large or very accurate floating
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:
78 * and contrast with the output from:
80 * require 'bigdecimal'
82 * sum = BigDecimal.new("0")
84 * sum = sum + BigDecimal.new("0.0001")
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.
101 * BigDecimal sometimes needs to return infinity, for example if you divide
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)
113 * When a computation results in an undefined value, the special value NaN
114 * (for 'not a number') is returned.
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')
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
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
148 * Note also that in mathematics, there is no particular concept of negative
149 * or positive zero; true mathematical zero has no sign.
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. */
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.
166 BigDecimal_version(VALUE self
)
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 ****
188 BigDecimal_delete(Real
*pv
)
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);
207 GetVpValue(VALUE v
, int must
)
216 if(RDATA(v
)->dfree
==(void *) BigDecimal_delete
) {
217 Data_Get_Struct(v
, Real
, pv
);
224 sprintf(szD
, "%ld", FIX2LONG(v
));
225 return VpCreateRbObject(VpBaseFig() * 2 + 1, szD
);
227 #ifdef ENABLE_NUMERIC_STRING
230 return VpCreateRbObject(strlen(RSTRING_PTR(v
)) + VpBaseFig() + 1,
232 #endif /* ENABLE_NUMERIC_STRING */
235 bg
= rb_big2str(v
, 10);
236 return VpCreateRbObject(strlen(RSTRING_PTR(bg
)) + VpBaseFig() + 1,
244 rb_raise(rb_eTypeError
, "%s can't be coerced into BigDecimal",
245 rb_special_const_p(v
)?
246 RSTRING_PTR(rb_inspect(v
)):
250 return NULL
; /* NULL means to coerce */
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
261 BigDecimal_double_fig(VALUE self
)
263 return INT2FIX(VpDblFig());
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.
276 BigDecimal_prec(VALUE self
)
282 GUARD_OBJ(p
,GetVpValue(self
,1));
283 obj
= rb_assoc_new(INT2NUM(p
->Prec
*VpBaseFig()),
284 INT2NUM(p
->MaxPrec
*VpBaseFig()));
289 BigDecimal_hash(VALUE self
)
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 */
299 for(i
= 0; i
< p
->Prec
;i
++) {
300 hash
= 31 * hash
+ p
->frac
[i
];
305 return INT2FIX(hash
);
309 BigDecimal_dump(int argc
, VALUE
*argv
, VALUE self
)
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.
329 BigDecimal_load(VALUE self
, VALUE str
)
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)':') {
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
));
349 if(m
&& pv
->MaxPrec
>m
) pv
->MaxPrec
= m
+1;
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
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)
392 BigDecimal_mode(int argc
, VALUE
*argv
, VALUE self
)
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();
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");
431 fo
= VpSetRoundMode((unsigned long)FIX2INT(val
));
434 rb_raise(rb_eTypeError
, "first argument for BigDecimal#mode invalid");
439 GetAddSubPrec(Real
*a
, Real
*b
)
445 if(!VpIsDef(a
) || !VpIsDef(b
)) return (-1L);
446 if(mx
< b
->Prec
) mx
= b
->Prec
;
447 if(a
->exponent
!=b
->exponent
) {
449 d
= a
->exponent
- b
->exponent
;
453 return VpException(VP_EXCEPTION_INFINITY
,"Exponent overflow",0);
460 GetPositiveInt(VALUE v
)
463 Check_Type(v
, T_FIXNUM
);
466 rb_raise(rb_eArgError
, "argument must be positive");
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
);
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
);
487 /* Returns True if the value is Not a Number */
489 BigDecimal_IsNaN(VALUE self
)
491 Real
*p
= GetVpValue(self
,1);
492 if(VpIsNaN(p
)) return Qtrue
;
496 /* Returns True if the value is infinite */
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);
506 /* Returns True if the value is finite (not NaN or infinite) */
508 BigDecimal_IsFinite(VALUE self
)
510 Real
*p
= GetVpValue(self
,1);
511 if(VpIsNaN(p
)) return Qfalse
;
512 if(VpIsInf(p
)) return Qfalse
;
516 /* Returns the value as an integer (Fixnum or Bignum).
518 * If the BigNumber is infinity or NaN, returns nil.
521 BigDecimal_to_i(VALUE self
)
529 GUARD_OBJ(p
,GetVpValue(self
,1));
531 /* Infinity or NaN not converted. */
533 VpException(VP_EXCEPTION_NaN
,"Computation results to 'NaN'(Not a Number)",0);
535 } else if(VpIsPosInf(p
)) {
536 VpException(VP_EXCEPTION_INFINITY
,"Computation results to 'Infinity'",0);
538 } else if(VpIsNegInf(p
)) {
539 VpException(VP_EXCEPTION_INFINITY
,"Computation results to '-Infinity'",0);
544 if(e
<=0) return INT2FIX(0);
547 e
= VpGetSign(p
)*p
->frac
[0];
550 psz
= ALLOCA_N(char,(unsigned int)(e
+nf
+2));
554 if(VpGetSign(p
)<0) *pch
++ = '-';
557 if(i
>=(int)p
->Prec
) {
567 *pch
++ = (char)(j
+ '0');
573 return rb_cstr2inum(psz
,10);
577 BigDecimal_induced_from(VALUE self
, VALUE x
)
579 Real
*p
= GetVpValue(x
,1);
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.
588 BigDecimal_to_f(VALUE self
)
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);
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.
618 * a = BigDecimal.new("1.0")
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.
625 BigDecimal_coerce(VALUE self
, VALUE other
)
630 if(TYPE(other
) == T_FLOAT
) {
631 obj
= rb_assoc_new(other
, BigDecimal_to_f(self
));
633 GUARD_OBJ(b
,GetVpValue(other
,1));
634 obj
= rb_assoc_new(b
->obj
, self
);
640 BigDecimal_uplus(VALUE self
)
648 * Add the specified value.
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.
657 BigDecimal_add(VALUE self
, VALUE r
)
662 GUARD_OBJ(a
,GetVpValue(self
,1));
664 if(!b
) return DoSomeOne(self
,r
,'+');
666 if(VpIsNaN(b
)) return b
->obj
;
667 if(VpIsNaN(a
)) return a
->obj
;
668 mx
= GetAddSubPrec(a
,b
);
670 GUARD_OBJ(c
,VpCreateRbObject(VpBaseFig() + 1, "0"));
671 VpAddSub(c
, a
, b
, 1);
673 GUARD_OBJ(c
,VpCreateRbObject(mx
*(VpBaseFig() + 1), "0"));
675 VpSetInf(c
,VpGetSign(a
));
677 VpAddSub(c
, a
, b
, 1);
686 * Subtract the specified value.
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.
695 BigDecimal_sub(VALUE self
, VALUE r
)
701 GUARD_OBJ(a
,GetVpValue(self
,1));
703 if(!b
) return DoSomeOne(self
,r
,'-');
706 if(VpIsNaN(b
)) return b
->obj
;
707 if(VpIsNaN(a
)) return a
->obj
;
709 mx
= GetAddSubPrec(a
,b
);
711 GUARD_OBJ(c
,VpCreateRbObject(VpBaseFig() + 1, "0"));
712 VpAddSub(c
, a
, b
, -1);
714 GUARD_OBJ(c
,VpCreateRbObject(mx
*(VpBaseFig() + 1), "0"));
716 VpSetInf(c
,VpGetSign(a
));
718 VpAddSub(c
, a
, b
, -1);
725 BigDecimalCmp(VALUE self
, VALUE r
,char op
)
730 GUARD_OBJ(a
,GetVpValue(self
,1));
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
);
748 if(e
==999) return Qnil
;
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. */
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. */
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.
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
793 * Values may be coerced to perform the comparison:
795 * BigDecimal.new('1.0') == 1.0 -> true
798 BigDecimal_eq(VALUE self
, VALUE r
)
800 return BigDecimalCmp(self
, r
, '=');
806 * Returns true if a is less than b. Values may be coerced to perform the
807 * comparison (see ==, coerce).
810 BigDecimal_lt(VALUE self
, VALUE r
)
812 return BigDecimalCmp(self
, r
, '<');
818 * Returns true if a is less than or equal to b. Values may be coerced to
819 * perform the comparison (see ==, coerce).
822 BigDecimal_le(VALUE self
, VALUE r
)
824 return BigDecimalCmp(self
, r
, 'L');
830 * Returns true if a is greater than b. Values may be coerced to
831 * perform the comparison (see ==, coerce).
834 BigDecimal_gt(VALUE self
, VALUE r
)
836 return BigDecimalCmp(self
, r
, '>');
842 * Returns true if a is greater than or equal to b. Values may be coerced to
843 * perform the comparison (see ==, coerce)
846 BigDecimal_ge(VALUE self
, VALUE r
)
848 return BigDecimalCmp(self
, r
, 'G');
852 BigDecimal_neg(VALUE self
)
856 GUARD_OBJ(a
,GetVpValue(self
,1));
857 GUARD_OBJ(c
,VpCreateRbObject(a
->Prec
*(VpBaseFig() + 1), "0"));
863 * mult(value, digits)
865 * Multiply by the specified value.
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.
874 BigDecimal_mult(VALUE self
, VALUE r
)
880 GUARD_OBJ(a
,GetVpValue(self
,1));
882 if(!b
) return DoSomeOne(self
,r
,'*');
885 mx
= a
->Prec
+ b
->Prec
;
886 GUARD_OBJ(c
,VpCreateRbObject(mx
*(VpBaseFig() + 1), "0"));
892 BigDecimal_divide(Real
**c
, Real
**res
, Real
**div
, VALUE self
, VALUE r
)
893 /* For c = self.div(r): with round operation */
899 GUARD_OBJ(a
,GetVpValue(self
,1));
901 if(!b
) return DoSomeOne(self
,r
,'/');
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
);
915 * Divide by the specified value.
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.
929 BigDecimal_div(VALUE self
, VALUE r
)
930 /* For c = self/r: with round operation */
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
);
939 r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
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]);
949 * %: mod = a%b = a - (a.to_f/b).floor * b
950 * div = (a.to_f/b).floor
953 BigDecimal_DoDivmod(VALUE self
, VALUE r
, Real
**div
, Real
**mod
)
956 Real
*c
=NULL
, *d
=NULL
, *res
=NULL
;
960 GUARD_OBJ(a
,GetVpValue(self
,1));
962 if(!b
) return DoSomeOne(self
,r
,rb_intern("divmod"));
965 if(VpIsNaN(a
) || VpIsNaN(b
)) goto NaN
;
966 if(VpIsInf(a
) || VpIsInf(b
)) goto NaN
;
967 if(VpIsZero(b
)) goto NaN
;
969 GUARD_OBJ(c
,VpCreateRbObject(1, "0"));
970 GUARD_OBJ(d
,VpCreateRbObject(1, "0"));
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);
986 VpAddSub(c
,a
,res
,-1);
987 if(!VpIsZero(c
) && (VpGetSign(a
)*VpGetSign(b
)<0)) {
988 VpAddSub(res
,d
,VpOne(),-1);
999 GUARD_OBJ(c
,VpCreateRbObject(1, "NaN"));
1000 GUARD_OBJ(d
,VpCreateRbObject(1, "NaN"));
1010 * Returns the modulus from dividing by b. See divmod.
1013 BigDecimal_mod(VALUE self
, VALUE r
) /* %: a%b = a - (a.to_f/b).floor * b */
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
);
1026 BigDecimal_divremain(VALUE self
, VALUE r
, Real
**dv
, Real
**rv
)
1030 Real
*a
=NULL
, *b
=NULL
, *c
=NULL
, *res
=NULL
, *d
=NULL
, *rr
=NULL
, *ff
=NULL
;
1033 GUARD_OBJ(a
,GetVpValue(self
,1));
1034 b
= GetVpValue(r
,0);
1035 if(!b
) return DoSomeOne(self
,r
,rb_intern("remainder"));
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 */
1055 VpAddSub(ff
,res
,rr
,1);
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.
1070 BigDecimal_remainder(VALUE self
, VALUE r
) /* remainder */
1074 f
= BigDecimal_divremain(self
,r
,&d
,&rv
);
1075 if(f
!=(VALUE
)0) return f
;
1079 /* Divides by the specified value, and returns the quotient and modulus
1080 * as BigDecimal numbers. The quotient is rounded towards negative infinity.
1084 * require 'bigdecimal'
1086 * a = BigDecimal.new("42")
1087 * b = BigDecimal.new("9")
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.
1099 BigDecimal_divmod(VALUE self
, VALUE r
)
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
));
1113 BigDecimal_div2(int argc
, VALUE
*argv
, VALUE self
)
1117 int na
= rb_scan_args(argc
,argv
,"11",&b
,&n
);
1118 if(na
==1) { /* div in Float sense */
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
);
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
);
1142 VpLeftRound(cv
,VpGetRoundMode(),ix
);
1149 BigDecimal_add2(VALUE self
, VALUE b
, VALUE n
)
1153 U_LONG mx
= (U_LONG
)GetPositiveInt(n
);
1154 if(mx
==0) return BigDecimal_add(self
,b
);
1156 U_LONG pl
= VpSetPrecLimit(0);
1157 VALUE c
= BigDecimal_add(self
,b
);
1159 GUARD_OBJ(cv
,GetVpValue(c
,1));
1160 VpLeftRound(cv
,VpGetRoundMode(),mx
);
1166 BigDecimal_sub2(VALUE self
, VALUE b
, VALUE n
)
1170 U_LONG mx
= (U_LONG
)GetPositiveInt(n
);
1171 if(mx
==0) return BigDecimal_sub(self
,b
);
1173 U_LONG pl
= VpSetPrecLimit(0);
1174 VALUE c
= BigDecimal_sub(self
,b
);
1176 GUARD_OBJ(cv
,GetVpValue(c
,1));
1177 VpLeftRound(cv
,VpGetRoundMode(),mx
);
1183 BigDecimal_mult2(VALUE self
, VALUE b
, VALUE n
)
1187 U_LONG mx
= (U_LONG
)GetPositiveInt(n
);
1188 if(mx
==0) return BigDecimal_mult(self
,b
);
1190 U_LONG pl
= VpSetPrecLimit(0);
1191 VALUE c
= BigDecimal_mult(self
,b
);
1193 GUARD_OBJ(cv
,GetVpValue(c
,1));
1194 VpLeftRound(cv
,VpGetRoundMode(),mx
);
1199 /* Returns the absolute value.
1201 * BigDecimal('5').abs -> 5
1203 * BigDecimal('-3').abs -> 3
1206 BigDecimal_abs(VALUE self
)
1212 GUARD_OBJ(a
,GetVpValue(self
,1));
1213 mx
= a
->Prec
*(VpBaseFig() + 1);
1214 GUARD_OBJ(c
,VpCreateRbObject(mx
, "0"));
1216 VpChangeSign(c
,(S_INT
)1);
1223 * Returns the square root of the value.
1225 * If n is specified, returns at least that many significant digits.
1228 BigDecimal_sqrt(VALUE self
, VALUE nFig
)
1234 GUARD_OBJ(a
,GetVpValue(self
,1));
1235 mx
= a
->Prec
*(VpBaseFig() + 1);
1237 n
= GetPositiveInt(nFig
) + VpDblFig() + 1;
1239 GUARD_OBJ(c
,VpCreateRbObject(mx
, "0"));
1244 /* Return the integer part of the number.
1247 BigDecimal_fix(VALUE self
)
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 */
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.
1283 BigDecimal_round(int argc
, VALUE
*argv
, VALUE self
)
1293 int sw
= VpGetRoundMode();
1295 int na
= rb_scan_args(argc
,argv
,"02",&vLoc
,&vRound
);
1301 Check_Type(vLoc
, T_FIXNUM
);
1302 iLoc
= FIX2INT(vLoc
);
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");
1316 pl
= VpSetPrecLimit(0);
1317 GUARD_OBJ(a
,GetVpValue(self
,1));
1318 mx
= a
->Prec
*(VpBaseFig() + 1);
1319 GUARD_OBJ(c
,VpCreateRbObject(mx
, "0"));
1321 VpActiveRound(c
,a
,sw
,iLoc
);
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
1345 BigDecimal_truncate(int argc
, VALUE
*argv
, VALUE self
)
1352 U_LONG pl
= VpSetPrecLimit(0);
1354 if(rb_scan_args(argc
,argv
,"01",&vLoc
)==0) {
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"));
1365 VpActiveRound(c
,a
,VP_ROUND_DOWN
,iLoc
); /* 0: truncate */
1369 /* Return the fractional part of the number.
1372 BigDecimal_frac(VALUE self
)
1378 GUARD_OBJ(a
,GetVpValue(self
,1));
1379 mx
= a
->Prec
*(VpBaseFig() + 1);
1380 GUARD_OBJ(c
,VpCreateRbObject(mx
, "0"));
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
1405 BigDecimal_floor(int argc
, VALUE
*argv
, VALUE self
)
1412 U_LONG pl
= VpSetPrecLimit(0);
1414 if(rb_scan_args(argc
,argv
,"01",&vLoc
)==0) {
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"));
1425 VpActiveRound(c
,a
,VP_ROUND_FLOOR
,iLoc
);
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
1449 BigDecimal_ceil(int argc
, VALUE
*argv
, VALUE self
)
1456 U_LONG pl
= VpSetPrecLimit(0);
1458 if(rb_scan_args(argc
,argv
,"01",&vLoc
)==0) {
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"));
1469 VpActiveRound(c
,a
,VP_ROUND_CEIL
,iLoc
);
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
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.
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'
1504 BigDecimal_to_s(int argc
, VALUE
*argv
, VALUE self
)
1507 int fmt
=0; /* 0:E format */
1508 int fPlus
=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
1516 GUARD_OBJ(vp
,GetVpValue(self
,1));
1518 if(rb_scan_args(argc
,argv
,"01",&f
)==1) {
1519 if(TYPE(f
)==T_STRING
) {
1521 psz
= RSTRING_PTR(f
);
1524 } else if(*psz
=='+') {
1527 while((ch
=*psz
++)!=0) {
1528 if(ISSPACE(ch
)) continue;
1530 if(ch
=='F' || ch
=='f') fmt
= 1; /* F format */
1533 mc
= mc
* 10 + ch
- '0';
1536 mc
= GetPositiveInt(f
);
1540 nc
= VpNumOfChars(vp
,"F");
1542 nc
= VpNumOfChars(vp
,"E");
1544 if(mc
>0) nc
+= (nc
+ mc
- 1) / mc
+ 1;
1546 psz
= ALLOCA_N(char,(unsigned int)nc
);
1549 VpToFString(vp
, psz
, mc
, fPlus
);
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
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.)
1581 BigDecimal_split(VALUE self
)
1590 GUARD_OBJ(vp
,GetVpValue(self
,1));
1591 psz1
= ALLOCA_N(char,(unsigned int)VpNumOfChars(vp
,"E"));
1592 VpSzMantissa(vp
,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
));
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.
1614 BigDecimal_exponent(VALUE self
)
1616 S_LONG e
= VpExponent10(GetVpValue(self
,1));
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.
1631 BigDecimal_inspect(VALUE self
)
1640 GUARD_OBJ(vp
,GetVpValue(self
,1));
1641 nc
= VpNumOfChars(vp
,"E");
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
);
1655 * Returns the value raised to the power of n. Note that n must be an Integer.
1657 * Also available as the operator **
1660 BigDecimal_power(VALUE self
, VALUE p
)
1666 Check_Type(p
, T_FIXNUM
);
1669 if(ma
< 0) ma
= -ma
;
1672 GUARD_OBJ(x
,GetVpValue(self
,1));
1674 mp
= x
->Prec
*(VpBaseFig() + 1);
1675 GUARD_OBJ(y
,VpCreateRbObject(mp
*(ma
+ 1), "0"));
1677 GUARD_OBJ(y
,VpCreateRbObject(1, "0"));
1684 BigDecimal_global_new(int argc
, VALUE
*argv
, VALUE self
)
1692 if(rb_scan_args(argc
,argv
,"11",&iniValue
,&nFig
)==1) {
1695 mf
= GetPositiveInt(nFig
);
1697 SafeStringValue(iniValue
);
1698 GUARD_OBJ(pv
,VpCreateRbObject(mf
, RSTRING_PTR(iniValue
)));
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.
1715 BigDecimal_new(int argc
, VALUE
*argv
, VALUE self
)
1723 if(rb_scan_args(argc
,argv
,"11",&iniValue
,&nFig
)==1) {
1726 mf
= GetPositiveInt(nFig
);
1728 SafeStringValue(iniValue
);
1729 GUARD_OBJ(pv
,VpNewRbClass(mf
, RSTRING_PTR(iniValue
),self
));
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.
1746 BigDecimal_limit(int argc
, VALUE
*argv
, VALUE self
)
1749 VALUE nCur
= INT2NUM(VpGetPrecLimit());
1751 if(rb_scan_args(argc
,argv
,"01",&nFig
)==1) {
1753 if(nFig
==Qnil
) return nCur
;
1754 Check_Type(nFig
, T_FIXNUM
);
1757 rb_raise(rb_eArgError
, "argument must be positive");
1764 /* Returns the sign of the value.
1766 * Returns a positive value if > 0, a negative value if < 0, and a
1769 * The specific value returned indicates the type and sign of the BigDecimal,
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
1781 BigDecimal_sign(VALUE self
)
1783 int s
= GetVpValue(self
,1)->sign
;
1788 Init_bigdecimal(void)
1790 /* Initialize VP routines */
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);
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
1817 rb_define_const(rb_cBigDecimal
, "BASE", INT2FIX((S_INT
)VpBaseVal()));
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
1862 rb_define_const(rb_cBigDecimal
, "ROUND_MODE",INT2FIX(VP_ROUND_MODE
));
1864 /* 1: Indicates that values should be rounded away from zero. See
1867 rb_define_const(rb_cBigDecimal
, "ROUND_UP",INT2FIX(VP_ROUND_UP
));
1869 /* 2: Indicates that values should be rounded towards zero. See
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 * ============================================================================
1977 /*static int gfDebug = 1;*/ /* Debug switch */
1978 static int gfCheckVal
= 1; /* Value checking flag in VpNmlz() */
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 */
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 */
1993 #error BASE_FIG is defined but BASE is not
1995 #define HALF_BASE (BASE/2)
1996 #define BASE1 (BASE/10)
1999 #define DBLE_FIG (DBL_DIG+1) /* figure of double */
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() */
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
);
2021 static int gnAlloc
=0; /* Memory allocation counter */
2025 VpMemAlloc(U_LONG mb
)
2027 void *p
= xmalloc((unsigned int)mb
);
2029 VpException(VP_EXCEPTION_MEMORY
,"failed to allocate memory",1);
2033 gnAlloc
++; /* Count allocation call */
2044 gnAlloc
--; /* Decrement allocation count */
2046 printf(" *************** All memories allocated freed ****************");
2050 printf(" ??????????? Too many memory free calls(%d) ?????????????\n",gnAlloc
);
2058 * EXCEPTION Handling.
2060 static unsigned short gfDoException
= 0; /* Exception flag */
2062 static unsigned short
2063 VpGetException (void)
2065 return gfDoException
;
2069 VpSetException(unsigned short f
)
2074 /* These 2 functions added at v1.1.7 */
2076 VpGetPrecLimit(void)
2082 VpSetPrecLimit(U_LONG n
)
2084 U_LONG s
= gnPrecLimit
;
2089 VP_EXPORT
unsigned long
2090 VpGetRoundMode(void)
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
2106 VP_EXPORT
unsigned long
2107 VpSetRoundMode(unsigned long n
)
2109 if(VpIsRoundMode(n
)) gfRoundMode
= n
;
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;
2126 return gZero_ABCED9B1_CE73__00400511F31D
;
2132 return gOne_ABCED9B4_CE73__00400511F31D
;
2154 ----------------------------------------------------------------
2155 Value of sign in Real structure is reserved for future use.
2161 -2 : Negative number
2162 3 : Positive infinite number
2163 -3 : Negative infinite number
2164 ----------------------------------------------------------------
2168 VpGetDoubleNaN(void) /* Returns the value of NaN */
2170 static double fNaN
= 0.0;
2171 if(fNaN
==0.0) fNaN
= Zero()/Zero();
2176 VpGetDoublePosInf(void) /* Returns the value of +Infinity */
2178 static double fInf
= 0.0;
2179 if(fInf
==0.0) fInf
= One()/Zero();
2184 VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
2186 static double fInf
= 0.0;
2187 if(fInf
==0.0) fInf
= -(One()/Zero());
2192 VpGetDoubleNegZero(void) /* Returns the value of -0 */
2194 static double nzero
= 1000.0;
2195 if(nzero
!=0.0) nzero
= (One()/VpGetDoubleNegInf());
2201 VpIsNegDoubleZero(double v
)
2203 double z
= VpGetDoubleNegZero();
2204 return MemCmp(&v
,&z
,sizeof(v
))==0;
2209 VpException(unsigned short f
, const char *str
,int always
)
2214 if(f
==VP_EXCEPTION_OP
|| f
==VP_EXCEPTION_MEMORY
) always
= 1;
2216 if(always
||(gfDoException
&f
)) {
2220 case VP_EXCEPTION_ZERODIVIDE:
2221 case VP_EXCEPTION_OVERFLOW:
2223 case VP_EXCEPTION_INFINITY
:
2224 exc
= rb_eFloatDomainError
;
2226 case VP_EXCEPTION_NaN
:
2227 exc
= rb_eFloatDomainError
;
2229 case VP_EXCEPTION_UNDERFLOW
:
2230 exc
= rb_eFloatDomainError
;
2232 case VP_EXCEPTION_OP
:
2233 exc
= rb_eFloatDomainError
;
2235 case VP_EXCEPTION_MEMORY
:
2243 return 0; /* 0 Means VpException() raised no exception */
2246 if(fatal
) rb_fatal("%s", str
);
2247 else rb_raise(exc
, "%s", str
);
2251 /* Throw exception or returns 0,when resulting c is Inf or NaN */
2252 /* sw=1:+ 2:- 3:* 4:/ */
2254 VpIsDefOP(Real
*c
,Real
*a
,Real
*b
,int sw
)
2256 if(VpIsNaN(a
) || VpIsNaN(b
)) {
2257 /* at least a or b is NaN */
2267 if(VpGetSign(a
)==VpGetSign(b
)) {
2268 VpSetInf(c
,VpGetSign(a
));
2275 if(VpGetSign(a
)!=VpGetSign(b
)) {
2276 VpSetInf(c
,VpGetSign(a
));
2284 VpSetInf(c
,VpGetSign(a
)*VpGetSign(b
));
2299 VpSetInf(c
,VpGetSign(a
));
2306 VpSetInf(c
,VpGetSign(a
)*VpGetSign(b
));
2309 VpSetInf(c
,VpGetSign(a
)*VpGetSign(b
));
2318 VpSetInf(c
,VpGetSign(b
));
2321 VpSetInf(c
,-VpGetSign(b
));
2328 VpSetInf(c
,VpGetSign(a
)*VpGetSign(b
));
2331 VpSetZero(c
,VpGetSign(a
)*VpGetSign(b
));
2335 return 1; /* Results OK */
2338 return VpException(VP_EXCEPTION_INFINITY
,"Computation results to 'Infinity'",0);
2340 return VpException(VP_EXCEPTION_NaN
,"Computation results to 'NaN'",0);
2344 ----------------------------------------------------------------
2348 * returns number of chars needed to represent vp in specified format.
2351 VpNumOfChars(Real
*vp
,const char *pszFmt
)
2356 if(vp
== NULL
) return BASE_FIG
*2+6;
2357 if(!VpIsDef(vp
)) return 32; /* not sure,may be OK */
2362 nc
= BASE_FIG
*(vp
->Prec
+ 1)+2;
2365 nc
+= BASE_FIG
*(-ex
);
2367 if(ex
> (S_INT
)vp
->Prec
) {
2368 nc
+= BASE_FIG
*(ex
- (S_INT
)vp
->Prec
);
2374 nc
= BASE_FIG
*(vp
->Prec
+ 2)+6; /* 3: sign + exponent chars */
2380 * Initializer for Vp routines and constants used.
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.
2394 VpInit(U_LONG BaseVal
)
2396 /* Setup +/- Inf NaN -0 */
2398 VpGetDoublePosInf();
2399 VpGetDoubleNegInf();
2400 VpGetDoubleNegZero();
2405 /* Base <= 0, then determine Base by calcuration. */
2409 ((w
= BASE
*(BASE
+ 1)) > BASE
) &&((w
/ BASE
) ==(BASE
+ 1))
2412 BASE
= BaseVal
* 10L;
2415 /* Set Base Values */
2417 HALF_BASE
= BASE
/ 2;
2420 while(BaseVal
/= 10) ++BASE_FIG
;
2423 /* Allocates Vp constants. */
2424 VpConstOne
= VpAlloc((U_LONG
)1, "1");
2425 VpPt5
= VpAlloc((U_LONG
)1, ".5");
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
);
2451 /* If exponent overflows,then raise exception or returns 0 */
2453 AddExponent(Real
*a
,S_INT n
)
2455 S_INT e
= a
->exponent
;
2462 if(mb
<eb
) goto overflow
;
2467 if(mb
>eb
) goto underflow
;
2472 /* Overflow/Underflow ==> Raise exception or returns 0 */
2474 VpSetZero(a
,VpGetSign(a
));
2475 return VpException(VP_EXCEPTION_UNDERFLOW
,"Exponent underflow",0);
2478 VpSetInf(a
,VpGetSign(a
));
2479 return VpException(VP_EXCEPTION_OVERFLOW
,"Exponent overflow",0);
2483 * Allocates variable.
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.
2492 * Pointer to the newly allocated variable, or
2493 * NULL be returned if memory allocation is failed,or any error.
2496 VpAlloc(U_LONG mx
, const char *szVal
)
2498 U_LONG i
, ni
, ipn
, ipf
, nf
, ipe
, ne
, nalloc
;
2502 U_LONG mf
= VpGetPrecLimit();
2504 mx
= (mx
+ BASE_FIG
- 1) / BASE_FIG
+ 1; /* Determine allocation unit. */
2506 while(ISSPACE(*szVal
)) szVal
++;
2509 mf
= (mf
+ BASE_FIG
- 1) / BASE_FIG
+ 2; /* Needs 1 more for div */
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. */
2528 /* Skip all '_' after digit: 2006-6-30 */
2530 psz
= ALLOCA_N(char,strlen(szVal
)+1);
2533 while((psz
[i
]=szVal
[ipn
])!=0) {
2534 if(ISDIGIT(psz
[i
])) ++ni
;
2536 if(ni
>0) {ipn
++;continue;}
2542 /* Skip trailing spaces */
2544 if(ISSPACE(psz
[i
])) psz
[i
] = 0;
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 */
2557 if(StrCmp(szVal
,SZ_NINF
)==0) {
2558 vp
= (Real
*) VpMemAlloc(sizeof(Real
) + sizeof(U_LONG
));
2559 vp
->MaxPrec
= 1; /* set max precision */
2563 if(StrCmp(szVal
,SZ_NaN
)==0) {
2564 vp
= (Real
*) VpMemAlloc(sizeof(Real
) + sizeof(U_LONG
));
2565 vp
->MaxPrec
= 1; /* set max precision */
2570 /* check on number szVal[] */
2572 if (szVal
[i
] == '-') {sign
=-1;++i
;}
2573 else if(szVal
[i
] == '+') ++i
;
2575 ni
= 0; /* digits in mantissa */
2576 while((v
= szVal
[i
]) != 0) {
2577 if(!ISDIGIT(v
)) break;
2586 /* other than digit nor \0 */
2587 if(szVal
[i
] == '.') { /* xxx. */
2590 while((v
= szVal
[i
]) != 0) { /* get fraction part. */
2591 if(!ISDIGIT(v
)) break;
2596 ipe
= 0; /* Exponent */
2607 if((v
== '-') ||(v
== '+')) ++i
;
2608 while((v
=szVal
[i
])!=0) {
2609 if(!ISDIGIT(v
)) break;
2618 nalloc
=(ni
+ nf
+ BASE_FIG
- 1) / BASE_FIG
+ 1; /* set effective allocation */
2619 /* units for szVal[] */
2621 nalloc
= Max(nalloc
, mx
);
2623 vp
=(Real
*) VpMemAlloc(sizeof(Real
) + mx
* sizeof(U_LONG
));
2624 /* xmalloc() alway returns(or throw interruption) */
2625 vp
->MaxPrec
= mx
; /* set max precision */
2627 VpCtoV(vp
, &(szVal
[ipn
]), ni
, &(szVal
[ipf
]), nf
, &(szVal
[ipe
]), ne
);
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.
2644 VpAsgn(Real
*c
, Real
*a
, int isw
)
2652 VpSetInf(c
,isw
*VpGetSign(a
));
2656 /* check if the RHS is zero */
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
);
2662 memcpy(c
->frac
, a
->frac
, n
* sizeof(U_LONG
));
2665 /* Not in ActiveRound */
2666 if(c
->Prec
< a
->Prec
) {
2667 VpInternalRound(c
,n
,(n
>0)?a
->frac
[n
-1]:0,a
->frac
[n
]);
2673 /* The value of 'a' is zero. */
2674 VpSetZero(c
,isw
*VpGetSign(a
));
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
2686 VpAddSub(Real
*c
, Real
*a
, Real
*b
, int operation
)
2689 Real
*a_ptr
, *b_ptr
;
2690 U_LONG n
, na
, nb
, i
;
2695 VPrint(stdout
, "VpAddSub(enter) a=% \n", a
);
2696 VPrint(stdout
, " b=% \n", b
);
2697 printf(" operation=%d\n", operation
);
2701 if(!VpIsDefOP(c
,a
,b
,(operation
>0)?1:2)) return 0; /* No significant digits */
2703 /* check if a or b is zero */
2705 /* a is zero,then assign b to c */
2707 VpAsgn(c
, b
, operation
);
2709 /* Both a and b are zero. */
2710 if(VpGetSign(a
)<0 && operation
*VpGetSign(b
)<0) {
2716 return 1; /* 0: 1 significant digits */
2718 return c
->Prec
*BASE_FIG
;
2721 /* b is zero,then assign a to c. */
2723 return c
->Prec
*BASE_FIG
;
2726 if(operation
< 0) sw
= -1;
2729 /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
2730 if(a
->exponent
> b
->exponent
) {
2734 else if(a
->exponent
< b
->exponent
) {
2739 /* Exponent part of a and b is the same,then compare fraction */
2744 for(i
=0;i
< n
; ++i
) {
2745 if(a
->frac
[i
] > b
->frac
[i
]) {
2749 } else if(a
->frac
[i
] < b
->frac
[i
]) {
2759 } else if(na
< nb
) {
2765 if(VpGetSign(a
) + sw
*VpGetSign(b
) == 0) {
2766 VpSetZero(c
,1); /* abs(a)=abs(b) and operation = '-' */
2767 return c
->Prec
*BASE_FIG
;
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
);
2790 VpSetSign(c
,VpGetSign(a
));
2792 VpSetSign(c
,VpGetSign(a_ptr
) * sw
);
2795 VpInternalRound(c
,0,(c
->Prec
>0)?c
->frac
[c
->Prec
-1]:0,mrv
);
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
);
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|
2814 VpAddAbs(Real
*a
, Real
*b
, Real
*c
)
2828 VPrint(stdout
, "VpAddAbs called: a = %\n", a
);
2829 VPrint(stdout
, " b = %\n", b
);
2833 word_shift
= VpSetPTR(a
, b
, c
, &ap
, &bp
, &cp
, &av
, &bv
);
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
) {
2847 c
->frac
[c_pos
] = b
->frac
[--b_pos
];
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
;
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 */
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
;
2874 /* Just assign the first few digits of a with considering */
2875 /* the carry obtained so far because b has been exhausted. */
2877 c
->frac
[--c_pos
] = a
->frac
[--a_pos
] + carry
;
2878 if(c
->frac
[c_pos
] >= BASE
) {
2879 c
->frac
[c_pos
] -= BASE
;
2885 if(c_pos
) c
->frac
[c_pos
- 1] += carry
;
2896 VPrint(stdout
, "VpAddAbs exit: c=% \n", c
);
2903 * c = abs(a) - abs(b)
2906 VpSubAbs(Real
*a
, Real
*b
, Real
*c
)
2921 VPrint(stdout
, "VpSubAbs called: a = %\n", a
);
2922 VPrint(stdout
, " b = %\n", b
);
2926 word_shift
= VpSetPTR(a
, b
, c
, &ap
, &bp
, &cp
, &av
, &bv
);
2930 if(word_shift
==-1L) return 0; /* Overflow */
2931 if(b_pos
== -1L) goto Assign_a
;
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
) {
2948 c
->frac
[c_pos
] = BASE
- b
->frac
[--b_pos
] - borrow
;
2951 c
->frac
[c_pos
] = BASE
- borrow
;
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
;
2961 c
->frac
[--c_pos
] = a
->frac
[--a_pos
];
2964 /* Now perform subtraction until every digits of b will be */
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
;
2972 c
->frac
[c_pos
] = a
->frac
[a_pos
] - b
->frac
[b_pos
] - borrow
;
2977 /* Just assign the first few digits of a with considering */
2978 /* the borrow obtained so far because b has been exhausted. */
2981 if(a
->frac
[--a_pos
] < borrow
) {
2982 c
->frac
[c_pos
] = BASE
+ a
->frac
[a_pos
] - borrow
;
2985 c
->frac
[c_pos
] = a
->frac
[a_pos
] - borrow
;
2989 if(c_pos
) c
->frac
[c_pos
- 1] -= borrow
;
2999 VPrint(stdout
, "VpSubAbs exit: c=% \n", c
);
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 -----------------------------------
3011 * c =xxxxxxxxxxxxxxx
3013 * right_word = | | (Total digits in RHSV)
3014 * left_word = | | (Total digits in LHSV)
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
;
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 = |-----|
3042 *c_pos
= right_word
= left_word
+ 1; /* Set resulting precision */
3043 /* be equal to that of c */
3044 if((a
->Prec
) >=(c
->MaxPrec
)) {
3051 *av
= a
->frac
[*a_pos
]; /* av is 'A' shown in above. */
3060 if((b
->Prec
+ word_shift
) >= c
->MaxPrec
) {
3067 if(c
->MaxPrec
>=(word_shift
+ 1)) {
3068 *b_pos
= c
->MaxPrec
- word_shift
- 1;
3069 *bv
= b
->frac
[*b_pos
];
3075 * a = xxxxxxxxxxxxxxxx
3082 } else { /* The MaxPrec of c - 1 > The Prec of a + b */
3091 *c_pos
= right_word
+ 1;
3094 c
->exponent
= a
->exponent
;
3095 if(!AddExponent(c
,(S_LONG
)1)) return (-1L);
3100 * Return number og significant digits
3101 * c = a * b , Where a = a0a1a2 ... an
3105 * a0 a1 ... an * bm-1
3108 * a0 a1 .... an * b0
3109 * +_____________________________
3110 * c0 c1 c2 ...... cl
3112 * MaxAB |--------------------|
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
;
3125 VPrint(stdout
, "VpMult(Enter): a=% \n", a
);
3126 VPrint(stdout
, " b=% \n", b
);
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 */
3139 VpAsgn(c
, b
, VpGetSign(a
));
3143 VpAsgn(c
, a
, VpGetSign(b
));
3146 if((b
->Prec
) >(a
->Prec
)) {
3147 /* Adjust so that digits(a)>digits(b) */
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) */
3160 c
= VpAlloc((U_LONG
)((MxIndAB
+ 1) * BASE_FIG
), "#0");
3164 /* set LHSV c info */
3166 c
->exponent
= a
->exponent
; /* set exponent */
3167 if(!AddExponent(c
,b
->exponent
)) {
3171 VpSetSign(c
,VpGetSign(a
)*VpGetSign(b
)); /* set sign */
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
;
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
);
3187 } else if(nc
> MxIndA
) { /* The right triangle of the Fig. */
3189 ind_ae
= MxIndAB
- nc
- 1;
3190 ind_bs
= MxIndB
-(nc
- MxIndA
);
3194 for(i
= ind_as
; i
<= ind_ae
; ++i
) {
3195 s
=((a
->frac
[i
]) *(b
->frac
[ind_bs
--]));
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
;
3202 c
->frac
[ind_c
] -= (s
* BASE
);
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
);
3218 if(w
!= NULL
) { /* free work variable */
3230 VPrint(stdout
, "VpMult(c=a*b): c=% \n", c
);
3231 VPrint(stdout
, " a=% \n", a
);
3232 VPrint(stdout
, " b=% \n", b
);
3235 return c
->Prec
*BASE_FIG
;
3239 * c = a / b, remainder = r
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
;
3247 U_LONG q
, b1
, b1p1
, b1b2
, b1b2p1
, r1r2
;
3248 U_LONG borrow
, borrow1
, borrow2
, qb
;
3252 VPrint(stdout
, " VpDivd(c=a/b) a=% \n", a
);
3253 VPrint(stdout
, " b=% \n", b
);
3258 if(!VpIsDefOP(c
,a
,b
,4)) goto Exit
;
3259 if(VpIsZero(a
)&&VpIsZero(b
)) {
3261 return VpException(VP_EXCEPTION_NaN
,"(VpDivd) 0/0 not defined(NaN)",0);
3264 VpSetInf(c
,VpGetSign(a
)*VpGetSign(b
));
3265 return VpException(VP_EXCEPTION_ZERODIVIDE
,"(VpDivd) Divide by zero",0);
3268 /* numerator a is zero */
3269 VpSetZero(c
,VpGetSign(a
)*VpGetSign(b
));
3270 VpSetZero(r
,VpGetSign(a
)*VpGetSign(b
));
3275 VpAsgn(c
, a
, VpGetSign(b
));
3276 VpSetZero(r
,VpGetSign(a
));
3282 word_c
= c
->MaxPrec
;
3283 word_r
= r
->MaxPrec
;
3288 if(word_a
>= word_r
) goto space_error
;
3291 while(ind_r
<= word_a
) {
3292 r
->frac
[ind_r
] = a
->frac
[ind_r
- 1];
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];
3302 b1b2p1
= b1b2
= b1p1
* BASE
;
3305 b1b2p1
= b1b2
= b1
* BASE
+ b
->frac
[1];
3306 if(b
->Prec
> 2) ++b1b2p1
;
3312 nLoop
= Min(word_c
,ind_c
);
3314 while(ind_c
< nLoop
) {
3315 if(r
->frac
[ind_c
] == 0) {
3319 r1r2
= r
->frac
[ind_c
] * BASE
+ r
->frac
[ind_c
+ 1];
3321 /* The first two word digits is the same */
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;
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
;
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
));
3343 r
->frac
[ind_r
] = r
->frac
[ind_r
] - b
->frac
[ind_b
] - borrow
;
3352 /* The first two word digits is not the same, */
3353 /* then compare magnitude, and divide actually. */
3354 if(r1r2
>= b1b2p1
) {
3356 c
->frac
[ind_c
] += q
;
3357 ind_r
= b
->Prec
+ ind_c
- 1;
3362 if(ind_c
+ 1 >= word_c
) goto out_side
;
3364 c
->frac
[ind_c
+ 1] += q
;
3365 ind_r
= b
->Prec
+ ind_c
;
3368 borrow1
= borrow2
= 0;
3370 if(ind_r
>= word_r
) goto space_error
;
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;
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;
3384 r
->frac
[ind_r
] -= qb
;
3388 if(r
->frac
[ind_r
- 1] < borrow2
) {
3389 r
->frac
[ind_r
- 1] +=(BASE
- borrow2
);
3392 r
->frac
[ind_r
- 1] -= borrow2
;
3400 r
->frac
[ind_r
] -= borrow2
;
3403 while(c
->frac
[ind_r
] >= BASE
) {
3404 c
->frac
[ind_r
] -= BASE
;
3409 /* End of operation, now final arrangement */
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 */
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) */
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
);
3435 rb_bug("ERROR(VpDivd): space for remainder too small.");
3440 VPrint(stdout
, " VpDivd(c=a/b), c=% \n", c
);
3441 VPrint(stdout
, " r=% \n", r
);
3444 return c
->Prec
*BASE_FIG
;
3448 * Input a = 00000xxxxxxxx En(5 preceeding zeros)
3449 * Output a = xxxxxxxx En-5
3456 if(!VpIsDef(a
)) goto NoVal
;
3457 if(VpIsZero(a
)) goto NoVal
;
3461 if(a
->frac
[ind_a
]) {
3462 a
->Prec
= ind_a
+ 1;
3464 while(a
->frac
[i
] == 0) ++i
; /* skip the first few zeros */
3467 if(!AddExponent(a
,-((S_INT
)i
))) return 0;
3468 memmove(&(a
->frac
[0]),&(a
->frac
[i
]),(a
->Prec
)*sizeof(U_LONG
));
3473 /* a is zero(no non-zero digit) */
3474 VpSetZero(a
,VpGetSign(a
));
3484 * VpComp = 0 ... if a=b,
3487 * 999 ... result undefined(NaN)
3490 VpComp(Real
*a
, Real
*b
)
3496 if(VpIsNaN(a
)||VpIsNaN(b
)) return 999;
3498 if(!VpIsDef(b
)) e
= a
->sign
- b
->sign
;
3501 else if(e
<0) return -1;
3511 if(VpIsZero(b
)) return 0; /* both zero */
3512 val
= -VpGetSign(b
);
3521 if(VpGetSign(a
) > VpGetSign(b
)) {
3525 if(VpGetSign(a
) < VpGetSign(b
)) {
3530 /* a and b have same sign, && signe!=0,then compare exponent */
3531 if((a
->exponent
) >(b
->exponent
)) {
3535 if((a
->exponent
) <(b
->exponent
)) {
3536 val
= -VpGetSign(b
);
3540 /* a and b have same exponent, then compare significand. */
3541 mx
=((a
->Prec
) <(b
->Prec
)) ?(a
->Prec
) :(b
->Prec
);
3544 if((a
->frac
[ind
]) >(b
->frac
[ind
])) {
3548 if((a
->frac
[ind
]) <(b
->frac
[ind
])) {
3549 val
= -VpGetSign(b
);
3554 if((a
->Prec
) >(b
->Prec
)) {
3556 } else if((a
->Prec
) <(b
->Prec
)) {
3557 val
= -VpGetSign(b
);
3561 if (val
> 1) val
= 1;
3562 else if(val
<-1) val
= -1;
3566 VPrint(stdout
, " VpComp a=%\n", a
);
3567 VPrint(stdout
, " b=%\n", b
);
3568 printf(" ans=%d\n", val
);
3576 * cntl_chr ... ASCIIZ Character, print control characters
3577 * Available control codes:
3578 * % ... VP variable. To print '%', use '%%'.
3582 * Note: % must must not appear more than once
3583 * a ... VP variable to be printed
3586 VPrint(FILE *fp
, char *cntl_chr
, Real
*a
)
3588 U_LONG i
, j
, nc
, nd
, ZeroSup
;
3591 /* Check if NaN & Inf. */
3601 fprintf(fp
,SZ_NINF
);
3610 nd
= nc
= 0; /* nd : number of digits in fraction part(every 10 digits, */
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) != '%')) {
3618 if(VpGetSign(a
) < 0) {
3622 nc
+= fprintf(fp
, "0.");
3624 for(i
=0;i
< n
;++i
) {
3629 if((!ZeroSup
) || nn
) {
3630 nc
+= fprintf(fp
, "%lu", nn
); /* The reading zero(s) */
3631 /* as 0.00xx will not */
3634 ZeroSup
= 0; /* Set to print succeeding zeros */
3636 if(nd
>= 10) { /* print ' ' after every 10 digits */
3638 nc
+= fprintf(fp
, " ");
3644 nc
+= fprintf(fp
, "E%ld", VpExponent10(a
));
3646 nc
+= fprintf(fp
, "0.0");
3650 if(*(cntl_chr
+ j
) == '\\') {
3651 switch(*(cntl_chr
+ j
+ 1)) {
3665 fprintf(fp
, "%c", *(cntl_chr
+ j
));
3669 fprintf(fp
, "%c", *(cntl_chr
+ j
));
3670 if(*(cntl_chr
+ j
) == '%') ++j
;
3680 VpFormatSt(char *psz
,S_INT fFmt
)
3690 for(i
= 0; i
< ie
; ++i
) {
3693 if(ISSPACE(ch
) || ch
=='-' || ch
=='+') continue;
3694 if(ch
== '.') { nf
= 0;continue;}
3695 if(ch
== 'E') break;
3698 memmove(psz
+ i
+ 1, psz
+ i
, ie
- i
+ 1);
3707 VpExponent10(Real
*a
)
3712 if(!VpHasVal(a
)) return 0;
3714 ex
=(a
->exponent
) * BASE_FIG
;
3716 while((a
->frac
[0] / n
) == 0) {
3724 VpSzMantissa(Real
*a
,char *psz
)
3730 sprintf(psz
,SZ_NaN
);
3734 sprintf(psz
,SZ_INF
);
3738 sprintf(psz
,SZ_NINF
);
3742 ZeroSup
= 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
3744 if(VpGetSign(a
) < 0) *psz
++ = '-';
3746 for(i
=0;i
< n
;++i
) {
3751 if((!ZeroSup
) || nn
) {
3752 sprintf(psz
, "%lu", nn
); /* The reading zero(s) */
3754 /* as 0.00xx will be ignored. */
3755 ZeroSup
= 0; /* Set to print succeeding zeros */
3762 while(psz
[-1]=='0') *(--psz
) = 0;
3764 if(VpIsPosZero(a
)) sprintf(psz
, "0");
3765 else sprintf(psz
, "-0");
3770 VpToSpecialString(Real
*a
,char *psz
,int fPlus
)
3771 /* fPlus =0:default, =1: set ' ' before digits , =2: set '+' before digits. */
3774 sprintf(psz
,SZ_NaN
);
3781 } else if(fPlus
==2) {
3784 sprintf(psz
,SZ_INF
);
3788 sprintf(psz
,SZ_NINF
);
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");
3803 VpToString(Real
*a
,char *psz
,int fFmt
,int fPlus
)
3804 /* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
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
++ = '+';
3822 for(i
=0;i
< n
;++i
) {
3827 if((!ZeroSup
) || nn
) {
3828 sprintf(psz
, "%lu", nn
); /* The reading zero(s) */
3830 /* as 0.00xx will be ignored. */
3831 ZeroSup
= 0; /* Set to print succeeding zeros */
3837 ex
=(a
->exponent
) * BASE_FIG
;
3839 while((a
->frac
[0] / n
) == 0) {
3843 while(psz
[-1]=='0') *(--psz
) = 0;
3844 sprintf(psz
, "E%ld", ex
);
3845 if(fFmt
) VpFormatSt(pszSav
, fFmt
);
3849 VpToFString(Real
*a
,char *psz
,int fFmt
,int fPlus
)
3850 /* fPlus =0:default,=1: set ' ' before digits ,set '+' before digits. */
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
++ = '+';
3866 *psz
++ = '0';*psz
++ = '.';
3868 for(i
=0;i
<BASE_FIG
;++i
) *psz
++ = '0';
3874 for(i
=0;i
< n
;++i
) {
3876 if(i
==0 && ex
>= 0) {
3877 sprintf(psz
, "%lu", a
->frac
[i
]);
3884 *psz
++ = (char)(nn
+ '0');
3889 if(ex
== 0) *psz
++ = '.';
3893 while(m
/=10) *psz
++ = '0';
3894 if(ex
== 0) *psz
++ = '.';
3897 while(psz
[-1]=='0') *(--psz
) = 0;
3898 if(psz
[-1]=='.') sprintf(psz
, "0");
3899 if(fFmt
) VpFormatSt(pszSav
, fFmt
);
3904 * a[] ... variable to be assigned the value.
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 '+/-'.
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
;
3920 /* get exponent part */
3926 memset(a
->frac
, 0, ma
* sizeof(U_LONG
));
3929 if(exp_chr
[0] == '-') {
3933 } else if(exp_chr
[0] == '+') {
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);
3947 /* get integer part */
3951 if(int_chr
[0] == '-') {
3955 } else if(int_chr
[0] == '+') {
3961 e
= signe
* e
; /* e: The value of exponent part. */
3962 e
= e
+ ni
; /* set actual exponent size. */
3964 if(e
> 0) signe
= 1;
3967 /* Adjust the exponent so that it is the multiple of BASE_FIG. */
3973 ef
= eb
/ ((S_INT
)BASE_FIG
);
3974 ef
= eb
- ef
* ((S_INT
)BASE_FIG
);
3976 ++j
; /* Means to add one more preceeding zero */
3981 eb
= e
/ ((S_INT
)BASE_FIG
);
3986 while((j
< (U_LONG
)BASE_FIG
) &&(i
< mi
)) {
3987 a
->frac
[ind_a
] = a
->frac
[ind_a
] * 10 + int_chr
[i
] - '0';
3993 if(ind_a
>= ma
) goto over_flow
;
3999 /* get fraction part */
4003 while((j
< (U_LONG
)BASE_FIG
) &&(i
< nf
)) {
4004 a
->frac
[ind_a
] = a
->frac
[ind_a
] * 10 + frac
[i
] - '0';
4010 if(ind_a
>= ma
) goto over_flow
;
4017 rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
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;
4025 a
->Prec
= ind_a
+ 1;
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
4048 VpVtoD(double *d
, S_LONG
*e
, Real
*m
)
4050 U_LONG ind_m
, mm
, fig
;
4055 *d
= VpGetDoubleNaN();
4060 if(VpIsPosZero(m
)) {
4066 if(VpIsNegZero(m
)) {
4067 *d
= VpGetDoubleNegZero();
4073 *d
= VpGetDoublePosInf();
4079 *d
= VpGetDoubleNegInf();
4085 fig
=(DBLE_FIG
+ BASE_FIG
- 1) / BASE_FIG
;
4087 mm
= Min(fig
,(m
->Prec
));
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
);
4100 VPrint(stdout
, " VpVtoD: m=%\n", m
);
4101 printf(" d=%e * 10 **%ld\n", *d
, *e
);
4102 printf(" DBLE_FIG = %ld\n", DBLE_FIG
);
4112 VpDtoV(Real
*m
, double d
)
4114 U_LONG i
, ind_m
, mm
;
4123 if(d
>0.0) VpSetPosInf(m
);
4124 else VpSetNegInf(m
);
4132 val
=(d
> 0.) ? d
:(-d
);
4136 val
/=(double)((S_INT
)BASE
);
4140 val2
= 1.0 /(double)((S_INT
)BASE
);
4142 val
*=(double)((S_INT
)BASE
);
4146 /* Now val = 0.xxxxx*BASE**ne */
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
);
4153 val
-=(double)((S_INT
)i
);
4156 if(ind_m
>= mm
) ind_m
= mm
- 1;
4158 VpSetSign(m
, (S_INT
)1);
4160 VpSetSign(m
,-(S_INT
)1);
4162 m
->Prec
= ind_m
+ 1;
4165 VpInternalRound(m
,0,(m
->Prec
>0)?m
->frac
[m
->Prec
-1]:0,
4166 (U_LONG
)(val
*((double)((S_INT
)BASE
))));
4171 printf("VpDtoV d=%30.30e\n", d
);
4172 VPrint(stdout
, " m=%\n", m
);
4183 VpItoV(Real
*m
, S_INT ival
)
4186 U_LONG val
, v1
, v2
, v
;
4198 val
=(U_LONG
)(-ival
);
4216 val
= val
- v2
* v1
;
4225 m
->Prec
= ind_m
- 1;
4233 printf(" VpItoV i=%d\n", ival
);
4234 VPrint(stdout
, " m=%\n", m
);
4242 * y = SQRT(x), y*y - x =>0
4245 VpSqrt(Real
*y
, Real
*x
)
4249 S_LONG y_prec
, f_prec
;
4256 /* Zero, NaN or Infinity ? */
4258 if(VpIsZero(x
)||VpGetSign(x
)>0) {
4263 return VpException(VP_EXCEPTION_OP
,"(VpSqrt) SQRT(NaN or negative value)",0);
4268 if(VpGetSign(x
) < 0) {
4270 return VpException(VP_EXCEPTION_OP
,"(VpSqrt) SQRT(negative value)",0);
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");
4286 y_prec
= (S_LONG
)y
->MaxPrec
;
4287 f_prec
= (S_LONG
)f
->MaxPrec
;
4290 if(prec
> 0) ++prec
;
4292 prec
= prec
- (S_LONG
)y
->MaxPrec
;
4293 VpVtoD(&val
, &e
, x
); /* val <- x */
4294 e
/= ((S_LONG
)BASE_FIG
);
4296 if(e
- n
* 2 != 0) {
4297 val
/=(double)((S_INT
)BASE
);
4300 VpDtoV(y
, sqrt(val
)); /* y <- sqrt(val) */
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
;
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
;
4322 printf("ERROR(VpSqrt): did not converge within %ld iterations.\n",
4326 y
->MaxPrec
= y_prec
;
4329 VpChangeSign(y
,(S_INT
)1);
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
);
4340 y
->MaxPrec
= y_prec
;
4350 * nf: digit position for operation.
4354 VpMidRound(Real
*y
, int f
, int nf
)
4356 * Round reletively from the decimal point.
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
;
4367 nf
+= y
->exponent
*((int)BASE_FIG
);
4370 /* rounding position too left(large). */
4371 if((f
!=VP_ROUND_CEIL
) && (f
!=VP_ROUND_FLOOR
)) {
4372 VpSetZero(y
,VpGetSign(y
)); /* truncate everything */
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
);
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);
4394 for(i
=ix
+1;i
<y
->Prec
;i
++) {
4395 if (y
->frac
[i
]%BASE
) {
4401 memset(y
->frac
+ix
+1, 0, (y
->Prec
- (ix
+1)) * sizeof(U_LONG
));
4403 case VP_ROUND_DOWN
: /* Truncate */
4405 case VP_ROUND_UP
: /* Roundup */
4408 case VP_ROUND_HALF_UP
: /* Round half up */
4411 case VP_ROUND_HALF_DOWN
: /* Round half down */
4414 case VP_ROUND_CEIL
: /* ceil */
4415 if(fracf
&& (VpGetSign(y
)>0)) ++div
;
4417 case VP_ROUND_FLOOR
: /* floor */
4418 if(fracf
&& (VpGetSign(y
)<0)) ++div
;
4420 case VP_ROUND_HALF_EVEN
: /* Banker's rounding */
4423 if((U_LONG
)i
==(BASE_FIG
-1)) {
4424 if(ix
&& (y
->frac
[ix
-1]%2)) ++div
;
4431 for(i
=0;i
<=n
;++i
) div
*= 10;
4437 S_INT s
= VpGetSign(y
);
4438 int e
= y
->exponent
;
4448 y
->exponent
+= exptoadd
/BASE_FIG
;
4449 exptoadd
%= BASE_FIG
;
4450 for(i
=0;i
<exptoadd
;i
++) {
4452 if (y
->frac
[0] >= BASE
) {
4462 VpLeftRound(Real
*y
, int f
, int nf
)
4464 * Round from the left hand side of the digits.
4468 if(!VpHasVal(y
)) return 0; /* Unable to round */
4470 nf
-= VpExponent(y
)*BASE_FIG
;
4471 while((v
/= 10) != 0) nf
--;
4473 return VpMidRound(y
,f
,nf
);
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
);
4485 VpLimitRound(Real
*c
,U_LONG ixDigit
)
4487 U_LONG ix
= VpGetPrecLimit();
4488 if(!VpNmlz(c
)) return -1;
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
);
4496 VpInternalRound(Real
*c
,int ixDigit
,U_LONG vPrev
,U_LONG v
)
4500 if(VpLimitRound(c
,ixDigit
)) return;
4504 switch(gfRoundMode
) {
4510 case VP_ROUND_HALF_UP
:
4513 case VP_ROUND_HALF_DOWN
:
4516 case VP_ROUND_CEIL
: /* ceil */
4517 if(v
&& (VpGetSign(c
)>0)) f
= 1;
4519 case VP_ROUND_FLOOR
: /* floor */
4520 if(v
&& (VpGetSign(c
)<0)) f
= 1;
4522 case VP_ROUND_HALF_EVEN
: /* Banker's rounding */
4524 else if(v
==5 && vPrev
%2) f
= 1;
4528 VpRdup(c
,ixDigit
); /* round up */
4534 * Rounds up m(plus one to final digit of m).
4537 VpRdup(Real
*m
,U_LONG ind_m
)
4541 if(!ind_m
) ind_m
= m
->Prec
;
4544 while(carry
> 0 && (ind_m
--)) {
4545 m
->frac
[ind_m
] += carry
;
4546 if(m
->frac
[ind_m
] >= BASE
) m
->frac
[ind_m
] -= BASE
;
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;
4562 VpFrac(Real
*y
, Real
*x
)
4564 U_LONG my
, ind_y
, ind_x
;
4571 if(x
->exponent
> 0 && (U_LONG
)x
->exponent
>= x
->Prec
) {
4572 VpSetZero(y
,VpGetSign(x
));
4574 } else if(x
->exponent
<= 0) {
4579 y
->Prec
= x
->Prec
-(U_LONG
) x
->exponent
;
4580 y
->Prec
= Min(y
->Prec
, y
->MaxPrec
);
4582 VpSetSign(y
,VpGetSign(x
));
4585 ind_x
= x
->exponent
;
4587 y
->frac
[ind_y
] = x
->frac
[ind_x
];
4596 VPrint(stdout
, "VpFrac y=%\n", y
);
4597 VPrint(stdout
, " x=%\n", x
);
4607 VpPower(Real
*y
, Real
*x
, S_INT n
)
4619 sign
= VpGetSign(x
);
4622 if(sign
<0) sign
= (n
%2)?(-1):(1);
4625 if(sign
<0) sign
= (n
%2)?(-1):(1);
4631 VpSetNaN(y
); /* Not sure !!! */
4635 if((x
->exponent
== 1) &&(x
->Prec
== 1) &&(x
->frac
[0] == 1)) {
4638 if(VpGetSign(x
) > 0) goto Exit
;
4639 if((n
% 2) == 0) goto Exit
;
4640 VpSetSign(y
,-(S_INT
)1);
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 */
4666 if(s
>(U_LONG
) n
) goto out_loop1
;
4676 VpDivd(w1
, w2
, VpConstOne
, y
);
4683 VPrint(stdout
, "VpPower y=%\n", y
);
4684 VPrint(stdout
, "VpPower x=%\n", x
);
4685 printf(" n=%d\n", n
);
4695 VpVarCheck(Real
* v
)
4697 * Checks the validity of the Real variable v.
4699 * v ... Real *, variable to be checked.
4707 if(v
->MaxPrec
<= 0) {
4708 printf("ERROR(VpVarCheck): Illegal Max. Precision(=%lu)\n",
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
);
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
);