Ruby: ext/bigdecimal/bigdecimal.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

bigdecimal.c
Go to the documentation of this file.
1/*
2 *
3 * Ruby BigDecimal(Variable decimal precision) extension library.
4 *
5 * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
6 *
7 */
8
9/* #define BIGDECIMAL_DEBUG 1 */
10#ifdef BIGDECIMAL_DEBUG
11# define BIGDECIMAL_ENABLE_VPRINT 1
12#endif
13#include "bigdecimal.h"
14#include "ruby/util.h"
15
16#ifndef BIGDECIMAL_DEBUG
17# undef NDEBUG
18# define NDEBUG
19#endif
20#include <assert.h>
21
22#include <ctype.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <errno.h>
27#include <math.h>
28
29#ifdef HAVE_IEEEFP_H
30#include <ieeefp.h>
31#endif
32
33/* #define ENABLE_NUMERIC_STRING */
34
35#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
36 (a) == 0 ? 0 : \
37 (a) == -1 ? (b) < -(max) : \
38 (a) > 0 ? \
39 ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
40 ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
41#define SIGNED_VALUE_MAX INTPTR_MAX
42#define SIGNED_VALUE_MIN INTPTR_MIN
43#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
44
45 VALUE rb_cBigDecimal;
46 VALUE rb_mBigMath;
47
48static ID id_BigDecimal_exception_mode;
49static ID id_BigDecimal_rounding_mode;
50static ID id_BigDecimal_precision_limit;
51
52static ID id_up;
53static ID id_down;
54static ID id_truncate;
55static ID id_half_up;
56static ID id_default;
57static ID id_half_down;
58static ID id_half_even;
59static ID id_banker;
60static ID id_ceiling;
61static ID id_ceil;
62static ID id_floor;
63static ID id_to_r;
64static ID id_eq;
65static ID id_half;
66
67/* MACRO's to guard objects from GC by keeping them in stack */
68#define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
69#define PUSH(x) (vStack[iStack++] = (VALUE)(x))
70#define SAVE(p) PUSH((p)->obj)
71#define GUARD_OBJ(p,y) ((p)=(y), SAVE(p))
72
73#define BASE_FIG RMPD_COMPONENT_FIGURES
74#define BASE RMPD_BASE
75
76#define HALF_BASE (BASE/2)
77#define BASE1 (BASE/10)
78
79#ifndef DBLE_FIG
80#define DBLE_FIG rmpd_double_figures() /* figure of double */
81#endif
82
83#ifndef RRATIONAL_ZERO_P
84# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
85 FIX2LONG(rb_rational_num(x)) == 0)
86#endif
87
88#ifndef RRATIONAL_NEGATIVE_P
89# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
90#endif
91
92#ifndef DECIMAL_SIZE_OF_BITS
93#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
94/* an approximation of ceil(n * log10(2)), upto 65536 at least */
95#endif
96
97#ifdef PRIsVALUE
98# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
99# define RB_OBJ_STRING(obj) (obj)
100#else
101# define PRIsVALUE "s"
102# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
103# define RB_OBJ_STRING(obj) StringValueCStr(obj)
104#endif
105
106#ifndef HAVE_RB_RATIONAL_NUM
107static inline VALUE
108rb_rational_num(VALUE rat)
109{
110#ifdef HAVE_TYPE_STRUCT_RRATIONAL
111 return RRATIONAL(rat)->num;
112#else
113 return rb_funcall(rat, rb_intern("numerator"), 0);
114#endif
115}
116#endif
117
118#ifndef HAVE_RB_RATIONAL_DEN
119static inline VALUE
120rb_rational_den(VALUE rat)
121{
122#ifdef HAVE_TYPE_STRUCT_RRATIONAL
123 return RRATIONAL(rat)->den;
124#else
125 return rb_funcall(rat, rb_intern("denominator"), 0);
126#endif
127}
128#endif
129
130#ifndef HAVE_RB_COMPLEX_REAL
131static inline VALUE
132 rb_complex_real(VALUE cmp)
133{
134#ifdef HAVE_TYPE_STRUCT_RCOMPLEX
135 return RCOMPLEX(cmp)->real;
136#else
137 return rb_funcall(cmp, rb_intern("real"), 0);
138#endif
139}
140#endif
141
142#ifndef HAVE_RB_COMPLEX_IMAG
143static inline VALUE
144 rb_complex_imag(VALUE cmp)
145{
146#ifdef HAVE_TYPE_STRUCT_RCOMPLEX
147 return RCOMPLEX(cmp)->imag;
148#else
149 return rb_funcall(cmp, rb_intern("imag"), 0);
150#endif
151}
152#endif
153
154#define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0)
155#define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0)
156
157/*
158 * ================== Ruby Interface part ==========================
159 */
160#define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
161
162/*
163 * VP routines used in BigDecimal part
164 */
165static unsigned short VpGetException(void);
166static void VpSetException(unsigned short f);
167static void VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v);
168static int VpLimitRound(Real *c, size_t ixDigit);
169static Real *VpCopy(Real *pv, Real const* const x);
170
171#ifdef BIGDECIMAL_ENABLE_VPRINT
172static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
173#endif
174
175/*
176 * **** BigDecimal part ****
177 */
178
179static void
180BigDecimal_delete(void *pv)
181{
182 VpFree(pv);
183}
184
185static size_t
186BigDecimal_memsize(const void *ptr)
187{
188 const Real *pv = ptr;
189 return (sizeof(*pv) + pv->MaxPrec * sizeof(BDIGIT));
190}
191
192#ifndef HAVE_RB_EXT_RACTOR_SAFE
193# undef RUBY_TYPED_FROZEN_SHAREABLE
194# define RUBY_TYPED_FROZEN_SHAREABLE 0
195#endif
196
197static const rb_data_type_t BigDecimal_data_type = {
198 "BigDecimal",
199 { 0, BigDecimal_delete, BigDecimal_memsize, },
200#ifdef RUBY_TYPED_FREE_IMMEDIATELY
201 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
202#endif
203};
204
205static inline int
206is_kind_of_BigDecimal(VALUE const v)
207{
208 return rb_typeddata_is_kind_of(v, &BigDecimal_data_type);
209}
210
211static VALUE
212ToValue(Real *p)
213{
214 if (VpIsNaN(p)) {
215 VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'(Not a Number)", 0);
216 }
217 else if (VpIsPosInf(p)) {
218 VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 0);
219 }
220 else if (VpIsNegInf(p)) {
221 VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 0);
222 }
223 return p->obj;
224}
225
226 NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
227
228static void
229cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
230{
231 VALUE str;
232
233 if (rb_special_const_p(v)) {
234 str = rb_inspect(v);
235 }
236 else {
237 str = rb_class_name(rb_obj_class(v));
238 }
239
240 str = rb_str_cat2(rb_str_dup(str), " can't be coerced into BigDecimal");
241 rb_exc_raise(rb_exc_new3(exc_class, str));
242}
243
244static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
245
246static Real*
247GetVpValueWithPrec(VALUE v, long prec, int must)
248{
249 ENTER(1);
250 Real *pv;
251 VALUE num, bg;
252 char szD[128];
253 VALUE orig = Qundef;
254 double d;
255
256again:
257 switch(TYPE(v)) {
258 case T_FLOAT:
259 if (prec < 0) goto unable_to_coerce_without_prec;
260 if (prec > (long)DBLE_FIG) goto SomeOneMayDoIt;
261 d = RFLOAT_VALUE(v);
262 if (!isfinite(d)) {
263 pv = VpCreateRbObject(1, NULL);
264 VpDtoV(pv, d);
265 return pv;
266 }
267 if (d != 0.0) {
268 v = rb_funcall(v, id_to_r, 0);
269 goto again;
270 }
271 if (1/d < 0.0) {
272 return VpCreateRbObject(prec, "-0");
273 }
274 return VpCreateRbObject(prec, "0");
275
276 case T_RATIONAL:
277 if (prec < 0) goto unable_to_coerce_without_prec;
278
279 if (orig == Qundef ? (orig = v, 1) : orig != v) {
280 num = rb_rational_num(v);
281 pv = GetVpValueWithPrec(num, -1, must);
282 if (pv == NULL) goto SomeOneMayDoIt;
283
284 v = BigDecimal_div2(ToValue(pv), rb_rational_den(v), LONG2NUM(prec));
285 goto again;
286 }
287
288 v = orig;
289 goto SomeOneMayDoIt;
290
291 case T_DATA:
292 if (is_kind_of_BigDecimal(v)) {
293 pv = DATA_PTR(v);
294 return pv;
295 }
296 else {
297 goto SomeOneMayDoIt;
298 }
299 break;
300
301 case T_FIXNUM:
302 sprintf(szD, "%ld", FIX2LONG(v));
303 return VpCreateRbObject(VpBaseFig() * 2 + 1, szD);
304
305#ifdef ENABLE_NUMERIC_STRING
306 case T_STRING:
307 StringValueCStr(v);
308 return VpCreateRbObject(RSTRING_LEN(v) + VpBaseFig() + 1,
309 RSTRING_PTR(v));
310#endif /* ENABLE_NUMERIC_STRING */
311
312 case T_BIGNUM:
313 bg = rb_big2str(v, 10);
314 PUSH(bg);
315 return VpCreateRbObject(strlen(RSTRING_PTR(bg)) + VpBaseFig() + 1,
316 RSTRING_PTR(bg));
317 default:
318 goto SomeOneMayDoIt;
319 }
320
321SomeOneMayDoIt:
322 if (must) {
323 cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
324 }
325 return NULL; /* NULL means to coerce */
326
327unable_to_coerce_without_prec:
328 if (must) {
329 rb_raise(rb_eArgError,
330 "%"PRIsVALUE" can't be coerced into BigDecimal without a precision",
331 RB_OBJ_CLASSNAME(v));
332 }
333 return NULL;
334}
335
336static Real*
337GetVpValue(VALUE v, int must)
338{
339 return GetVpValueWithPrec(v, -1, must);
340}
341
342/* call-seq:
343 * BigDecimal.double_fig
344 *
345 * The BigDecimal.double_fig class method returns the number of digits a
346 * Float number is allowed to have. The result depends upon the CPU and OS
347 * in use.
348 */
349static VALUE
350BigDecimal_double_fig(VALUE self)
351{
352 return INT2FIX(VpDblFig());
353}
354
355/* call-seq:
356 * big_decimal.precs -> array
357 *
358 * Returns an Array of two Integer values that represent platform-dependent
359 * internal storage properties.
360 *
361 * This method is deprecated and will be removed in the future.
362 * Instead, use BigDecimal#n_significant_digits for obtaining the number of
363 * significant digits in scientific notation, and BigDecimal#precision for
364 * obtaining the number of digits in decimal notation.
365 *
366 * BigDecimal('5').precs #=> [9, 18]
367 */
368
369static VALUE
370BigDecimal_prec(VALUE self)
371{
372 ENTER(1);
373 Real *p;
374 VALUE obj;
375
376 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
377 "BigDecimal#precs is deprecated and will be removed in the future; "
378 "use BigDecimal#precision instead.");
379
380 GUARD_OBJ(p, GetVpValue(self, 1));
381 obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
382 SIZET2NUM(p->MaxPrec*VpBaseFig()));
383 return obj;
384}
385
386/*
387 * call-seq:
388 * big_decimal.precision -> intreger
389 *
390 * Returns the number of decimal digits in this number.
391 *
392 * Example:
393 *
394 * BigDecimal("0").precision # => 0
395 * BigDecimal("1").precision # => 1
396 * BigDecimal("-1e20").precision # => 21
397 * BigDecimal("1e-20").precision # => 20
398 * BigDecimal("Infinity").precision # => 0
399 * BigDecimal("-Infinity").precision # => 0
400 * BigDecimal("NaN").precision # => 0
401 */
402static VALUE
403BigDecimal_precision(VALUE self)
404{
405 ENTER(1);
406
407 Real *p;
408 GUARD_OBJ(p, GetVpValue(self, 1));
409
410 /*
411 * The most significant digit is frac[0], and the least significant digit is frac[Prec-1].
412 * When the exponent is zero, the decimal point is located just before frac[0].
413 * When the exponent is negative, the decimal point moves to leftward.
414 * Conversely, when the exponent is positive, the decimal point moves to rightward.
415 *
416 * | frac[0] frac[1] frac[2] . frac[3] frac[4] ... frac[Prec-1]
417 * |------------------------> exponent == 3
418 */
419
420 ssize_t ex = p->exponent;
421 ssize_t precision = 0;
422 if (ex < 0) {
423 precision = (-ex + 1) * BASE_FIG; /* 1 is for p->frac[0] */
424 ex = 0;
425 }
426 else if (p->Prec > 0) {
427 BDIGIT x = p->frac[0];
428 for (precision = 0; x > 0; x /= 10) {
429 ++precision;
430 }
431 }
432
433 if (ex > (ssize_t)p->Prec) {
434 precision += (ex - 1) * BASE_FIG;
435 }
436 else if (p->Prec > 0) {
437 ssize_t n = (ssize_t)p->Prec - 1;
438 while (n > 0 && p->frac[n] == 0) --n;
439
440 precision += n * BASE_FIG;
441
442 if (ex < (ssize_t)p->Prec) {
443 BDIGIT x = p->frac[n];
444 for (; x > 0 && x % 10 == 0; x /= 10) {
445 --precision;
446 }
447 }
448 }
449
450 return SSIZET2NUM(precision);
451}
452
453static VALUE
454BigDecimal_n_significant_digits(VALUE self)
455{
456 ENTER(1);
457
458 Real *p;
459 GUARD_OBJ(p, GetVpValue(self, 1));
460
461 ssize_t n = p->Prec;
462 while (n > 0 && p->frac[n-1] == 0) --n;
463 if (n <= 0) {
464 return INT2FIX(0);
465 }
466
467 int nlz, ntz;
468
469 BDIGIT x = p->frac[0];
470 for (nlz = BASE_FIG; x > 0; x /= 10) --nlz;
471
472 x = p->frac[n-1];
473 for (ntz = 0; x > 0 && x % 10 == 0; x /= 10) ++ntz;
474
475 ssize_t n_digits = BASE_FIG * n - nlz - ntz;
476 return SSIZET2NUM(n_digits);
477}
478
479/*
480 * call-seq: hash
481 *
482 * Creates a hash for this BigDecimal.
483 *
484 * Two BigDecimals with equal sign,
485 * fractional part and exponent have the same hash.
486 */
487static VALUE
488BigDecimal_hash(VALUE self)
489{
490 ENTER(1);
491 Real *p;
492 st_index_t hash;
493
494 GUARD_OBJ(p, GetVpValue(self, 1));
495 hash = (st_index_t)p->sign;
496 /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
497 if(hash == 2 || hash == (st_index_t)-2) {
498 hash ^= rb_memhash(p->frac, sizeof(BDIGIT)*p->Prec);
499 hash += p->exponent;
500 }
501 return ST2FIX(hash);
502}
503
504/*
505 * call-seq: _dump
506 *
507 * Method used to provide marshalling support.
508 *
509 * inf = BigDecimal('Infinity')
510 * #=> Infinity
511 * BigDecimal._load(inf._dump)
512 * #=> Infinity
513 *
514 * See the Marshal module.
515 */
516static VALUE
517BigDecimal_dump(int argc, VALUE *argv, VALUE self)
518{
519 ENTER(5);
520 Real *vp;
521 char *psz;
522 VALUE dummy;
523 volatile VALUE dump;
524
525 rb_scan_args(argc, argv, "01", &dummy);
526 GUARD_OBJ(vp,GetVpValue(self, 1));
527 dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
528 psz = RSTRING_PTR(dump);
529 sprintf(psz, "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
530 VpToString(vp, psz+strlen(psz), 0, 0);
531 rb_str_resize(dump, strlen(psz));
532 return dump;
533}
534
535/*
536 * Internal method used to provide marshalling support. See the Marshal module.
537 */
538static VALUE
539BigDecimal_load(VALUE self, VALUE str)
540{
541 ENTER(2);
542 Real *pv;
543 unsigned char *pch;
544 unsigned char ch;
545 unsigned long m=0;
546
547 pch = (unsigned char *)StringValueCStr(str);
548 /* First get max prec */
549 while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
550 if(!ISDIGIT(ch)) {
551 rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
552 }
553 m = m*10 + (unsigned long)(ch-'0');
554 }
555 if (m > VpBaseFig()) m -= VpBaseFig();
556 GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self));
557 m /= VpBaseFig();
558 if (m && pv->MaxPrec > m) {
559 pv->MaxPrec = m+1;
560 }
561 return ToValue(pv);
562}
563
564static unsigned short
565check_rounding_mode_option(VALUE const opts)
566{
567 VALUE mode;
568 char const *s;
569 long l;
570
571 assert(RB_TYPE_P(opts, T_HASH));
572
573 if (NIL_P(opts))
574 goto noopt;
575
576 mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef);
577 if (mode == Qundef || NIL_P(mode))
578 goto noopt;
579
580 if (SYMBOL_P(mode))
581 mode = rb_sym2str(mode);
582 else if (!RB_TYPE_P(mode, T_STRING)) {
583 VALUE str_mode = rb_check_string_type(mode);
584 if (NIL_P(str_mode)) goto invalid;
585 mode = str_mode;
586 }
587 s = RSTRING_PTR(mode);
588 l = RSTRING_LEN(mode);
589 switch (l) {
590 case 2:
591 if (strncasecmp(s, "up", 2) == 0)
592 return VP_ROUND_HALF_UP;
593 break;
594 case 4:
595 if (strncasecmp(s, "even", 4) == 0)
596 return VP_ROUND_HALF_EVEN;
597 else if (strncasecmp(s, "down", 4) == 0)
598 return VP_ROUND_HALF_DOWN;
599 break;
600 default:
601 break;
602 }
603 invalid:
604 if (NIL_P(mode))
605 rb_raise(rb_eArgError, "invalid rounding mode: nil");
606 else
607 rb_raise(rb_eArgError, "invalid rounding mode: %"PRIsVALUE, mode);
608
609 noopt:
610 return VpGetRoundMode();
611}
612
613static unsigned short
614check_rounding_mode(VALUE const v)
615{
616 unsigned short sw;
617 ID id;
618 switch (TYPE(v)) {
619 case T_SYMBOL:
620 id = SYM2ID(v);
621 if (id == id_up)
622 return VP_ROUND_UP;
623 if (id == id_down || id == id_truncate)
624 return VP_ROUND_DOWN;
625 if (id == id_half_up || id == id_default)
626 return VP_ROUND_HALF_UP;
627 if (id == id_half_down)
628 return VP_ROUND_HALF_DOWN;
629 if (id == id_half_even || id == id_banker)
630 return VP_ROUND_HALF_EVEN;
631 if (id == id_ceiling || id == id_ceil)
632 return VP_ROUND_CEIL;
633 if (id == id_floor)
634 return VP_ROUND_FLOOR;
635 rb_raise(rb_eArgError, "invalid rounding mode");
636
637 default:
638 break;
639 }
640
641 sw = NUM2USHORT(v);
642 if (!VpIsRoundMode(sw)) {
643 rb_raise(rb_eArgError, "invalid rounding mode");
644 }
645 return sw;
646}
647
648/* call-seq:
649 * BigDecimal.mode(mode, value)
650 *
651 * Controls handling of arithmetic exceptions and rounding. If no value
652 * is supplied, the current value is returned.
653 *
654 * Six values of the mode parameter control the handling of arithmetic
655 * exceptions:
656 *
657 * BigDecimal::EXCEPTION_NaN
658 * BigDecimal::EXCEPTION_INFINITY
659 * BigDecimal::EXCEPTION_UNDERFLOW
660 * BigDecimal::EXCEPTION_OVERFLOW
661 * BigDecimal::EXCEPTION_ZERODIVIDE
662 * BigDecimal::EXCEPTION_ALL
663 *
664 * For each mode parameter above, if the value set is false, computation
665 * continues after an arithmetic exception of the appropriate type.
666 * When computation continues, results are as follows:
667 *
668 * EXCEPTION_NaN:: NaN
669 * EXCEPTION_INFINITY:: +Infinity or -Infinity
670 * EXCEPTION_UNDERFLOW:: 0
671 * EXCEPTION_OVERFLOW:: +Infinity or -Infinity
672 * EXCEPTION_ZERODIVIDE:: +Infinity or -Infinity
673 *
674 * One value of the mode parameter controls the rounding of numeric values:
675 * BigDecimal::ROUND_MODE. The values it can take are:
676 *
677 * ROUND_UP, :up:: round away from zero
678 * ROUND_DOWN, :down, :truncate:: round towards zero (truncate)
679 * ROUND_HALF_UP, :half_up, :default:: round towards the nearest neighbor, unless both neighbors are equidistant, in which case round away from zero. (default)
680 * ROUND_HALF_DOWN, :half_down:: round towards the nearest neighbor, unless both neighbors are equidistant, in which case round towards zero.
681 * ROUND_HALF_EVEN, :half_even, :banker:: round towards the nearest neighbor, unless both neighbors are equidistant, in which case round towards the even neighbor (Banker's rounding)
682 * ROUND_CEILING, :ceiling, :ceil:: round towards positive infinity (ceil)
683 * ROUND_FLOOR, :floor:: round towards negative infinity (floor)
684 *
685 */
686static VALUE
687BigDecimal_mode(int argc, VALUE *argv, VALUE self)
688{
689 VALUE which;
690 VALUE val;
691 unsigned long f,fo;
692
693 rb_scan_args(argc, argv, "11", &which, &val);
694 f = (unsigned long)NUM2INT(which);
695
696 if (f & VP_EXCEPTION_ALL) {
697 /* Exception mode setting */
698 fo = VpGetException();
699 if (val == Qnil) return INT2FIX(fo);
700 if (val != Qfalse && val!=Qtrue) {
701 rb_raise(rb_eArgError, "second argument must be true or false");
702 return Qnil; /* Not reached */
703 }
704 if (f & VP_EXCEPTION_INFINITY) {
705 VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) :
706 (fo & (~VP_EXCEPTION_INFINITY))));
707 }
708 fo = VpGetException();
709 if (f & VP_EXCEPTION_NaN) {
710 VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) :
711 (fo & (~VP_EXCEPTION_NaN))));
712 }
713 fo = VpGetException();
714 if (f & VP_EXCEPTION_UNDERFLOW) {
715 VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) :
716 (fo & (~VP_EXCEPTION_UNDERFLOW))));
717 }
718 fo = VpGetException();
719 if(f & VP_EXCEPTION_ZERODIVIDE) {
720 VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) :
721 (fo & (~VP_EXCEPTION_ZERODIVIDE))));
722 }
723 fo = VpGetException();
724 return INT2FIX(fo);
725 }
726 if (VP_ROUND_MODE == f) {
727 /* Rounding mode setting */
728 unsigned short sw;
729 fo = VpGetRoundMode();
730 if (NIL_P(val)) return INT2FIX(fo);
731 sw = check_rounding_mode(val);
732 fo = VpSetRoundMode(sw);
733 return INT2FIX(fo);
734 }
735 rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid");
736 return Qnil;
737}
738
739static size_t
740GetAddSubPrec(Real *a, Real *b)
741{
742 size_t mxs;
743 size_t mx = a->Prec;
744 SIGNED_VALUE d;
745
746 if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
747 if (mx < b->Prec) mx = b->Prec;
748 if (a->exponent != b->exponent) {
749 mxs = mx;
750 d = a->exponent - b->exponent;
751 if (d < 0) d = -d;
752 mx = mx + (size_t)d;
753 if (mx < mxs) {
754 return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
755 }
756 }
757 return mx;
758}
759
760static SIGNED_VALUE
761GetPrecisionInt(VALUE v)
762{
763 SIGNED_VALUE n;
764 n = NUM2INT(v);
765 if (n < 0) {
766 rb_raise(rb_eArgError, "negative precision");
767 }
768 return n;
769}
770
771 VP_EXPORT Real *
772VpNewRbClass(size_t mx, const char *str, VALUE klass)
773{
774 VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
775 Real *pv = VpAlloc(mx, str, 1, 1);
776 RTYPEDDATA_DATA(obj) = pv;
777 pv->obj = obj;
778 RB_OBJ_FREEZE(obj);
779 return pv;
780}
781
782 VP_EXPORT Real *
783VpCreateRbObject(size_t mx, const char *str)
784{
785 return VpNewRbClass(mx, str, rb_cBigDecimal);
786}
787
788#define VpAllocReal(prec) (Real *)VpMemAlloc(offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
789#define VpReallocReal(ptr, prec) (Real *)VpMemRealloc((ptr), offsetof(Real, frac) + (prec) * sizeof(BDIGIT))
790
791static Real *
792VpCopy(Real *pv, Real const* const x)
793{
794 assert(x != NULL);
795
796 pv = VpReallocReal(pv, x->MaxPrec);
797 pv->MaxPrec = x->MaxPrec;
798 pv->Prec = x->Prec;
799 pv->exponent = x->exponent;
800 pv->sign = x->sign;
801 pv->flag = x->flag;
802 MEMCPY(pv->frac, x->frac, BDIGIT, pv->MaxPrec);
803
804 return pv;
805}
806
807/* Returns True if the value is Not a Number. */
808static VALUE
809BigDecimal_IsNaN(VALUE self)
810{
811 Real *p = GetVpValue(self, 1);
812 if (VpIsNaN(p)) return Qtrue;
813 return Qfalse;
814}
815
816/* Returns nil, -1, or +1 depending on whether the value is finite,
817 * -Infinity, or +Infinity.
818 */
819static VALUE
820BigDecimal_IsInfinite(VALUE self)
821{
822 Real *p = GetVpValue(self, 1);
823 if (VpIsPosInf(p)) return INT2FIX(1);
824 if (VpIsNegInf(p)) return INT2FIX(-1);
825 return Qnil;
826}
827
828/* Returns True if the value is finite (not NaN or infinite). */
829static VALUE
830BigDecimal_IsFinite(VALUE self)
831{
832 Real *p = GetVpValue(self, 1);
833 if (VpIsNaN(p)) return Qfalse;
834 if (VpIsInf(p)) return Qfalse;
835 return Qtrue;
836}
837
838static void
839BigDecimal_check_num(Real *p)
840{
841 if (VpIsNaN(p)) {
842 VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'(Not a Number)", 1);
843 }
844 else if (VpIsPosInf(p)) {
845 VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 1);
846 }
847 else if (VpIsNegInf(p)) {
848 VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 1);
849 }
850}
851
852static VALUE BigDecimal_split(VALUE self);
853
854/* Returns the value as an Integer.
855 *
856 * If the BigDecimal is infinity or NaN, raises FloatDomainError.
857 */
858static VALUE
859BigDecimal_to_i(VALUE self)
860{
861 ENTER(5);
862 ssize_t e, nf;
863 Real *p;
864
865 GUARD_OBJ(p, GetVpValue(self, 1));
866 BigDecimal_check_num(p);
867
868 e = VpExponent10(p);
869 if (e <= 0) return INT2FIX(0);
870 nf = VpBaseFig();
871 if (e <= nf) {
872 return LONG2NUM((long)(VpGetSign(p) * (BDIGIT_DBL_SIGNED)p->frac[0]));
873 }
874 else {
875 VALUE a = BigDecimal_split(self);
876 VALUE digits = RARRAY_AREF(a, 1);
877 VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
878 VALUE ret;
879 ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
880
881 if (BIGDECIMAL_NEGATIVE_P(p)) {
882 numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
883 }
884 if (dpower < 0) {
885 ret = rb_funcall(numerator, rb_intern("div"), 1,
886 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
887 INT2FIX(-dpower)));
888 }
889 else {
890 ret = rb_funcall(numerator, '*', 1,
891 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
892 INT2FIX(dpower)));
893 }
894 if (RB_TYPE_P(ret, T_FLOAT)) {
895 rb_raise(rb_eFloatDomainError, "Infinity");
896 }
897 return ret;
898 }
899}
900
901/* Returns a new Float object having approximately the same value as the
902 * BigDecimal number. Normal accuracy limits and built-in errors of binary
903 * Float arithmetic apply.
904 */
905static VALUE
906BigDecimal_to_f(VALUE self)
907{
908 ENTER(1);
909 Real *p;
910 double d;
911 SIGNED_VALUE e;
912 char *buf;
913 volatile VALUE str;
914
915 GUARD_OBJ(p, GetVpValue(self, 1));
916 if (VpVtoD(&d, &e, p) != 1)
917 return rb_float_new(d);
918 if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
919 goto overflow;
920 if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
921 goto underflow;
922
923 str = rb_str_new(0, VpNumOfChars(p, "E"));
924 buf = RSTRING_PTR(str);
925 VpToString(p, buf, 0, 0);
926 errno = 0;
927 d = strtod(buf, 0);
928 if (errno == ERANGE) {
929 if (d == 0.0) goto underflow;
930 if (fabs(d) >= HUGE_VAL) goto overflow;
931 }
932 return rb_float_new(d);
933
934overflow:
935 VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
936 if (BIGDECIMAL_NEGATIVE_P(p))
937 return rb_float_new(VpGetDoubleNegInf());
938 else
939 return rb_float_new(VpGetDoublePosInf());
940
941underflow:
942 VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
943 if (BIGDECIMAL_NEGATIVE_P(p))
944 return rb_float_new(-0.0);
945 else
946 return rb_float_new(0.0);
947}
948
949
950/* Converts a BigDecimal to a Rational.
951 */
952static VALUE
953BigDecimal_to_r(VALUE self)
954{
955 Real *p;
956 ssize_t sign, power, denomi_power;
957 VALUE a, digits, numerator;
958
959 p = GetVpValue(self, 1);
960 BigDecimal_check_num(p);
961
962 sign = VpGetSign(p);
963 power = VpExponent10(p);
964 a = BigDecimal_split(self);
965 digits = RARRAY_AREF(a, 1);
966 denomi_power = power - RSTRING_LEN(digits);
967 numerator = rb_funcall(digits, rb_intern("to_i"), 0);
968
969 if (sign < 0) {
970 numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
971 }
972 if (denomi_power < 0) {
973 return rb_Rational(numerator,
974 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
975 INT2FIX(-denomi_power)));
976 }
977 else {
978 return rb_Rational1(rb_funcall(numerator, '*', 1,
979 rb_funcall(INT2FIX(10), rb_intern("**"), 1,
980 INT2FIX(denomi_power))));
981 }
982}
983
984/* The coerce method provides support for Ruby type coercion. It is not
985 * enabled by default.
986 *
987 * This means that binary operations like + * / or - can often be performed
988 * on a BigDecimal and an object of another type, if the other object can
989 * be coerced into a BigDecimal value.
990 *
991 * e.g.
992 * a = BigDecimal("1.0")
993 * b = a / 2.0 #=> 0.5
994 *
995 * Note that coercing a String to a BigDecimal is not supported by default;
996 * it requires a special compile-time option when building Ruby.
997 */
998static VALUE
999BigDecimal_coerce(VALUE self, VALUE other)
1000{
1001 ENTER(2);
1002 VALUE obj;
1003 Real *b;
1004
1005 if (RB_TYPE_P(other, T_FLOAT)) {
1006 GUARD_OBJ(b, GetVpValueWithPrec(other, DBLE_FIG, 1));
1007 obj = rb_assoc_new(ToValue(b), self);
1008 }
1009 else {
1010 if (RB_TYPE_P(other, T_RATIONAL)) {
1011 Real* pv = DATA_PTR(self);
1012 GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
1013 }
1014 else {
1015 GUARD_OBJ(b, GetVpValue(other, 1));
1016 }
1017 obj = rb_assoc_new(b->obj, self);
1018 }
1019
1020 return obj;
1021}
1022
1023/*
1024 * call-seq:
1025 * +big_decimal -> big_decimal
1026 *
1027 * Return self.
1028 *
1029 * +BigDecimal('5') #=> 0.5e1
1030 */
1031
1032static VALUE
1033BigDecimal_uplus(VALUE self)
1034{
1035 return self;
1036}
1037
1038 /*
1039 * Document-method: BigDecimal#add
1040 * Document-method: BigDecimal#+
1041 *
1042 * call-seq:
1043 * add(value, digits)
1044 *
1045 * Add the specified value.
1046 *
1047 * e.g.
1048 * c = a.add(b,n)
1049 * c = a + b
1050 *
1051 * digits:: If specified and less than the number of significant digits of the
1052 * result, the result is rounded to that number of digits, according
1053 * to BigDecimal.mode.
1054 */
1055static VALUE
1056BigDecimal_add(VALUE self, VALUE r)
1057{
1058 ENTER(5);
1059 Real *c, *a, *b;
1060 size_t mx;
1061
1062 GUARD_OBJ(a, GetVpValue(self, 1));
1063 if (RB_TYPE_P(r, T_FLOAT)) {
1064 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1065 }
1066 else if (RB_TYPE_P(r, T_RATIONAL)) {
1067 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1068 }
1069 else {
1070 b = GetVpValue(r, 0);
1071 }
1072
1073 if (!b) return DoSomeOne(self,r,'+');
1074 SAVE(b);
1075
1076 if (VpIsNaN(b)) return b->obj;
1077 if (VpIsNaN(a)) return a->obj;
1078
1079 mx = GetAddSubPrec(a, b);
1080 if (mx == (size_t)-1L) {
1081 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
1082 VpAddSub(c, a, b, 1);
1083 }
1084 else {
1085 GUARD_OBJ(c, VpCreateRbObject(mx * (VpBaseFig() + 1), "0"));
1086 if(!mx) {
1087 VpSetInf(c, VpGetSign(a));
1088 }
1089 else {
1090 VpAddSub(c, a, b, 1);
1091 }
1092 }
1093 return ToValue(c);
1094}
1095
1096 /* call-seq:
1097 * a - b -> bigdecimal
1098 *
1099 * Subtract the specified value.
1100 *
1101 * e.g.
1102 * c = a - b
1103 *
1104 * The precision of the result value depends on the type of +b+.
1105 *
1106 * If +b+ is a Float, the precision of the result is Float::DIG+1.
1107 *
1108 * If +b+ is a BigDecimal, the precision of the result is +b+'s precision of
1109 * internal representation from platform. So, it's return value is platform
1110 * dependent.
1111 *
1112 */
1113static VALUE
1114BigDecimal_sub(VALUE self, VALUE r)
1115{
1116 ENTER(5);
1117 Real *c, *a, *b;
1118 size_t mx;
1119
1120 GUARD_OBJ(a, GetVpValue(self,1));
1121 if (RB_TYPE_P(r, T_FLOAT)) {
1122 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1123 }
1124 else if (RB_TYPE_P(r, T_RATIONAL)) {
1125 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1126 }
1127 else {
1128 b = GetVpValue(r,0);
1129 }
1130
1131 if (!b) return DoSomeOne(self,r,'-');
1132 SAVE(b);
1133
1134 if (VpIsNaN(b)) return b->obj;
1135 if (VpIsNaN(a)) return a->obj;
1136
1137 mx = GetAddSubPrec(a,b);
1138 if (mx == (size_t)-1L) {
1139 GUARD_OBJ(c,VpCreateRbObject(VpBaseFig() + 1, "0"));
1140 VpAddSub(c, a, b, -1);
1141 }
1142 else {
1143 GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
1144 if (!mx) {
1145 VpSetInf(c,VpGetSign(a));
1146 }
1147 else {
1148 VpAddSub(c, a, b, -1);
1149 }
1150 }
1151 return ToValue(c);
1152}
1153
1154static VALUE
1155BigDecimalCmp(VALUE self, VALUE r,char op)
1156{
1157 ENTER(5);
1158 SIGNED_VALUE e;
1159 Real *a, *b=0;
1160 GUARD_OBJ(a, GetVpValue(self, 1));
1161 switch (TYPE(r)) {
1162 case T_DATA:
1163 if (!is_kind_of_BigDecimal(r)) break;
1164 /* fall through */
1165 case T_FIXNUM:
1166 /* fall through */
1167 case T_BIGNUM:
1168 GUARD_OBJ(b, GetVpValue(r, 0));
1169 break;
1170
1171 case T_FLOAT:
1172 GUARD_OBJ(b, GetVpValueWithPrec(r, DBLE_FIG, 0));
1173 break;
1174
1175 case T_RATIONAL:
1176 GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
1177 break;
1178
1179 default:
1180 break;
1181 }
1182 if (b == NULL) {
1183 ID f = 0;
1184
1185 switch (op) {
1186 case '*':
1187 return rb_num_coerce_cmp(self, r, rb_intern("<=>"));
1188
1189 case '=':
1190 return RTEST(rb_num_coerce_cmp(self, r, rb_intern("=="))) ? Qtrue : Qfalse;
1191
1192 case 'G':
1193 f = rb_intern(">=");
1194 break;
1195
1196 case 'L':
1197 f = rb_intern("<=");
1198 break;
1199
1200 case '>':
1201 /* fall through */
1202 case '<':
1203 f = (ID)op;
1204 break;
1205
1206 default:
1207 break;
1208 }
1209 return rb_num_coerce_relop(self, r, f);
1210 }
1211 SAVE(b);
1212 e = VpComp(a, b);
1213 if (e == 999)
1214 return (op == '*') ? Qnil : Qfalse;
1215 switch (op) {
1216 case '*':
1217 return INT2FIX(e); /* any op */
1218
1219 case '=':
1220 if (e == 0) return Qtrue;
1221 return Qfalse;
1222
1223 case 'G':
1224 if (e >= 0) return Qtrue;
1225 return Qfalse;
1226
1227 case '>':
1228 if (e > 0) return Qtrue;
1229 return Qfalse;
1230
1231 case 'L':
1232 if (e <= 0) return Qtrue;
1233 return Qfalse;
1234
1235 case '<':
1236 if (e < 0) return Qtrue;
1237 return Qfalse;
1238
1239 default:
1240 break;
1241 }
1242
1243 rb_bug("Undefined operation in BigDecimalCmp()");
1244
1245 UNREACHABLE;
1246}
1247
1248/* Returns True if the value is zero. */
1249static VALUE
1250BigDecimal_zero(VALUE self)
1251{
1252 Real *a = GetVpValue(self, 1);
1253 return VpIsZero(a) ? Qtrue : Qfalse;
1254}
1255
1256/* Returns self if the value is non-zero, nil otherwise. */
1257static VALUE
1258BigDecimal_nonzero(VALUE self)
1259{
1260 Real *a = GetVpValue(self, 1);
1261 return VpIsZero(a) ? Qnil : self;
1262}
1263
1264/* The comparison operator.
1265 * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
1266 */
1267static VALUE
1268BigDecimal_comp(VALUE self, VALUE r)
1269{
1270 return BigDecimalCmp(self, r, '*');
1271}
1272
1273/*
1274 * Tests for value equality; returns true if the values are equal.
1275 *
1276 * The == and === operators and the eql? method have the same implementation
1277 * for BigDecimal.
1278 *
1279 * Values may be coerced to perform the comparison:
1280 *
1281 * BigDecimal('1.0') == 1.0 #=> true
1282 */
1283static VALUE
1284BigDecimal_eq(VALUE self, VALUE r)
1285{
1286 return BigDecimalCmp(self, r, '=');
1287}
1288
1289/* call-seq:
1290 * a < b
1291 *
1292 * Returns true if a is less than b.
1293 *
1294 * Values may be coerced to perform the comparison (see ==, BigDecimal#coerce).
1295 */
1296static VALUE
1297BigDecimal_lt(VALUE self, VALUE r)
1298{
1299 return BigDecimalCmp(self, r, '<');
1300}
1301
1302/* call-seq:
1303 * a <= b
1304 *
1305 * Returns true if a is less than or equal to b.
1306 *
1307 * Values may be coerced to perform the comparison (see ==, BigDecimal#coerce).
1308 */
1309static VALUE
1310BigDecimal_le(VALUE self, VALUE r)
1311{
1312 return BigDecimalCmp(self, r, 'L');
1313}
1314
1315/* call-seq:
1316 * a > b
1317 *
1318 * Returns true if a is greater than b.
1319 *
1320 * Values may be coerced to perform the comparison (see ==, BigDecimal#coerce).
1321 */
1322static VALUE
1323BigDecimal_gt(VALUE self, VALUE r)
1324{
1325 return BigDecimalCmp(self, r, '>');
1326}
1327
1328/* call-seq:
1329 * a >= b
1330 *
1331 * Returns true if a is greater than or equal to b.
1332 *
1333 * Values may be coerced to perform the comparison (see ==, BigDecimal#coerce)
1334 */
1335static VALUE
1336BigDecimal_ge(VALUE self, VALUE r)
1337{
1338 return BigDecimalCmp(self, r, 'G');
1339}
1340
1341/*
1342 * call-seq:
1343 * -big_decimal -> big_decimal
1344 *
1345 * Return the negation of self.
1346 *
1347 * -BigDecimal('5') #=> -0.5e1
1348 */
1349
1350static VALUE
1351BigDecimal_neg(VALUE self)
1352{
1353 ENTER(5);
1354 Real *c, *a;
1355 GUARD_OBJ(a, GetVpValue(self, 1));
1356 GUARD_OBJ(c, VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0"));
1357 VpAsgn(c, a, -1);
1358 return ToValue(c);
1359}
1360
1361 /*
1362 * Document-method: BigDecimal#mult
1363 *
1364 * call-seq: mult(value, digits)
1365 *
1366 * Multiply by the specified value.
1367 *
1368 * e.g.
1369 * c = a.mult(b,n)
1370 * c = a * b
1371 *
1372 * digits:: If specified and less than the number of significant digits of the
1373 * result, the result is rounded to that number of digits, according
1374 * to BigDecimal.mode.
1375 */
1376static VALUE
1377BigDecimal_mult(VALUE self, VALUE r)
1378{
1379 ENTER(5);
1380 Real *c, *a, *b;
1381 size_t mx;
1382
1383 GUARD_OBJ(a, GetVpValue(self, 1));
1384 if (RB_TYPE_P(r, T_FLOAT)) {
1385 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1386 }
1387 else if (RB_TYPE_P(r, T_RATIONAL)) {
1388 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1389 }
1390 else {
1391 b = GetVpValue(r,0);
1392 }
1393
1394 if (!b) return DoSomeOne(self, r, '*');
1395 SAVE(b);
1396
1397 mx = a->Prec + b->Prec;
1398 GUARD_OBJ(c, VpCreateRbObject(mx *(VpBaseFig() + 1), "0"));
1399 VpMult(c, a, b);
1400 return ToValue(c);
1401}
1402
1403static VALUE
1404BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
1405/* For c = self.div(r): with round operation */
1406{
1407 ENTER(5);
1408 Real *a, *b;
1409 size_t mx;
1410
1411 GUARD_OBJ(a, GetVpValue(self, 1));
1412 if (RB_TYPE_P(r, T_FLOAT)) {
1413 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1414 }
1415 else if (RB_TYPE_P(r, T_RATIONAL)) {
1416 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1417 }
1418 else {
1419 b = GetVpValue(r, 0);
1420 }
1421
1422 if (!b) return DoSomeOne(self, r, '/');
1423 SAVE(b);
1424
1425 *div = b;
1426 mx = a->Prec + vabs(a->exponent);
1427 if (mx < b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
1428 mx++; /* NOTE: An additional digit is needed for the compatibility to
1429 the version 1.2.1 and the former. */
1430 mx = (mx + 1) * VpBaseFig();
1431 GUARD_OBJ((*c), VpCreateRbObject(mx, "#0"));
1432 GUARD_OBJ((*res), VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
1433 VpDivd(*c, *res, a, b);
1434 return Qnil;
1435}
1436
1437/* call-seq:
1438 * a / b -> bigdecimal
1439 * quo(value) -> bigdecimal
1440 *
1441 * Divide by the specified value.
1442 *
1443 * See BigDecimal#div.
1444 */
1445static VALUE
1446BigDecimal_div(VALUE self, VALUE r)
1447/* For c = self/r: with round operation */
1448{
1449 ENTER(5);
1450 Real *c=NULL, *res=NULL, *div = NULL;
1451 r = BigDecimal_divide(&c, &res, &div, self, r);
1452 if (!NIL_P(r)) return r; /* coerced by other */
1453 SAVE(c); SAVE(res); SAVE(div);
1454 /* a/b = c + r/b */
1455 /* c xxxxx
1456 r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
1457 */
1458 /* Round */
1459 if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
1460 VpInternalRound(c, 0, c->frac[c->Prec-1], (BDIGIT)(VpBaseVal() * (BDIGIT_DBL)res->frac[0] / div->frac[0]));
1461 }
1462 return ToValue(c);
1463}
1464
1465/*
1466 * %: mod = a%b = a - (a.to_f/b).floor * b
1467 * div = (a.to_f/b).floor
1468 */
1469static VALUE
1470BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1471{
1472 ENTER(8);
1473 Real *c=NULL, *d=NULL, *res=NULL;
1474 Real *a, *b;
1475 size_t mx;
1476
1477 GUARD_OBJ(a, GetVpValue(self, 1));
1478 if (RB_TYPE_P(r, T_FLOAT)) {
1479 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1480 }
1481 else if (RB_TYPE_P(r, T_RATIONAL)) {
1482 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1483 }
1484 else {
1485 b = GetVpValue(r, 0);
1486 }
1487
1488 if (!b) return Qfalse;
1489 SAVE(b);
1490
1491 if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
1492 if (VpIsInf(a) && VpIsInf(b)) goto NaN;
1493 if (VpIsZero(b)) {
1494 rb_raise(rb_eZeroDivError, "divided by 0");
1495 }
1496 if (VpIsInf(a)) {
1497 GUARD_OBJ(d, VpCreateRbObject(1, "0"));
1498 VpSetInf(d, (SIGNED_VALUE)(VpGetSign(a) == VpGetSign(b) ? 1 : -1));
1499 GUARD_OBJ(c, VpCreateRbObject(1, "NaN"));
1500 *div = d;
1501 *mod = c;
1502 return Qtrue;
1503 }
1504 if (VpIsInf(b)) {
1505 GUARD_OBJ(d, VpCreateRbObject(1, "0"));
1506 *div = d;
1507 *mod = a;
1508 return Qtrue;
1509 }
1510 if (VpIsZero(a)) {
1511 GUARD_OBJ(c, VpCreateRbObject(1, "0"));
1512 GUARD_OBJ(d, VpCreateRbObject(1, "0"));
1513 *div = d;
1514 *mod = c;
1515 return Qtrue;
1516 }
1517
1518 mx = a->Prec + vabs(a->exponent);
1519 if (mx<b->Prec + vabs(b->exponent)) mx = b->Prec + vabs(b->exponent);
1520 mx = (mx + 1) * VpBaseFig();
1521 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1522 GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0"));
1523 VpDivd(c, res, a, b);
1524 mx = c->Prec * (VpBaseFig() + 1);
1525 GUARD_OBJ(d, VpCreateRbObject(mx, "0"));
1526 VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1527 VpMult(res, d, b);
1528 VpAddSub(c, a, res, -1);
1529 if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1530 VpAddSub(res, d, VpOne(), -1);
1531 GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0"));
1532 VpAddSub(d, c, b, 1);
1533 *div = res;
1534 *mod = d;
1535 } else {
1536 *div = d;
1537 *mod = c;
1538 }
1539 return Qtrue;
1540
1541NaN:
1542 GUARD_OBJ(c, VpCreateRbObject(1, "NaN"));
1543 GUARD_OBJ(d, VpCreateRbObject(1, "NaN"));
1544 *div = d;
1545 *mod = c;
1546 return Qtrue;
1547}
1548
1549/* call-seq:
1550 * a % b
1551 * a.modulo(b)
1552 *
1553 * Returns the modulus from dividing by b.
1554 *
1555 * See BigDecimal#divmod.
1556 */
1557static VALUE
1558BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
1559{
1560 ENTER(3);
1561 Real *div = NULL, *mod = NULL;
1562
1563 if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
1564 SAVE(div); SAVE(mod);
1565 return ToValue(mod);
1566 }
1567 return DoSomeOne(self, r, '%');
1568}
1569
1570static VALUE
1571BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1572{
1573 ENTER(10);
1574 size_t mx;
1575 Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
1576 Real *f = NULL;
1577
1578 GUARD_OBJ(a, GetVpValue(self, 1));
1579 if (RB_TYPE_P(r, T_FLOAT)) {
1580 b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1581 }
1582 else if (RB_TYPE_P(r, T_RATIONAL)) {
1583 b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1584 }
1585 else {
1586 b = GetVpValue(r, 0);
1587 }
1588
1589 if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
1590 SAVE(b);
1591
1592 mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
1593 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1594 GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0"));
1595 GUARD_OBJ(rr, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0"));
1596 GUARD_OBJ(ff, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0"));
1597
1598 VpDivd(c, res, a, b);
1599
1600 mx = c->Prec *(VpBaseFig() + 1);
1601
1602 GUARD_OBJ(d, VpCreateRbObject(mx, "0"));
1603 GUARD_OBJ(f, VpCreateRbObject(mx, "0"));
1604
1605 VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
1606
1607 VpFrac(f, c);
1608 VpMult(rr, f, b);
1609 VpAddSub(ff, res, rr, 1);
1610
1611 *dv = d;
1612 *rv = ff;
1613 return Qnil;
1614}
1615
1616/* call-seq:
1617 * remainder(value)
1618 *
1619 * Returns the remainder from dividing by the value.
1620 *
1621 * x.remainder(y) means x-y*(x/y).truncate
1622 */
1623static VALUE
1624BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
1625{
1626 VALUE f;
1627 Real *d, *rv = 0;
1628 f = BigDecimal_divremain(self, r, &d, &rv);
1629 if (!NIL_P(f)) return f;
1630 return ToValue(rv);
1631}
1632
1633/* call-seq:
1634 * divmod(value)
1635 *
1636 * Divides by the specified value, and returns the quotient and modulus
1637 * as BigDecimal numbers. The quotient is rounded towards negative infinity.
1638 *
1639 * For example:
1640 *
1641 * require 'bigdecimal'
1642 *
1643 * a = BigDecimal("42")
1644 * b = BigDecimal("9")
1645 *
1646 * q, m = a.divmod(b)
1647 *
1648 * c = q * b + m
1649 *
1650 * a == c #=> true
1651 *
1652 * The quotient q is (a/b).floor, and the modulus is the amount that must be
1653 * added to q * b to get a.
1654 */
1655static VALUE
1656BigDecimal_divmod(VALUE self, VALUE r)
1657{
1658 ENTER(5);
1659 Real *div = NULL, *mod = NULL;
1660
1661 if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
1662 SAVE(div); SAVE(mod);
1663 return rb_assoc_new(ToValue(div), ToValue(mod));
1664 }
1665 return DoSomeOne(self,r,rb_intern("divmod"));
1666}
1667
1668/*
1669 * See BigDecimal#quo
1670 */
1671static inline VALUE
1672BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1673{
1674 ENTER(5);
1675 SIGNED_VALUE ix;
1676
1677 if (NIL_P(n)) { /* div in Float sense */
1678 Real *div = NULL;
1679 Real *mod;
1680 if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
1681 return BigDecimal_to_i(ToValue(div));
1682 }
1683 return DoSomeOne(self, b, rb_intern("div"));
1684 }
1685
1686 /* div in BigDecimal sense */
1687 ix = GetPrecisionInt(n);
1688 if (ix == 0) {
1689 return BigDecimal_div(self, b);
1690 }
1691 else {
1692 Real *res = NULL;
1693 Real *av = NULL, *bv = NULL, *cv = NULL;
1694 size_t mx = ix + VpBaseFig()*2;
1695 size_t pl = VpSetPrecLimit(0);
1696
1697 GUARD_OBJ(cv, VpCreateRbObject(mx + VpBaseFig(), "0"));
1698 GUARD_OBJ(av, GetVpValue(self, 1));
1699 GUARD_OBJ(bv, GetVpValue(b, 1));
1700 mx = av->Prec + bv->Prec + 2;
1701 if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
1702 GUARD_OBJ(res, VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0"));
1703 VpDivd(cv, res, av, bv);
1704 VpSetPrecLimit(pl);
1705 VpLeftRound(cv, VpGetRoundMode(), ix);
1706 return ToValue(cv);
1707 }
1708}
1709
1710 /*
1711 * Document-method: BigDecimal#div
1712 *
1713 * call-seq:
1714 * div(value, digits) -> bigdecimal or integer
1715 *
1716 * Divide by the specified value.
1717 *
1718 * digits:: If specified and less than the number of significant digits of the
1719 * result, the result is rounded to that number of digits, according
1720 * to BigDecimal.mode.
1721 *
1722 * If digits is 0, the result is the same as for the / operator
1723 * or #quo.
1724 *
1725 * If digits is not specified, the result is an integer,
1726 * by analogy with Float#div; see also BigDecimal#divmod.
1727 *
1728 * Examples:
1729 *
1730 * a = BigDecimal("4")
1731 * b = BigDecimal("3")
1732 *
1733 * a.div(b, 3) # => 0.133e1
1734 *
1735 * a.div(b, 0) # => 0.1333333333333333333e1
1736 * a / b # => 0.1333333333333333333e1
1737 * a.quo(b) # => 0.1333333333333333333e1
1738 *
1739 * a.div(b) # => 1
1740 */
1741static VALUE
1742BigDecimal_div3(int argc, VALUE *argv, VALUE self)
1743{
1744 VALUE b,n;
1745
1746 rb_scan_args(argc, argv, "11", &b, &n);
1747
1748 return BigDecimal_div2(self, b, n);
1749}
1750
1751static VALUE
1752BigDecimal_add2(VALUE self, VALUE b, VALUE n)
1753{
1754 ENTER(2);
1755 Real *cv;
1756 SIGNED_VALUE mx = GetPrecisionInt(n);
1757 if (mx == 0) return BigDecimal_add(self, b);
1758 else {
1759 size_t pl = VpSetPrecLimit(0);
1760 VALUE c = BigDecimal_add(self, b);
1761 VpSetPrecLimit(pl);
1762 GUARD_OBJ(cv, GetVpValue(c, 1));
1763 VpLeftRound(cv, VpGetRoundMode(), mx);
1764 return ToValue(cv);
1765 }
1766}
1767
1768/* call-seq:
1769 * sub(value, digits) -> bigdecimal
1770 *
1771 * Subtract the specified value.
1772 *
1773 * e.g.
1774 * c = a.sub(b,n)
1775 *
1776 * digits:: If specified and less than the number of significant digits of the
1777 * result, the result is rounded to that number of digits, according
1778 * to BigDecimal.mode.
1779 *
1780 */
1781static VALUE
1782BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
1783{
1784 ENTER(2);
1785 Real *cv;
1786 SIGNED_VALUE mx = GetPrecisionInt(n);
1787 if (mx == 0) return BigDecimal_sub(self, b);
1788 else {
1789 size_t pl = VpSetPrecLimit(0);
1790 VALUE c = BigDecimal_sub(self, b);
1791 VpSetPrecLimit(pl);
1792 GUARD_OBJ(cv, GetVpValue(c, 1));
1793 VpLeftRound(cv, VpGetRoundMode(), mx);
1794 return ToValue(cv);
1795 }
1796}
1797
1798
1799static VALUE
1800BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
1801{
1802 ENTER(2);
1803 Real *cv;
1804 SIGNED_VALUE mx = GetPrecisionInt(n);
1805 if (mx == 0) return BigDecimal_mult(self, b);
1806 else {
1807 size_t pl = VpSetPrecLimit(0);
1808 VALUE c = BigDecimal_mult(self, b);
1809 VpSetPrecLimit(pl);
1810 GUARD_OBJ(cv, GetVpValue(c, 1));
1811 VpLeftRound(cv, VpGetRoundMode(), mx);
1812 return ToValue(cv);
1813 }
1814}
1815
1816/*
1817 * call-seq:
1818 * big_decimal.abs -> big_decimal
1819 *
1820 * Returns the absolute value, as a BigDecimal.
1821 *
1822 * BigDecimal('5').abs #=> 0.5e1
1823 * BigDecimal('-3').abs #=> 0.3e1
1824 */
1825
1826static VALUE
1827BigDecimal_abs(VALUE self)
1828{
1829 ENTER(5);
1830 Real *c, *a;
1831 size_t mx;
1832
1833 GUARD_OBJ(a, GetVpValue(self, 1));
1834 mx = a->Prec *(VpBaseFig() + 1);
1835 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1836 VpAsgn(c, a, 1);
1837 VpChangeSign(c, 1);
1838 return ToValue(c);
1839}
1840
1841/* call-seq:
1842 * sqrt(n)
1843 *
1844 * Returns the square root of the value.
1845 *
1846 * Result has at least n significant digits.
1847 */
1848static VALUE
1849BigDecimal_sqrt(VALUE self, VALUE nFig)
1850{
1851 ENTER(5);
1852 Real *c, *a;
1853 size_t mx, n;
1854
1855 GUARD_OBJ(a, GetVpValue(self, 1));
1856 mx = a->Prec * (VpBaseFig() + 1);
1857
1858 n = GetPrecisionInt(nFig) + VpDblFig() + BASE_FIG;
1859 if (mx <= n) mx = n;
1860 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1861 VpSqrt(c, a);
1862 return ToValue(c);
1863}
1864
1865/* Return the integer part of the number, as a BigDecimal.
1866 */
1867static VALUE
1868BigDecimal_fix(VALUE self)
1869{
1870 ENTER(5);
1871 Real *c, *a;
1872 size_t mx;
1873
1874 GUARD_OBJ(a, GetVpValue(self, 1));
1875 mx = a->Prec *(VpBaseFig() + 1);
1876 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1877 VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
1878 return ToValue(c);
1879}
1880
1881/* call-seq:
1882 * round(n, mode)
1883 *
1884 * Round to the nearest integer (by default), returning the result as a
1885 * BigDecimal if n is specified, or as an Integer if it isn't.
1886 *
1887 * BigDecimal('3.14159').round #=> 3
1888 * BigDecimal('8.7').round #=> 9
1889 * BigDecimal('-9.9').round #=> -10
1890 *
1891 * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
1892 * BigDecimal('3.14159').round.class.name #=> "Integer"
1893 *
1894 * If n is specified and positive, the fractional part of the result has no
1895 * more than that many digits.
1896 *
1897 * If n is specified and negative, at least that many digits to the left of the
1898 * decimal point will be 0 in the result, and return value will be an Integer.
1899 *
1900 * BigDecimal('3.14159').round(3) #=> 3.142
1901 * BigDecimal('13345.234').round(-2) #=> 13300
1902 *
1903 * The value of the optional mode argument can be used to determine how
1904 * rounding is performed; see BigDecimal.mode.
1905 */
1906static VALUE
1907BigDecimal_round(int argc, VALUE *argv, VALUE self)
1908{
1909 ENTER(5);
1910 Real *c, *a;
1911 int iLoc = 0;
1912 VALUE vLoc;
1913 VALUE vRound;
1914 int round_to_int = 0;
1915 size_t mx, pl;
1916
1917 unsigned short sw = VpGetRoundMode();
1918
1919 switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
1920 case 0:
1921 iLoc = 0;
1922 round_to_int = 1;
1923 break;
1924 case 1:
1925 if (RB_TYPE_P(vLoc, T_HASH)) {
1926 sw = check_rounding_mode_option(vLoc);
1927 }
1928 else {
1929 iLoc = NUM2INT(vLoc);
1930 if (iLoc < 1) round_to_int = 1;
1931 }
1932 break;
1933 case 2:
1934 iLoc = NUM2INT(vLoc);
1935 if (RB_TYPE_P(vRound, T_HASH)) {
1936 sw = check_rounding_mode_option(vRound);
1937 }
1938 else {
1939 sw = check_rounding_mode(vRound);
1940 }
1941 break;
1942 default:
1943 break;
1944 }
1945
1946 pl = VpSetPrecLimit(0);
1947 GUARD_OBJ(a, GetVpValue(self, 1));
1948 mx = a->Prec * (VpBaseFig() + 1);
1949 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1950 VpSetPrecLimit(pl);
1951 VpActiveRound(c, a, sw, iLoc);
1952 if (round_to_int) {
1953 return BigDecimal_to_i(ToValue(c));
1954 }
1955 return ToValue(c);
1956}
1957
1958/* call-seq:
1959 * truncate(n)
1960 *
1961 * Truncate to the nearest integer (by default), returning the result as a
1962 * BigDecimal.
1963 *
1964 * BigDecimal('3.14159').truncate #=> 3
1965 * BigDecimal('8.7').truncate #=> 8
1966 * BigDecimal('-9.9').truncate #=> -9
1967 *
1968 * If n is specified and positive, the fractional part of the result has no
1969 * more than that many digits.
1970 *
1971 * If n is specified and negative, at least that many digits to the left of the
1972 * decimal point will be 0 in the result.
1973 *
1974 * BigDecimal('3.14159').truncate(3) #=> 3.141
1975 * BigDecimal('13345.234').truncate(-2) #=> 13300.0
1976 */
1977static VALUE
1978BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
1979{
1980 ENTER(5);
1981 Real *c, *a;
1982 int iLoc;
1983 VALUE vLoc;
1984 size_t mx, pl = VpSetPrecLimit(0);
1985
1986 if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
1987 iLoc = 0;
1988 }
1989 else {
1990 iLoc = NUM2INT(vLoc);
1991 }
1992
1993 GUARD_OBJ(a, GetVpValue(self, 1));
1994 mx = a->Prec * (VpBaseFig() + 1);
1995 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1996 VpSetPrecLimit(pl);
1997 VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
1998 if (argc == 0) {
1999 return BigDecimal_to_i(ToValue(c));
2000 }
2001 return ToValue(c);
2002}
2003
2004/* Return the fractional part of the number, as a BigDecimal.
2005 */
2006static VALUE
2007BigDecimal_frac(VALUE self)
2008{
2009 ENTER(5);
2010 Real *c, *a;
2011 size_t mx;
2012
2013 GUARD_OBJ(a, GetVpValue(self, 1));
2014 mx = a->Prec * (VpBaseFig() + 1);
2015 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
2016 VpFrac(c, a);
2017 return ToValue(c);
2018}
2019
2020/* call-seq:
2021 * floor(n)
2022 *
2023 * Return the largest integer less than or equal to the value, as a BigDecimal.
2024 *
2025 * BigDecimal('3.14159').floor #=> 3
2026 * BigDecimal('-9.1').floor #=> -10
2027 *
2028 * If n is specified and positive, the fractional part of the result has no
2029 * more than that many digits.
2030 *
2031 * If n is specified and negative, at least that
2032 * many digits to the left of the decimal point will be 0 in the result.
2033 *
2034 * BigDecimal('3.14159').floor(3) #=> 3.141
2035 * BigDecimal('13345.234').floor(-2) #=> 13300.0
2036 */
2037static VALUE
2038BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2039{
2040 ENTER(5);
2041 Real *c, *a;
2042 int iLoc;
2043 VALUE vLoc;
2044 size_t mx, pl = VpSetPrecLimit(0);
2045
2046 if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
2047 iLoc = 0;
2048 }
2049 else {
2050 iLoc = NUM2INT(vLoc);
2051 }
2052
2053 GUARD_OBJ(a, GetVpValue(self, 1));
2054 mx = a->Prec * (VpBaseFig() + 1);
2055 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
2056 VpSetPrecLimit(pl);
2057 VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2058#ifdef BIGDECIMAL_DEBUG
2059 VPrint(stderr, "floor: c=%\n", c);
2060#endif
2061 if (argc == 0) {
2062 return BigDecimal_to_i(ToValue(c));
2063 }
2064 return ToValue(c);
2065}
2066
2067/* call-seq:
2068 * ceil(n)
2069 *
2070 * Return the smallest integer greater than or equal to the value, as a BigDecimal.
2071 *
2072 * BigDecimal('3.14159').ceil #=> 4
2073 * BigDecimal('-9.1').ceil #=> -9
2074 *
2075 * If n is specified and positive, the fractional part of the result has no
2076 * more than that many digits.
2077 *
2078 * If n is specified and negative, at least that
2079 * many digits to the left of the decimal point will be 0 in the result.
2080 *
2081 * BigDecimal('3.14159').ceil(3) #=> 3.142
2082 * BigDecimal('13345.234').ceil(-2) #=> 13400.0
2083 */
2084static VALUE
2085BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2086{
2087 ENTER(5);
2088 Real *c, *a;
2089 int iLoc;
2090 VALUE vLoc;
2091 size_t mx, pl = VpSetPrecLimit(0);
2092
2093 if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2094 iLoc = 0;
2095 } else {
2096 iLoc = NUM2INT(vLoc);
2097 }
2098
2099 GUARD_OBJ(a, GetVpValue(self, 1));
2100 mx = a->Prec * (VpBaseFig() + 1);
2101 GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
2102 VpSetPrecLimit(pl);
2103 VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2104 if (argc == 0) {
2105 return BigDecimal_to_i(ToValue(c));
2106 }
2107 return ToValue(c);
2108}
2109
2110/* call-seq:
2111 * to_s(s)
2112 *
2113 * Converts the value to a string.
2114 *
2115 * The default format looks like 0.xxxxEnn.
2116 *
2117 * The optional parameter s consists of either an integer; or an optional '+'
2118 * or ' ', followed by an optional number, followed by an optional 'E' or 'F'.
2119 *
2120 * If there is a '+' at the start of s, positive values are returned with
2121 * a leading '+'.
2122 *
2123 * A space at the start of s returns positive values with a leading space.
2124 *
2125 * If s contains a number, a space is inserted after each group of that many
2126 * fractional digits.
2127 *
2128 * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2129 *
2130 * If s ends with an 'F', conventional floating point notation is used.
2131 *
2132 * Examples:
2133 *
2134 * BigDecimal('-123.45678901234567890').to_s('5F')
2135 * #=> '-123.45678 90123 45678 9'
2136 *
2137 * BigDecimal('123.45678901234567890').to_s('+8F')
2138 * #=> '+123.45678901 23456789'
2139 *
2140 * BigDecimal('123.45678901234567890').to_s(' F')
2141 * #=> ' 123.4567890123456789'
2142 */
2143static VALUE
2144BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2145{
2146 ENTER(5);
2147 int fmt = 0; /* 0: E format, 1: F format */
2148 int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2149 Real *vp;
2150 volatile VALUE str;
2151 char *psz;
2152 char ch;
2153 size_t nc, mc = 0;
2154 SIGNED_VALUE m;
2155 VALUE f;
2156
2157 GUARD_OBJ(vp, GetVpValue(self, 1));
2158
2159 if (rb_scan_args(argc, argv, "01", &f) == 1) {
2160 if (RB_TYPE_P(f, T_STRING)) {
2161 psz = StringValueCStr(f);
2162 if (*psz == ' ') {
2163 fPlus = 1;
2164 psz++;
2165 }
2166 else if (*psz == '+') {
2167 fPlus = 2;
2168 psz++;
2169 }
2170 while ((ch = *psz++) != 0) {
2171 if (ISSPACE(ch)) {
2172 continue;
2173 }
2174 if (!ISDIGIT(ch)) {
2175 if (ch == 'F' || ch == 'f') {
2176 fmt = 1; /* F format */
2177 }
2178 break;
2179 }
2180 mc = mc*10 + ch - '0';
2181 }
2182 }
2183 else {
2184 m = NUM2INT(f);
2185 if (m <= 0) {
2186 rb_raise(rb_eArgError, "argument must be positive");
2187 }
2188 mc = (size_t)m;
2189 }
2190 }
2191 if (fmt) {
2192 nc = VpNumOfChars(vp, "F");
2193 }
2194 else {
2195 nc = VpNumOfChars(vp, "E");
2196 }
2197 if (mc > 0) {
2198 nc += (nc + mc - 1) / mc + 1;
2199 }
2200
2201 str = rb_usascii_str_new(0, nc);
2202 psz = RSTRING_PTR(str);
2203
2204 if (fmt) {
2205 VpToFString(vp, psz, mc, fPlus);
2206 }
2207 else {
2208 VpToString (vp, psz, mc, fPlus);
2209 }
2210 rb_str_resize(str, strlen(psz));
2211 return str;
2212}
2213
2214/* Splits a BigDecimal number into four parts, returned as an array of values.
2215 *
2216 * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
2217 * if the BigDecimal is Not a Number.
2218 *
2219 * The second value is a string representing the significant digits of the
2220 * BigDecimal, with no leading zeros.
2221 *
2222 * The third value is the base used for arithmetic (currently always 10) as an
2223 * Integer.
2224 *
2225 * The fourth value is an Integer exponent.
2226 *
2227 * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
2228 * string of significant digits with no leading zeros, and n is the exponent.
2229 *
2230 * From these values, you can translate a BigDecimal to a float as follows:
2231 *
2232 * sign, significant_digits, base, exponent = a.split
2233 * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
2234 *
2235 * (Note that the to_f method is provided as a more convenient way to translate
2236 * a BigDecimal to a Float.)
2237 */
2238static VALUE
2239BigDecimal_split(VALUE self)
2240{
2241 ENTER(5);
2242 Real *vp;
2243 VALUE obj,str;
2244 ssize_t e, s;
2245 char *psz1;
2246
2247 GUARD_OBJ(vp, GetVpValue(self, 1));
2248 str = rb_str_new(0, VpNumOfChars(vp, "E"));
2249 psz1 = RSTRING_PTR(str);
2250 VpSzMantissa(vp, psz1);
2251 s = 1;
2252 if(psz1[0] == '-') {
2253 size_t len = strlen(psz1 + 1);
2254
2255 memmove(psz1, psz1 + 1, len);
2256 psz1[len] = '\0';
2257 s = -1;
2258 }
2259 if (psz1[0] == 'N') s = 0; /* NaN */
2260 e = VpExponent10(vp);
2261 obj = rb_ary_new2(4);
2262 rb_ary_push(obj, INT2FIX(s));
2263 rb_ary_push(obj, str);
2264 rb_str_resize(str, strlen(psz1));
2265 rb_ary_push(obj, INT2FIX(10));
2266 rb_ary_push(obj, SSIZET2NUM(e));
2267 return obj;
2268}
2269
2270/* Returns the exponent of the BigDecimal number, as an Integer.
2271 *
2272 * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
2273 * of digits with no leading zeros, then n is the exponent.
2274 */
2275static VALUE
2276BigDecimal_exponent(VALUE self)
2277{
2278 ssize_t e = VpExponent10(GetVpValue(self, 1));
2279 return SSIZET2NUM(e);
2280}
2281
2282/* Returns a string representation of self.
2283 *
2284 * BigDecimal("1234.5678").inspect
2285 * #=> "0.12345678e4"
2286 */
2287static VALUE
2288BigDecimal_inspect(VALUE self)
2289{
2290 ENTER(5);
2291 Real *vp;
2292 volatile VALUE str;
2293 size_t nc;
2294
2295 GUARD_OBJ(vp, GetVpValue(self, 1));
2296 nc = VpNumOfChars(vp, "E");
2297
2298 str = rb_str_new(0, nc);
2299 VpToString(vp, RSTRING_PTR(str), 0, 0);
2300 rb_str_resize(str, strlen(RSTRING_PTR(str)));
2301 return str;
2302}
2303
2304static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
2305static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
2306
2307#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
2308#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
2309
2310inline static int
2311is_integer(VALUE x)
2312{
2313 return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2314}
2315
2316inline static int
2317is_negative(VALUE x)
2318{
2319 if (FIXNUM_P(x)) {
2320 return FIX2LONG(x) < 0;
2321 }
2322 else if (RB_TYPE_P(x, T_BIGNUM)) {
2323 return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
2324 }
2325 else if (RB_TYPE_P(x, T_FLOAT)) {
2326 return RFLOAT_VALUE(x) < 0.0;
2327 }
2328 return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2329}
2330
2331#define is_positive(x) (!is_negative(x))
2332
2333inline static int
2334is_zero(VALUE x)
2335{
2336 VALUE num;
2337
2338 switch (TYPE(x)) {
2339 case T_FIXNUM:
2340 return FIX2LONG(x) == 0;
2341
2342 case T_BIGNUM:
2343 return Qfalse;
2344
2345 case T_RATIONAL:
2346 num = rb_rational_num(x);
2347 return FIXNUM_P(num) && FIX2LONG(num) == 0;
2348
2349 default:
2350 break;
2351 }
2352
2353 return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2354}
2355
2356inline static int
2357is_one(VALUE x)
2358{
2359 VALUE num, den;
2360
2361 switch (TYPE(x)) {
2362 case T_FIXNUM:
2363 return FIX2LONG(x) == 1;
2364
2365 case T_BIGNUM:
2366 return Qfalse;
2367
2368 case T_RATIONAL:
2369 num = rb_rational_num(x);
2370 den = rb_rational_den(x);
2371 return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
2372 FIXNUM_P(num) && FIX2LONG(num) == 1;
2373
2374 default:
2375 break;
2376 }
2377
2378 return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
2379}
2380
2381inline static int
2382is_even(VALUE x)
2383{
2384 switch (TYPE(x)) {
2385 case T_FIXNUM:
2386 return (FIX2LONG(x) % 2) == 0;
2387
2388 case T_BIGNUM:
2389 {
2390 unsigned long l;
2391 rb_big_pack(x, &l, 1);
2392 return l % 2 == 0;
2393 }
2394
2395 default:
2396 break;
2397 }
2398
2399 return 0;
2400}
2401
2402static VALUE
2403rmpd_power_by_big_decimal(Real const* x, Real const* exp, ssize_t const n)
2404{
2405 VALUE log_x, multiplied, y;
2406 volatile VALUE obj = exp->obj;
2407
2408 if (VpIsZero(exp)) {
2409 return ToValue(VpCreateRbObject(n, "1"));
2410 }
2411
2412 log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
2413 multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
2414 y = BigMath_exp(multiplied, SSIZET2NUM(n));
2415 RB_GC_GUARD(obj);
2416
2417 return y;
2418}
2419
2420/* call-seq:
2421 * power(n)
2422 * power(n, prec)
2423 *
2424 * Returns the value raised to the power of n.
2425 *
2426 * Note that n must be an Integer.
2427 *
2428 * Also available as the operator **.
2429 */
2430static VALUE
2431BigDecimal_power(int argc, VALUE*argv, VALUE self)
2432{
2433 ENTER(5);
2434 VALUE vexp, prec;
2435 Real* exp = NULL;
2436 Real *x, *y;
2437 ssize_t mp, ma, n;
2438 SIGNED_VALUE int_exp;
2439 double d;
2440
2441 rb_scan_args(argc, argv, "11", &vexp, &prec);
2442
2443 GUARD_OBJ(x, GetVpValue(self, 1));
2444 n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2445
2446 if (VpIsNaN(x)) {
2447 y = VpCreateRbObject(n, "0");
2448 RB_GC_GUARD(y->obj);
2449 VpSetNaN(y);
2450 return ToValue(y);
2451 }
2452
2453 retry:
2454 switch (TYPE(vexp)) {
2455 case T_FIXNUM:
2456 break;
2457
2458 case T_BIGNUM:
2459 break;
2460
2461 case T_FLOAT:
2462 d = RFLOAT_VALUE(vexp);
2463 if (d == round(d)) {
2464 if (FIXABLE(d)) {
2465 vexp = LONG2FIX((long)d);
2466 }
2467 else {
2468 vexp = rb_dbl2big(d);
2469 }
2470 goto retry;
2471 }
2472 if (NIL_P(prec)) {
2473 n += DBLE_FIG;
2474 }
2475 exp = GetVpValueWithPrec(vexp, DBLE_FIG, 1);
2476 break;
2477
2478 case T_RATIONAL:
2479 if (is_zero(rb_rational_num(vexp))) {
2480 if (is_positive(vexp)) {
2481 vexp = INT2FIX(0);
2482 goto retry;
2483 }
2484 }
2485 else if (is_one(rb_rational_den(vexp))) {
2486 vexp = rb_rational_num(vexp);
2487 goto retry;
2488 }
2489 exp = GetVpValueWithPrec(vexp, n, 1);
2490 if (NIL_P(prec)) {
2491 n += n;
2492 }
2493 break;
2494
2495 case T_DATA:
2496 if (is_kind_of_BigDecimal(vexp)) {
2497 VALUE zero = INT2FIX(0);
2498 VALUE rounded = BigDecimal_round(1, &zero, vexp);
2499 if (RTEST(BigDecimal_eq(vexp, rounded))) {
2500 vexp = BigDecimal_to_i(vexp);
2501 goto retry;
2502 }
2503 if (NIL_P(prec)) {
2504 GUARD_OBJ(y, GetVpValue(vexp, 1));
2505 n += y->Prec*VpBaseFig();
2506 }
2507 exp = DATA_PTR(vexp);
2508 break;
2509 }
2510 /* fall through */
2511 default:
2512 rb_raise(rb_eTypeError,
2513 "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
2514 RB_OBJ_CLASSNAME(vexp));
2515 }
2516
2517 if (VpIsZero(x)) {
2518 if (is_negative(vexp)) {
2519 y = VpCreateRbObject(n, "#0");
2520 RB_GC_GUARD(y->obj);
2521 if (BIGDECIMAL_NEGATIVE_P(x)) {
2522 if (is_integer(vexp)) {
2523 if (is_even(vexp)) {
2524 /* (-0) ** (-even_integer) -> Infinity */
2525 VpSetPosInf(y);
2526 }
2527 else {
2528 /* (-0) ** (-odd_integer) -> -Infinity */
2529 VpSetNegInf(y);
2530 }
2531 }
2532 else {
2533 /* (-0) ** (-non_integer) -> Infinity */
2534 VpSetPosInf(y);
2535 }
2536 }
2537 else {
2538 /* (+0) ** (-num) -> Infinity */
2539 VpSetPosInf(y);
2540 }
2541 return ToValue(y);
2542 }
2543 else if (is_zero(vexp)) {
2544 return ToValue(VpCreateRbObject(n, "1"));
2545 }
2546 else {
2547 return ToValue(VpCreateRbObject(n, "0"));
2548 }
2549 }
2550
2551 if (is_zero(vexp)) {
2552 return ToValue(VpCreateRbObject(n, "1"));
2553 }
2554 else if (is_one(vexp)) {
2555 return self;
2556 }
2557
2558 if (VpIsInf(x)) {
2559 if (is_negative(vexp)) {
2560 if (BIGDECIMAL_NEGATIVE_P(x)) {
2561 if (is_integer(vexp)) {
2562 if (is_even(vexp)) {
2563 /* (-Infinity) ** (-even_integer) -> +0 */
2564 return ToValue(VpCreateRbObject(n, "0"));
2565 }
2566 else {
2567 /* (-Infinity) ** (-odd_integer) -> -0 */
2568 return ToValue(VpCreateRbObject(n, "-0"));
2569 }
2570 }
2571 else {
2572 /* (-Infinity) ** (-non_integer) -> -0 */
2573 return ToValue(VpCreateRbObject(n, "-0"));
2574 }
2575 }
2576 else {
2577 return ToValue(VpCreateRbObject(n, "0"));
2578 }
2579 }
2580 else {
2581 y = VpCreateRbObject(n, "0");
2582 if (BIGDECIMAL_NEGATIVE_P(x)) {
2583 if (is_integer(vexp)) {
2584 if (is_even(vexp)) {
2585 VpSetPosInf(y);
2586 }
2587 else {
2588 VpSetNegInf(y);
2589 }
2590 }
2591 else {
2592 /* TODO: support complex */
2593 rb_raise(rb_eMathDomainError,
2594 "a non-integral exponent for a negative base");
2595 }
2596 }
2597 else {
2598 VpSetPosInf(y);
2599 }
2600 return ToValue(y);
2601 }
2602 }
2603
2604 if (exp != NULL) {
2605 return rmpd_power_by_big_decimal(x, exp, n);
2606 }
2607 else if (RB_TYPE_P(vexp, T_BIGNUM)) {
2608 VALUE abs_value = BigDecimal_abs(self);
2609 if (is_one(abs_value)) {
2610 return ToValue(VpCreateRbObject(n, "1"));
2611 }
2612 else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
2613 if (is_negative(vexp)) {
2614 y = VpCreateRbObject(n, "0");
2615 if (is_even(vexp)) {
2616 VpSetInf(y, VpGetSign(x));
2617 }
2618 else {
2619 VpSetInf(y, -VpGetSign(x));
2620 }
2621 return ToValue(y);
2622 }
2623 else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
2624 return ToValue(VpCreateRbObject(n, "-0"));
2625 }
2626 else {
2627 return ToValue(VpCreateRbObject(n, "0"));
2628 }
2629 }
2630 else {
2631 if (is_positive(vexp)) {
2632 y = VpCreateRbObject(n, "0");
2633 if (is_even(vexp)) {
2634 VpSetInf(y, VpGetSign(x));
2635 }
2636 else {
2637 VpSetInf(y, -VpGetSign(x));
2638 }
2639 return ToValue(y);
2640 }
2641 else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
2642 return ToValue(VpCreateRbObject(n, "-0"));
2643 }
2644 else {
2645 return ToValue(VpCreateRbObject(n, "0"));
2646 }
2647 }
2648 }
2649
2650 int_exp = FIX2LONG(vexp);
2651 ma = int_exp;
2652 if (ma < 0) ma = -ma;
2653 if (ma == 0) ma = 1;
2654
2655 if (VpIsDef(x)) {
2656 mp = x->Prec * (VpBaseFig() + 1);
2657 GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0"));
2658 }
2659 else {
2660 GUARD_OBJ(y, VpCreateRbObject(1, "0"));
2661 }
2662 VpPower(y, x, int_exp);
2663 if (!NIL_P(prec) && VpIsDef(y)) {
2664 VpMidRound(y, VpGetRoundMode(), n);
2665 }
2666 return ToValue(y);
2667}
2668
2669/* call-seq:
2670 * a ** n -> bigdecimal
2671 *
2672 * Returns the value raised to the power of n.
2673 *
2674 * See BigDecimal#power.
2675 */
2676static VALUE
2677BigDecimal_power_op(VALUE self, VALUE exp)
2678{
2679 return BigDecimal_power(1, &exp, self);
2680}
2681
2682/* :nodoc:
2683 *
2684 * private method for dup and clone the provided BigDecimal +other+
2685 */
2686static VALUE
2687BigDecimal_initialize_copy(VALUE self, VALUE other)
2688{
2689 Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
2690 Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
2691
2692 if (self != other) {
2693 DATA_PTR(self) = VpCopy(pv, x);
2694 }
2695 return self;
2696}
2697
2698static VALUE
2699BigDecimal_clone(VALUE self)
2700{
2701 return self;
2702}
2703
2704#ifdef HAVE_RB_OPTS_EXCEPTION_P
2705int rb_opts_exception_p(VALUE opts, int default_value);
2706#define opts_exception_p(opts) rb_opts_exception_p((opts), 1)
2707#else
2708static int
2709 opts_exception_p(VALUE opts)
2710{
2711 static ID kwds[1];
2712 VALUE exception;
2713 if (!kwds[0]) {
2714 kwds[0] = rb_intern_const("exception");
2715 }
2716 if (!rb_get_kwargs(opts, kwds, 0, 1, &exception)) return 1;
2717 switch (exception) {
2718 case Qtrue: case Qfalse:
2719 break;
2720 default:
2721 rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE,
2722 exception);
2723 }
2724 return exception != Qfalse;
2725}
2726#endif
2727
2728static Real *
2729VpNewVarArg(int argc, VALUE *argv)
2730{
2731 size_t mf;
2732 VALUE opts = Qnil;
2733 VALUE nFig;
2734 VALUE iniValue;
2735 double d;
2736 int exc;
2737
2738 argc = rb_scan_args(argc, argv, "11:", &iniValue, &nFig, &opts);
2739 exc = opts_exception_p(opts);
2740
2741 if (argc == 1) {
2742 mf = 0;
2743 }
2744 else {
2745 /* expand GetPrecisionInt for exception suppression */
2746 ssize_t n = NUM2INT(nFig);
2747 if (n < 0) {
2748 if (!exc) {
2749 return NULL;
2750 }
2751 rb_raise(rb_eArgError, "negative precision");
2752 }
2753 mf = (size_t)n;
2754 }
2755
2756 if (SPECIAL_CONST_P(iniValue)) {
2757 switch (iniValue) {
2758 case Qnil:
2759 if (!exc) return NULL;
2760 rb_raise(rb_eTypeError, "can't convert nil into BigDecimal");
2761 case Qtrue:
2762 if (!exc) return NULL;
2763 rb_raise(rb_eTypeError, "can't convert true into BigDecimal");
2764 case Qfalse:
2765 if (!exc) return NULL;
2766 rb_raise(rb_eTypeError, "can't convert false into BigDecimal");
2767 default:
2768 break;
2769 }
2770 }
2771
2772 retry:
2773 switch (TYPE(iniValue)) {
2774 case T_DATA:
2775 if (is_kind_of_BigDecimal(iniValue)) {
2776 return DATA_PTR(iniValue);
2777 }
2778 break;
2779
2780 case T_FIXNUM:
2781 /* fall through */
2782 case T_BIGNUM:
2783 return GetVpValue(iniValue, 1);
2784
2785 case T_FLOAT:
2786 d = RFLOAT_VALUE(iniValue);
2787 if (!isfinite(d)) {
2788 Real *pv = VpCreateRbObject(1, NULL);
2789 VpDtoV(pv, d);
2790 return pv;
2791 }
2792 if (mf > DBLE_FIG) {
2793 if (!exc) {
2794 return NULL;
2795 }
2796 rb_raise(rb_eArgError, "precision too large.");
2797 }
2798 /* fall through */
2799 case T_RATIONAL:
2800 if (NIL_P(nFig)) {
2801 if (!exc) {
2802 return NULL;
2803 }
2804 rb_raise(rb_eArgError,
2805 "can't omit precision for a %"PRIsVALUE".",
2806 RB_OBJ_CLASSNAME(iniValue));
2807 }
2808 return GetVpValueWithPrec(iniValue, mf, 1);
2809
2810 case T_COMPLEX:
2811 {
2812 VALUE im;
2813 im = rb_complex_imag(iniValue);
2814 if (!is_zero(im)) {
2815 rb_raise(rb_eArgError,
2816 "Unable to make a BigDecimal from non-zero imaginary number");
2817 }
2818 iniValue = rb_complex_real(iniValue);
2819 goto retry;
2820 }
2821
2822 case T_STRING:
2823 /* fall through */
2824 default:
2825 break;
2826 }
2827 /* TODO: support to_d */
2828 if (!exc) {
2829 iniValue = rb_check_convert_type(iniValue, T_STRING, "String", "to_str");
2830 if (NIL_P(iniValue)) return NULL;
2831 }
2832 StringValueCStr(iniValue);
2833 return VpAlloc(mf, RSTRING_PTR(iniValue), 1, exc);
2834}
2835
2836/* call-seq:
2837 * BigDecimal(initial, digits, exception: true)
2838 *
2839 * Create a new BigDecimal object.
2840 *
2841 * initial:: The initial value, as an Integer, a Float, a Rational,
2842 * a BigDecimal, or a String.
2843 *
2844 * If it is a String, spaces are ignored and unrecognized characters
2845 * terminate the value.
2846 *
2847 * digits:: The number of significant digits, as an Integer. If omitted or 0,
2848 * the number of significant digits is determined from the initial
2849 * value.
2850 *
2851 * The actual number of significant digits used in computation is
2852 * usually larger than the specified number.
2853 *
2854 * exception:: Whether an exception should be raised on invalid arguments.
2855 * +true+ by default, if passed +false+, just returns +nil+
2856 * for invalid.
2857 *
2858 *
2859 * ==== Exceptions
2860 *
2861 * TypeError:: If the +initial+ type is neither Integer, Float,
2862 * Rational, nor BigDecimal, this exception is raised.
2863 *
2864 * TypeError:: If the +digits+ is not an Integer, this exception is raised.
2865 *
2866 * ArgumentError:: If +initial+ is a Float, and the +digits+ is larger than
2867 * Float::DIG + 1, this exception is raised.
2868 *
2869 * ArgumentError:: If the +initial+ is a Float or Rational, and the +digits+
2870 * value is omitted, this exception is raised.
2871 */
2872static VALUE
2873f_BigDecimal(int argc, VALUE *argv, VALUE self)
2874{
2875 ENTER(1);
2876 Real *pv;
2877 VALUE obj;
2878
2879 if (argc > 0 && CLASS_OF(argv[0]) == rb_cBigDecimal) {
2880 if (argc == 1 || (argc == 2 && RB_TYPE_P(argv[1], T_HASH))) return argv[0];
2881 }
2882 obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
2883 pv = VpNewVarArg(argc, argv);
2884 if (pv == NULL) return Qnil;
2885 SAVE(pv);
2886 if (ToValue(pv)) pv = VpCopy(NULL, pv);
2887 RTYPEDDATA_DATA(obj) = pv;
2888 RB_OBJ_FREEZE(obj);
2889 return pv->obj = obj;
2890}
2891
2892static VALUE
2893BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
2894{
2895 ENTER(1);
2896 char const *c_str;
2897 Real *pv;
2898
2899 c_str = StringValueCStr(str);
2900 GUARD_OBJ(pv, VpAlloc(0, c_str, 0, 1));
2901 pv->obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, pv);
2902 RB_OBJ_FREEZE(pv->obj);
2903 return pv->obj;
2904}
2905
2906 /* call-seq:
2907 * BigDecimal.limit(digits)
2908 *
2909 * Limit the number of significant digits in newly created BigDecimal
2910 * numbers to the specified value. Rounding is performed as necessary,
2911 * as specified by BigDecimal.mode.
2912 *
2913 * A limit of 0, the default, means no upper limit.
2914 *
2915 * The limit specified by this method takes less priority over any limit
2916 * specified to instance methods such as ceil, floor, truncate, or round.
2917 */
2918static VALUE
2919BigDecimal_limit(int argc, VALUE *argv, VALUE self)
2920{
2921 VALUE nFig;
2922 VALUE nCur = SIZET2NUM(VpGetPrecLimit());
2923
2924 if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
2925 int nf;
2926 if (NIL_P(nFig)) return nCur;
2927 nf = NUM2INT(nFig);
2928 if (nf < 0) {
2929 rb_raise(rb_eArgError, "argument must be positive");
2930 }
2931 VpSetPrecLimit(nf);
2932 }
2933 return nCur;
2934}
2935
2936/* Returns the sign of the value.
2937 *
2938 * Returns a positive value if > 0, a negative value if < 0, and a
2939 * zero if == 0.
2940 *
2941 * The specific value returned indicates the type and sign of the BigDecimal,
2942 * as follows:
2943 *
2944 * BigDecimal::SIGN_NaN:: value is Not a Number
2945 * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0
2946 * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0
2947 * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +Infinity
2948 * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -Infinity
2949 * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive
2950 * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
2951 */
2952static VALUE
2953BigDecimal_sign(VALUE self)
2954{ /* sign */
2955 int s = GetVpValue(self, 1)->sign;
2956 return INT2FIX(s);
2957}
2958
2959/*
2960 * call-seq: BigDecimal.save_exception_mode { ... }
2961 *
2962 * Execute the provided block, but preserve the exception mode
2963 *
2964 * BigDecimal.save_exception_mode do
2965 * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
2966 * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
2967 *
2968 * BigDecimal(BigDecimal('Infinity'))
2969 * BigDecimal(BigDecimal('-Infinity'))
2970 * BigDecimal(BigDecimal('NaN'))
2971 * end
2972 *
2973 * For use with the BigDecimal::EXCEPTION_*
2974 *
2975 * See BigDecimal.mode
2976 */
2977static VALUE
2978BigDecimal_save_exception_mode(VALUE self)
2979{
2980 unsigned short const exception_mode = VpGetException();
2981 int state;
2982 VALUE ret = rb_protect(rb_yield, Qnil, &state);
2983 VpSetException(exception_mode);
2984 if (state) rb_jump_tag(state);
2985 return ret;
2986}
2987
2988/*
2989 * call-seq: BigDecimal.save_rounding_mode { ... }
2990 *
2991 * Execute the provided block, but preserve the rounding mode
2992 *
2993 * BigDecimal.save_rounding_mode do
2994 * BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
2995 * puts BigDecimal.mode(BigDecimal::ROUND_MODE)
2996 * end
2997 *
2998 * For use with the BigDecimal::ROUND_*
2999 *
3000 * See BigDecimal.mode
3001 */
3002static VALUE
3003BigDecimal_save_rounding_mode(VALUE self)
3004{
3005 unsigned short const round_mode = VpGetRoundMode();
3006 int state;
3007 VALUE ret = rb_protect(rb_yield, Qnil, &state);
3008 VpSetRoundMode(round_mode);
3009 if (state) rb_jump_tag(state);
3010 return ret;
3011}
3012
3013/*
3014 * call-seq: BigDecimal.save_limit { ... }
3015 *
3016 * Execute the provided block, but preserve the precision limit
3017 *
3018 * BigDecimal.limit(100)
3019 * puts BigDecimal.limit
3020 * BigDecimal.save_limit do
3021 * BigDecimal.limit(200)
3022 * puts BigDecimal.limit
3023 * end
3024 * puts BigDecimal.limit
3025 *
3026 */
3027static VALUE
3028BigDecimal_save_limit(VALUE self)
3029{
3030 size_t const limit = VpGetPrecLimit();
3031 int state;
3032 VALUE ret = rb_protect(rb_yield, Qnil, &state);
3033 VpSetPrecLimit(limit);
3034 if (state) rb_jump_tag(state);
3035 return ret;
3036}
3037
3038/* call-seq:
3039 * BigMath.exp(decimal, numeric) -> BigDecimal
3040 *
3041 * Computes the value of e (the base of natural logarithms) raised to the
3042 * power of +decimal+, to the specified number of digits of precision.
3043 *
3044 * If +decimal+ is infinity, returns Infinity.
3045 *
3046 * If +decimal+ is NaN, returns NaN.
3047 */
3048static VALUE
3049BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3050{
3051 ssize_t prec, n, i;
3052 Real* vx = NULL;
3053 VALUE one, d, y;
3054 int negative = 0;
3055 int infinite = 0;
3056 int nan = 0;
3057 double flo;
3058
3059 prec = NUM2SSIZET(vprec);
3060 if (prec <= 0) {
3061 rb_raise(rb_eArgError, "Zero or negative precision for exp");
3062 }
3063
3064 /* TODO: the following switch statement is almost same as one in the
3065 * BigDecimalCmp function. */
3066 switch (TYPE(x)) {
3067 case T_DATA:
3068 if (!is_kind_of_BigDecimal(x)) break;
3069 vx = DATA_PTR(x);
3070 negative = BIGDECIMAL_NEGATIVE_P(vx);
3071 infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3072 nan = VpIsNaN(vx);
3073 break;
3074
3075 case T_FIXNUM:
3076 /* fall through */
3077 case T_BIGNUM:
3078 vx = GetVpValue(x, 0);
3079 break;
3080
3081 case T_FLOAT:
3082 flo = RFLOAT_VALUE(x);
3083 negative = flo < 0;
3084 infinite = isinf(flo);
3085 nan = isnan(flo);
3086 if (!infinite && !nan) {
3087 vx = GetVpValueWithPrec(x, DBLE_FIG, 0);
3088 }
3089 break;
3090
3091 case T_RATIONAL:
3092 vx = GetVpValueWithPrec(x, prec, 0);
3093 break;
3094
3095 default:
3096 break;
3097 }
3098 if (infinite) {
3099 if (negative) {
3100 return ToValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3101 }
3102 else {
3103 Real* vy;
3104 vy = VpCreateRbObject(prec, "#0");
3105 VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3106 RB_GC_GUARD(vy->obj);
3107 return ToValue(vy);
3108 }
3109 }
3110 else if (nan) {
3111 Real* vy;
3112 vy = VpCreateRbObject(prec, "#0");
3113 VpSetNaN(vy);
3114 RB_GC_GUARD(vy->obj);
3115 return ToValue(vy);
3116 }
3117 else if (vx == NULL) {
3118 cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
3119 }
3120 x = vx->obj;
3121
3122 n = prec + rmpd_double_figures();
3123 negative = BIGDECIMAL_NEGATIVE_P(vx);
3124 if (negative) {
3125 VALUE x_zero = INT2NUM(1);
3126 VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
3127 x = BigDecimal_initialize_copy(x_copy, x);
3128 vx = DATA_PTR(x);
3129 VpSetSign(vx, 1);
3130 }
3131
3132 one = ToValue(VpCreateRbObject(1, "1"));
3133 y = one;
3134 d = y;
3135 i = 1;
3136
3137 while (!VpIsZero((Real*)DATA_PTR(d))) {
3138 SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
3139 SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
3140 ssize_t m = n - vabs(ey - ed);
3141
3142 rb_thread_check_ints();
3143
3144 if (m <= 0) {
3145 break;
3146 }
3147 else if ((size_t)m < rmpd_double_figures()) {
3148 m = rmpd_double_figures();
3149 }
3150
3151 d = BigDecimal_mult(d, x); /* d <- d * x */
3152 d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
3153 y = BigDecimal_add(y, d); /* y <- y + d */
3154 ++i; /* i <- i + 1 */
3155 }
3156
3157 if (negative) {
3158 return BigDecimal_div2(one, y, vprec);
3159 }
3160 else {
3161 vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
3162 return BigDecimal_round(1, &vprec, y);
3163 }
3164
3165 RB_GC_GUARD(one);
3166 RB_GC_GUARD(x);
3167 RB_GC_GUARD(y);
3168 RB_GC_GUARD(d);
3169}
3170
3171/* call-seq:
3172 * BigMath.log(decimal, numeric) -> BigDecimal
3173 *
3174 * Computes the natural logarithm of +decimal+ to the specified number of
3175 * digits of precision, +numeric+.
3176 *
3177 * If +decimal+ is zero or negative, raises Math::DomainError.
3178 *
3179 * If +decimal+ is positive infinity, returns Infinity.
3180 *
3181 * If +decimal+ is NaN, returns NaN.
3182 */
3183static VALUE
3184BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
3185{
3186 ssize_t prec, n, i;
3187 SIGNED_VALUE expo;
3188 Real* vx = NULL;
3189 VALUE vn, one, two, w, x2, y, d;
3190 int zero = 0;
3191 int negative = 0;
3192 int infinite = 0;
3193 int nan = 0;
3194 double flo;
3195 long fix;
3196
3197 if (!is_integer(vprec)) {
3198 rb_raise(rb_eArgError, "precision must be an Integer");
3199 }
3200
3201 prec = NUM2SSIZET(vprec);
3202 if (prec <= 0) {
3203 rb_raise(rb_eArgError, "Zero or negative precision for exp");
3204 }
3205
3206 /* TODO: the following switch statement is almost same as one in the
3207 * BigDecimalCmp function. */
3208 switch (TYPE(x)) {
3209 case T_DATA:
3210 if (!is_kind_of_BigDecimal(x)) break;
3211 vx = DATA_PTR(x);
3212 zero = VpIsZero(vx);
3213 negative = BIGDECIMAL_NEGATIVE_P(vx);
3214 infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3215 nan = VpIsNaN(vx);
3216 break;
3217
3218 case T_FIXNUM:
3219 fix = FIX2LONG(x);
3220 zero = fix == 0;
3221 negative = fix < 0;
3222 goto get_vp_value;
3223
3224 case T_BIGNUM:
3225 i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
3226 zero = i == 0;
3227 negative = i < 0;
3228get_vp_value:
3229 if (zero || negative) break;
3230 vx = GetVpValue(x, 0);
3231 break;
3232
3233 case T_FLOAT:
3234 flo = RFLOAT_VALUE(x);
3235 zero = flo == 0;
3236 negative = flo < 0;
3237 infinite = isinf(flo);
3238 nan = isnan(flo);
3239 if (!zero && !negative && !infinite && !nan) {
3240 vx = GetVpValueWithPrec(x, DBLE_FIG, 1);
3241 }
3242 break;
3243
3244 case T_RATIONAL:
3245 zero = RRATIONAL_ZERO_P(x);
3246 negative = RRATIONAL_NEGATIVE_P(x);
3247 if (zero || negative) break;
3248 vx = GetVpValueWithPrec(x, prec, 1);
3249 break;
3250
3251 case T_COMPLEX:
3252 rb_raise(rb_eMathDomainError,
3253 "Complex argument for BigMath.log");
3254
3255 default:
3256 break;
3257 }
3258 if (infinite && !negative) {
3259 Real* vy;
3260 vy = VpCreateRbObject(prec, "#0");
3261 RB_GC_GUARD(vy->obj);
3262 VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3263 return ToValue(vy);
3264 }
3265 else if (nan) {
3266 Real* vy;
3267 vy = VpCreateRbObject(prec, "#0");
3268 RB_GC_GUARD(vy->obj);
3269 VpSetNaN(vy);
3270 return ToValue(vy);
3271 }
3272 else if (zero || negative) {
3273 rb_raise(rb_eMathDomainError,
3274 "Zero or negative argument for log");
3275 }
3276 else if (vx == NULL) {
3277 cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
3278 }
3279 x = ToValue(vx);
3280
3281 RB_GC_GUARD(one) = ToValue(VpCreateRbObject(1, "1"));
3282 RB_GC_GUARD(two) = ToValue(VpCreateRbObject(1, "2"));
3283
3284 n = prec + rmpd_double_figures();
3285 RB_GC_GUARD(vn) = SSIZET2NUM(n);
3286 expo = VpExponent10(vx);
3287 if (expo < 0 || expo >= 3) {
3288 char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
3289 snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
3290 x = BigDecimal_mult2(x, ToValue(VpCreateRbObject(1, buf)), vn);
3291 }
3292 else {
3293 expo = 0;
3294 }
3295 w = BigDecimal_sub(x, one);
3296 x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
3297 RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
3298 RB_GC_GUARD(y) = x;
3299 RB_GC_GUARD(d) = y;
3300 i = 1;
3301 while (!VpIsZero((Real*)DATA_PTR(d))) {
3302 SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
3303 SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
3304 ssize_t m = n - vabs(ey - ed);
3305 if (m <= 0) {
3306 break;
3307 }
3308 else if ((size_t)m < rmpd_double_figures()) {
3309 m = rmpd_double_figures();
3310 }
3311
3312 x = BigDecimal_mult2(x2, x, vn);
3313 i += 2;
3314 d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
3315 y = BigDecimal_add(y, d);
3316 }
3317
3318 y = BigDecimal_mult(y, two);
3319 if (expo != 0) {
3320 VALUE log10, vexpo, dy;
3321 log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
3322 vexpo = ToValue(GetVpValue(SSIZET2NUM(expo), 1));
3323 dy = BigDecimal_mult(log10, vexpo);
3324 y = BigDecimal_add(y, dy);
3325 }
3326
3327 return y;
3328}
3329
3330/* Document-class: BigDecimal
3331 * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
3332 *
3333 * == Introduction
3334 *
3335 * Ruby provides built-in support for arbitrary precision integer arithmetic.
3336 *
3337 * For example:
3338 *
3339 * 42**13 #=> 1265437718438866624512
3340 *
3341 * BigDecimal provides similar support for very large or very accurate floating
3342 * point numbers.
3343 *
3344 * Decimal arithmetic is also useful for general calculation, because it
3345 * provides the correct answers people expect--whereas normal binary floating
3346 * point arithmetic often introduces subtle errors because of the conversion
3347 * between base 10 and base 2.
3348 *
3349 * For example, try:
3350 *
3351 * sum = 0
3352 * 10_000.times do
3353 * sum = sum + 0.0001
3354 * end
3355 * print sum #=> 0.9999999999999062
3356 *
3357 * and contrast with the output from:
3358 *
3359 * require 'bigdecimal'
3360 *
3361 * sum = BigDecimal("0")
3362 * 10_000.times do
3363 * sum = sum + BigDecimal("0.0001")
3364 * end
3365 * print sum #=> 0.1E1
3366 *
3367 * Similarly:
3368 *
3369 * (BigDecimal("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true
3370 *
3371 * (1.2 - 1.0) == 0.2 #=> false
3372 *
3373 * == Special features of accurate decimal arithmetic
3374 *
3375 * Because BigDecimal is more accurate than normal binary floating point
3376 * arithmetic, it requires some special values.
3377 *
3378 * === Infinity
3379 *
3380 * BigDecimal sometimes needs to return infinity, for example if you divide
3381 * a value by zero.
3382 *
3383 * BigDecimal("1.0") / BigDecimal("0.0") #=> Infinity
3384 * BigDecimal("-1.0") / BigDecimal("0.0") #=> -Infinity
3385 *
3386 * You can represent infinite numbers to BigDecimal using the strings
3387 * <code>'Infinity'</code>, <code>'+Infinity'</code> and
3388 * <code>'-Infinity'</code> (case-sensitive)
3389 *
3390 * === Not a Number
3391 *
3392 * When a computation results in an undefined value, the special value +NaN+
3393 * (for 'not a number') is returned.
3394 *
3395 * Example:
3396 *
3397 * BigDecimal("0.0") / BigDecimal("0.0") #=> NaN
3398 *
3399 * You can also create undefined values.
3400 *
3401 * NaN is never considered to be the same as any other value, even NaN itself:
3402 *
3403 * n = BigDecimal('NaN')
3404 * n == 0.0 #=> false
3405 * n == n #=> false
3406 *
3407 * === Positive and negative zero
3408 *
3409 * If a computation results in a value which is too small to be represented as
3410 * a BigDecimal within the currently specified limits of precision, zero must
3411 * be returned.
3412 *
3413 * If the value which is too small to be represented is negative, a BigDecimal
3414 * value of negative zero is returned.
3415 *
3416 * BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0
3417 *
3418 * If the value is positive, a value of positive zero is returned.
3419 *
3420 * BigDecimal("1.0") / BigDecimal("Infinity") #=> 0.0
3421 *
3422 * (See BigDecimal.mode for how to specify limits of precision.)
3423 *
3424 * Note that +-0.0+ and +0.0+ are considered to be the same for the purposes of
3425 * comparison.
3426 *
3427 * Note also that in mathematics, there is no particular concept of negative
3428 * or positive zero; true mathematical zero has no sign.
3429 *
3430 * == bigdecimal/util
3431 *
3432 * When you require +bigdecimal/util+, the #to_d method will be
3433 * available on BigDecimal and the native Integer, Float, Rational,
3434 * and String classes:
3435 *
3436 * require 'bigdecimal/util'
3437 *
3438 * 42.to_d # => 0.42e2
3439 * 0.5.to_d # => 0.5e0
3440 * (2/3r).to_d(3) # => 0.667e0
3441 * "0.5".to_d # => 0.5e0
3442 *
3443 * == License
3444 *
3445 * Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
3446 *
3447 * BigDecimal is released under the Ruby and 2-clause BSD licenses.
3448 * See LICENSE.txt for details.
3449 *
3450 * Maintained by mrkn <mrkn@mrkn.jp> and ruby-core members.
3451 *
3452 * Documented by zzak <zachary@zacharyscott.net>, mathew <meta@pobox.com>, and
3453 * many other contributors.
3454 */
3455void
3456Init_bigdecimal(void)
3457{
3458#ifdef HAVE_RB_EXT_RACTOR_SAFE
3459 rb_ext_ractor_safe(true);
3460#endif
3461 VALUE arg;
3462
3463 id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
3464 id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode");
3465 id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit");
3466
3467 /* Initialize VP routines */
3468 VpInit(0UL);
3469
3470 /* Class and method registration */
3471 rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric);
3472
3473 /* Global function */
3474 rb_define_global_function("BigDecimal", f_BigDecimal, -1);
3475
3476 /* Class methods */
3477 rb_undef_alloc_func(rb_cBigDecimal);
3478 rb_undef_method(CLASS_OF(rb_cBigDecimal), "new");
3479 rb_define_singleton_method(rb_cBigDecimal, "interpret_loosely", BigDecimal_s_interpret_loosely, 1);
3480 rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
3481 rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
3482 rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
3483 rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
3484
3485 rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
3486 rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
3487 rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0);
3488
3489 /* Constants definition */
3490
3491#ifndef RUBY_BIGDECIMAL_VERSION
3492# error RUBY_BIGDECIMAL_VERSION is not defined
3493#endif
3494 /*
3495 * The version of bigdecimal library
3496 */
3497 rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(RUBY_BIGDECIMAL_VERSION));
3498
3499 /*
3500 * Base value used in internal calculations. On a 32 bit system, BASE
3501 * is 10000, indicating that calculation is done in groups of 4 digits.
3502 * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
3503 * guarantee that two groups could always be multiplied together without
3504 * overflow.)
3505 */
3506 rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3507
3508 /* Exceptions */
3509
3510 /*
3511 * 0xff: Determines whether overflow, underflow or zero divide result in
3512 * an exception being thrown. See BigDecimal.mode.
3513 */
3514 rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL", INT2FIX(VP_EXCEPTION_ALL));
3515
3516 /*
3517 * 0x02: Determines what happens when the result of a computation is not a
3518 * number (NaN). See BigDecimal.mode.
3519 */
3520 rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN", INT2FIX(VP_EXCEPTION_NaN));
3521
3522 /*
3523 * 0x01: Determines what happens when the result of a computation is
3524 * infinity. See BigDecimal.mode.
3525 */
3526 rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY", INT2FIX(VP_EXCEPTION_INFINITY));
3527
3528 /*
3529 * 0x04: Determines what happens when the result of a computation is an
3530 * underflow (a result too small to be represented). See BigDecimal.mode.
3531 */
3532 rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW", INT2FIX(VP_EXCEPTION_UNDERFLOW));
3533
3534 /*
3535 * 0x01: Determines what happens when the result of a computation is an
3536 * overflow (a result too large to be represented). See BigDecimal.mode.
3537 */
3538 rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW", INT2FIX(VP_EXCEPTION_OVERFLOW));
3539
3540 /*
3541 * 0x10: Determines what happens when a division by zero is performed.
3542 * See BigDecimal.mode.
3543 */
3544 rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE", INT2FIX(VP_EXCEPTION_ZERODIVIDE));
3545
3546 /*
3547 * 0x100: Determines what happens when a result must be rounded in order to
3548 * fit in the appropriate number of significant digits. See
3549 * BigDecimal.mode.
3550 */
3551 rb_define_const(rb_cBigDecimal, "ROUND_MODE", INT2FIX(VP_ROUND_MODE));
3552
3553 /* 1: Indicates that values should be rounded away from zero. See
3554 * BigDecimal.mode.
3555 */
3556 rb_define_const(rb_cBigDecimal, "ROUND_UP", INT2FIX(VP_ROUND_UP));
3557
3558 /* 2: Indicates that values should be rounded towards zero. See
3559 * BigDecimal.mode.
3560 */
3561 rb_define_const(rb_cBigDecimal, "ROUND_DOWN", INT2FIX(VP_ROUND_DOWN));
3562
3563 /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
3564 * See BigDecimal.mode. */
3565 rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP", INT2FIX(VP_ROUND_HALF_UP));
3566
3567 /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
3568 * See BigDecimal.mode.
3569 */
3570 rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN", INT2FIX(VP_ROUND_HALF_DOWN));
3571 /* 5: Round towards +Infinity. See BigDecimal.mode. */
3572 rb_define_const(rb_cBigDecimal, "ROUND_CEILING", INT2FIX(VP_ROUND_CEIL));
3573
3574 /* 6: Round towards -Infinity. See BigDecimal.mode. */
3575 rb_define_const(rb_cBigDecimal, "ROUND_FLOOR", INT2FIX(VP_ROUND_FLOOR));
3576
3577 /* 7: Round towards the even neighbor. See BigDecimal.mode. */
3578 rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN", INT2FIX(VP_ROUND_HALF_EVEN));
3579
3580 /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
3581 rb_define_const(rb_cBigDecimal, "SIGN_NaN", INT2FIX(VP_SIGN_NaN));
3582
3583 /* 1: Indicates that a value is +0. See BigDecimal.sign. */
3584 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO", INT2FIX(VP_SIGN_POSITIVE_ZERO));
3585
3586 /* -1: Indicates that a value is -0. See BigDecimal.sign. */
3587 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO", INT2FIX(VP_SIGN_NEGATIVE_ZERO));
3588
3589 /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
3590 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE", INT2FIX(VP_SIGN_POSITIVE_FINITE));
3591
3592 /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
3593 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE", INT2FIX(VP_SIGN_NEGATIVE_FINITE));
3594
3595 /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
3596 rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE", INT2FIX(VP_SIGN_POSITIVE_INFINITE));
3597
3598 /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
3599 rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE", INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
3600
3601 arg = rb_str_new2("+Infinity");
3602 /* Positive infinity value. */
3603 rb_define_const(rb_cBigDecimal, "INFINITY", f_BigDecimal(1, &arg, rb_cBigDecimal));
3604 arg = rb_str_new2("NaN");
3605 /* 'Not a Number' value. */
3606 rb_define_const(rb_cBigDecimal, "NAN", f_BigDecimal(1, &arg, rb_cBigDecimal));
3607
3608
3609 /* instance methods */
3610 rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
3611 rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
3612 rb_define_method(rb_cBigDecimal, "n_significant_digits", BigDecimal_n_significant_digits, 0);
3613
3614 rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
3615 rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
3616 rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
3617 rb_define_method(rb_cBigDecimal, "div", BigDecimal_div3, -1);
3618 rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
3619 rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
3620 rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
3621 rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
3622 rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0);
3623 rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
3624 rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
3625 rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
3626 rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
3627 rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
3628 rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
3629 rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
3630 rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
3631 rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
3632 rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
3633 rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
3634 rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
3635 rb_define_method(rb_cBigDecimal, "clone", BigDecimal_clone, 0);
3636 rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
3637 rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
3638 rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
3639 rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
3640 rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
3641 rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
3642 rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
3643 rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
3644 rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
3645 rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
3646 rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
3647 rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
3648 rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
3649 rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
3650 rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
3651 rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
3652 rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
3653 rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
3654 rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
3655 rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
3656 rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
3657 rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
3658 rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
3659 rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
3660 rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
3661 rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0);
3662 rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
3663 rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
3664 rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3665 rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
3666
3667 rb_mBigMath = rb_define_module("BigMath");
3668 rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
3669 rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
3670
3671 id_up = rb_intern_const("up");
3672 id_down = rb_intern_const("down");
3673 id_truncate = rb_intern_const("truncate");
3674 id_half_up = rb_intern_const("half_up");
3675 id_default = rb_intern_const("default");
3676 id_half_down = rb_intern_const("half_down");
3677 id_half_even = rb_intern_const("half_even");
3678 id_banker = rb_intern_const("banker");
3679 id_ceiling = rb_intern_const("ceiling");
3680 id_ceil = rb_intern_const("ceil");
3681 id_floor = rb_intern_const("floor");
3682 id_to_r = rb_intern_const("to_r");
3683 id_eq = rb_intern_const("==");
3684 id_half = rb_intern_const("half");
3685}
3686
3687/*
3688 *
3689 * ============================================================================
3690 *
3691 * vp_ routines begin from here.
3692 *
3693 * ============================================================================
3694 *
3695 */
3696#ifdef BIGDECIMAL_DEBUG
3697static int gfDebug = 1; /* Debug switch */
3698#if 0
3699static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
3700#endif
3701#endif /* BIGDECIMAL_DEBUG */
3702
3703static Real *VpConstOne; /* constant 1.0 */
3704static Real *VpPt5; /* constant 0.5 */
3705#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
3706 /* used in VpSqrt() */
3707
3708/* ETC */
3709#define MemCmp(x,y,z) memcmp(x,y,z)
3710#define StrCmp(x,y) strcmp(x,y)
3711
3712 enum op_sw {
3713 OP_SW_ADD = 1, /* + */
3714 OP_SW_SUB, /* - */
3715 OP_SW_MULT, /* * */
3716 OP_SW_DIV /* / */
3717};
3718
3719static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
3720static int AddExponent(Real *a, SIGNED_VALUE n);
3721static BDIGIT VpAddAbs(Real *a,Real *b,Real *c);
3722static BDIGIT VpSubAbs(Real *a,Real *b,Real *c);
3723static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv);
3724static int VpNmlz(Real *a);
3725static void VpFormatSt(char *psz, size_t fFmt);
3726static int VpRdup(Real *m, size_t ind_m);
3727
3728#ifdef BIGDECIMAL_DEBUG
3729# ifdef HAVE_RB_EXT_RACTOR_SAFE
3730# error Need to make rewiting gnAlloc atomic
3731# endif
3732static int gnAlloc = 0; /* Memory allocation counter */
3733#endif /* BIGDECIMAL_DEBUG */
3734
3735 VP_EXPORT void *
3736VpMemAlloc(size_t mb)
3737{
3738 void *p = xmalloc(mb);
3739 if (!p) {
3740 VpException(VP_EXCEPTION_MEMORY, "failed to allocate memory", 1);
3741 }
3742 memset(p, 0, mb);
3743#ifdef BIGDECIMAL_DEBUG
3744 gnAlloc++; /* Count allocation call */
3745#endif /* BIGDECIMAL_DEBUG */
3746 return p;
3747}
3748
3749 VP_EXPORT void *
3750VpMemRealloc(void *ptr, size_t mb)
3751{
3752 void *p = xrealloc(ptr, mb);
3753 if (!p) {
3754 VpException(VP_EXCEPTION_MEMORY, "failed to allocate memory", 1);
3755 }
3756 return p;
3757}
3758
3759 VP_EXPORT void
3760VpFree(Real *pv)
3761{
3762 if (pv != NULL) {
3763 xfree(pv);
3764#ifdef BIGDECIMAL_DEBUG
3765 gnAlloc--; /* Decrement allocation count */
3766 if (gnAlloc == 0) {
3767 printf(" *************** All memories allocated freed ****************\n");
3768 /*getchar();*/
3769 }
3770 if (gnAlloc < 0) {
3771 printf(" ??????????? Too many memory free calls(%d) ?????????????\n", gnAlloc);
3772 /*getchar();*/
3773 }
3774#endif /* BIGDECIMAL_DEBUG */
3775 }
3776}
3777
3778/*
3779 * EXCEPTION Handling.
3780 */
3781
3782#define rmpd_set_thread_local_exception_mode(mode) \
3783 rb_thread_local_aset( \
3784 rb_thread_current(), \
3785 id_BigDecimal_exception_mode, \
3786 INT2FIX((int)(mode)) \
3787 )
3788
3789static unsigned short
3790VpGetException (void)
3791{
3792 VALUE const vmode = rb_thread_local_aref(
3793 rb_thread_current(),
3794 id_BigDecimal_exception_mode
3795 );
3796
3797 if (NIL_P(vmode)) {
3798 rmpd_set_thread_local_exception_mode(RMPD_EXCEPTION_MODE_DEFAULT);
3799 return RMPD_EXCEPTION_MODE_DEFAULT;
3800 }
3801
3802 return NUM2USHORT(vmode);
3803}
3804
3805static void
3806VpSetException(unsigned short f)
3807{
3808 rmpd_set_thread_local_exception_mode(f);
3809}
3810
3811/*
3812 * Precision limit.
3813 */
3814
3815#define rmpd_set_thread_local_precision_limit(limit) \
3816 rb_thread_local_aset( \
3817 rb_thread_current(), \
3818 id_BigDecimal_precision_limit, \
3819 SIZET2NUM(limit) \
3820 )
3821#define RMPD_PRECISION_LIMIT_DEFAULT ((size_t)0)
3822
3823/* These 2 functions added at v1.1.7 */
3824 VP_EXPORT size_t
3825VpGetPrecLimit(void)
3826{
3827 VALUE const vlimit = rb_thread_local_aref(
3828 rb_thread_current(),
3829 id_BigDecimal_precision_limit
3830 );
3831
3832 if (NIL_P(vlimit)) {
3833 rmpd_set_thread_local_precision_limit(RMPD_PRECISION_LIMIT_DEFAULT);
3834 return RMPD_PRECISION_LIMIT_DEFAULT;
3835 }
3836
3837 return NUM2SIZET(vlimit);
3838}
3839
3840 VP_EXPORT size_t
3841VpSetPrecLimit(size_t n)
3842{
3843 size_t const s = VpGetPrecLimit();
3844 rmpd_set_thread_local_precision_limit(n);
3845 return s;
3846}
3847
3848/*
3849 * Rounding mode.
3850 */
3851
3852#define rmpd_set_thread_local_rounding_mode(mode) \
3853 rb_thread_local_aset( \
3854 rb_thread_current(), \
3855 id_BigDecimal_rounding_mode, \
3856 INT2FIX((int)(mode)) \
3857 )
3858
3859 VP_EXPORT unsigned short
3860VpGetRoundMode(void)
3861{
3862 VALUE const vmode = rb_thread_local_aref(
3863 rb_thread_current(),
3864 id_BigDecimal_rounding_mode
3865 );
3866
3867 if (NIL_P(vmode)) {
3868 rmpd_set_thread_local_rounding_mode(RMPD_ROUNDING_MODE_DEFAULT);
3869 return RMPD_ROUNDING_MODE_DEFAULT;
3870 }
3871
3872 return NUM2USHORT(vmode);
3873}
3874
3875 VP_EXPORT int
3876VpIsRoundMode(unsigned short n)
3877{
3878 switch (n) {
3879 case VP_ROUND_UP:
3880 case VP_ROUND_DOWN:
3881 case VP_ROUND_HALF_UP:
3882 case VP_ROUND_HALF_DOWN:
3883 case VP_ROUND_CEIL:
3884 case VP_ROUND_FLOOR:
3885 case VP_ROUND_HALF_EVEN:
3886 return 1;
3887
3888 default:
3889 return 0;
3890 }
3891}
3892
3893 VP_EXPORT unsigned short
3894VpSetRoundMode(unsigned short n)
3895{
3896 if (VpIsRoundMode(n)) {
3897 rmpd_set_thread_local_rounding_mode(n);
3898 return n;
3899 }
3900
3901 return VpGetRoundMode();
3902}
3903
3904/*
3905 * 0.0 & 1.0 generator
3906 * These gZero_..... and gOne_..... can be any name
3907 * referenced from nowhere except Zero() and One().
3908 * gZero_..... and gOne_..... must have global scope
3909 * (to let the compiler know they may be changed in outside
3910 * (... but not actually..)).
3911 */
3912 volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
3913
3914static double
3915One(void)
3916{
3917 return gOne_ABCED9B4_CE73__00400511F31D;
3918}
3919
3920/*
3921 ----------------------------------------------------------------
3922 Value of sign in Real structure is reserved for future use.
3923 short sign;
3924 ==0 : NaN
3925 1 : Positive zero
3926 -1 : Negative zero
3927 2 : Positive number
3928 -2 : Negative number
3929 3 : Positive infinite number
3930 -3 : Negative infinite number
3931 ----------------------------------------------------------------
3932*/
3933
3934 VP_EXPORT double
3935VpGetDoubleNaN(void) /* Returns the value of NaN */
3936{
3937 return nan("");
3938}
3939
3940 VP_EXPORT double
3941VpGetDoublePosInf(void) /* Returns the value of +Infinity */
3942{
3943 return HUGE_VAL;
3944}
3945
3946 VP_EXPORT double
3947VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
3948{
3949 return -HUGE_VAL;
3950}
3951
3952 VP_EXPORT double
3953VpGetDoubleNegZero(void) /* Returns the value of -0 */
3954{
3955 static double nzero = 1000.0;
3956 if (nzero != 0.0) nzero = (One()/VpGetDoubleNegInf());
3957 return nzero;
3958}
3959
3960#if 0 /* unused */
3961 VP_EXPORT int
3962VpIsNegDoubleZero(double v)
3963{
3964 double z = VpGetDoubleNegZero();
3965 return MemCmp(&v,&z,sizeof(v))==0;
3966}
3967#endif
3968
3969 VP_EXPORT int
3970VpException(unsigned short f, const char *str,int always)
3971{
3972 unsigned short const exception_mode = VpGetException();
3973
3974 if (f == VP_EXCEPTION_OP || f == VP_EXCEPTION_MEMORY) always = 1;
3975
3976 if (always || (exception_mode & f)) {
3977 switch(f) {
3978 /* case VP_EXCEPTION_OVERFLOW: */
3979 case VP_EXCEPTION_ZERODIVIDE:
3980 case VP_EXCEPTION_INFINITY:
3981 case VP_EXCEPTION_NaN:
3982 case VP_EXCEPTION_UNDERFLOW:
3983 case VP_EXCEPTION_OP:
3984 rb_raise(rb_eFloatDomainError, "%s", str);
3985 break;
3986 case VP_EXCEPTION_MEMORY:
3987 default:
3988 rb_fatal("%s", str);
3989 }
3990 }
3991 return 0; /* 0 Means VpException() raised no exception */
3992}
3993
3994/* Throw exception or returns 0,when resulting c is Inf or NaN */
3995/* sw=1:+ 2:- 3:* 4:/ */
3996static int
3997VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw)
3998{
3999 if (VpIsNaN(a) || VpIsNaN(b)) {
4000 /* at least a or b is NaN */
4001 VpSetNaN(c);
4002 goto NaN;
4003 }
4004
4005 if (VpIsInf(a)) {
4006 if (VpIsInf(b)) {
4007 switch(sw) {
4008 case OP_SW_ADD: /* + */
4009 if (VpGetSign(a) == VpGetSign(b)) {
4010 VpSetInf(c, VpGetSign(a));
4011 goto Inf;
4012 }
4013 else {
4014 VpSetNaN(c);
4015 goto NaN;
4016 }
4017 case OP_SW_SUB: /* - */
4018 if (VpGetSign(a) != VpGetSign(b)) {
4019 VpSetInf(c, VpGetSign(a));
4020 goto Inf;
4021 }
4022 else {
4023 VpSetNaN(c);
4024 goto NaN;
4025 }
4026 case OP_SW_MULT: /* * */
4027 VpSetInf(c, VpGetSign(a)*VpGetSign(b));
4028 goto Inf;
4029 case OP_SW_DIV: /* / */
4030 VpSetNaN(c);
4031 goto NaN;
4032 }
4033 VpSetNaN(c);
4034 goto NaN;
4035 }
4036 /* Inf op Finite */
4037 switch(sw) {
4038 case OP_SW_ADD: /* + */
4039 case OP_SW_SUB: /* - */
4040 VpSetInf(c, VpGetSign(a));
4041 break;
4042 case OP_SW_MULT: /* * */
4043 if (VpIsZero(b)) {
4044 VpSetNaN(c);
4045 goto NaN;
4046 }
4047 VpSetInf(c, VpGetSign(a)*VpGetSign(b));
4048 break;
4049 case OP_SW_DIV: /* / */
4050 VpSetInf(c, VpGetSign(a)*VpGetSign(b));
4051 }
4052 goto Inf;
4053 }
4054
4055 if (VpIsInf(b)) {
4056 switch(sw) {
4057 case OP_SW_ADD: /* + */
4058 VpSetInf(c, VpGetSign(b));
4059 break;
4060 case OP_SW_SUB: /* - */
4061 VpSetInf(c, -VpGetSign(b));
4062 break;
4063 case OP_SW_MULT: /* * */
4064 if (VpIsZero(a)) {
4065 VpSetNaN(c);
4066 goto NaN;
4067 }
4068 VpSetInf(c, VpGetSign(a)*VpGetSign(b));
4069 break;
4070 case OP_SW_DIV: /* / */
4071 VpSetZero(c, VpGetSign(a)*VpGetSign(b));
4072 }
4073 goto Inf;
4074 }
4075 return 1; /* Results OK */
4076
4077Inf:
4078 if (VpIsPosInf(c)) {
4079 return VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 0);
4080 }
4081 else {
4082 return VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 0);
4083 }
4084
4085NaN:
4086 return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
4087}
4088
4089/*
4090 ----------------------------------------------------------------
4091*/
4092
4093/*
4094 * returns number of chars needed to represent vp in specified format.
4095 */
4096 VP_EXPORT size_t
4097VpNumOfChars(Real *vp,const char *pszFmt)
4098{
4099 SIGNED_VALUE ex;
4100 size_t nc;
4101
4102 if (vp == NULL) return BASE_FIG*2+6;
4103 if (!VpIsDef(vp)) return 32; /* not sure,may be OK */
4104
4105 switch(*pszFmt) {
4106 case 'F':
4107 nc = BASE_FIG*(vp->Prec + 1)+2;
4108 ex = vp->exponent;
4109 if (ex < 0) {
4110 nc += BASE_FIG*(size_t)(-ex);
4111 }
4112 else {
4113 if ((size_t)ex > vp->Prec) {
4114 nc += BASE_FIG*((size_t)ex - vp->Prec);
4115 }
4116 }
4117 break;
4118 case 'E':
4119 /* fall through */
4120 default:
4121 nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4122 }
4123 return nc;
4124}
4125
4126/*
4127 * Initializer for Vp routines and constants used.
4128 * [Input]
4129 * BaseVal: Base value(assigned to BASE) for Vp calculation.
4130 * It must be the form BaseVal=10**n.(n=1,2,3,...)
4131 * If Base <= 0L,then the BASE will be calculated so
4132 * that BASE is as large as possible satisfying the
4133 * relation MaxVal <= BASE*(BASE+1). Where the value
4134 * MaxVal is the largest value which can be represented
4135 * by one BDIGIT word in the computer used.
4136 *
4137 * [Returns]
4138 * DBLE_FIG ... OK
4139 */
4140 VP_EXPORT size_t
4141VpInit(BDIGIT BaseVal)
4142{
4143 /* Setup +/- Inf NaN -0 */
4144 VpGetDoubleNegZero();
4145
4146 /* Allocates Vp constants. */
4147 VpConstOne = VpAlloc(1UL, "1", 1, 1);
4148 VpPt5 = VpAlloc(1UL, ".5", 1, 1);
4149
4150#ifdef BIGDECIMAL_DEBUG
4151 gnAlloc = 0;
4152#endif /* BIGDECIMAL_DEBUG */
4153
4154#ifdef BIGDECIMAL_DEBUG
4155 if (gfDebug) {
4156 printf("VpInit: BaseVal = %"PRIuBDIGIT"\n", BaseVal);
4157 printf("\tBASE = %"PRIuBDIGIT"\n", BASE);
4158 printf("\tHALF_BASE = %"PRIuBDIGIT"\n", HALF_BASE);
4159 printf("\tBASE1 = %"PRIuBDIGIT"\n", BASE1);
4160 printf("\tBASE_FIG = %u\n", BASE_FIG);
4161 printf("\tDBLE_FIG = %d\n", DBLE_FIG);
4162 }
4163#endif /* BIGDECIMAL_DEBUG */
4164
4165 return rmpd_double_figures();
4166}
4167
4168 VP_EXPORT Real *
4169VpOne(void)
4170{
4171 return VpConstOne;
4172}
4173
4174/* If exponent overflows,then raise exception or returns 0 */
4175static int
4176AddExponent(Real *a, SIGNED_VALUE n)
4177{
4178 SIGNED_VALUE e = a->exponent;
4179 SIGNED_VALUE m = e+n;
4180 SIGNED_VALUE eb, mb;
4181 if (e > 0) {
4182 if (n > 0) {
4183 if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
4184 MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
4185 goto overflow;
4186 mb = m*(SIGNED_VALUE)BASE_FIG;
4187 eb = e*(SIGNED_VALUE)BASE_FIG;
4188 if (eb - mb > 0) goto overflow;
4189 }
4190 }
4191 else if (n < 0) {
4192 if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
4193 MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
4194 goto underflow;
4195 mb = m*(SIGNED_VALUE)BASE_FIG;
4196 eb = e*(SIGNED_VALUE)BASE_FIG;
4197 if (mb - eb > 0) goto underflow;
4198 }
4199 a->exponent = m;
4200 return 1;
4201
4202/* Overflow/Underflow ==> Raise exception or returns 0 */
4203underflow:
4204 VpSetZero(a, VpGetSign(a));
4205 return VpException(VP_EXCEPTION_UNDERFLOW, "Exponent underflow", 0);
4206
4207overflow:
4208 VpSetInf(a, VpGetSign(a));
4209 return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
4210}
4211
4212 Real *
4213rmpd_parse_special_string(const char *str)
4214{
4215 static const struct {
4216 const char *str;
4217 size_t len;
4218 int sign;
4219 } table[] = {
4220 { SZ_INF, sizeof(SZ_INF) - 1, VP_SIGN_POSITIVE_INFINITE },
4221 { SZ_PINF, sizeof(SZ_PINF) - 1, VP_SIGN_POSITIVE_INFINITE },
4222 { SZ_NINF, sizeof(SZ_NINF) - 1, VP_SIGN_NEGATIVE_INFINITE },
4223 { SZ_NaN, sizeof(SZ_NaN) - 1, VP_SIGN_NaN }
4224 };
4225 static const size_t table_length = sizeof(table) / sizeof(table[0]);
4226 size_t i;
4227
4228 for (i = 0; i < table_length; ++i) {
4229 const char *p;
4230 if (strncmp(str, table[i].str, table[i].len) != 0) {
4231 continue;
4232 }
4233
4234 p = str + table[i].len;
4235 while (*p && ISSPACE(*p)) ++p;
4236 if (*p == '\0') {
4237 Real *vp = VpAllocReal(1);
4238 vp->MaxPrec = 1;
4239 switch (table[i].sign) {
4240 default:
4241 UNREACHABLE; break;
4242 case VP_SIGN_POSITIVE_INFINITE:
4243 VpSetPosInf(vp);
4244 return vp;
4245 case VP_SIGN_NEGATIVE_INFINITE:
4246 VpSetNegInf(vp);
4247 return vp;
4248 case VP_SIGN_NaN:
4249 VpSetNaN(vp);
4250 return vp;
4251 }
4252 }
4253 }
4254
4255 return NULL;
4256}
4257
4258/*
4259 * Allocates variable.
4260 * [Input]
4261 * mx ... allocation unit, if zero then mx is determined by szVal.
4262 * The mx is the number of effective digits can to be stored.
4263 * szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
4264 * If szVal[0]=='#' then Max. Prec. will not be considered(1.1.7),
4265 * full precision specified by szVal is allocated.
4266 *
4267 * [Returns]
4268 * Pointer to the newly allocated variable, or
4269 * NULL be returned if memory allocation is failed,or any error.
4270 */
4271 VP_EXPORT Real *
4272VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4273{
4274 const char *orig_szVal = szVal;
4275 size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
4276 char v, *psz;
4277 int sign=1;
4278 Real *vp = NULL;
4279 size_t mf = VpGetPrecLimit();
4280 VALUE buf;
4281
4282 mx = (mx + BASE_FIG - 1) / BASE_FIG; /* Determine allocation unit. */
4283 if (mx == 0) ++mx;
4284
4285 if (szVal) {
4286 /* Skipping leading spaces */
4287 while (ISSPACE(*szVal)) szVal++;
4288
4289 /* Processing the leading one `#` */
4290 if (*szVal != '#') {
4291 if (mf) {
4292 mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
4293 if (mx > mf) {
4294 mx = mf;
4295 }
4296 }
4297 }
4298 else {
4299 ++szVal;
4300 }
4301 }
4302 else {
4303 return_zero:
4304 /* necessary to be able to store */
4305 /* at least mx digits. */
4306 /* szVal==NULL ==> allocate zero value. */
4307 vp = VpAllocReal(mx);
4308 /* xmalloc() always returns(or throw interruption) */
4309 vp->MaxPrec = mx; /* set max precision */
4310 VpSetZero(vp, 1); /* initialize vp to zero. */
4311 return vp;
4312 }
4313
4314 /* Check on Inf & NaN */
4315 if ((vp = rmpd_parse_special_string(szVal)) != NULL) {
4316 return vp;
4317 }
4318
4319 /* Scanning digits */
4320
4321 /* A buffer for keeping scanned digits */
4322 buf = rb_str_tmp_new(strlen(szVal) + 1);
4323 psz = RSTRING_PTR(buf);
4324
4325 /* cursor: i for psz, and j for szVal */
4326 i = j = 0;
4327
4328 /* Scanning: sign part */
4329 v = psz[i] = szVal[j];
4330 if ((v == '-') || (v == '+')) {
4331 sign = -(v == '-');
4332 ++i;
4333 ++j;
4334 }
4335
4336 /* Scanning: integer part */
4337 ni = 0; /* number of digits in the integer part */
4338 while ((v = psz[i] = szVal[j]) != '\0') {
4339 if (!strict_p && ISSPACE(v)) {
4340 v = psz[i] = '\0';
4341 break;
4342 }
4343 if (v == '_') {
4344 if (ni > 0) {
4345 v = szVal[j+1];
4346 if (v == '\0' || ISSPACE(v) || ISDIGIT(v)) {
4347 ++j;
4348 continue;
4349 }
4350 if (!strict_p) {
4351 v = psz[i] = '\0';
4352 break;
4353 }
4354 }
4355 goto invalid_value;
4356 }
4357 if (!ISDIGIT(v)) {
4358 break;
4359 }
4360 ++ni;
4361 ++i;
4362 ++j;
4363 }
4364
4365 /* Scanning: fractional part */
4366 nf = 0; /* number of digits in the fractional part */
4367 ne = 0; /* number of digits in the exponential part */
4368 ipf = 0; /* index of the beginning of the fractional part */
4369 ipe = 0; /* index of the beginning of the exponential part */
4370 dot_seen = 0;
4371 exp_seen = 0;
4372
4373 if (v != '\0') {
4374 /* Scanning fractional part */
4375 if ((psz[i] = szVal[j]) == '.') {
4376 dot_seen = 1;
4377 ++i;
4378 ++j;
4379 ipf = i;
4380 while ((v = psz[i] = szVal[j]) != '\0') {
4381 if (!strict_p && ISSPACE(v)) {
4382 v = psz[i] = '\0';
4383 break;
4384 }
4385 if (v == '_') {
4386 if (nf > 0 && ISDIGIT(szVal[j+1])) {
4387 ++j;
4388 continue;
4389 }
4390 if (!strict_p) {
4391 v = psz[i] = '\0';
4392 if (nf == 0) {
4393 dot_seen = 0;
4394 }
4395 break;
4396 }
4397 goto invalid_value;
4398 }
4399 if (!ISDIGIT(v)) break;
4400 ++i;
4401 ++j;
4402 ++nf;
4403 }
4404 }
4405
4406 /* Scanning exponential part */
4407 if (v != '\0') {
4408 switch ((psz[i] = szVal[j])) {
4409 case '\0':
4410 break;
4411 case 'e': case 'E':
4412 case 'd': case 'D':
4413 exp_seen = 1;
4414 ++i;
4415 ++j;
4416 ipe = i;
4417 v = psz[i] = szVal[j];
4418 if ((v == '-') || (v == '+')) {
4419 ++i;
4420 ++j;
4421 }
4422 while ((v = psz[i] = szVal[j]) != '\0') {
4423 if (!strict_p && ISSPACE(v)) {
4424 v = psz[i] = '\0';
4425 break;
4426 }
4427 if (v == '_') {
4428 if (ne > 0 && ISDIGIT(szVal[j+1])) {
4429 ++j;
4430 continue;
4431 }
4432 if (!strict_p) {
4433 v = psz[i] = '\0';
4434 if (ne == 0) {
4435 exp_seen = 0;
4436 }
4437 break;
4438 }
4439 goto invalid_value;
4440 }
4441 if (!ISDIGIT(v)) break;
4442 ++i;
4443 ++j;
4444 ++ne;
4445 }
4446 break;
4447 default:
4448 break;
4449 }
4450 }
4451
4452 if (v != '\0') {
4453 /* Scanning trailing spaces */
4454 while (ISSPACE(szVal[j])) ++j;
4455
4456 /* Invalid character */
4457 if (szVal[j] && strict_p) {
4458 goto invalid_value;
4459 }
4460 }
4461 }
4462
4463 psz[i] = '\0';
4464
4465 if (strict_p && (((ni == 0 || dot_seen) && nf == 0) || (exp_seen && ne == 0))) {
4466 VALUE str;
4467 invalid_value:
4468 if (!strict_p) {
4469 goto return_zero;
4470 }
4471 if (!exc) {
4472 return NULL;
4473 }
4474 str = rb_str_new2(orig_szVal);
4475 rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
4476 }
4477
4478 nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
4479 /* units for szVal[] */
4480 if (mx == 0) mx = 1;
4481 nalloc = Max(nalloc, mx);
4482 mx = nalloc;
4483 vp = VpAllocReal(mx);
4484 /* xmalloc() always returns(or throw interruption) */
4485 vp->MaxPrec = mx; /* set max precision */
4486 VpSetZero(vp, sign);
4487 VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
4488 rb_str_resize(buf, 0);
4489 return vp;
4490}
4491
4492/*
4493 * Assignment(c=a).
4494 * [Input]
4495 * a ... RHSV
4496 * isw ... switch for assignment.
4497 * c = a when isw > 0
4498 * c = -a when isw < 0
4499 * if c->MaxPrec < a->Prec,then round operation
4500 * will be performed.
4501 * [Output]
4502 * c ... LHSV
4503 */
4504 VP_EXPORT size_t
4505VpAsgn(Real *c, Real *a, int isw)
4506{
4507 size_t n;
4508 if (VpIsNaN(a)) {
4509 VpSetNaN(c);
4510 return 0;
4511 }
4512 if (VpIsInf(a)) {
4513 VpSetInf(c, isw * VpGetSign(a));
4514 return 0;
4515 }
4516
4517 /* check if the RHS is zero */
4518 if (!VpIsZero(a)) {
4519 c->exponent = a->exponent; /* store exponent */
4520 VpSetSign(c, isw * VpGetSign(a)); /* set sign */
4521 n = (a->Prec < c->MaxPrec) ? (a->Prec) : (c->MaxPrec);
4522 c->Prec = n;
4523 memcpy(c->frac, a->frac, n * sizeof(BDIGIT));
4524 /* Needs round ? */
4525 if (isw != 10) {
4526 /* Not in ActiveRound */
4527 if(c->Prec < a->Prec) {
4528 VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
4529 }
4530 else {
4531 VpLimitRound(c,0);
4532 }
4533 }
4534 }
4535 else {
4536 /* The value of 'a' is zero. */
4537 VpSetZero(c, isw * VpGetSign(a));
4538 return 1;
4539 }
4540 return c->Prec * BASE_FIG;
4541}
4542
4543/*
4544 * c = a + b when operation = 1 or 2
4545 * c = a - b when operation = -1 or -2.
4546 * Returns number of significant digits of c
4547 */
4548 VP_EXPORT size_t
4549VpAddSub(Real *c, Real *a, Real *b, int operation)
4550{
4551 short sw, isw;
4552 Real *a_ptr, *b_ptr;
4553 size_t n, na, nb, i;
4554 BDIGIT mrv;
4555
4556#ifdef BIGDECIMAL_DEBUG
4557 if (gfDebug) {
4558 VPrint(stdout, "VpAddSub(enter) a=% \n", a);
4559 VPrint(stdout, " b=% \n", b);
4560 printf(" operation=%d\n", operation);
4561 }
4562#endif /* BIGDECIMAL_DEBUG */
4563
4564 if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
4565
4566 /* check if a or b is zero */
4567 if (VpIsZero(a)) {
4568 /* a is zero,then assign b to c */
4569 if (!VpIsZero(b)) {
4570 VpAsgn(c, b, operation);
4571 }
4572 else {
4573 /* Both a and b are zero. */
4574 if (VpGetSign(a) < 0 && operation * VpGetSign(b) < 0) {
4575 /* -0 -0 */
4576 VpSetZero(c, -1);
4577 }
4578 else {
4579 VpSetZero(c, 1);
4580 }
4581 return 1; /* 0: 1 significant digits */
4582 }
4583 return c->Prec * BASE_FIG;
4584 }
4585 if (VpIsZero(b)) {
4586 /* b is zero,then assign a to c. */
4587 VpAsgn(c, a, 1);
4588 return c->Prec*BASE_FIG;
4589 }
4590
4591 if (operation < 0) sw = -1;
4592 else sw = 1;
4593
4594 /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
4595 if (a->exponent > b->exponent) {
4596 a_ptr = a;
4597 b_ptr = b;
4598 } /* |a|>|b| */
4599 else if (a->exponent < b->exponent) {
4600 a_ptr = b;
4601 b_ptr = a;
4602 } /* |a|<|b| */
4603 else {
4604 /* Exponent part of a and b is the same,then compare fraction */
4605 /* part */
4606 na = a->Prec;
4607 nb = b->Prec;
4608 n = Min(na, nb);
4609 for (i=0; i < n; ++i) {
4610 if (a->frac[i] > b->frac[i]) {
4611 a_ptr = a;
4612 b_ptr = b;
4613 goto end_if;
4614 }
4615 else if (a->frac[i] < b->frac[i]) {
4616 a_ptr = b;
4617 b_ptr = a;
4618 goto end_if;
4619 }
4620 }
4621 if (na > nb) {
4622 a_ptr = a;
4623 b_ptr = b;
4624 goto end_if;
4625 }
4626 else if (na < nb) {
4627 a_ptr = b;
4628 b_ptr = a;
4629 goto end_if;
4630 }
4631 /* |a| == |b| */
4632 if (VpGetSign(a) + sw *VpGetSign(b) == 0) {
4633 VpSetZero(c, 1); /* abs(a)=abs(b) and operation = '-' */
4634 return c->Prec * BASE_FIG;
4635 }
4636 a_ptr = a;
4637 b_ptr = b;
4638 }
4639
4640end_if:
4641 isw = VpGetSign(a) + sw *VpGetSign(b);
4642 /*
4643 * isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1)
4644 * = 2 ...( 1)+( 1),( 1)-(-1)
4645 * =-2 ...(-1)+(-1),(-1)-( 1)
4646 * If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|)
4647 * else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
4648 */
4649 if (isw) { /* addition */
4650 VpSetSign(c, 1);
4651 mrv = VpAddAbs(a_ptr, b_ptr, c);
4652 VpSetSign(c, isw / 2);
4653 }
4654 else { /* subtraction */
4655 VpSetSign(c, 1);
4656 mrv = VpSubAbs(a_ptr, b_ptr, c);
4657 if (a_ptr == a) {
4658 VpSetSign(c,VpGetSign(a));
4659 }
4660 else {
4661 VpSetSign(c, VpGetSign(a_ptr) * sw);
4662 }
4663 }
4664 VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4665
4666#ifdef BIGDECIMAL_DEBUG
4667 if (gfDebug) {
4668 VPrint(stdout, "VpAddSub(result) c=% \n", c);
4669 VPrint(stdout, " a=% \n", a);
4670 VPrint(stdout, " b=% \n", b);
4671 printf(" operation=%d\n", operation);
4672 }
4673#endif /* BIGDECIMAL_DEBUG */
4674 return c->Prec * BASE_FIG;
4675}
4676
4677/*
4678 * Addition of two values with variable precision
4679 * a and b assuming abs(a)>abs(b).
4680 * c = abs(a) + abs(b) ; where |a|>=|b|
4681 */
4682static BDIGIT
4683VpAddAbs(Real *a, Real *b, Real *c)
4684{
4685 size_t word_shift;
4686 size_t ap;
4687 size_t bp;
4688 size_t cp;
4689 size_t a_pos;
4690 size_t b_pos, b_pos_with_word_shift;
4691 size_t c_pos;
4692 BDIGIT av, bv, carry, mrv;
4693
4694#ifdef BIGDECIMAL_DEBUG
4695 if (gfDebug) {
4696 VPrint(stdout, "VpAddAbs called: a = %\n", a);
4697 VPrint(stdout, " b = %\n", b);
4698 }
4699#endif /* BIGDECIMAL_DEBUG */
4700
4701 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
4702 a_pos = ap;
4703 b_pos = bp;
4704 c_pos = cp;
4705
4706 if (word_shift == (size_t)-1L) return 0; /* Overflow */
4707 if (b_pos == (size_t)-1L) goto Assign_a;
4708
4709 mrv = av + bv; /* Most right val. Used for round. */
4710
4711 /* Just assign the last few digits of b to c because a has no */
4712 /* corresponding digits to be added. */
4713 if (b_pos > 0) {
4714 while (b_pos > 0 && b_pos + word_shift > a_pos) {
4715 c->frac[--c_pos] = b->frac[--b_pos];
4716 }
4717 }
4718 if (b_pos == 0 && word_shift > a_pos) {
4719 while (word_shift-- > a_pos) {
4720 c->frac[--c_pos] = 0;
4721 }
4722 }
4723
4724 /* Just assign the last few digits of a to c because b has no */
4725 /* corresponding digits to be added. */
4726 b_pos_with_word_shift = b_pos + word_shift;
4727 while (a_pos > b_pos_with_word_shift) {
4728 c->frac[--c_pos] = a->frac[--a_pos];
4729 }
4730 carry = 0; /* set first carry be zero */
4731
4732 /* Now perform addition until every digits of b will be */
4733 /* exhausted. */
4734 while (b_pos > 0) {
4735 c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
4736 if (c->frac[c_pos] >= BASE) {
4737 c->frac[c_pos] -= BASE;
4738 carry = 1;
4739 }
4740 else {
4741 carry = 0;
4742 }
4743 }
4744
4745 /* Just assign the first few digits of a with considering */
4746 /* the carry obtained so far because b has been exhausted. */
4747 while (a_pos > 0) {
4748 c->frac[--c_pos] = a->frac[--a_pos] + carry;
4749 if (c->frac[c_pos] >= BASE) {
4750 c->frac[c_pos] -= BASE;
4751 carry = 1;
4752 }
4753 else {
4754 carry = 0;
4755 }
4756 }
4757 if (c_pos) c->frac[c_pos - 1] += carry;
4758 goto Exit;
4759
4760Assign_a:
4761 VpAsgn(c, a, 1);
4762 mrv = 0;
4763
4764Exit:
4765
4766#ifdef BIGDECIMAL_DEBUG
4767 if (gfDebug) {
4768 VPrint(stdout, "VpAddAbs exit: c=% \n", c);
4769 }
4770#endif /* BIGDECIMAL_DEBUG */
4771 return mrv;
4772}
4773
4774/*
4775 * c = abs(a) - abs(b)
4776 */
4777static BDIGIT
4778VpSubAbs(Real *a, Real *b, Real *c)
4779{
4780 size_t word_shift;
4781 size_t ap;
4782 size_t bp;
4783 size_t cp;
4784 size_t a_pos;
4785 size_t b_pos, b_pos_with_word_shift;
4786 size_t c_pos;
4787 BDIGIT av, bv, borrow, mrv;
4788
4789#ifdef BIGDECIMAL_DEBUG
4790 if (gfDebug) {
4791 VPrint(stdout, "VpSubAbs called: a = %\n", a);
4792 VPrint(stdout, " b = %\n", b);
4793 }
4794#endif /* BIGDECIMAL_DEBUG */
4795
4796 word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
4797 a_pos = ap;
4798 b_pos = bp;
4799 c_pos = cp;
4800 if (word_shift == (size_t)-1L) return 0; /* Overflow */
4801 if (b_pos == (size_t)-1L) goto Assign_a;
4802
4803 if (av >= bv) {
4804 mrv = av - bv;
4805 borrow = 0;
4806 }
4807 else {
4808 mrv = 0;
4809 borrow = 1;
4810 }
4811
4812 /* Just assign the values which are the BASE subtracted by */
4813 /* each of the last few digits of the b because the a has no */
4814 /* corresponding digits to be subtracted. */
4815 if (b_pos + word_shift > a_pos) {
4816 while (b_pos > 0 && b_pos + word_shift > a_pos) {
4817 c->frac[--c_pos] = BASE - b->frac[--b_pos] - borrow;
4818 borrow = 1;
4819 }
4820 if (b_pos == 0) {
4821 while (word_shift > a_pos) {
4822 --word_shift;
4823 c->frac[--c_pos] = BASE - borrow;
4824 borrow = 1;
4825 }
4826 }
4827 }
4828 /* Just assign the last few digits of a to c because b has no */
4829 /* corresponding digits to subtract. */
4830
4831 b_pos_with_word_shift = b_pos + word_shift;
4832 while (a_pos > b_pos_with_word_shift) {
4833 c->frac[--c_pos] = a->frac[--a_pos];
4834 }
4835
4836 /* Now perform subtraction until every digits of b will be */
4837 /* exhausted. */
4838 while (b_pos > 0) {
4839 --c_pos;
4840 if (a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
4841 c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
4842 borrow = 1;
4843 }
4844 else {
4845 c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
4846 borrow = 0;
4847 }
4848 }
4849
4850 /* Just assign the first few digits of a with considering */
4851 /* the borrow obtained so far because b has been exhausted. */
4852 while (a_pos > 0) {
4853 --c_pos;
4854 if (a->frac[--a_pos] < borrow) {
4855 c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
4856 borrow = 1;
4857 }
4858 else {
4859 c->frac[c_pos] = a->frac[a_pos] - borrow;
4860 borrow = 0;
4861 }
4862 }
4863 if (c_pos) c->frac[c_pos - 1] -= borrow;
4864 goto Exit;
4865
4866Assign_a:
4867 VpAsgn(c, a, 1);
4868 mrv = 0;
4869
4870Exit:
4871#ifdef BIGDECIMAL_DEBUG
4872 if (gfDebug) {
4873 VPrint(stdout, "VpSubAbs exit: c=% \n", c);
4874 }
4875#endif /* BIGDECIMAL_DEBUG */
4876 return mrv;
4877}
4878
4879/*
4880 * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant
4881 * digit of c(In case of addition).
4882 * ------------------------- figure of output -----------------------------------
4883 * a = xxxxxxxxxxx
4884 * b = xxxxxxxxxx
4885 * c =xxxxxxxxxxxxxxx
4886 * word_shift = | |
4887 * right_word = | | (Total digits in RHSV)
4888 * left_word = | | (Total digits in LHSV)
4889 * a_pos = |
4890 * b_pos = |
4891 * c_pos = |
4892 */
4893static size_t
4894VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv)
4895{
4896 size_t left_word, right_word, word_shift;
4897
4898 size_t const round_limit = (VpGetPrecLimit() + BASE_FIG - 1) / BASE_FIG;
4899
4900 assert(a->exponent >= b->exponent);
4901
4902 c->frac[0] = 0;
4903 *av = *bv = 0;
4904
4905 word_shift = (a->exponent - b->exponent);
4906 left_word = b->Prec + word_shift;
4907 right_word = Max(a->Prec, left_word);
4908 left_word = c->MaxPrec - 1; /* -1 ... prepare for round up */
4909
4910 /*
4911 * check if 'round' is needed.
4912 */
4913 if (right_word > left_word) { /* round ? */
4914 /*---------------------------------
4915 * Actual size of a = xxxxxxAxx
4916 * Actual size of b = xxxBxxxxx
4917 * Max. size of c = xxxxxx
4918 * Round off = |-----|
4919 * c_pos = |
4920 * right_word = |
4921 * a_pos = |
4922 */
4923 *c_pos = right_word = left_word + 1; /* Set resulting precision */
4924 /* be equal to that of c */
4925 if (a->Prec >= c->MaxPrec) {
4926 /*
4927 * a = xxxxxxAxxx
4928 * c = xxxxxx
4929 * a_pos = |
4930 */
4931 *a_pos = left_word;
4932 if (*a_pos <= round_limit) {
4933 *av = a->frac[*a_pos]; /* av is 'A' shown in above. */
4934 }
4935 }
4936 else {
4937 /*
4938 * a = xxxxxxx
4939 * c = xxxxxxxxxx
4940 * a_pos = |
4941 */
4942 *a_pos = a->Prec;
4943 }
4944 if (b->Prec + word_shift >= c->MaxPrec) {
4945 /*
4946 * a = xxxxxxxxx
4947 * b = xxxxxxxBxxx
4948 * c = xxxxxxxxxxx
4949 * b_pos = |
4950 */
4951 if (c->MaxPrec >= word_shift + 1) {
4952 *b_pos = c->MaxPrec - word_shift - 1;
4953 if (*b_pos + word_shift <= round_limit) {
4954 *bv = b->frac[*b_pos];
4955 }
4956 }
4957 else {
4958 *b_pos = -1L;
4959 }
4960 }
4961 else {
4962 /*
4963 * a = xxxxxxxxxxxxxxxx
4964 * b = xxxxxx
4965 * c = xxxxxxxxxxxxx
4966 * b_pos = |
4967 */
4968 *b_pos = b->Prec;
4969 }
4970 }
4971 else { /* The MaxPrec of c - 1 > The Prec of a + b */
4972 /*
4973 * a = xxxxxxx
4974 * b = xxxxxx
4975 * c = xxxxxxxxxxx
4976 * c_pos = |
4977 */
4978 *b_pos = b->Prec;
4979 *a_pos = a->Prec;
4980 *c_pos = right_word + 1;
4981 }
4982 c->Prec = *c_pos;
4983 c->exponent = a->exponent;
4984 if (!AddExponent(c, 1)) return (size_t)-1L;
4985 return word_shift;
4986}
4987
4988/*
4989 * Return number of significant digits
4990 * c = a * b , Where a = a0a1a2 ... an
4991 * b = b0b1b2 ... bm
4992 * c = c0c1c2 ... cl
4993 * a0 a1 ... an * bm
4994 * a0 a1 ... an * bm-1
4995 * . . .
4996 * . . .
4997 * a0 a1 .... an * b0
4998 * +_____________________________
4999 * c0 c1 c2 ...... cl
5000 * nc <---|
5001 * MaxAB |--------------------|
5002 */
5003 VP_EXPORT size_t
5004VpMult(Real *c, Real *a, Real *b)
5005{
5006 size_t MxIndA, MxIndB, MxIndAB, MxIndC;
5007 size_t ind_c, i, ii, nc;
5008 size_t ind_as, ind_ae, ind_bs;
5009 BDIGIT carry;
5010 BDIGIT_DBL s;
5011 Real *w;
5012
5013#ifdef BIGDECIMAL_DEBUG
5014 if (gfDebug) {
5015 VPrint(stdout, "VpMult(Enter): a=% \n", a);
5016 VPrint(stdout, " b=% \n", b);
5017 }
5018#endif /* BIGDECIMAL_DEBUG */
5019
5020 if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
5021
5022 if (VpIsZero(a) || VpIsZero(b)) {
5023 /* at least a or b is zero */
5024 VpSetZero(c, VpGetSign(a) * VpGetSign(b));
5025 return 1; /* 0: 1 significant digit */
5026 }
5027
5028 if (VpIsOne(a)) {
5029 VpAsgn(c, b, VpGetSign(a));
5030 goto Exit;
5031 }
5032 if (VpIsOne(b)) {
5033 VpAsgn(c, a, VpGetSign(b));
5034 goto Exit;
5035 }
5036 if (b->Prec > a->Prec) {
5037 /* Adjust so that digits(a)>digits(b) */
5038 w = a;
5039 a = b;
5040 b = w;
5041 }
5042 w = NULL;
5043 MxIndA = a->Prec - 1;
5044 MxIndB = b->Prec - 1;
5045 MxIndC = c->MaxPrec - 1;
5046 MxIndAB = a->Prec + b->Prec - 1;
5047
5048 if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
5049 w = c;
5050 c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1, 1);
5051 MxIndC = MxIndAB;
5052 }
5053
5054 /* set LHSV c info */
5055
5056 c->exponent = a->exponent; /* set exponent */
5057 if (!AddExponent(c, b->exponent)) {
5058 if (w) VpFree(c);
5059 return 0;
5060 }
5061 VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
5062 carry = 0;
5063 nc = ind_c = MxIndAB;
5064 memset(c->frac, 0, (nc + 1) * sizeof(BDIGIT)); /* Initialize c */
5065 c->Prec = nc + 1; /* set precision */
5066 for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
5067 if (nc < MxIndB) { /* The left triangle of the Fig. */
5068 ind_as = MxIndA - nc;
5069 ind_ae = MxIndA;
5070 ind_bs = MxIndB;
5071 }
5072 else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
5073 ind_as = MxIndA - nc;
5074 ind_ae = MxIndA - (nc - MxIndB);
5075 ind_bs = MxIndB;
5076 }
5077 else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
5078 ind_as = 0;
5079 ind_ae = MxIndAB - nc - 1;
5080 ind_bs = MxIndB - (nc - MxIndA);
5081 }
5082
5083 for (i = ind_as; i <= ind_ae; ++i) {
5084 s = (BDIGIT_DBL)a->frac[i] * b->frac[ind_bs--];
5085 carry = (BDIGIT)(s / BASE);
5086 s -= (BDIGIT_DBL)carry * BASE;
5087 c->frac[ind_c] += (BDIGIT)s;
5088 if (c->frac[ind_c] >= BASE) {
5089 s = c->frac[ind_c] / BASE;
5090 carry += (BDIGIT)s;
5091 c->frac[ind_c] -= (BDIGIT)(s * BASE);
5092 }
5093 if (carry) {
5094 ii = ind_c;
5095 while (ii-- > 0) {
5096 c->frac[ii] += carry;
5097 if (c->frac[ii] >= BASE) {
5098 carry = c->frac[ii] / BASE;
5099 c->frac[ii] -= (carry * BASE);
5100 }
5101 else {
5102 break;
5103 }
5104 }
5105 }
5106 }
5107 }
5108 if (w != NULL) { /* free work variable */
5109 VpNmlz(c);
5110 VpAsgn(w, c, 1);
5111 VpFree(c);
5112 c = w;
5113 }
5114 else {
5115 VpLimitRound(c,0);
5116 }
5117
5118Exit:
5119#ifdef BIGDECIMAL_DEBUG
5120 if (gfDebug) {
5121 VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
5122 VPrint(stdout, " a=% \n", a);
5123 VPrint(stdout, " b=% \n", b);
5124 }
5125#endif /*BIGDECIMAL_DEBUG */
5126 return c->Prec*BASE_FIG;
5127}
5128
5129/*
5130 * c = a / b, remainder = r
5131 */
5132 VP_EXPORT size_t
5133VpDivd(Real *c, Real *r, Real *a, Real *b)
5134{
5135 size_t word_a, word_b, word_c, word_r;
5136 size_t i, n, ind_a, ind_b, ind_c, ind_r;
5137 size_t nLoop;
5138 BDIGIT_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
5139 BDIGIT borrow, borrow1, borrow2;
5140 BDIGIT_DBL qb;
5141
5142#ifdef BIGDECIMAL_DEBUG
5143 if (gfDebug) {
5144 VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
5145 VPrint(stdout, " b=% \n", b);
5146 }
5147#endif /*BIGDECIMAL_DEBUG */
5148
5149 VpSetNaN(r);
5150 if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
5151 if (VpIsZero(a) && VpIsZero(b)) {
5152 VpSetNaN(c);
5153 return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
5154 }
5155 if (VpIsZero(b)) {
5156 VpSetInf(c, VpGetSign(a) * VpGetSign(b));
5157 return VpException(VP_EXCEPTION_ZERODIVIDE, "Divide by zero", 0);
5158 }
5159 if (VpIsZero(a)) {
5160 /* numerator a is zero */
5161 VpSetZero(c, VpGetSign(a) * VpGetSign(b));
5162 VpSetZero(r, VpGetSign(a) * VpGetSign(b));
5163 goto Exit;
5164 }
5165 if (VpIsOne(b)) {
5166 /* divide by one */
5167 VpAsgn(c, a, VpGetSign(b));
5168 VpSetZero(r, VpGetSign(a));
5169 goto Exit;
5170 }
5171
5172 word_a = a->Prec;
5173 word_b = b->Prec;
5174 word_c = c->MaxPrec;
5175 word_r = r->MaxPrec;
5176
5177 ind_c = 0;
5178 ind_r = 1;
5179
5180 if (word_a >= word_r) goto space_error;
5181
5182 r->frac[0] = 0;
5183 while (ind_r <= word_a) {
5184 r->frac[ind_r] = a->frac[ind_r - 1];
5185 ++ind_r;
5186 }
5187
5188 while (ind_r < word_r) r->frac[ind_r++] = 0;
5189 while (ind_c < word_c) c->frac[ind_c++] = 0;
5190
5191 /* initial procedure */
5192 b1 = b1p1 = b->frac[0];
5193 if (b->Prec <= 1) {
5194 b1b2p1 = b1b2 = b1p1 * BASE;
5195 }
5196 else {
5197 b1p1 = b1 + 1;
5198 b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
5199 if (b->Prec > 2) ++b1b2p1;
5200 }
5201
5202 /* */
5203 /* loop start */
5204 ind_c = word_r - 1;
5205 nLoop = Min(word_c,ind_c);
5206 ind_c = 1;
5207 while (ind_c < nLoop) {
5208 if (r->frac[ind_c] == 0) {
5209 ++ind_c;
5210 continue;
5211 }
5212 r1r2 = (BDIGIT_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
5213 if (r1r2 == b1b2) {
5214 /* The first two word digits is the same */
5215 ind_b = 2;
5216 ind_a = ind_c + 2;
5217 while (ind_b < word_b) {
5218 if (r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
5219 if (r->frac[ind_a] > b->frac[ind_b]) break;
5220 ++ind_a;
5221 ++ind_b;
5222 }
5223 /* The first few word digits of r and b is the same and */
5224 /* the first different word digit of w is greater than that */
5225 /* of b, so quotient is 1 and just subtract b from r. */
5226 borrow = 0; /* quotient=1, then just r-b */
5227 ind_b = b->Prec - 1;
5228 ind_r = ind_c + ind_b;
5229 if (ind_r >= word_r) goto space_error;
5230 n = ind_b;
5231 for (i = 0; i <= n; ++i) {
5232 if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
5233 r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
5234 borrow = 1;
5235 }
5236 else {
5237 r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
5238 borrow = 0;
5239 }
5240 --ind_r;
5241 --ind_b;
5242 }
5243 ++c->frac[ind_c];
5244 goto carry;
5245 }
5246 /* The first two word digits is not the same, */
5247 /* then compare magnitude, and divide actually. */
5248 if (r1r2 >= b1b2p1) {
5249 q = r1r2 / b1b2p1; /* q == (BDIGIT)q */
5250 c->frac[ind_c] += (BDIGIT)q;
5251 ind_r = b->Prec + ind_c - 1;
5252 goto sub_mult;
5253 }
5254
5255div_b1p1:
5256 if (ind_c + 1 >= word_c) goto out_side;
5257 q = r1r2 / b1p1; /* q == (BDIGIT)q */
5258 c->frac[ind_c + 1] += (BDIGIT)q;
5259 ind_r = b->Prec + ind_c;
5260
5261sub_mult:
5262 borrow1 = borrow2 = 0;
5263 ind_b = word_b - 1;
5264 if (ind_r >= word_r) goto space_error;
5265 n = ind_b;
5266 for (i = 0; i <= n; ++i) {
5267 /* now, perform r = r - q * b */
5268 qb = q * b->frac[ind_b];
5269 if (qb < BASE) borrow1 = 0;
5270 else {
5271 borrow1 = (BDIGIT)(qb / BASE);
5272 qb -= (BDIGIT_DBL)borrow1 * BASE; /* get qb < BASE */
5273 }
5274 if(r->frac[ind_r] < qb) {
5275 r->frac[ind_r] += (BDIGIT)(BASE - qb);
5276 borrow2 = borrow2 + borrow1 + 1;
5277 }
5278 else {
5279 r->frac[ind_r] -= (BDIGIT)qb;
5280 borrow2 += borrow1;
5281 }
5282 if (borrow2) {
5283 if(r->frac[ind_r - 1] < borrow2) {
5284 r->frac[ind_r - 1] += (BASE - borrow2);
5285 borrow2 = 1;
5286 }
5287 else {
5288 r->frac[ind_r - 1] -= borrow2;
5289 borrow2 = 0;
5290 }
5291 }
5292 --ind_r;
5293 --ind_b;
5294 }
5295
5296 r->frac[ind_r] -= borrow2;
5297carry:
5298 ind_r = ind_c;
5299 while (c->frac[ind_r] >= BASE) {
5300 c->frac[ind_r] -= BASE;
5301 --ind_r;
5302 ++c->frac[ind_r];
5303 }
5304 }
5305 /* End of operation, now final arrangement */
5306out_side:
5307 c->Prec = word_c;
5308 c->exponent = a->exponent;
5309 if (!AddExponent(c, 2)) return 0;
5310 if (!AddExponent(c, -(b->exponent))) return 0;
5311
5312 VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5313 VpNmlz(c); /* normalize c */
5314 r->Prec = word_r;
5315 r->exponent = a->exponent;
5316 if (!AddExponent(r, 1)) return 0;
5317 VpSetSign(r, VpGetSign(a));
5318 VpNmlz(r); /* normalize r(remainder) */
5319 goto Exit;
5320
5321space_error:
5322#ifdef BIGDECIMAL_DEBUG
5323 if (gfDebug) {
5324 printf(" word_a=%"PRIuSIZE"\n", word_a);
5325 printf(" word_b=%"PRIuSIZE"\n", word_b);
5326 printf(" word_c=%"PRIuSIZE"\n", word_c);
5327 printf(" word_r=%"PRIuSIZE"\n", word_r);
5328 printf(" ind_r =%"PRIuSIZE"\n", ind_r);
5329 }
5330#endif /* BIGDECIMAL_DEBUG */
5331 rb_bug("ERROR(VpDivd): space for remainder too small.");
5332
5333Exit:
5334#ifdef BIGDECIMAL_DEBUG
5335 if (gfDebug) {
5336 VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
5337 VPrint(stdout, " r=% \n", r);
5338 }
5339#endif /* BIGDECIMAL_DEBUG */
5340 return c->Prec * BASE_FIG;
5341}
5342
5343/*
5344 * Input a = 00000xxxxxxxx En(5 preceding zeros)
5345 * Output a = xxxxxxxx En-5
5346 */
5347static int
5348VpNmlz(Real *a)
5349{
5350 size_t ind_a, i;
5351
5352 if (!VpIsDef(a)) goto NoVal;
5353 if (VpIsZero(a)) goto NoVal;
5354
5355 ind_a = a->Prec;
5356 while (ind_a--) {
5357 if (a->frac[ind_a]) {
5358 a->Prec = ind_a + 1;
5359 i = 0;
5360 while (a->frac[i] == 0) ++i; /* skip the first few zeros */
5361 if (i) {
5362 a->Prec -= i;
5363 if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0;
5364 memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(BDIGIT));
5365 }
5366 return 1;
5367 }
5368 }
5369 /* a is zero(no non-zero digit) */
5370 VpSetZero(a, VpGetSign(a));
5371 return 0;
5372
5373NoVal:
5374 a->frac[0] = 0;
5375 a->Prec = 1;
5376 return 0;
5377}
5378
5379/*
5380 * VpComp = 0 ... if a=b,
5381 * Pos ... a>b,
5382 * Neg ... a<b.
5383 * 999 ... result undefined(NaN)
5384 */
5385 VP_EXPORT int
5386VpComp(Real *a, Real *b)
5387{
5388 int val;
5389 size_t mx, ind;
5390 int e;
5391 val = 0;
5392 if (VpIsNaN(a) || VpIsNaN(b)) return 999;
5393 if (!VpIsDef(a)) {
5394 if (!VpIsDef(b)) e = a->sign - b->sign;
5395 else e = a->sign;
5396
5397 if (e > 0) return 1;
5398 else if (e < 0) return -1;
5399 else return 0;
5400 }
5401 if (!VpIsDef(b)) {
5402 e = -b->sign;
5403 if (e > 0) return 1;
5404 else return -1;
5405 }
5406 /* Zero check */
5407 if (VpIsZero(a)) {
5408 if (VpIsZero(b)) return 0; /* both zero */
5409 val = -VpGetSign(b);
5410 goto Exit;
5411 }
5412 if (VpIsZero(b)) {
5413 val = VpGetSign(a);
5414 goto Exit;
5415 }
5416
5417 /* compare sign */
5418 if (VpGetSign(a) > VpGetSign(b)) {
5419 val = 1; /* a>b */
5420 goto Exit;
5421 }
5422 if (VpGetSign(a) < VpGetSign(b)) {
5423 val = -1; /* a<b */
5424 goto Exit;
5425 }
5426
5427 /* a and b have same sign, && sign!=0,then compare exponent */
5428 if (a->exponent > b->exponent) {
5429 val = VpGetSign(a);
5430 goto Exit;
5431 }
5432 if (a->exponent < b->exponent) {
5433 val = -VpGetSign(b);
5434 goto Exit;
5435 }
5436
5437 /* a and b have same exponent, then compare their significand. */
5438 mx = (a->Prec < b->Prec) ? a->Prec : b->Prec;
5439 ind = 0;
5440 while (ind < mx) {
5441 if (a->frac[ind] > b->frac[ind]) {
5442 val = VpGetSign(a);
5443 goto Exit;
5444 }
5445 if (a->frac[ind] < b->frac[ind]) {
5446 val = -VpGetSign(b);
5447 goto Exit;
5448 }
5449 ++ind;
5450 }
5451 if (a->Prec > b->Prec) {
5452 val = VpGetSign(a);
5453 }
5454 else if (a->Prec < b->Prec) {
5455 val = -VpGetSign(b);
5456 }
5457
5458Exit:
5459 if (val > 1) val = 1;
5460 else if (val < -1) val = -1;
5461
5462#ifdef BIGDECIMAL_DEBUG
5463 if (gfDebug) {
5464 VPrint(stdout, " VpComp a=%\n", a);
5465 VPrint(stdout, " b=%\n", b);
5466 printf(" ans=%d\n", val);
5467 }
5468#endif /* BIGDECIMAL_DEBUG */
5469 return (int)val;
5470}
5471
5472/*
5473 * cntl_chr ... ASCIIZ Character, print control characters
5474 * Available control codes:
5475 * % ... VP variable. To print '%', use '%%'.
5476 * \n ... new line
5477 * \b ... backspace
5478 * \t ... tab
5479 * Note: % must not appear more than once
5480 * a ... VP variable to be printed
5481 */
5482#ifdef BIGDECIMAL_ENABLE_VPRINT
5483static int
5484VPrint(FILE *fp, const char *cntl_chr, Real *a)
5485{
5486 size_t i, j, nc, nd, ZeroSup, sep = 10;
5487 BDIGIT m, e, nn;
5488
5489 j = 0;
5490 nd = nc = 0; /* nd : number of digits in fraction part(every 10 digits, */
5491 /* nd<=10). */
5492 /* nc : number of characters printed */
5493 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
5494 while (*(cntl_chr + j)) {
5495 if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
5496 nc = 0;
5497 if (VpIsNaN(a)) {
5498 fprintf(fp, SZ_NaN);
5499 nc += 8;
5500 }
5501 else if (VpIsPosInf(a)) {
5502 fprintf(fp, SZ_INF);
5503 nc += 8;
5504 }
5505 else if (VpIsNegInf(a)) {
5506 fprintf(fp, SZ_NINF);
5507 nc += 9;
5508 }
5509 else if (!VpIsZero(a)) {
5510 if (BIGDECIMAL_NEGATIVE_P(a)) {
5511 fprintf(fp, "-");
5512 ++nc;
5513 }
5514 nc += fprintf(fp, "0.");
5515 switch (*(cntl_chr + j + 1)) {
5516 default:
5517 break;
5518
5519 case '0': case 'z':
5520 ZeroSup = 0;
5521 ++j;
5522 sep = cntl_chr[j] == 'z' ? RMPD_COMPONENT_FIGURES : 10;
5523 break;
5524 }
5525 for (i = 0; i < a->Prec; ++i) {
5526 m = BASE1;
5527 e = a->frac[i];
5528 while (m) {
5529 nn = e / m;
5530 if (!ZeroSup || nn) {
5531 nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
5532 /* as 0.00xx will not */
5533 /* be printed. */
5534 ++nd;
5535 ZeroSup = 0; /* Set to print succeeding zeros */
5536 }
5537 if (nd >= sep) { /* print ' ' after every 10 digits */
5538 nd = 0;
5539 nc += fprintf(fp, " ");
5540 }
5541 e = e - nn * m;
5542 m /= 10;
5543 }
5544 }
5545 nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
5546 nc += fprintf(fp, " (%"PRIdVALUE", %lu, %lu)", a->exponent, a->Prec, a->MaxPrec);
5547 }
5548 else {
5549 nc += fprintf(fp, "0.0");
5550 }
5551 }
5552 else {
5553 ++nc;
5554 if (*(cntl_chr + j) == '\\') {
5555 switch (*(cntl_chr + j + 1)) {
5556 case 'n':
5557 fprintf(fp, "\n");
5558 ++j;
5559 break;
5560 case 't':
5561 fprintf(fp, "\t");
5562 ++j;
5563 break;
5564 case 'b':
5565 fprintf(fp, "\n");
5566 ++j;
5567 break;
5568 default:
5569 fprintf(fp, "%c", *(cntl_chr + j));
5570 break;
5571 }
5572 }
5573 else {
5574 fprintf(fp, "%c", *(cntl_chr + j));
5575 if (*(cntl_chr + j) == '%') ++j;
5576 }
5577 }
5578 j++;
5579 }
5580
5581 return (int)nc;
5582}
5583#endif
5584
5585static void
5586VpFormatSt(char *psz, size_t fFmt)
5587{
5588 size_t ie, i, nf = 0;
5589 char ch;
5590
5591 if (fFmt == 0) return;
5592
5593 ie = strlen(psz);
5594 for (i = 0; i < ie; ++i) {
5595 ch = psz[i];
5596 if (!ch) break;
5597 if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
5598 if (ch == '.') { nf = 0; continue; }
5599 if (ch == 'E' || ch == 'e') break;
5600
5601 if (++nf > fFmt) {
5602 memmove(psz + i + 1, psz + i, ie - i + 1);
5603 ++ie;
5604 nf = 0;
5605 psz[i] = ' ';
5606 }
5607 }
5608}
5609
5610 VP_EXPORT ssize_t
5611VpExponent10(Real *a)
5612{
5613 ssize_t ex;
5614 size_t n;
5615
5616 if (!VpHasVal(a)) return 0;
5617
5618 ex = a->exponent * (ssize_t)BASE_FIG;
5619 n = BASE1;
5620 while ((a->frac[0] / n) == 0) {
5621 --ex;
5622 n /= 10;
5623 }
5624 return ex;
5625}
5626
5627 VP_EXPORT void
5628VpSzMantissa(Real *a,char *psz)
5629{
5630 size_t i, n, ZeroSup;
5631 BDIGIT_DBL m, e, nn;
5632
5633 if (VpIsNaN(a)) {
5634 sprintf(psz, SZ_NaN);
5635 return;
5636 }
5637 if (VpIsPosInf(a)) {
5638 sprintf(psz, SZ_INF);
5639 return;
5640 }
5641 if (VpIsNegInf(a)) {
5642 sprintf(psz, SZ_NINF);
5643 return;
5644 }
5645
5646 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
5647 if (!VpIsZero(a)) {
5648 if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
5649 n = a->Prec;
5650 for (i = 0; i < n; ++i) {
5651 m = BASE1;
5652 e = a->frac[i];
5653 while (m) {
5654 nn = e / m;
5655 if (!ZeroSup || nn) {
5656 sprintf(psz, "%lu", (unsigned long)nn); /* The leading zero(s) */
5657 psz += strlen(psz);
5658 /* as 0.00xx will be ignored. */
5659 ZeroSup = 0; /* Set to print succeeding zeros */
5660 }
5661 e = e - nn * m;
5662 m /= 10;
5663 }
5664 }
5665 *psz = 0;
5666 while (psz[-1] == '0') *(--psz) = 0;
5667 }
5668 else {
5669 if (VpIsPosZero(a)) sprintf(psz, "0");
5670 else sprintf(psz, "-0");
5671 }
5672}
5673
5674 VP_EXPORT int
5675VpToSpecialString(Real *a,char *psz,int fPlus)
5676/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
5677{
5678 if (VpIsNaN(a)) {
5679 sprintf(psz,SZ_NaN);
5680 return 1;
5681 }
5682
5683 if (VpIsPosInf(a)) {
5684 if (fPlus == 1) {
5685 *psz++ = ' ';
5686 }
5687 else if (fPlus == 2) {
5688 *psz++ = '+';
5689 }
5690 sprintf(psz, SZ_INF);
5691 return 1;
5692 }
5693 if (VpIsNegInf(a)) {
5694 sprintf(psz, SZ_NINF);
5695 return 1;
5696 }
5697 if (VpIsZero(a)) {
5698 if (VpIsPosZero(a)) {
5699 if (fPlus == 1) sprintf(psz, " 0.0");
5700 else if (fPlus == 2) sprintf(psz, "+0.0");
5701 else sprintf(psz, "0.0");
5702 }
5703 else sprintf(psz, "-0.0");
5704 return 1;
5705 }
5706 return 0;
5707}
5708
5709 VP_EXPORT void
5710VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
5711/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
5712{
5713 size_t i, n, ZeroSup;
5714 BDIGIT shift, m, e, nn;
5715 char *pszSav = psz;
5716 ssize_t ex;
5717
5718 if (VpToSpecialString(a, psz, fPlus)) return;
5719
5720 ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
5721
5722 if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
5723 else if (fPlus == 1) *psz++ = ' ';
5724 else if (fPlus == 2) *psz++ = '+';
5725
5726 *psz++ = '0';
5727 *psz++ = '.';
5728 n = a->Prec;
5729 for (i = 0; i < n; ++i) {
5730 m = BASE1;
5731 e = a->frac[i];
5732 while (m) {
5733 nn = e / m;
5734 if (!ZeroSup || nn) {
5735 sprintf(psz, "%lu", (unsigned long)nn); /* The reading zero(s) */
5736 psz += strlen(psz);
5737 /* as 0.00xx will be ignored. */
5738 ZeroSup = 0; /* Set to print succeeding zeros */
5739 }
5740 e = e - nn * m;
5741 m /= 10;
5742 }
5743 }
5744 ex = a->exponent * (ssize_t)BASE_FIG;
5745 shift = BASE1;
5746 while (a->frac[0] / shift == 0) {
5747 --ex;
5748 shift /= 10;
5749 }
5750 while (psz[-1] == '0') {
5751 *(--psz) = 0;
5752 }
5753 sprintf(psz, "e%"PRIdSIZE, ex);
5754 if (fFmt) VpFormatSt(pszSav, fFmt);
5755}
5756
5757 VP_EXPORT void
5758VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
5759/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
5760{
5761 size_t i, n;
5762 BDIGIT m, e, nn;
5763 char *pszSav = psz;
5764 ssize_t ex;
5765
5766 if (VpToSpecialString(a, psz, fPlus)) return;
5767
5768 if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
5769 else if (fPlus == 1) *psz++ = ' ';
5770 else if (fPlus == 2) *psz++ = '+';
5771
5772 n = a->Prec;
5773 ex = a->exponent;
5774 if (ex <= 0) {
5775 *psz++ = '0';*psz++ = '.';
5776 while (ex < 0) {
5777 for (i=0; i < BASE_FIG; ++i) *psz++ = '0';
5778 ++ex;
5779 }
5780 ex = -1;
5781 }
5782
5783 for (i = 0; i < n; ++i) {
5784 --ex;
5785 if (i == 0 && ex >= 0) {
5786 sprintf(psz, "%lu", (unsigned long)a->frac[i]);
5787 psz += strlen(psz);
5788 }
5789 else {
5790 m = BASE1;
5791 e = a->frac[i];
5792 while (m) {
5793 nn = e / m;
5794 *psz++ = (char)(nn + '0');
5795 e = e - nn * m;
5796 m /= 10;
5797 }
5798 }
5799 if (ex == 0) *psz++ = '.';
5800 }
5801 while (--ex>=0) {
5802 m = BASE;
5803 while (m /= 10) *psz++ = '0';
5804 if (ex == 0) *psz++ = '.';
5805 }
5806 *psz = 0;
5807 while (psz[-1] == '0') *(--psz) = 0;
5808 if (psz[-1] == '.') sprintf(psz, "0");
5809 if (fFmt) VpFormatSt(pszSav, fFmt);
5810}
5811
5812/*
5813 * [Output]
5814 * a[] ... variable to be assigned the value.
5815 * [Input]
5816 * int_chr[] ... integer part(may include '+/-').
5817 * ni ... number of characters in int_chr[],not including '+/-'.
5818 * frac[] ... fraction part.
5819 * nf ... number of characters in frac[].
5820 * exp_chr[] ... exponent part(including '+/-').
5821 * ne ... number of characters in exp_chr[],not including '+/-'.
5822 */
5823 VP_EXPORT int
5824VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
5825{
5826 size_t i, j, ind_a, ma, mi, me;
5827 SIGNED_VALUE e, es, eb, ef;
5828 int sign, signe, exponent_overflow;
5829
5830 /* get exponent part */
5831 e = 0;
5832 ma = a->MaxPrec;
5833 mi = ni;
5834 me = ne;
5835 signe = 1;
5836 exponent_overflow = 0;
5837 memset(a->frac, 0, ma * sizeof(BDIGIT));
5838 if (ne > 0) {
5839 i = 0;
5840 if (exp_chr[0] == '-') {
5841 signe = -1;
5842 ++i;
5843 ++me;
5844 }
5845 else if (exp_chr[0] == '+') {
5846 ++i;
5847 ++me;
5848 }
5849 while (i < me) {
5850 if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
5851 es = e;
5852 goto exp_overflow;
5853 }
5854 es = e * (SIGNED_VALUE)BASE_FIG;
5855 if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5856 SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
5857 goto exp_overflow;
5858 e = e * 10 + exp_chr[i] - '0';
5859 if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5860 goto exp_overflow;
5861 if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
5862 exp_overflow:
5863 exponent_overflow = 1;
5864 e = es; /* keep sign */
5865 break;
5866 }
5867 ++i;
5868 }
5869 }
5870
5871 /* get integer part */
5872 i = 0;
5873 sign = 1;
5874 if (1 /*ni >= 0*/) {
5875 if (int_chr[0] == '-') {
5876 sign = -1;
5877 ++i;
5878 ++mi;
5879 }
5880 else if (int_chr[0] == '+') {
5881 ++i;
5882 ++mi;
5883 }
5884 }
5885
5886 e = signe * e; /* e: The value of exponent part. */
5887 e = e + ni; /* set actual exponent size. */
5888
5889 if (e > 0) signe = 1;
5890 else signe = -1;
5891
5892 /* Adjust the exponent so that it is the multiple of BASE_FIG. */
5893 j = 0;
5894 ef = 1;
5895 while (ef) {
5896 if (e >= 0) eb = e;
5897 else eb = -e;
5898 ef = eb / (SIGNED_VALUE)BASE_FIG;
5899 ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
5900 if (ef) {
5901 ++j; /* Means to add one more preceding zero */
5902 ++e;
5903 }
5904 }
5905
5906 eb = e / (SIGNED_VALUE)BASE_FIG;
5907
5908 if (exponent_overflow) {
5909 int zero = 1;
5910 for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
5911 for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
5912 if (!zero && signe > 0) {
5913 VpSetInf(a, sign);
5914 VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
5915 }
5916 else VpSetZero(a, sign);
5917 return 1;
5918 }
5919
5920 ind_a = 0;
5921 while (i < mi) {
5922 a->frac[ind_a] = 0;
5923 while (j < BASE_FIG && i < mi) {
5924 a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
5925 ++j;
5926 ++i;
5927 }
5928 if (i < mi) {
5929 ++ind_a;
5930 if (ind_a >= ma) goto over_flow;
5931 j = 0;
5932 }
5933 }
5934
5935 /* get fraction part */
5936
5937 i = 0;
5938 while (i < nf) {
5939 while (j < BASE_FIG && i < nf) {
5940 a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
5941 ++j;
5942 ++i;
5943 }
5944 if (i < nf) {
5945 ++ind_a;
5946 if (ind_a >= ma) goto over_flow;
5947 j = 0;
5948 }
5949 }
5950 goto Final;
5951
5952over_flow:
5953 rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
5954
5955Final:
5956 if (ind_a >= ma) ind_a = ma - 1;
5957 while (j < BASE_FIG) {
5958 a->frac[ind_a] = a->frac[ind_a] * 10;
5959 ++j;
5960 }
5961 a->Prec = ind_a + 1;
5962 a->exponent = eb;
5963 VpSetSign(a, sign);
5964 VpNmlz(a);
5965 return 1;
5966}
5967
5968/*
5969 * [Input]
5970 * *m ... Real
5971 * [Output]
5972 * *d ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
5973 * *e ... exponent of m.
5974 * DBLE_FIG ... Number of digits in a double variable.
5975 *
5976 * m -> d*10**e, 0<d<BASE
5977 * [Returns]
5978 * 0 ... Zero
5979 * 1 ... Normal
5980 * 2 ... Infinity
5981 * -1 ... NaN
5982 */
5983 VP_EXPORT int
5984VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
5985{
5986 size_t ind_m, mm, fig;
5987 double div;
5988 int f = 1;
5989
5990 if (VpIsNaN(m)) {
5991 *d = VpGetDoubleNaN();
5992 *e = 0;
5993 f = -1; /* NaN */
5994 goto Exit;
5995 }
5996 else if (VpIsPosZero(m)) {
5997 *d = 0.0;
5998 *e = 0;
5999 f = 0;
6000 goto Exit;
6001 }
6002 else if (VpIsNegZero(m)) {
6003 *d = VpGetDoubleNegZero();
6004 *e = 0;
6005 f = 0;
6006 goto Exit;
6007 }
6008 else if (VpIsPosInf(m)) {
6009 *d = VpGetDoublePosInf();
6010 *e = 0;
6011 f = 2;
6012 goto Exit;
6013 }
6014 else if (VpIsNegInf(m)) {
6015 *d = VpGetDoubleNegInf();
6016 *e = 0;
6017 f = 2;
6018 goto Exit;
6019 }
6020 /* Normal number */
6021 fig = (DBLE_FIG + BASE_FIG - 1) / BASE_FIG;
6022 ind_m = 0;
6023 mm = Min(fig, m->Prec);
6024 *d = 0.0;
6025 div = 1.;
6026 while (ind_m < mm) {
6027 div /= (double)BASE;
6028 *d = *d + (double)m->frac[ind_m++] * div;
6029 }
6030 *e = m->exponent * (SIGNED_VALUE)BASE_FIG;
6031 *d *= VpGetSign(m);
6032
6033Exit:
6034#ifdef BIGDECIMAL_DEBUG
6035 if (gfDebug) {
6036 VPrint(stdout, " VpVtoD: m=%\n", m);
6037 printf(" d=%e * 10 **%ld\n", *d, *e);
6038 printf(" DBLE_FIG = %d\n", DBLE_FIG);
6039 }
6040#endif /*BIGDECIMAL_DEBUG */
6041 return f;
6042}
6043
6044/*
6045 * m <- d
6046 */
6047 VP_EXPORT void
6048VpDtoV(Real *m, double d)
6049{
6050 size_t ind_m, mm;
6051 SIGNED_VALUE ne;
6052 BDIGIT i;
6053 double val, val2;
6054
6055 if (isnan(d)) {
6056 VpSetNaN(m);
6057 goto Exit;
6058 }
6059 if (isinf(d)) {
6060 if (d > 0.0) VpSetPosInf(m);
6061 else VpSetNegInf(m);
6062 goto Exit;
6063 }
6064
6065 if (d == 0.0) {
6066 VpSetZero(m, 1);
6067 goto Exit;
6068 }
6069 val = (d > 0.) ? d : -d;
6070 ne = 0;
6071 if (val >= 1.0) {
6072 while (val >= 1.0) {
6073 val /= (double)BASE;
6074 ++ne;
6075 }
6076 }
6077 else {
6078 val2 = 1.0 / (double)BASE;
6079 while (val < val2) {
6080 val *= (double)BASE;
6081 --ne;
6082 }
6083 }
6084 /* Now val = 0.xxxxx*BASE**ne */
6085
6086 mm = m->MaxPrec;
6087 memset(m->frac, 0, mm * sizeof(BDIGIT));
6088 for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
6089 val *= (double)BASE;
6090 i = (BDIGIT)val;
6091 val -= (double)i;
6092 m->frac[ind_m] = i;
6093 }
6094 if (ind_m >= mm) ind_m = mm - 1;
6095 VpSetSign(m, (d > 0.0) ? 1 : -1);
6096 m->Prec = ind_m + 1;
6097 m->exponent = ne;
6098
6099 VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
6100 (BDIGIT)(val*(double)BASE));
6101
6102Exit:
6103#ifdef BIGDECIMAL_DEBUG
6104 if (gfDebug) {
6105 printf("VpDtoV d=%30.30e\n", d);
6106 VPrint(stdout, " m=%\n", m);
6107 }
6108#endif /* BIGDECIMAL_DEBUG */
6109 return;
6110}
6111
6112/*
6113 * m <- ival
6114 */
6115#if 0 /* unused */
6116 VP_EXPORT void
6117VpItoV(Real *m, SIGNED_VALUE ival)
6118{
6119 size_t mm, ind_m;
6120 size_t val, v1, v2, v;
6121 int isign;
6122 SIGNED_VALUE ne;
6123
6124 if (ival == 0) {
6125 VpSetZero(m, 1);
6126 goto Exit;
6127 }
6128 isign = 1;
6129 val = ival;
6130 if (ival < 0) {
6131 isign = -1;
6132 val =(size_t)(-ival);
6133 }
6134 ne = 0;
6135 ind_m = 0;
6136 mm = m->MaxPrec;
6137 while (ind_m < mm) {
6138 m->frac[ind_m] = 0;
6139 ++ind_m;
6140 }
6141 ind_m = 0;
6142 while (val > 0) {
6143 if (val) {
6144 v1 = val;
6145 v2 = 1;
6146 while (v1 >= BASE) {
6147 v1 /= BASE;
6148 v2 *= BASE;
6149 }
6150 val = val - v2 * v1;
6151 v = v1;
6152 }
6153 else {
6154 v = 0;
6155 }
6156 m->frac[ind_m] = v;
6157 ++ind_m;
6158 ++ne;
6159 }
6160 m->Prec = ind_m - 1;
6161 m->exponent = ne;
6162 VpSetSign(m, isign);
6163 VpNmlz(m);
6164
6165Exit:
6166#ifdef BIGDECIMAL_DEBUG
6167 if (gfDebug) {
6168 printf(" VpItoV i=%d\n", ival);
6169 VPrint(stdout, " m=%\n", m);
6170 }
6171#endif /* BIGDECIMAL_DEBUG */
6172 return;
6173}
6174#endif
6175
6176/*
6177 * y = SQRT(x), y*y - x =>0
6178 */
6179 VP_EXPORT int
6180VpSqrt(Real *y, Real *x)
6181{
6182 Real *f = NULL;
6183 Real *r = NULL;
6184 size_t y_prec;
6185 SIGNED_VALUE n, e;
6186 SIGNED_VALUE prec;
6187 ssize_t nr;
6188 double val;
6189
6190 /* Zero or +Infinity ? */
6191 if (VpIsZero(x) || VpIsPosInf(x)) {
6192 VpAsgn(y,x,1);
6193 goto Exit;
6194 }
6195
6196 /* Negative ? */
6197 if (BIGDECIMAL_NEGATIVE_P(x)) {
6198 VpSetNaN(y);
6199 return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
6200 }
6201
6202 /* NaN ? */
6203 if (VpIsNaN(x)) {
6204 VpSetNaN(y);
6205 return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
6206 }
6207
6208 /* One ? */
6209 if (VpIsOne(x)) {
6210 VpSetOne(y);
6211 goto Exit;
6212 }
6213
6214 n = (SIGNED_VALUE)y->MaxPrec;
6215 if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
6216
6217 /* allocate temporally variables */
6218 f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1, 1);
6219 r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1, 1);
6220
6221 nr = 0;
6222 y_prec = y->MaxPrec;
6223
6224 prec = x->exponent - (ssize_t)y_prec;
6225 if (x->exponent > 0)
6226 ++prec;
6227 else
6228 --prec;
6229
6230 VpVtoD(&val, &e, x); /* val <- x */
6231 e /= (SIGNED_VALUE)BASE_FIG;
6232 n = e / 2;
6233 if (e - n * 2 != 0) {
6234 val /= BASE;
6235 n = (e + 1) / 2;
6236 }
6237 VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
6238 y->exponent += n;
6239 n = (SIGNED_VALUE)((DBLE_FIG + BASE_FIG - 1) / BASE_FIG);
6240 y->MaxPrec = Min((size_t)n , y_prec);
6241 f->MaxPrec = y->MaxPrec + 1;
6242 n = (SIGNED_VALUE)(y_prec * BASE_FIG);
6243 if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
6244 do {
6245 y->MaxPrec *= 2;
6246 if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
6247 f->MaxPrec = y->MaxPrec;
6248 VpDivd(f, r, x, y); /* f = x/y */
6249 VpAddSub(r, f, y, -1); /* r = f - y */
6250 VpMult(f, VpPt5, r); /* f = 0.5*r */
6251 if (VpIsZero(f)) goto converge;
6252 VpAddSub(r, f, y, 1); /* r = y + f */
6253 VpAsgn(y, r, 1); /* y = r */
6254 } while (++nr < n);
6255
6256#ifdef BIGDECIMAL_DEBUG
6257 if (gfDebug) {
6258 printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
6259 }
6260#endif /* BIGDECIMAL_DEBUG */
6261 y->MaxPrec = y_prec;
6262
6263converge:
6264 VpChangeSign(y, 1);
6265#ifdef BIGDECIMAL_DEBUG
6266 if (gfDebug) {
6267 VpMult(r, y, y);
6268 VpAddSub(f, x, r, -1);
6269 printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
6270 VPrint(stdout, " y =% \n", y);
6271 VPrint(stdout, " x =% \n", x);
6272 VPrint(stdout, " x-y*y = % \n", f);
6273 }
6274#endif /* BIGDECIMAL_DEBUG */
6275 y->MaxPrec = y_prec;
6276
6277Exit:
6278 VpFree(f);
6279 VpFree(r);
6280 return 1;
6281}
6282
6283/*
6284 * Round relatively from the decimal point.
6285 * f: rounding mode
6286 * nf: digit location to round from the decimal point.
6287 */
6288 VP_EXPORT int
6289VpMidRound(Real *y, unsigned short f, ssize_t nf)
6290{
6291 /* fracf: any positive digit under rounding position? */
6292 /* fracf_1further: any positive digits under one further than the rounding position? */
6293 /* exptoadd: number of digits needed to compensate negative nf */
6294 int fracf, fracf_1further;
6295 ssize_t n,i,ix,ioffset, exptoadd;
6296 BDIGIT v, shifter;
6297 BDIGIT div;
6298
6299 nf += y->exponent * (ssize_t)BASE_FIG;
6300 exptoadd=0;
6301 if (nf < 0) {
6302 /* rounding position too left(large). */
6303 if (f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) {
6304 VpSetZero(y, VpGetSign(y)); /* truncate everything */
6305 return 0;
6306 }
6307 exptoadd = -nf;
6308 nf = 0;
6309 }
6310
6311 ix = nf / (ssize_t)BASE_FIG;
6312 if ((size_t)ix >= y->Prec) return 0; /* rounding position too right(small). */
6313 v = y->frac[ix];
6314
6315 ioffset = nf - ix*(ssize_t)BASE_FIG;
6316 n = (ssize_t)BASE_FIG - ioffset - 1;
6317 for (shifter = 1, i = 0; i < n; ++i) shifter *= 10;
6318
6319 /* so the representation used (in y->frac) is an array of BDIGIT, where
6320 each BDIGIT contains a value between 0 and BASE-1, consisting of BASE_FIG
6321 decimal places.
6322
6323 (that numbers of decimal places are typed as ssize_t is somewhat confusing)
6324
6325 nf is now position (in decimal places) of the digit from the start of
6326 the array.
6327
6328 ix is the position (in BDIGITS) of the BDIGIT containing the decimal digit,
6329 from the start of the array.
6330
6331 v is the value of this BDIGIT
6332
6333 ioffset is the number of extra decimal places along of this decimal digit
6334 within v.
6335
6336 n is the number of decimal digits remaining within v after this decimal digit
6337 shifter is 10**n,
6338
6339 v % shifter are the remaining digits within v
6340 v % (shifter * 10) are the digit together with the remaining digits within v
6341 v / shifter are the digit's predecessors together with the digit
6342 div = v / shifter / 10 is just the digit's precessors
6343 (v / shifter) - div*10 is just the digit, which is what v ends up being reassigned to.
6344 */
6345
6346 fracf = (v % (shifter * 10) > 0);
6347 fracf_1further = ((v % shifter) > 0);
6348
6349 v /= shifter;
6350 div = v / 10;
6351 v = v - div*10;
6352 /* now v is just the digit required.
6353 now fracf is whether the digit or any of the remaining digits within v are non-zero
6354 now fracf_1further is whether any of the remaining digits within v are non-zero
6355 */
6356
6357 /* now check all the remaining BDIGITS for zero-ness a whole BDIGIT at a time.
6358 if we spot any non-zeroness, that means that we found a positive digit under
6359 rounding position, and we also found a positive digit under one further than
6360 the rounding position, so both searches (to see if any such non-zero digit exists)
6361 can stop */
6362
6363 for (i = ix + 1; (size_t)i < y->Prec; i++) {
6364 if (y->frac[i] % BASE) {
6365 fracf = fracf_1further = 1;
6366 break;
6367 }
6368 }
6369
6370 /* now fracf = does any positive digit exist under the rounding position?
6371 now fracf_1further = does any positive digit exist under one further than the
6372 rounding position?
6373 now v = the first digit under the rounding position */
6374
6375 /* drop digits after pointed digit */
6376 memset(y->frac + ix + 1, 0, (y->Prec - (ix + 1)) * sizeof(BDIGIT));
6377
6378 switch (f) {
6379 case VP_ROUND_DOWN: /* Truncate */
6380 break;
6381 case VP_ROUND_UP: /* Roundup */
6382 if (fracf) ++div;
6383 break;
6384 case VP_ROUND_HALF_UP:
6385 if (v>=5) ++div;
6386 break;
6387 case VP_ROUND_HALF_DOWN:
6388 if (v > 5 || (v == 5 && fracf_1further)) ++div;
6389 break;
6390 case VP_ROUND_CEIL:
6391 if (fracf && BIGDECIMAL_POSITIVE_P(y)) ++div;
6392 break;
6393 case VP_ROUND_FLOOR:
6394 if (fracf && BIGDECIMAL_NEGATIVE_P(y)) ++div;
6395 break;
6396 case VP_ROUND_HALF_EVEN: /* Banker's rounding */
6397 if (v > 5) ++div;
6398 else if (v == 5) {
6399 if (fracf_1further) {
6400 ++div;
6401 }
6402 else {
6403 if (ioffset == 0) {
6404 /* v is the first decimal digit of its BDIGIT;
6405 need to grab the previous BDIGIT if present
6406 to check for evenness of the previous decimal
6407 digit (which is same as that of the BDIGIT since
6408 base 10 has a factor of 2) */
6409 if (ix && (y->frac[ix-1] % 2)) ++div;
6410 }
6411 else {
6412 if (div % 2) ++div;
6413 }
6414 }
6415 }
6416 break;
6417 }
6418 for (i = 0; i <= n; ++i) div *= 10;
6419 if (div >= BASE) {
6420 if (ix) {
6421 y->frac[ix] = 0;
6422 VpRdup(y, ix);
6423 }
6424 else {
6425 short s = VpGetSign(y);
6426 SIGNED_VALUE e = y->exponent;
6427 VpSetOne(y);
6428 VpSetSign(y, s);
6429 y->exponent = e + 1;
6430 }
6431 }
6432 else {
6433 y->frac[ix] = div;
6434 VpNmlz(y);
6435 }
6436 if (exptoadd > 0) {
6437 y->exponent += (SIGNED_VALUE)(exptoadd / BASE_FIG);
6438 exptoadd %= (ssize_t)BASE_FIG;
6439 for (i = 0; i < exptoadd; i++) {
6440 y->frac[0] *= 10;
6441 if (y->frac[0] >= BASE) {
6442 y->frac[0] /= BASE;
6443 y->exponent++;
6444 }
6445 }
6446 }
6447 return 1;
6448}
6449
6450 VP_EXPORT int
6451VpLeftRound(Real *y, unsigned short f, ssize_t nf)
6452/*
6453 * Round from the left hand side of the digits.
6454 */
6455{
6456 BDIGIT v;
6457 if (!VpHasVal(y)) return 0; /* Unable to round */
6458 v = y->frac[0];
6459 nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6460 while ((v /= 10) != 0) nf--;
6461 nf += (ssize_t)BASE_FIG-1;
6462 return VpMidRound(y, f, nf);
6463}
6464
6465 VP_EXPORT int
6466VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
6467{
6468 /* First,assign whole value in truncation mode */
6469 if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */
6470 return VpMidRound(y, f, nf);
6471}
6472
6473static int
6474VpLimitRound(Real *c, size_t ixDigit)
6475{
6476 size_t ix = VpGetPrecLimit();
6477 if (!VpNmlz(c)) return -1;
6478 if (!ix) return 0;
6479 if (!ixDigit) ixDigit = c->Prec-1;
6480 if ((ix + BASE_FIG - 1) / BASE_FIG > ixDigit + 1) return 0;
6481 return VpLeftRound(c, VpGetRoundMode(), (ssize_t)ix);
6482}
6483
6484/* If I understand correctly, this is only ever used to round off the final decimal
6485 digit of precision */
6486static void
6487VpInternalRound(Real *c, size_t ixDigit, BDIGIT vPrev, BDIGIT v)
6488{
6489 int f = 0;
6490
6491 unsigned short const rounding_mode = VpGetRoundMode();
6492
6493 if (VpLimitRound(c, ixDigit)) return;
6494 if (!v) return;
6495
6496 v /= BASE1;
6497 switch (rounding_mode) {
6498 case VP_ROUND_DOWN:
6499 break;
6500 case VP_ROUND_UP:
6501 if (v) f = 1;
6502 break;
6503 case VP_ROUND_HALF_UP:
6504 if (v >= 5) f = 1;
6505 break;
6506 case VP_ROUND_HALF_DOWN:
6507 /* this is ok - because this is the last digit of precision,
6508 the case where v == 5 and some further digits are nonzero
6509 will never occur */
6510 if (v >= 6) f = 1;
6511 break;
6512 case VP_ROUND_CEIL:
6513 if (v && BIGDECIMAL_POSITIVE_P(c)) f = 1;
6514 break;
6515 case VP_ROUND_FLOOR:
6516 if (v && BIGDECIMAL_NEGATIVE_P(c)) f = 1;
6517 break;
6518 case VP_ROUND_HALF_EVEN: /* Banker's rounding */
6519 /* as per VP_ROUND_HALF_DOWN, because this is the last digit of precision,
6520 there is no case to worry about where v == 5 and some further digits are nonzero */
6521 if (v > 5) f = 1;
6522 else if (v == 5 && vPrev % 2) f = 1;
6523 break;
6524 }
6525 if (f) {
6526 VpRdup(c, ixDigit);
6527 VpNmlz(c);
6528 }
6529}
6530
6531/*
6532 * Rounds up m(plus one to final digit of m).
6533 */
6534static int
6535VpRdup(Real *m, size_t ind_m)
6536{
6537 BDIGIT carry;
6538
6539 if (!ind_m) ind_m = m->Prec;
6540
6541 carry = 1;
6542 while (carry > 0 && ind_m--) {
6543 m->frac[ind_m] += carry;
6544 if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
6545 else carry = 0;
6546 }
6547 if (carry > 0) { /* Overflow,count exponent and set fraction part be 1 */
6548 if (!AddExponent(m, 1)) return 0;
6549 m->Prec = m->frac[0] = 1;
6550 }
6551 else {
6552 VpNmlz(m);
6553 }
6554 return 1;
6555}
6556
6557/*
6558 * y = x - fix(x)
6559 */
6560 VP_EXPORT void
6561VpFrac(Real *y, Real *x)
6562{
6563 size_t my, ind_y, ind_x;
6564
6565 if (!VpHasVal(x)) {
6566 VpAsgn(y, x, 1);
6567 goto Exit;
6568 }
6569
6570 if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) {
6571 VpSetZero(y, VpGetSign(x));
6572 goto Exit;
6573 }
6574 else if (x->exponent <= 0) {
6575 VpAsgn(y, x, 1);
6576 goto Exit;
6577 }
6578
6579 /* satisfy: x->exponent > 0 */
6580
6581 y->Prec = x->Prec - (size_t)x->exponent;
6582 y->Prec = Min(y->Prec, y->MaxPrec);
6583 y->exponent = 0;
6584 VpSetSign(y, VpGetSign(x));
6585 ind_y = 0;
6586 my = y->Prec;
6587 ind_x = x->exponent;
6588 while (ind_y < my) {
6589 y->frac[ind_y] = x->frac[ind_x];
6590 ++ind_y;
6591 ++ind_x;
6592 }
6593 VpNmlz(y);
6594
6595Exit:
6596#ifdef BIGDECIMAL_DEBUG
6597 if (gfDebug) {
6598 VPrint(stdout, "VpFrac y=%\n", y);
6599 VPrint(stdout, " x=%\n", x);
6600 }
6601#endif /* BIGDECIMAL_DEBUG */
6602 return;
6603}
6604
6605/*
6606 * y = x ** n
6607 */
6608 VP_EXPORT int
6609VpPower(Real *y, Real *x, SIGNED_VALUE n)
6610{
6611 size_t s, ss;
6612 ssize_t sign;
6613 Real *w1 = NULL;
6614 Real *w2 = NULL;
6615
6616 if (VpIsZero(x)) {
6617 if (n == 0) {
6618 VpSetOne(y);
6619 goto Exit;
6620 }
6621 sign = VpGetSign(x);
6622 if (n < 0) {
6623 n = -n;
6624 if (sign < 0) sign = (n % 2) ? -1 : 1;
6625 VpSetInf(y, sign);
6626 }
6627 else {
6628 if (sign < 0) sign = (n % 2) ? -1 : 1;
6629 VpSetZero(y,sign);
6630 }
6631 goto Exit;
6632 }
6633 if (VpIsNaN(x)) {
6634 VpSetNaN(y);
6635 goto Exit;
6636 }
6637 if (VpIsInf(x)) {
6638 if (n == 0) {
6639 VpSetOne(y);
6640 goto Exit;
6641 }
6642 if (n > 0) {
6643 VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
6644 goto Exit;
6645 }
6646 VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
6647 goto Exit;
6648 }
6649
6650 if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
6651 /* abs(x) = 1 */
6652 VpSetOne(y);
6653 if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
6654 if ((n % 2) == 0) goto Exit;
6655 VpSetSign(y, -1);
6656 goto Exit;
6657 }
6658
6659 if (n > 0) sign = 1;
6660 else if (n < 0) {
6661 sign = -1;
6662 n = -n;
6663 }
6664 else {
6665 VpSetOne(y);
6666 goto Exit;
6667 }
6668
6669 /* Allocate working variables */
6670
6671 w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1);
6672 w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1);
6673 /* calculation start */
6674
6675 VpAsgn(y, x, 1);
6676 --n;
6677 while (n > 0) {
6678 VpAsgn(w1, x, 1);
6679 s = 1;
6680 while (ss = s, (s += s) <= (size_t)n) {
6681 VpMult(w2, w1, w1);
6682 VpAsgn(w1, w2, 1);
6683 }
6684 n -= (SIGNED_VALUE)ss;
6685 VpMult(w2, y, w1);
6686 VpAsgn(y, w2, 1);
6687 }
6688 if (sign < 0) {
6689 VpDivd(w1, w2, VpConstOne, y);
6690 VpAsgn(y, w1, 1);
6691 }
6692
6693Exit:
6694#ifdef BIGDECIMAL_DEBUG
6695 if (gfDebug) {
6696 VPrint(stdout, "VpPower y=%\n", y);
6697 VPrint(stdout, "VpPower x=%\n", x);
6698 printf(" n=%"PRIdVALUE"\n", n);
6699 }
6700#endif /* BIGDECIMAL_DEBUG */
6701 VpFree(w2);
6702 VpFree(w1);
6703 return 1;
6704}
6705
6706#ifdef BIGDECIMAL_DEBUG
6707int
6708VpVarCheck(Real * v)
6709/*
6710 * Checks the validity of the Real variable v.
6711 * [Input]
6712 * v ... Real *, variable to be checked.
6713 * [Returns]
6714 * 0 ... correct v.
6715 * other ... error
6716 */
6717{
6718 size_t i;
6719
6720 if (v->MaxPrec == 0) {
6721 printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n",
6722 v->MaxPrec);
6723 return 1;
6724 }
6725 if (v->Prec == 0 || v->Prec > v->MaxPrec) {
6726 printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec);
6727 printf(" Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec);
6728 return 2;
6729 }
6730 for (i = 0; i < v->Prec; ++i) {
6731 if (v->frac[i] >= BASE) {
6732 printf("ERROR(VpVarCheck): Illegal fraction\n");
6733 printf(" Frac[%"PRIuSIZE"]=%"PRIuBDIGIT"\n", i, v->frac[i]);
6734 printf(" Prec. =%"PRIuSIZE"\n", v->Prec);
6735 printf(" Exp. =%"PRIdVALUE"\n", v->exponent);
6736 printf(" BASE =%"PRIuBDIGIT"\n", BASE);
6737 return 3;
6738 }
6739 }
6740 return 0;
6741}
6742#endif /* BIGDECIMAL_DEBUG */
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
assert.h
NORETURN
#define NORETURN(x)
Definition: attributes.h:152
UNREACHABLE
#define UNREACHABLE
Definition: assume.h:30
VpGetDoubleNegZero
VP_EXPORT double VpGetDoubleNegZero(void)
Definition: bigdecimal.c:3953
VpDivd
VP_EXPORT size_t VpDivd(Real *c, Real *r, Real *a, Real *b)
Definition: bigdecimal.c:5133
PUSH
#define PUSH(x)
Definition: bigdecimal.c:69
VpCreateRbObject
VP_EXPORT Real * VpCreateRbObject(size_t mx, const char *str)
Definition: bigdecimal.c:783
RB_OBJ_CLASSNAME
#define RB_OBJ_CLASSNAME(obj)
Definition: bigdecimal.c:98
GUARD_OBJ
#define GUARD_OBJ(p, y)
Definition: bigdecimal.c:71
BigMath_exp
#define BigMath_exp(x, n)
Definition: bigdecimal.c:2307
SIGNED_VALUE_MAX
#define SIGNED_VALUE_MAX
Definition: bigdecimal.c:41
VpIsRoundMode
VP_EXPORT int VpIsRoundMode(unsigned short n)
Definition: bigdecimal.c:3876
VpToString
VP_EXPORT void VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
Definition: bigdecimal.c:5710
VpInit
VP_EXPORT size_t VpInit(BDIGIT BaseVal)
Definition: bigdecimal.c:4141
rmpd_set_thread_local_rounding_mode
#define rmpd_set_thread_local_rounding_mode(mode)
Definition: bigdecimal.c:3852
VpGetDoubleNaN
VP_EXPORT double VpGetDoubleNaN(void)
Definition: bigdecimal.c:3935
rb_cBigDecimal
VALUE rb_cBigDecimal
Definition: bigdecimal.c:45
VpGetDoubleNegInf
VP_EXPORT double VpGetDoubleNegInf(void)
Definition: bigdecimal.c:3947
SAVE
#define SAVE(p)
Definition: bigdecimal.c:70
ENTER
#define ENTER(n)
Definition: bigdecimal.c:68
MUL_OVERFLOW_SIGNED_VALUE_P
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b)
Definition: bigdecimal.c:43
VpGetRoundMode
VP_EXPORT unsigned short VpGetRoundMode(void)
Definition: bigdecimal.c:3860
VpDtoV
VP_EXPORT void VpDtoV(Real *m, double d)
Definition: bigdecimal.c:6048
maxnr
#define maxnr
Definition: bigdecimal.c:3705
VpMult
VP_EXPORT size_t VpMult(Real *c, Real *a, Real *b)
Definition: bigdecimal.c:5004
VpActiveRound
VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
Definition: bigdecimal.c:6466
RMPD_PRECISION_LIMIT_DEFAULT
#define RMPD_PRECISION_LIMIT_DEFAULT
Definition: bigdecimal.c:3821
VpAllocReal
#define VpAllocReal(prec)
Definition: bigdecimal.c:788
BIGDECIMAL_NEGATIVE_P
#define BIGDECIMAL_NEGATIVE_P(bd)
Definition: bigdecimal.c:155
VpFrac
VP_EXPORT void VpFrac(Real *y, Real *x)
Definition: bigdecimal.c:6561
Init_bigdecimal
void Init_bigdecimal(void)
Definition: bigdecimal.c:3456
VpExponent10
VP_EXPORT ssize_t VpExponent10(Real *a)
Definition: bigdecimal.c:5611
VpLeftRound
VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf)
Definition: bigdecimal.c:6451
VpOne
VP_EXPORT Real * VpOne(void)
Definition: bigdecimal.c:4169
VpAddSub
VP_EXPORT size_t VpAddSub(Real *c, Real *a, Real *b, int operation)
Definition: bigdecimal.c:4549
VpGetPrecLimit
VP_EXPORT size_t VpGetPrecLimit(void)
Definition: bigdecimal.c:3825
VpSetRoundMode
VP_EXPORT unsigned short VpSetRoundMode(unsigned short n)
Definition: bigdecimal.c:3894
BASE
#define BASE
Definition: bigdecimal.c:74
VpSetPrecLimit
VP_EXPORT size_t VpSetPrecLimit(size_t n)
Definition: bigdecimal.c:3841
VpNewRbClass
VP_EXPORT Real * VpNewRbClass(size_t mx, const char *str, VALUE klass)
Definition: bigdecimal.c:772
VpSzMantissa
VP_EXPORT void VpSzMantissa(Real *a, char *psz)
Definition: bigdecimal.c:5628
VpNumOfChars
VP_EXPORT size_t VpNumOfChars(Real *vp, const char *pszFmt)
Definition: bigdecimal.c:4097
VpSqrt
VP_EXPORT int VpSqrt(Real *y, Real *x)
Definition: bigdecimal.c:6180
op_sw
op_sw
Definition: bigdecimal.c:3712
OP_SW_ADD
@ OP_SW_ADD
Definition: bigdecimal.c:3713
OP_SW_DIV
@ OP_SW_DIV
Definition: bigdecimal.c:3716
OP_SW_SUB
@ OP_SW_SUB
Definition: bigdecimal.c:3714
OP_SW_MULT
@ OP_SW_MULT
Definition: bigdecimal.c:3715
BASE_FIG
#define BASE_FIG
Definition: bigdecimal.c:73
gOne_ABCED9B4_CE73__00400511F31D
volatile const double gOne_ABCED9B4_CE73__00400511F31D
Definition: bigdecimal.c:3912
RRATIONAL_NEGATIVE_P
#define RRATIONAL_NEGATIVE_P(x)
Definition: bigdecimal.c:89
VpAlloc
VP_EXPORT Real * VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
Definition: bigdecimal.c:4272
rmpd_parse_special_string
Real * rmpd_parse_special_string(const char *str)
Definition: bigdecimal.c:4213
BIGDECIMAL_POSITIVE_P
#define BIGDECIMAL_POSITIVE_P(bd)
Definition: bigdecimal.c:154
VpMemAlloc
VP_EXPORT void * VpMemAlloc(size_t mb)
Definition: bigdecimal.c:3736
VpComp
VP_EXPORT int VpComp(Real *a, Real *b)
Definition: bigdecimal.c:5386
DoSomeOne
#define DoSomeOne(x, y, f)
Definition: bigdecimal.c:160
VpMidRound
VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf)
Definition: bigdecimal.c:6289
is_positive
#define is_positive(x)
Definition: bigdecimal.c:2331
DBLE_FIG
#define DBLE_FIG
Definition: bigdecimal.c:80
HALF_BASE
#define HALF_BASE
Definition: bigdecimal.c:76
BigMath_log
#define BigMath_log(x, n)
Definition: bigdecimal.c:2308
rb_mBigMath
VALUE rb_mBigMath
Definition: bigdecimal.c:46
rmpd_set_thread_local_precision_limit
#define rmpd_set_thread_local_precision_limit(limit)
Definition: bigdecimal.c:3815
RRATIONAL_ZERO_P
#define RRATIONAL_ZERO_P(x)
Definition: bigdecimal.c:84
VpException
VP_EXPORT int VpException(unsigned short f, const char *str, int always)
Definition: bigdecimal.c:3970
VpMemRealloc
VP_EXPORT void * VpMemRealloc(void *ptr, size_t mb)
Definition: bigdecimal.c:3750
BASE1
#define BASE1
Definition: bigdecimal.c:77
VpPower
VP_EXPORT int VpPower(Real *y, Real *x, SIGNED_VALUE n)
Definition: bigdecimal.c:6609
VpVtoD
VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
Definition: bigdecimal.c:5984
VpToFString
VP_EXPORT void VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
Definition: bigdecimal.c:5758
MemCmp
#define MemCmp(x, y, z)
Definition: bigdecimal.c:3709
rmpd_set_thread_local_exception_mode
#define rmpd_set_thread_local_exception_mode(mode)
Definition: bigdecimal.c:3782
VpAsgn
VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw)
Definition: bigdecimal.c:4505
VpCtoV
VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
Definition: bigdecimal.c:5824
VpReallocReal
#define VpReallocReal(ptr, prec)
Definition: bigdecimal.c:789
VpFree
VP_EXPORT void VpFree(Real *pv)
Definition: bigdecimal.c:3760
VpToSpecialString
VP_EXPORT int VpToSpecialString(Real *a, char *psz, int fPlus)
Definition: bigdecimal.c:5675
VpGetDoublePosInf
VP_EXPORT double VpGetDoublePosInf(void)
Definition: bigdecimal.c:3941
bigdecimal.h
VP_SIGN_NaN
#define VP_SIGN_NaN
Definition: bigdecimal.h:226
SZ_NINF
#define SZ_NINF
Definition: bigdecimal.h:192
VP_EXCEPTION_ZERODIVIDE
#define VP_EXCEPTION_ZERODIVIDE
Definition: bigdecimal.h:206
BDIGIT_DBL
#define BDIGIT_DBL
Definition: bigdecimal.h:49
VpMaxPrec
#define VpMaxPrec(a)
Definition: bigdecimal.h:351
VpIsInf
#define VpIsInf(a)
Definition: bigdecimal.h:382
VpIsNaN
#define VpIsNaN(a)
Definition: bigdecimal.h:376
SZ_INF
#define SZ_INF
Definition: bigdecimal.h:190
VpIsDef
#define VpIsDef(a)
Definition: bigdecimal.h:383
VP_EXPORT
#define VP_EXPORT
Definition: bigdecimal.h:198
VP_ROUND_DOWN
#define VP_ROUND_DOWN
Definition: bigdecimal.h:217
VP_ROUND_FLOOR
#define VP_ROUND_FLOOR
Definition: bigdecimal.h:221
VP_SIGN_NEGATIVE_INFINITE
#define VP_SIGN_NEGATIVE_INFINITE
Definition: bigdecimal.h:232
VP_SIGN_POSITIVE_ZERO
#define VP_SIGN_POSITIVE_ZERO
Definition: bigdecimal.h:227
VP_ROUND_HALF_EVEN
#define VP_ROUND_HALF_EVEN
Definition: bigdecimal.h:222
VpExponent
#define VpExponent(a)
Definition: bigdecimal.h:389
VpChangeSign
#define VpChangeSign(a, s)
Definition: bigdecimal.h:360
rb_category_warn
#define rb_category_warn(category,...)
Definition: bigdecimal.h:163
VpSetNaN
#define VpSetNaN(a)
Definition: bigdecimal.h:377
VpBaseVal
#define VpBaseVal()
Definition: bigdecimal.h:289
VP_EXCEPTION_OP
#define VP_EXCEPTION_OP
Definition: bigdecimal.h:209
Max
#define Max(a, b)
Definition: bigdecimal.h:348
VP_EXCEPTION_UNDERFLOW
#define VP_EXCEPTION_UNDERFLOW
Definition: bigdecimal.h:204
VpIsZero
#define VpIsZero(a)
Definition: bigdecimal.h:370
BDIGIT_DBL_SIGNED
#define BDIGIT_DBL_SIGNED
Definition: bigdecimal.h:50
VpSetInf
#define VpSetInf(a, s)
Definition: bigdecimal.h:386
VpDblFig
#define VpDblFig()
Definition: bigdecimal.h:288
VpSetPosInf
#define VpSetPosInf(a)
Definition: bigdecimal.h:384
VP_ROUND_CEIL
#define VP_ROUND_CEIL
Definition: bigdecimal.h:220
VpIsPosInf
#define VpIsPosInf(a)
Definition: bigdecimal.h:380
VP_ROUND_HALF_DOWN
#define VP_ROUND_HALF_DOWN
Definition: bigdecimal.h:219
VpSetSign
#define VpSetSign(a, s)
Definition: bigdecimal.h:362
RMPD_ROUNDING_MODE_DEFAULT
#define RMPD_ROUNDING_MODE_DEFAULT
Definition: bigdecimal.h:224
VP_SIGN_NEGATIVE_FINITE
#define VP_SIGN_NEGATIVE_FINITE
Definition: bigdecimal.h:230
VpHasVal
#define VpHasVal(a)
Definition: bigdecimal.h:387
VpGetSign
#define VpGetSign(a)
Definition: bigdecimal.h:358
VpSetNegInf
#define VpSetNegInf(a)
Definition: bigdecimal.h:385
RMPD_EXCEPTION_MODE_DEFAULT
#define RMPD_EXCEPTION_MODE_DEFAULT
Definition: bigdecimal.h:212
Min
#define Min(a, b)
Definition: bigdecimal.h:349
VpIsNegZero
#define VpIsNegZero(a)
Definition: bigdecimal.h:369
VpIsNegInf
#define VpIsNegInf(a)
Definition: bigdecimal.h:381
VP_SIGN_NEGATIVE_ZERO
#define VP_SIGN_NEGATIVE_ZERO
Definition: bigdecimal.h:228
VpBaseFig
#define VpBaseFig()
Definition: bigdecimal.h:287
BDIGIT
#define BDIGIT
Definition: bigdecimal.h:48
VP_SIGN_POSITIVE_INFINITE
#define VP_SIGN_POSITIVE_INFINITE
Definition: bigdecimal.h:231
VP_EXCEPTION_OVERFLOW
#define VP_EXCEPTION_OVERFLOW
Definition: bigdecimal.h:205
VpSetOne
#define VpSetOne(a)
Definition: bigdecimal.h:365
VP_EXCEPTION_ALL
#define VP_EXCEPTION_ALL
Definition: bigdecimal.h:201
vabs
#define vabs
Definition: bigdecimal.h:155
SZ_NaN
#define SZ_NaN
Definition: bigdecimal.h:189
VP_ROUND_UP
#define VP_ROUND_UP
Definition: bigdecimal.h:216
VP_SIGN_POSITIVE_FINITE
#define VP_SIGN_POSITIVE_FINITE
Definition: bigdecimal.h:229
SZ_PINF
#define SZ_PINF
Definition: bigdecimal.h:191
VpIsPosZero
#define VpIsPosZero(a)
Definition: bigdecimal.h:368
VP_EXCEPTION_MEMORY
#define VP_EXCEPTION_MEMORY
Definition: bigdecimal.h:210
PRIuBDIGIT
#define PRIuBDIGIT
Definition: bigdecimal.h:59
VP_EXCEPTION_NaN
#define VP_EXCEPTION_NaN
Definition: bigdecimal.h:203
VP_EXCEPTION_INFINITY
#define VP_EXCEPTION_INFINITY
Definition: bigdecimal.h:202
VpIsOne
#define VpIsOne(a)
Definition: bigdecimal.h:388
VP_ROUND_MODE
#define VP_ROUND_MODE
Definition: bigdecimal.h:215
RMPD_COMPONENT_FIGURES
#define RMPD_COMPONENT_FIGURES
Definition: bigdecimal.h:181
VP_ROUND_HALF_UP
#define VP_ROUND_HALF_UP
Definition: bigdecimal.h:218
VpSetZero
#define VpSetZero(a, s)
Definition: bigdecimal.h:373
rb_big2str
VALUE rb_big2str(VALUE x, int base)
Definition: bignum.c:5090
rb_big_cmp
VALUE rb_big_cmp(VALUE x, VALUE y)
Definition: bignum.c:5416
rb_dbl2big
VALUE rb_dbl2big(double d)
Definition: bignum.c:5248
rb_big_pack
void rb_big_pack(VALUE val, unsigned long *buf, long num_longs)
Definition: bignum.c:3221
rb_complex_real
VALUE rb_complex_real(VALUE self)
Definition: complex.c:735
id_to_r
#define id_to_r
Definition: complex.c:52
rb_complex_imag
VALUE rb_complex_imag(VALUE self)
Definition: complex.c:752
ctype.h
Our own, locale independent, character handling routines.
ISSPACE
#define ISSPACE
Definition: ctype.h:38
ISDIGIT
#define ISDIGIT
Definition: ctype.h:43
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition: cxxanyargs.hpp:678
mod
#define mod(x, y)
Definition: date_strftime.c:28
div
#define div(x, y)
Definition: date_strftime.c:27
ptr
struct RIMemo * ptr
Definition: debug.c:88
assert
#define assert(x)
Definition: dlmalloc.c:1176
RFLOAT_VALUE
#define RFLOAT_VALUE
Definition: double.h:28
num
big_t * num
Definition: enough.c:232
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
RSTRING_LEN
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
memcpy
#define memcpy(d, s, n)
Definition: ffi_common.h:55
RB_OBJ_FREEZE
#define RB_OBJ_FREEZE
Definition: fl_type.h:86
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_eZeroDivError
VALUE rb_eZeroDivError
Definition: numeric.c:193
CLASS_OF
#define CLASS_OF
Definition: globals.h:153
rb_cNumeric
VALUE rb_cNumeric
Definition: numeric.c:189
rb_eFloatDomainError
VALUE rb_eFloatDomainError
Definition: numeric.c:194
rb_eMathDomainError
VALUE rb_eMathDomainError
Definition: math.c:37
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:871
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1777
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:2085
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:712
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:1007
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:768
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:1057
rb_fatal
void rb_fatal(const char *fmt,...)
Definition: error.c:2968
rb_protect
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *pstate)
Protects a function call from potential global escapes from the function.
Definition: eval.c:1105
rb_check_typeddata
void * rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:1024
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:408
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_jump_tag
void rb_jump_tag(int tag)
Continues the exception caught by rb_protect() and rb_eval_string_protect().
Definition: eval.c:921
opts_exception_p
#define opts_exception_p(opts)
Definition: object.c:3166
rb_check_convert_type
VALUE rb_check_convert_type(VALUE, int, const char *, const char *)
Tries to convert an object into another type.
Definition: object.c:2971
rb_opts_exception_p
int rb_opts_exception_p(VALUE opts, int default_value)
Definition: object.c:3157
rb_obj_class
VALUE rb_obj_class(VALUE)
Definition: object.c:245
rb_inspect
VALUE rb_inspect(VALUE)
Convenient wrapper of Object::inspect.
Definition: object.c:585
rb_hash_lookup2
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Definition: hash.c:2059
FIXABLE
#define FIXABLE
Definition: fixnum.h:25
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Definition: error.h:34
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
rb_ary_new2
#define rb_ary_new2
Definition: array.h:72
rb_exc_new3
#define rb_exc_new3
Definition: error.h:31
rb_ext_ractor_safe
void rb_ext_ractor_safe(bool flag)
Definition: load.c:1058
rb_num_coerce_cmp
VALUE rb_num_coerce_cmp(VALUE, VALUE, ID)
Definition: numeric.c:459
rb_num_coerce_relop
VALUE rb_num_coerce_relop(VALUE, VALUE, ID)
Definition: numeric.c:474
rb_Rational
VALUE rb_Rational(VALUE, VALUE)
Definition: rational.c:1968
rb_Rational1
#define rb_Rational1(x)
Definition: rational.h:37
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_str_resize
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2859
rb_str_cat2
#define rb_str_cat2
Definition: string.h:285
rb_memhash
st_index_t rb_memhash(const void *ptr, long len)
Definition: random.c:1629
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_usascii_str_new
#define rb_usascii_str_new(str, len)
Definition: string.h:224
rb_check_string_type
VALUE rb_check_string_type(VALUE)
Definition: string.c:2462
rb_str_tmp_new
VALUE rb_str_tmp_new(long)
Definition: string.c:1427
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1631
rb_thread_local_aref
VALUE rb_thread_local_aref(VALUE, ID)
Definition: thread.c:3480
rb_thread_check_ints
void rb_thread_check_ints(void)
Definition: thread.c:1577
rb_thread_current
VALUE rb_thread_current(void)
Definition: thread.c:2911
rb_class_name
VALUE rb_class_name(VALUE)
Definition: variable.c:293
rb_undef_alloc_func
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:954
ID2SYM
#define ID2SYM
Definition: symbol.h:44
SYM2ID
#define SYM2ID
Definition: symbol.h:45
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:3150
round
double round(double)
Definition: numeric.c:92
isfinite
#define isfinite(x)
Definition: missing.h:187
nan
double nan(const char *)
Definition: nan.c:7
memmove
void * memmove(void *, const void *, size_t)
Definition: memmove.c:7
HUGE_VAL
#define HUGE_VAL
Definition: missing.h:156
util.h
strtod
#define strtod(s, e)
Definition: util.h:45
DECIMAL_SIZE_OF_BITS
#define DECIMAL_SIZE_OF_BITS(n)
Definition: util.h:19
FIX2INT
#define FIX2INT
Definition: int.h:41
NUM2INT
#define NUM2INT
Definition: int.h:44
INT2NUM
#define INT2NUM
Definition: int.h:43
RCOMPLEX
#define RCOMPLEX(obj)
Definition: complex.h:20
rb_float_new
#define rb_float_new
Definition: numeric.h:95
RRATIONAL
#define RRATIONAL(obj)
Definition: rational.h:24
bp
#define bp()
Definition: internal.h:105
PRIdVALUE
#define PRIdVALUE
Definition: inttypes.h:72
PRIuSIZE
#define PRIuSIZE
Definition: inttypes.h:127
PRIdSIZE
#define PRIdSIZE
Definition: inttypes.h:124
long
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
mode
const char int mode
Definition: ioapi.h:137
buf
voidpf void * buf
Definition: ioapi.h:138
isinf
int isinf(double n)
Definition: isinf.c:56
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
CHAR_BIT
#define CHAR_BIT
Definition: limits.h:44
INT2FIX
#define INT2FIX
Definition: long.h:48
LONG2FIX
#define LONG2FIX
Definition: long.h:49
LONG2NUM
#define LONG2NUM
Definition: long.h:50
FIX2LONG
#define FIX2LONG
Definition: long.h:46
math.h
Internal header for Math.
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: memory.h:91
id
const int id
Definition: nkf.c:209
DBL_MIN_10_EXP
#define DBL_MIN_10_EXP
Definition: numeric.c:61
DBL_MAX_10_EXP
#define DBL_MAX_10_EXP
Definition: numeric.c:64
id_eq
#define id_eq
Definition: numeric.c:186
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
id_ceil
#define id_ceil
Definition: rational.c:1587
DATA_PTR
#define DATA_PTR(obj)
Definition: rdata.h:56
NULL
#define NULL
Definition: regenc.h:69
StringValueCStr
#define StringValueCStr(v)
Definition: rstring.h:52
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Definition: rtypeddata.h:47
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: rtypeddata.h:101
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
RUBY_TYPED_FROZEN_SHAREABLE
@ RUBY_TYPED_FROZEN_SHAREABLE
Definition: rtypeddata.h:63
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
ST2FIX
#define ST2FIX(h)
Definition: ruby_missing.h:21
NUM2USHORT
#define NUM2USHORT
Definition: short.h:33
NUM2SSIZET
#define NUM2SSIZET
Definition: size_t.h:53
SSIZET2NUM
#define SSIZET2NUM
Definition: size_t.h:54
SIZET2NUM
#define SIZET2NUM
Definition: size_t.h:52
NUM2SIZET
#define NUM2SIZET
Definition: size_t.h:51
Qundef
#define Qundef
Definition: special_consts.h:53
SPECIAL_CONST_P
#define SPECIAL_CONST_P
Definition: special_consts.h:47
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
FIXNUM_P
#define FIXNUM_P
Definition: special_consts.h:44
f
#define f
st_index_t
st_data_t st_index_t
Definition: st.h:50
strlen
size_t strlen(const char *)
__sFILE
Definition: vsnprintf.c:169
Real
Definition: bigdecimal.h:246
Real::MaxPrec
size_t MaxPrec
Definition: bigdecimal.h:248
Real::exponent
SIGNED_VALUE exponent
Definition: bigdecimal.h:254
Real::Prec
size_t Prec
Definition: bigdecimal.h:251
Real::flag
short flag
Definition: bigdecimal.h:265
Real::frac
BDIGIT frac[FLEXIBLE_ARRAY_SIZE]
Definition: bigdecimal.h:266
Real::obj
VALUE obj
Definition: bigdecimal.h:247
Real::sign
short sign
Definition: bigdecimal.h:255
ind
Definition: gun.c:81
rb_data_type_struct
Definition: rtypeddata.h:70
state
Definition: blast.c:41
snprintf
#define snprintf
Definition: subst.h:14
ne
#define ne(x, y)
Definition: time.c:92
VALUE
unsigned long VALUE
Definition: value.h:38
SIGNED_VALUE
#define SIGNED_VALUE
Definition: value.h:40
SIZEOF_VALUE
#define SIZEOF_VALUE
Definition: value.h:41
ID
unsigned long ID
Definition: value.h:39
T_COMPLEX
#define T_COMPLEX
Definition: value_type.h:58
TYPE
#define TYPE(_)
Definition: value_type.h:105
T_STRING
#define T_STRING
Definition: value_type.h:77
T_FLOAT
#define T_FLOAT
Definition: value_type.h:63
T_BIGNUM
#define T_BIGNUM
Definition: value_type.h:56
T_FIXNUM
#define T_FIXNUM
Definition: value_type.h:62
T_DATA
#define T_DATA
Definition: value_type.h:59
T_RATIONAL
#define T_RATIONAL
Definition: value_type.h:75
T_HASH
#define T_HASH
Definition: value_type.h:64
T_SYMBOL
#define T_SYMBOL
Definition: value_type.h:79
SYMBOL_P
#define SYMBOL_P
Definition: value_type.h:87
isnan
#define isnan(x)
Definition: win32.h:346
strncasecmp
#define strncasecmp
Definition: win32.h:208
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357
xfree
#define xfree
Definition: xmalloc.h:49
xrealloc
#define xrealloc
Definition: xmalloc.h:47
xmalloc
#define xmalloc
Definition: xmalloc.h:44