bigdecimal 3.2.2 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,16 +31,23 @@
31
31
  #include "bits.h"
32
32
  #include "static_assert.h"
33
33
 
34
- #define BIGDECIMAL_VERSION "3.2.2"
34
+ #define BIGDECIMAL_VERSION "3.3.0"
35
35
 
36
36
  /* #define ENABLE_NUMERIC_STRING */
37
37
 
38
38
  #define SIGNED_VALUE_MAX INTPTR_MAX
39
39
  #define SIGNED_VALUE_MIN INTPTR_MIN
40
40
  #define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
41
+ #define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
42
+
43
+ /* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
44
+ #define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
45
+ /* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
46
+ #define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
47
+ #define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
48
+ #define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
41
49
 
42
50
  VALUE rb_cBigDecimal;
43
- VALUE rb_mBigMath;
44
51
 
45
52
  static ID id_BigDecimal_exception_mode;
46
53
  static ID id_BigDecimal_rounding_mode;
@@ -68,15 +75,28 @@ static struct {
68
75
  uint8_t mode;
69
76
  } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
70
77
 
71
- /* MACRO's to guard objects from GC by keeping them in stack */
72
- #ifdef RBIMPL_ATTR_MAYBE_UNUSED
73
- #define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0
74
- #else
75
- #define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
76
- #endif
77
- #define PUSH(x) (vStack[iStack++] = (VALUE)(x))
78
- #define SAVE(p) PUSH((p)->obj)
79
- #define GUARD_OBJ(p,y) ((p)=(y), SAVE(p))
78
+ typedef struct {
79
+ VALUE bigdecimal;
80
+ Real *real;
81
+ } BDVALUE;
82
+
83
+ typedef struct {
84
+ VALUE bigdecimal_or_nil;
85
+ Real *real_or_null;
86
+ } NULLABLE_BDVALUE;
87
+
88
+ static inline BDVALUE
89
+ bdvalue_nonnullable(NULLABLE_BDVALUE v)
90
+ {
91
+ assert(v.real_or_null != NULL);
92
+ return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
93
+ }
94
+
95
+ static inline NULLABLE_BDVALUE
96
+ bdvalue_nullable(BDVALUE v)
97
+ {
98
+ return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
99
+ }
80
100
 
81
101
  #define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
82
102
  #define BASE BIGDECIMAL_BASE
@@ -84,31 +104,6 @@ static struct {
84
104
  #define HALF_BASE (BASE/2)
85
105
  #define BASE1 (BASE/10)
86
106
 
87
- #define LOG10_2 0.3010299956639812
88
-
89
- #ifndef RRATIONAL_ZERO_P
90
- # define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
91
- FIX2LONG(rb_rational_num(x)) == 0)
92
- #endif
93
-
94
- #ifndef RRATIONAL_NEGATIVE_P
95
- # define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
96
- #endif
97
-
98
- #ifndef DECIMAL_SIZE_OF_BITS
99
- #define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
100
- /* an approximation of ceil(n * log10(2)), upto 65536 at least */
101
- #endif
102
-
103
- #ifdef PRIsVALUE
104
- # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
105
- # define RB_OBJ_STRING(obj) (obj)
106
- #else
107
- # define PRIsVALUE "s"
108
- # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
109
- # define RB_OBJ_STRING(obj) StringValueCStr(obj)
110
- #endif
111
-
112
107
  #ifndef MAYBE_UNUSED
113
108
  # define MAYBE_UNUSED(x) x
114
109
  #endif
@@ -145,6 +140,17 @@ check_allocation_count_nonzero(void)
145
140
  # define check_allocation_count_nonzero() /* nothing */
146
141
  #endif /* BIGDECIMAL_DEBUG */
147
142
 
143
+ /* VpMult VpDivd helpers */
144
+ #define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
145
+ /* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
146
+ /* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
147
+ #define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
148
+ /* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
149
+ #define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
150
+
151
+ static NULLABLE_BDVALUE
152
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
153
+
148
154
  PUREFUNC(static inline size_t rbd_struct_size(size_t const));
149
155
 
150
156
  static inline size_t
@@ -164,44 +170,10 @@ rbd_allocate_struct(size_t const internal_digits)
164
170
  return real;
165
171
  }
166
172
 
167
- static size_t
168
- rbd_calculate_internal_digits(size_t const digits, bool limit_precision)
169
- {
170
- size_t const len = roomof(digits, BASE_FIG);
171
- if (limit_precision) {
172
- size_t const prec_limit = VpGetPrecLimit();
173
- if (prec_limit > 0) {
174
- /* NOTE: 2 more digits for rounding and division */
175
- size_t const max_len = roomof(prec_limit, BASE_FIG) + 2;
176
- if (len > max_len)
177
- return max_len;
178
- }
179
- }
180
-
181
- return len;
182
- }
183
-
184
173
  static inline Real *
185
- rbd_allocate_struct_decimal_digits(size_t const decimal_digits, bool limit_precision)
186
- {
187
- size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision);
188
- return rbd_allocate_struct(internal_digits);
189
- }
190
-
191
- static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp);
192
-
193
- static Real *
194
- rbd_reallocate_struct(Real *real, size_t const internal_digits)
174
+ rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
195
175
  {
196
- size_t const size = rbd_struct_size(internal_digits);
197
- VALUE obj = real ? real->obj : 0;
198
- Real *new_real = (Real *)ruby_xrealloc(real, size);
199
- new_real->MaxPrec = internal_digits;
200
- if (obj) {
201
- new_real->obj = 0;
202
- BigDecimal_wrap_struct(obj, new_real);
203
- }
204
- return new_real;
176
+ return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
205
177
  }
206
178
 
207
179
  static void
@@ -214,58 +186,16 @@ rbd_free_struct(Real *real)
214
186
  }
215
187
  }
216
188
 
189
+ MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
217
190
  #define NewZero rbd_allocate_struct_zero
218
- static Real *
219
- rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision)
220
- {
221
- Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
222
- VpSetZero(real, sign);
223
- return real;
224
- }
225
-
226
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits));
227
- #define NewZeroLimited rbd_allocate_struct_zero_limited
228
- static inline Real *
229
- rbd_allocate_struct_zero_limited(int sign, size_t const digits)
230
- {
231
- return rbd_allocate_struct_zero(sign, digits, true);
232
- }
233
-
234
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits));
235
- #define NewZeroNolimit rbd_allocate_struct_zero_nolimit
236
191
  static inline Real *
237
- rbd_allocate_struct_zero_nolimit(int sign, size_t const digits)
238
- {
239
- return rbd_allocate_struct_zero(sign, digits, false);
240
- }
241
-
242
- #define NewOne rbd_allocate_struct_one
243
- static Real *
244
- rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision)
192
+ rbd_allocate_struct_zero(int sign, size_t const digits)
245
193
  {
246
- Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
247
- VpSetOne(real);
248
- if (sign < 0)
249
- VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
194
+ Real *real = rbd_allocate_struct_decimal_digits(digits);
195
+ VpSetZero(real, sign);
250
196
  return real;
251
197
  }
252
198
 
253
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits));
254
- #define NewOneLimited rbd_allocate_struct_one_limited
255
- static inline Real *
256
- rbd_allocate_struct_one_limited(int sign, size_t const digits)
257
- {
258
- return rbd_allocate_struct_one(sign, digits, true);
259
- }
260
-
261
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits));
262
- #define NewOneNolimit rbd_allocate_struct_one_nolimit
263
- static inline Real *
264
- rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
265
- {
266
- return rbd_allocate_struct_one(sign, digits, false);
267
- }
268
-
269
199
  /*
270
200
  * ================== Ruby Interface part ==========================
271
201
  */
@@ -277,7 +207,8 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
277
207
  static unsigned short VpGetException(void);
278
208
  static void VpSetException(unsigned short f);
279
209
  static void VpCheckException(Real *p, bool always);
280
- static VALUE VpCheckGetValue(Real *p);
210
+ static int AddExponent(Real *a, SIGNED_VALUE n);
211
+ static VALUE CheckGetValue(BDVALUE v);
281
212
  static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
282
213
  static int VpLimitRound(Real *c, size_t ixDigit);
283
214
  static Real *VpCopy(Real *pv, Real const* const x);
@@ -292,6 +223,8 @@ static VALUE BigDecimal_positive_infinity(void);
292
223
  static VALUE BigDecimal_negative_infinity(void);
293
224
  static VALUE BigDecimal_positive_zero(void);
294
225
  static VALUE BigDecimal_negative_zero(void);
226
+ static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
227
+ static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
295
228
 
296
229
  static void
297
230
  BigDecimal_delete(void *pv)
@@ -319,58 +252,33 @@ static const rb_data_type_t BigDecimal_data_type = {
319
252
  #endif
320
253
  };
321
254
 
322
- static Real *
323
- rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
324
- {
325
- Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision);
326
- if (real != NULL) {
327
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
328
- BigDecimal_wrap_struct(obj, real);
329
- }
330
- return real;
331
- }
332
-
333
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
334
- #define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
335
- static inline Real *
336
- rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
337
- {
338
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
339
- }
340
-
341
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
342
- #define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
343
- static inline Real *
344
- rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
345
- {
346
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
347
- }
348
-
349
- static Real *
350
- rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
255
+ // TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
256
+ // We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
257
+ typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
258
+ static NULL_WRAPPED_VALUE
259
+ BigDecimal_alloc_empty_struct(VALUE klass)
351
260
  {
352
- Real *real = rbd_allocate_struct_one(sign, digits, limit_precision);
353
- if (real != NULL) {
354
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
355
- BigDecimal_wrap_struct(obj, real);
356
- }
357
- return real;
261
+ return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
358
262
  }
359
263
 
360
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits));
361
- #define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap
362
- static inline Real *
363
- rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
264
+ static VALUE
265
+ BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
364
266
  {
365
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
267
+ VALUE obj = v._obj;
268
+ assert(RTYPEDDATA_DATA(obj) == NULL);
269
+ RTYPEDDATA_DATA(obj) = real;
270
+ RB_OBJ_FREEZE(obj);
271
+ return obj;
366
272
  }
367
273
 
368
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits));
369
- #define NewOneWrapNolimit rbd_allocate_struct_one_nolimit_wrap
370
- static inline Real *
371
- rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)
274
+ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
275
+ #define NewZeroWrap rbd_allocate_struct_zero_wrap
276
+ static BDVALUE
277
+ rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
372
278
  {
373
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
279
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
280
+ Real *real = rbd_allocate_struct_zero(sign, digits);
281
+ return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
374
282
  }
375
283
 
376
284
  static inline int
@@ -398,24 +306,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
398
306
  }
399
307
 
400
308
  static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
401
- static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
309
+ static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
402
310
  static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
403
311
  static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
404
- static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception);
312
+ static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
405
313
  static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
406
314
 
407
- static Real*
408
- GetVpValueWithPrec(VALUE v, long prec, int must)
315
+ static NULLABLE_BDVALUE
316
+ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
409
317
  {
410
- const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
411
-
412
318
  switch(TYPE(v)) {
413
319
  case T_FLOAT:
414
- v = rb_float_convert_to_BigDecimal(v, digs, must);
320
+ v = rb_float_convert_to_BigDecimal(v, 0, true);
415
321
  break;
416
322
 
417
323
  case T_RATIONAL:
418
- v = rb_rational_convert_to_BigDecimal(v, digs, must);
324
+ v = rb_rational_convert_to_BigDecimal(v, prec, true);
419
325
  break;
420
326
 
421
327
  case T_DATA:
@@ -424,47 +330,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
424
330
  }
425
331
  break;
426
332
 
427
- case T_FIXNUM: {
428
- char szD[128];
429
- snprintf(szD, 128, "%ld", FIX2LONG(v));
430
- v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
333
+ case T_FIXNUM:
334
+ case T_BIGNUM: {
335
+ v = rb_inum_convert_to_BigDecimal(v);
431
336
  break;
432
337
  }
433
338
 
434
339
  #ifdef ENABLE_NUMERIC_STRING
435
340
  case T_STRING: {
436
341
  const char *c_str = StringValueCStr(v);
437
- v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
342
+ v = rb_cstr_convert_to_BigDecimal(c_str, must);
438
343
  break;
439
344
  }
440
345
  #endif /* ENABLE_NUMERIC_STRING */
441
346
 
442
- case T_BIGNUM: {
443
- VALUE bg = rb_big2str(v, 10);
444
- v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
445
- RB_GC_GUARD(bg);
446
- break;
447
- }
448
-
449
347
  default:
450
348
  goto SomeOneMayDoIt;
451
349
  }
452
350
 
453
351
  Real *vp;
454
352
  TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
455
- return vp;
353
+ return (NULLABLE_BDVALUE) { v, vp };
456
354
 
457
355
  SomeOneMayDoIt:
458
356
  if (must) {
459
357
  cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
460
358
  }
461
- return NULL; /* NULL means to coerce */
359
+ return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
360
+ }
361
+
362
+ static inline NULLABLE_BDVALUE
363
+ GetBDValueWithPrec(VALUE v, size_t prec)
364
+ {
365
+ return GetBDValueWithPrecInternal(v, prec, 0);
366
+ }
367
+
368
+
369
+ static inline BDVALUE
370
+ GetBDValueWithPrecMust(VALUE v, size_t prec)
371
+ {
372
+ return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
462
373
  }
463
374
 
375
+ // self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
464
376
  static inline Real*
465
- GetVpValue(VALUE v, int must)
377
+ GetSelfVpValue(VALUE self)
378
+ {
379
+ return GetBDValueWithPrecMust(self, 0).real;
380
+ }
381
+
382
+ static inline BDVALUE
383
+ GetBDValueMust(VALUE v)
466
384
  {
467
- return GetVpValueWithPrec(v, -1, must);
385
+ return GetBDValueWithPrecMust(v, 0);
468
386
  }
469
387
 
470
388
  /* call-seq:
@@ -479,7 +397,7 @@ GetVpValue(VALUE v, int must)
479
397
  static inline VALUE
480
398
  BigDecimal_double_fig(VALUE self)
481
399
  {
482
- return INT2FIX(VpDblFig());
400
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
483
401
  }
484
402
 
485
403
  /* call-seq:
@@ -498,17 +416,18 @@ BigDecimal_double_fig(VALUE self)
498
416
  static VALUE
499
417
  BigDecimal_prec(VALUE self)
500
418
  {
501
- ENTER(1);
502
- Real *p;
419
+ BDVALUE v;
503
420
  VALUE obj;
504
421
 
505
422
  rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
506
423
  "BigDecimal#precs is deprecated and will be removed in the future; "
507
424
  "use BigDecimal#precision instead.");
508
425
 
509
- GUARD_OBJ(p, GetVpValue(self, 1));
510
- obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
511
- SIZET2NUM(p->MaxPrec*VpBaseFig()));
426
+ v = GetBDValueMust(self);
427
+ obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
428
+ SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
429
+
430
+ RB_GC_GUARD(v.bigdecimal);
512
431
  return obj;
513
432
  }
514
433
 
@@ -623,10 +542,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
623
542
  static void
624
543
  BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
625
544
  {
626
- ENTER(1);
627
- Real *p;
628
- GUARD_OBJ(p, GetVpValue(self, 1));
629
- VpCountPrecisionAndScale(p, out_precision, out_scale);
545
+ BDVALUE v = GetBDValueMust(self);
546
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
547
+ RB_GC_GUARD(v.bigdecimal);
630
548
  }
631
549
 
632
550
  /*
@@ -664,8 +582,8 @@ BigDecimal_precision(VALUE self)
664
582
  * BigDecimal("1").scale # => 0
665
583
  * BigDecimal("1.1").scale # => 1
666
584
  * BigDecimal("3.1415").scale # => 4
667
- * BigDecimal("-1e20").precision # => 0
668
- * BigDecimal("1e-20").precision # => 20
585
+ * BigDecimal("-1e20").scale # => 0
586
+ * BigDecimal("1e-20").scale # => 20
669
587
  * BigDecimal("Infinity").scale # => 0
670
588
  * BigDecimal("-Infinity").scale # => 0
671
589
  * BigDecimal("NaN").scale # => 0
@@ -715,25 +633,23 @@ BigDecimal_precision_scale(VALUE self)
715
633
  static VALUE
716
634
  BigDecimal_n_significant_digits(VALUE self)
717
635
  {
718
- ENTER(1);
719
-
720
- Real *p;
721
- GUARD_OBJ(p, GetVpValue(self, 1));
722
- if (VpIsZero(p) || !VpIsDef(p)) {
636
+ BDVALUE v = GetBDValueMust(self);
637
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
723
638
  return INT2FIX(0);
724
639
  }
725
640
 
726
- ssize_t n = p->Prec; /* The length of frac without trailing zeros. */
727
- for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n);
641
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
642
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
728
643
  if (n == 0) return INT2FIX(0);
729
644
 
730
645
  DECDIG x;
731
646
  int nlz = BASE_FIG;
732
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
647
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
733
648
 
734
649
  int ntz = 0;
735
- for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
650
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
736
651
 
652
+ RB_GC_GUARD(v.bigdecimal);
737
653
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
738
654
  return SSIZET2NUM(n_significant_digits);
739
655
  }
@@ -755,17 +671,14 @@ BigDecimal_n_significant_digits(VALUE self)
755
671
  static VALUE
756
672
  BigDecimal_hash(VALUE self)
757
673
  {
758
- ENTER(1);
759
- Real *p;
760
- st_index_t hash;
761
-
762
- GUARD_OBJ(p, GetVpValue(self, 1));
763
- hash = (st_index_t)p->sign;
674
+ BDVALUE v = GetBDValueMust(self);
675
+ st_index_t hash = (st_index_t)v.real->sign;
764
676
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
765
677
  if(hash == 2 || hash == (st_index_t)-2) {
766
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
767
- hash += p->exponent;
678
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
679
+ hash += v.real->exponent;
768
680
  }
681
+ RB_GC_GUARD(v.bigdecimal);
769
682
  return ST2FIX(hash);
770
683
  }
771
684
 
@@ -784,21 +697,22 @@ BigDecimal_hash(VALUE self)
784
697
  static VALUE
785
698
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
786
699
  {
787
- ENTER(5);
788
- Real *vp;
700
+ BDVALUE v;
789
701
  char *psz;
790
702
  VALUE dummy;
791
703
  volatile VALUE dump;
792
704
  size_t len;
793
705
 
794
706
  rb_scan_args(argc, argv, "01", &dummy);
795
- GUARD_OBJ(vp,GetVpValue(self, 1));
796
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
707
+ v = GetBDValueMust(self);
708
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
797
709
  psz = RSTRING_PTR(dump);
798
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
710
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
799
711
  len = strlen(psz);
800
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
712
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
801
713
  rb_str_resize(dump, strlen(psz));
714
+
715
+ RB_GC_GUARD(v.bigdecimal);
802
716
  return dump;
803
717
  }
804
718
 
@@ -808,27 +722,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
808
722
  static VALUE
809
723
  BigDecimal_load(VALUE self, VALUE str)
810
724
  {
811
- ENTER(2);
812
- Real *pv;
725
+ BDVALUE v;
813
726
  unsigned char *pch;
814
727
  unsigned char ch;
815
- unsigned long m=0;
816
728
 
817
729
  pch = (unsigned char *)StringValueCStr(str);
818
- /* First get max prec */
730
+ /* First skip max prec. Don't trust the value. */
819
731
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
820
732
  if(!ISDIGIT(ch)) {
821
733
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
822
734
  }
823
- m = m*10 + (unsigned long)(ch-'0');
824
735
  }
825
- if (m > VpBaseFig()) m -= VpBaseFig();
826
- GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
827
- m /= VpBaseFig();
828
- if (m && pv->MaxPrec > m) {
829
- pv->MaxPrec = m+1;
830
- }
831
- return VpCheckGetValue(pv);
736
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
737
+ return CheckGetValue(v);
832
738
  }
833
739
 
834
740
  static unsigned short
@@ -1121,22 +1027,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1121
1027
  static size_t
1122
1028
  GetAddSubPrec(Real *a, Real *b)
1123
1029
  {
1124
- size_t mxs;
1125
- size_t mx = a->Prec;
1126
- SIGNED_VALUE d;
1127
-
1128
1030
  if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
1129
- if (mx < b->Prec) mx = b->Prec;
1130
- if (a->exponent != b->exponent) {
1131
- mxs = mx;
1132
- d = a->exponent - b->exponent;
1133
- if (d < 0) d = -d;
1134
- mx = mx + (size_t)d;
1135
- if (mx < mxs) {
1136
- return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
1137
- }
1138
- }
1139
- return mx;
1031
+ ssize_t min_a = a->exponent - a->Prec;
1032
+ ssize_t min_b = b->exponent - b->Prec;
1033
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
1140
1034
  }
1141
1035
 
1142
1036
  static inline SIGNED_VALUE
@@ -1156,39 +1050,13 @@ check_int_precision(VALUE v)
1156
1050
  return n;
1157
1051
  }
1158
1052
 
1159
- static VALUE
1160
- BigDecimal_wrap_struct(VALUE obj, Real *vp)
1161
- {
1162
- assert(is_kind_of_BigDecimal(obj));
1163
- assert(vp != NULL);
1164
-
1165
- if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
1166
- return obj;
1167
-
1168
- assert(RTYPEDDATA_DATA(obj) == NULL);
1169
- assert(vp->obj == 0);
1170
-
1171
- RTYPEDDATA_DATA(obj) = vp;
1172
- vp->obj = obj;
1173
- RB_OBJ_FREEZE(obj);
1174
- return obj;
1175
- }
1176
-
1177
- VP_EXPORT Real *
1178
- VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
1179
- {
1180
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
1181
- Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
1182
- if (!pv)
1183
- return NULL;
1184
- BigDecimal_wrap_struct(obj, pv);
1185
- return pv;
1186
- }
1187
-
1188
- VP_EXPORT Real *
1189
- VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
1053
+ static NULLABLE_BDVALUE
1054
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1190
1055
  {
1191
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
1056
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
1057
+ Real *pv = VpAlloc(str, strict_p, raise_exception);
1058
+ if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
1059
+ return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
1192
1060
  }
1193
1061
 
1194
1062
  static Real *
@@ -1196,7 +1064,7 @@ VpCopy(Real *pv, Real const* const x)
1196
1064
  {
1197
1065
  assert(x != NULL);
1198
1066
 
1199
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1067
+ pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
1200
1068
  pv->MaxPrec = x->MaxPrec;
1201
1069
  pv->Prec = x->Prec;
1202
1070
  pv->exponent = x->exponent;
@@ -1211,7 +1079,7 @@ VpCopy(Real *pv, Real const* const x)
1211
1079
  static VALUE
1212
1080
  BigDecimal_IsNaN(VALUE self)
1213
1081
  {
1214
- Real *p = GetVpValue(self, 1);
1082
+ Real *p = GetSelfVpValue(self);
1215
1083
  if (VpIsNaN(p)) return Qtrue;
1216
1084
  return Qfalse;
1217
1085
  }
@@ -1222,7 +1090,7 @@ BigDecimal_IsNaN(VALUE self)
1222
1090
  static VALUE
1223
1091
  BigDecimal_IsInfinite(VALUE self)
1224
1092
  {
1225
- Real *p = GetVpValue(self, 1);
1093
+ Real *p = GetSelfVpValue(self);
1226
1094
  if (VpIsPosInf(p)) return INT2FIX(1);
1227
1095
  if (VpIsNegInf(p)) return INT2FIX(-1);
1228
1096
  return Qnil;
@@ -1232,7 +1100,7 @@ BigDecimal_IsInfinite(VALUE self)
1232
1100
  static VALUE
1233
1101
  BigDecimal_IsFinite(VALUE self)
1234
1102
  {
1235
- Real *p = GetVpValue(self, 1);
1103
+ Real *p = GetSelfVpValue(self);
1236
1104
  if (VpIsNaN(p)) return Qfalse;
1237
1105
  if (VpIsInf(p)) return Qfalse;
1238
1106
  return Qtrue;
@@ -1244,6 +1112,7 @@ BigDecimal_check_num(Real *p)
1244
1112
  VpCheckException(p, true);
1245
1113
  }
1246
1114
 
1115
+ static VALUE BigDecimal_fix(VALUE self);
1247
1116
  static VALUE BigDecimal_split(VALUE self);
1248
1117
 
1249
1118
  /* Returns the value as an Integer.
@@ -1253,44 +1122,36 @@ static VALUE BigDecimal_split(VALUE self);
1253
1122
  static VALUE
1254
1123
  BigDecimal_to_i(VALUE self)
1255
1124
  {
1256
- ENTER(5);
1257
- ssize_t e, nf;
1258
- Real *p;
1125
+ BDVALUE v;
1126
+ VALUE ret;
1259
1127
 
1260
- GUARD_OBJ(p, GetVpValue(self, 1));
1261
- BigDecimal_check_num(p);
1128
+ v = GetBDValueMust(self);
1129
+ BigDecimal_check_num(v.real);
1262
1130
 
1263
- e = VpExponent10(p);
1264
- if (e <= 0) return INT2FIX(0);
1265
- nf = VpBaseFig();
1266
- if (e <= nf) {
1267
- return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
1131
+ if (v.real->exponent <= 0) return INT2FIX(0);
1132
+ if (v.real->exponent == 1) {
1133
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
1268
1134
  }
1269
1135
  else {
1270
- VALUE a = BigDecimal_split(self);
1271
- VALUE digits = RARRAY_AREF(a, 1);
1272
- VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
1273
- VALUE ret;
1274
- ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
1275
-
1276
- if (BIGDECIMAL_NEGATIVE_P(p)) {
1277
- numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
1278
- }
1279
- if (dpower < 0) {
1280
- ret = rb_funcall(numerator, rb_intern("div"), 1,
1281
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1282
- INT2FIX(-dpower)));
1283
- }
1284
- else {
1285
- ret = rb_funcall(numerator, '*', 1,
1286
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1287
- INT2FIX(dpower)));
1288
- }
1289
- if (RB_TYPE_P(ret, T_FLOAT)) {
1290
- rb_raise(rb_eFloatDomainError, "Infinity");
1291
- }
1292
- return ret;
1136
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
1137
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
1138
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
1139
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
1140
+
1141
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
1142
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
1143
+ }
1144
+ if (dpower) {
1145
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
1146
+ // In Ruby < 3.4, int**int may return Float::INFINITY
1147
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
1148
+
1149
+ ret = rb_funcall(ret, '*', 1, pow10);
1150
+ }
1293
1151
  }
1152
+
1153
+ RB_GC_GUARD(v.bigdecimal);
1154
+ return ret;
1294
1155
  }
1295
1156
 
1296
1157
  /* Returns a new Float object having approximately the same value as the
@@ -1300,24 +1161,26 @@ BigDecimal_to_i(VALUE self)
1300
1161
  static VALUE
1301
1162
  BigDecimal_to_f(VALUE self)
1302
1163
  {
1303
- ENTER(1);
1304
- Real *p;
1305
1164
  double d;
1306
1165
  SIGNED_VALUE e;
1307
1166
  char *buf;
1308
1167
  volatile VALUE str;
1168
+ BDVALUE v = GetBDValueMust(self);
1169
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1309
1170
 
1310
- GUARD_OBJ(p, GetVpValue(self, 1));
1311
- if (VpVtoD(&d, &e, p) != 1)
1171
+ if (VpVtoD(&d, &e, v.real) != 1)
1312
1172
  return rb_float_new(d);
1313
1173
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1314
1174
  goto overflow;
1315
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1175
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1316
1176
  goto underflow;
1317
1177
 
1318
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1178
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1319
1179
  buf = RSTRING_PTR(str);
1320
- VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1180
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
1181
+
1182
+ RB_GC_GUARD(v.bigdecimal);
1183
+
1321
1184
  errno = 0;
1322
1185
  d = strtod(buf, 0);
1323
1186
  if (errno == ERANGE) {
@@ -1328,14 +1191,14 @@ BigDecimal_to_f(VALUE self)
1328
1191
 
1329
1192
  overflow:
1330
1193
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1331
- if (BIGDECIMAL_NEGATIVE_P(p))
1194
+ if (negative)
1332
1195
  return rb_float_new(VpGetDoubleNegInf());
1333
1196
  else
1334
1197
  return rb_float_new(VpGetDoublePosInf());
1335
1198
 
1336
1199
  underflow:
1337
1200
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1338
- if (BIGDECIMAL_NEGATIVE_P(p))
1201
+ if (negative)
1339
1202
  return rb_float_new(-0.0);
1340
1203
  else
1341
1204
  return rb_float_new(0.0);
@@ -1347,15 +1210,16 @@ underflow:
1347
1210
  static VALUE
1348
1211
  BigDecimal_to_r(VALUE self)
1349
1212
  {
1350
- Real *p;
1213
+ BDVALUE v;
1351
1214
  ssize_t sign, power, denomi_power;
1352
1215
  VALUE a, digits, numerator;
1353
1216
 
1354
- p = GetVpValue(self, 1);
1355
- BigDecimal_check_num(p);
1217
+ v = GetBDValueMust(self);
1218
+ BigDecimal_check_num(v.real);
1219
+ sign = VpGetSign(v.real);
1220
+ power = VpExponent10(v.real);
1221
+ RB_GC_GUARD(v.bigdecimal);
1356
1222
 
1357
- sign = VpGetSign(p);
1358
- power = VpExponent10(p);
1359
1223
  a = BigDecimal_split(self);
1360
1224
  digits = RARRAY_AREF(a, 1);
1361
1225
  denomi_power = power - RSTRING_LEN(digits);
@@ -1376,6 +1240,14 @@ BigDecimal_to_r(VALUE self)
1376
1240
  }
1377
1241
  }
1378
1242
 
1243
+ static size_t
1244
+ GetCoercePrec(Real *a, size_t prec)
1245
+ {
1246
+ if (prec == 0) prec = a->Prec * BASE_FIG;
1247
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1248
+ return prec;
1249
+ }
1250
+
1379
1251
  /* The coerce method provides support for Ruby type coercion. It is not
1380
1252
  * enabled by default.
1381
1253
  *
@@ -1393,26 +1265,9 @@ BigDecimal_to_r(VALUE self)
1393
1265
  static VALUE
1394
1266
  BigDecimal_coerce(VALUE self, VALUE other)
1395
1267
  {
1396
- ENTER(2);
1397
- VALUE obj;
1398
- Real *b;
1399
-
1400
- if (RB_TYPE_P(other, T_FLOAT)) {
1401
- GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
1402
- obj = rb_assoc_new(VpCheckGetValue(b), self);
1403
- }
1404
- else {
1405
- if (RB_TYPE_P(other, T_RATIONAL)) {
1406
- Real* pv = DATA_PTR(self);
1407
- GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
1408
- }
1409
- else {
1410
- GUARD_OBJ(b, GetVpValue(other, 1));
1411
- }
1412
- obj = rb_assoc_new(b->obj, self);
1413
- }
1414
-
1415
- return obj;
1268
+ Real* pv = DATA_PTR(self);
1269
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1270
+ return rb_assoc_new(CheckGetValue(b), self);
1416
1271
  }
1417
1272
 
1418
1273
  /*
@@ -1432,6 +1287,15 @@ BigDecimal_uplus(VALUE self)
1432
1287
  return self;
1433
1288
  }
1434
1289
 
1290
+ static bool
1291
+ is_coerceable_to_BigDecimal(VALUE r)
1292
+ {
1293
+ return is_kind_of_BigDecimal(r) ||
1294
+ RB_INTEGER_TYPE_P(r) ||
1295
+ RB_TYPE_P(r, T_FLOAT) ||
1296
+ RB_TYPE_P(r, T_RATIONAL);
1297
+ }
1298
+
1435
1299
  /*
1436
1300
  * call-seq:
1437
1301
  * self + value -> bigdecimal
@@ -1451,42 +1315,40 @@ BigDecimal_uplus(VALUE self)
1451
1315
  static VALUE
1452
1316
  BigDecimal_add(VALUE self, VALUE r)
1453
1317
  {
1454
- ENTER(5);
1455
- Real *c, *a, *b;
1456
- size_t mx;
1318
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
1319
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
1320
+ }
1457
1321
 
1458
- GUARD_OBJ(a, GetVpValue(self, 1));
1459
- if (RB_TYPE_P(r, T_FLOAT)) {
1460
- b = GetVpValueWithPrec(r, 0, 1);
1461
- }
1462
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1463
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1464
- }
1465
- else {
1466
- b = GetVpValue(r, 0);
1467
- }
1322
+ static VALUE
1323
+ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1324
+ {
1325
+ BDVALUE a, b, c;
1326
+ size_t mx;
1468
1327
 
1469
- if (!b) return DoSomeOne(self,r,'+');
1470
- SAVE(b);
1328
+ a = GetBDValueMust(self);
1329
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1471
1330
 
1472
- if (VpIsNaN(b)) return b->obj;
1473
- if (VpIsNaN(a)) return a->obj;
1331
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1332
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1474
1333
 
1475
- mx = GetAddSubPrec(a, b);
1334
+ mx = GetAddSubPrec(a.real, b.real);
1476
1335
  if (mx == (size_t)-1L) {
1477
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1478
- VpAddSub(c, a, b, 1);
1336
+ /* a or b is inf */
1337
+ c = NewZeroWrap(1, BASE_FIG);
1338
+ VpAddSub(c.real, a.real, b.real, operation);
1479
1339
  }
1480
1340
  else {
1481
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1482
- if (!mx) {
1483
- VpSetInf(c, VpGetSign(a));
1484
- }
1485
- else {
1486
- VpAddSub(c, a, b, 1);
1487
- }
1341
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1342
+ size_t pl = VpGetPrecLimit();
1343
+ if (prec) VpSetPrecLimit(prec);
1344
+ // Let VpAddSub round the result
1345
+ VpAddSub(c.real, a.real, b.real, operation);
1346
+ if (prec) VpSetPrecLimit(pl);
1488
1347
  }
1489
- return VpCheckGetValue(c);
1348
+
1349
+ RB_GC_GUARD(a.bigdecimal);
1350
+ RB_GC_GUARD(b.bigdecimal);
1351
+ return CheckGetValue(c);
1490
1352
  }
1491
1353
 
1492
1354
  /*
@@ -1507,73 +1369,18 @@ BigDecimal_add(VALUE self, VALUE r)
1507
1369
  static VALUE
1508
1370
  BigDecimal_sub(VALUE self, VALUE r)
1509
1371
  {
1510
- ENTER(5);
1511
- Real *c, *a, *b;
1512
- size_t mx;
1513
-
1514
- GUARD_OBJ(a, GetVpValue(self,1));
1515
- if (RB_TYPE_P(r, T_FLOAT)) {
1516
- b = GetVpValueWithPrec(r, 0, 1);
1517
- }
1518
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1519
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1520
- }
1521
- else {
1522
- b = GetVpValue(r,0);
1523
- }
1524
-
1525
- if (!b) return DoSomeOne(self,r,'-');
1526
- SAVE(b);
1527
-
1528
- if (VpIsNaN(b)) return b->obj;
1529
- if (VpIsNaN(a)) return a->obj;
1530
-
1531
- mx = GetAddSubPrec(a,b);
1532
- if (mx == (size_t)-1L) {
1533
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1534
- VpAddSub(c, a, b, -1);
1535
- }
1536
- else {
1537
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
1538
- if (!mx) {
1539
- VpSetInf(c,VpGetSign(a));
1540
- }
1541
- else {
1542
- VpAddSub(c, a, b, -1);
1543
- }
1544
- }
1545
- return VpCheckGetValue(c);
1372
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1373
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1546
1374
  }
1547
1375
 
1548
1376
  static VALUE
1549
1377
  BigDecimalCmp(VALUE self, VALUE r,char op)
1550
1378
  {
1551
- ENTER(5);
1552
1379
  SIGNED_VALUE e;
1553
- Real *a, *b=0;
1554
- GUARD_OBJ(a, GetVpValue(self, 1));
1555
- switch (TYPE(r)) {
1556
- case T_DATA:
1557
- if (!is_kind_of_BigDecimal(r)) break;
1558
- /* fall through */
1559
- case T_FIXNUM:
1560
- /* fall through */
1561
- case T_BIGNUM:
1562
- GUARD_OBJ(b, GetVpValue(r, 0));
1563
- break;
1380
+ BDVALUE a = GetBDValueMust(self);
1381
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1564
1382
 
1565
- case T_FLOAT:
1566
- GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
1567
- break;
1568
-
1569
- case T_RATIONAL:
1570
- GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
1571
- break;
1572
-
1573
- default:
1574
- break;
1575
- }
1576
- if (b == NULL) {
1383
+ if (b.real_or_null == NULL) {
1577
1384
  ID f = 0;
1578
1385
 
1579
1386
  switch (op) {
@@ -1602,8 +1409,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1602
1409
  }
1603
1410
  return rb_num_coerce_relop(self, r, f);
1604
1411
  }
1605
- SAVE(b);
1606
- e = VpComp(a, b);
1412
+ e = VpComp(a.real, b.real_or_null);
1413
+
1414
+ RB_GC_GUARD(a.bigdecimal);
1415
+ RB_GC_GUARD(b.bigdecimal_or_nil);
1416
+
1607
1417
  if (e == 999)
1608
1418
  return (op == '*') ? Qnil : Qfalse;
1609
1419
  switch (op) {
@@ -1643,7 +1453,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1643
1453
  static VALUE
1644
1454
  BigDecimal_zero(VALUE self)
1645
1455
  {
1646
- Real *a = GetVpValue(self, 1);
1456
+ Real *a = GetSelfVpValue(self);
1647
1457
  return VpIsZero(a) ? Qtrue : Qfalse;
1648
1458
  }
1649
1459
 
@@ -1651,7 +1461,7 @@ BigDecimal_zero(VALUE self)
1651
1461
  static VALUE
1652
1462
  BigDecimal_nonzero(VALUE self)
1653
1463
  {
1654
- Real *a = GetVpValue(self, 1);
1464
+ Real *a = GetSelfVpValue(self);
1655
1465
  return VpIsZero(a) ? Qnil : self;
1656
1466
  }
1657
1467
 
@@ -1777,12 +1587,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1777
1587
  static VALUE
1778
1588
  BigDecimal_neg(VALUE self)
1779
1589
  {
1780
- ENTER(5);
1781
- Real *c, *a;
1782
- GUARD_OBJ(a, GetVpValue(self, 1));
1783
- GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
1784
- VpAsgn(c, a, -1);
1785
- return VpCheckGetValue(c);
1590
+ BDVALUE a = GetBDValueMust(self);
1591
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
1592
+ VpAsgn(c.real, a.real, -10);
1593
+ RB_GC_GUARD(a.bigdecimal);
1594
+ return CheckGetValue(c);
1786
1595
  }
1787
1596
 
1788
1597
  /*
@@ -1795,35 +1604,36 @@ BigDecimal_neg(VALUE self)
1795
1604
  *
1796
1605
  * See BigDecimal#mult.
1797
1606
  */
1798
-
1799
1607
  static VALUE
1800
1608
  BigDecimal_mult(VALUE self, VALUE r)
1801
1609
  {
1802
- ENTER(5);
1803
- Real *c, *a, *b;
1804
- size_t mx;
1610
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1611
+ return BigDecimal_mult_with_coerce(self, r, 0);
1612
+ }
1805
1613
 
1806
- GUARD_OBJ(a, GetVpValue(self, 1));
1807
- if (RB_TYPE_P(r, T_FLOAT)) {
1808
- b = GetVpValueWithPrec(r, 0, 1);
1809
- }
1810
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1811
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1614
+ static VALUE
1615
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1616
+ {
1617
+ BDVALUE a, b, c;
1618
+
1619
+ a = GetBDValueMust(self);
1620
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1621
+
1622
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
1623
+ VpMult(c.real, a.real, b.real);
1624
+ if (prec) {
1625
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
1812
1626
  }
1813
1627
  else {
1814
- b = GetVpValue(r,0);
1628
+ VpLimitRound(c.real, 0);
1815
1629
  }
1816
1630
 
1817
- if (!b) return DoSomeOne(self, r, '*');
1818
- SAVE(b);
1819
-
1820
- mx = a->Prec + b->Prec;
1821
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1822
- VpMult(c, a, b);
1823
- return VpCheckGetValue(c);
1631
+ RB_GC_GUARD(a.bigdecimal);
1632
+ RB_GC_GUARD(b.bigdecimal);
1633
+ return CheckGetValue(c);
1824
1634
  }
1825
1635
 
1826
- static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1636
+ static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
1827
1637
 
1828
1638
  /* call-seq:
1829
1639
  * a / b -> bigdecimal
@@ -1840,14 +1650,7 @@ static VALUE
1840
1650
  BigDecimal_div(VALUE self, VALUE r)
1841
1651
  /* For c = self/r: with round operation */
1842
1652
  {
1843
- if (
1844
- !is_kind_of_BigDecimal(r) &&
1845
- !RB_INTEGER_TYPE_P(r) &&
1846
- !RB_TYPE_P(r, T_FLOAT) &&
1847
- !RB_TYPE_P(r, T_RATIONAL)
1848
- ) {
1849
- return DoSomeOne(self, r, '/');
1850
- }
1653
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1851
1654
  return BigDecimal_div2(self, r, INT2FIX(0));
1852
1655
  }
1853
1656
 
@@ -1893,114 +1696,109 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1893
1696
  /*
1894
1697
  * %: mod = a%b = a - (a.to_f/b).floor * b
1895
1698
  * div = (a.to_f/b).floor
1699
+ * In truncate mode, use truncate instead of floor.
1896
1700
  */
1897
- static VALUE
1898
- BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1701
+ static bool
1702
+ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
1899
1703
  {
1900
- ENTER(8);
1901
- Real *c=NULL, *d=NULL, *res=NULL;
1902
- Real *a, *b;
1903
- ssize_t a_prec, b_prec;
1904
- size_t mx;
1704
+ BDVALUE a, b, dv, md, res;
1705
+ NULLABLE_BDVALUE b2;
1706
+ ssize_t a_exponent, b_exponent;
1707
+ size_t mx, rx, pl;
1905
1708
 
1906
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1907
- SAVE(a);
1709
+ a = GetBDValueMust(self);
1908
1710
 
1909
- VALUE rr = r;
1910
- if (is_kind_of_BigDecimal(rr)) {
1911
- /* do nothing */
1912
- }
1913
- else if (RB_INTEGER_TYPE_P(r)) {
1914
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
1915
- }
1916
- else if (RB_TYPE_P(r, T_FLOAT)) {
1917
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1918
- }
1919
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1920
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1921
- }
1711
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1712
+ if (!b2.real_or_null) return false;
1713
+ b = bdvalue_nonnullable(b2);
1922
1714
 
1923
- if (!is_kind_of_BigDecimal(rr)) {
1924
- return Qfalse;
1715
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1716
+ VALUE nan = BigDecimal_nan();
1717
+ *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1718
+ goto Done;
1925
1719
  }
1926
-
1927
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1928
- SAVE(b);
1929
-
1930
- if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
1931
- if (VpIsInf(a) && VpIsInf(b)) goto NaN;
1932
- if (VpIsZero(b)) {
1720
+ if (VpIsZero(b.real)) {
1933
1721
  rb_raise(rb_eZeroDivError, "divided by 0");
1934
1722
  }
1935
- if (VpIsInf(a)) {
1936
- if (VpGetSign(a) == VpGetSign(b)) {
1723
+ if (VpIsInf(a.real)) {
1724
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1937
1725
  VALUE inf = BigDecimal_positive_infinity();
1938
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1726
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1939
1727
  }
1940
1728
  else {
1941
1729
  VALUE inf = BigDecimal_negative_infinity();
1942
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1730
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1943
1731
  }
1944
1732
  VALUE nan = BigDecimal_nan();
1945
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
1946
- return Qtrue;
1947
- }
1948
- if (VpIsInf(b)) {
1949
- VALUE zero = BigDecimal_positive_zero();
1950
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
1951
- *mod = a;
1952
- return Qtrue;
1733
+ *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1734
+ goto Done;
1953
1735
  }
1954
- if (VpIsZero(a)) {
1736
+ if (VpIsZero(a.real)) {
1955
1737
  VALUE zero = BigDecimal_positive_zero();
1956
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
1957
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
1958
- return Qtrue;
1959
- }
1960
-
1961
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
1962
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
1963
-
1964
- mx = (a_prec > b_prec) ? a_prec : b_prec;
1965
- mx *= 2;
1966
-
1967
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1968
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1969
-
1970
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
1971
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
1972
- VpDivd(c, res, a, b);
1973
-
1974
- mx = c->Prec * BASE_FIG;
1975
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
1976
- VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1977
-
1978
- VpMult(res, d, b);
1979
- VpAddSub(c, a, res, -1);
1738
+ *div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1739
+ goto Done;
1740
+ }
1741
+ if (VpIsInf(b.real)) {
1742
+ if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
1743
+ BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
1744
+ VpSetOne(minus_one.real);
1745
+ VpSetSign(minus_one.real, -1);
1746
+ RB_GC_GUARD(minus_one.bigdecimal);
1747
+ *div = bdvalue_nullable(minus_one);
1748
+ *mod = bdvalue_nullable(b);
1749
+ } else {
1750
+ VALUE zero = BigDecimal_positive_zero();
1751
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1752
+ *mod = bdvalue_nullable(a);
1753
+ }
1754
+ goto Done;
1755
+ }
1756
+
1757
+ a_exponent = VpExponent10(a.real);
1758
+ b_exponent = VpExponent10(b.real);
1759
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
1760
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
1761
+
1762
+ /* res is reused for VpDivd remainder and VpMult result */
1763
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
1764
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
1765
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
1766
+ /* AddSub needs one more prec */
1767
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
1768
+
1769
+ VpDivd(dv.real, res.real, a.real, b.real);
1770
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
1771
+ VpMult(res.real, dv.real, b.real);
1772
+ pl = VpGetPrecLimit();
1773
+ VpSetPrecLimit(0);
1774
+ VpAddSub(md.real, a.real, res.real, -1);
1775
+ VpSetPrecLimit(pl);
1980
1776
 
1981
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1777
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
1982
1778
  /* result adjustment for negative case */
1983
- res = rbd_reallocate_struct(res, d->MaxPrec);
1984
- res->MaxPrec = d->MaxPrec;
1985
- VpAddSub(res, d, VpOne(), -1);
1986
- GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
1987
- VpAddSub(d, c, b, 1);
1988
- *div = res;
1989
- *mod = d;
1779
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
1780
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
1781
+ VpSetPrecLimit(0);
1782
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
1783
+ VpAddSub(md2.real, md.real, b.real, 1);
1784
+ VpSetPrecLimit(pl);
1785
+ *div = bdvalue_nullable(dv2);
1786
+ *mod = bdvalue_nullable(md2);
1787
+ RB_GC_GUARD(dv2.bigdecimal);
1788
+ RB_GC_GUARD(md2.bigdecimal);
1990
1789
  }
1991
1790
  else {
1992
- *div = d;
1993
- *mod = c;
1791
+ *div = bdvalue_nullable(dv);
1792
+ *mod = bdvalue_nullable(md);
1994
1793
  }
1995
- return Qtrue;
1996
1794
 
1997
- NaN:
1998
- {
1999
- VALUE nan = BigDecimal_nan();
2000
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
2001
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
2002
- }
2003
- return Qtrue;
1795
+ Done:
1796
+ RB_GC_GUARD(a.bigdecimal);
1797
+ RB_GC_GUARD(b.bigdecimal);
1798
+ RB_GC_GUARD(dv.bigdecimal);
1799
+ RB_GC_GUARD(md.bigdecimal);
1800
+ RB_GC_GUARD(res.bigdecimal);
1801
+ return true;
2004
1802
  }
2005
1803
 
2006
1804
  /* call-seq:
@@ -2014,85 +1812,31 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2014
1812
  static VALUE
2015
1813
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2016
1814
  {
2017
- ENTER(3);
2018
- Real *div = NULL, *mod = NULL;
1815
+ NULLABLE_BDVALUE div, mod;
2019
1816
 
2020
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2021
- SAVE(div); SAVE(mod);
2022
- return VpCheckGetValue(mod);
1817
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1818
+ return CheckGetValue(bdvalue_nonnullable(mod));
2023
1819
  }
2024
1820
  return DoSomeOne(self, r, '%');
2025
1821
  }
2026
1822
 
1823
+ /* call-seq:
1824
+ * remainder(value)
1825
+ *
1826
+ * Returns the remainder from dividing by the value.
1827
+ *
1828
+ * x.remainder(y) means x-y*(x/y).truncate
1829
+ */
2027
1830
  static VALUE
2028
- BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1831
+ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2029
1832
  {
2030
- ENTER(10);
2031
- size_t mx;
2032
- Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
2033
- Real *f = NULL;
1833
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
2034
1834
 
2035
- GUARD_OBJ(a, GetVpValue(self, 1));
2036
- if (RB_TYPE_P(r, T_FLOAT)) {
2037
- b = GetVpValueWithPrec(r, 0, 1);
1835
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
1836
+ return CheckGetValue(bdvalue_nonnullable(mod));
2038
1837
  }
2039
- else if (RB_TYPE_P(r, T_RATIONAL)) {
2040
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
2041
- }
2042
- else {
2043
- b = GetVpValue(r, 0);
2044
- }
2045
-
2046
- if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
2047
- SAVE(b);
2048
-
2049
- if (VpIsPosInf(b) || VpIsNegInf(b)) {
2050
- GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2051
- VpSetZero(*dv, 1);
2052
- *rv = a;
2053
- return Qnil;
2054
- }
2055
-
2056
- mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
2057
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2058
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2059
- GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2060
- GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2061
-
2062
- VpDivd(c, res, a, b);
2063
-
2064
- mx = c->Prec *(VpBaseFig() + 1);
2065
-
2066
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2067
- GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
2068
-
2069
- VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
2070
-
2071
- VpFrac(f, c);
2072
- VpMult(rr, f, b);
2073
- VpAddSub(ff, res, rr, 1);
2074
-
2075
- *dv = d;
2076
- *rv = ff;
2077
- return Qnil;
2078
- }
2079
-
2080
- /* call-seq:
2081
- * remainder(value)
2082
- *
2083
- * Returns the remainder from dividing by the value.
2084
- *
2085
- * x.remainder(y) means x-y*(x/y).truncate
2086
- */
2087
- static VALUE
2088
- BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2089
- {
2090
- VALUE f;
2091
- Real *d, *rv = 0;
2092
- f = BigDecimal_divremain(self, r, &d, &rv);
2093
- if (!NIL_P(f)) return f;
2094
- return VpCheckGetValue(rv);
2095
- }
1838
+ return DoSomeOne(self, r, rb_intern("remainder"));
1839
+ }
2096
1840
 
2097
1841
  /* call-seq:
2098
1842
  * divmod(value)
@@ -2119,12 +1863,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2119
1863
  static VALUE
2120
1864
  BigDecimal_divmod(VALUE self, VALUE r)
2121
1865
  {
2122
- ENTER(5);
2123
- Real *div = NULL, *mod = NULL;
1866
+ NULLABLE_BDVALUE div, mod;
2124
1867
 
2125
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2126
- SAVE(div); SAVE(mod);
2127
- return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
1868
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1869
+ return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
2128
1870
  }
2129
1871
  return DoSomeOne(self,r,rb_intern("divmod"));
2130
1872
  }
@@ -2136,17 +1878,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
2136
1878
  static inline VALUE
2137
1879
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2138
1880
  {
2139
- ENTER(5);
2140
1881
  SIGNED_VALUE ix;
2141
- Real *res = NULL;
2142
- Real *av = NULL, *bv = NULL, *cv = NULL;
2143
- size_t mx, pl;
1882
+ BDVALUE av, bv, cv, res;
2144
1883
 
2145
1884
  if (NIL_P(n)) { /* div in Float sense */
2146
- Real *div = NULL;
2147
- Real *mod;
2148
- if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
2149
- return BigDecimal_to_i(VpCheckGetValue(div));
1885
+ NULLABLE_BDVALUE div;
1886
+ NULLABLE_BDVALUE mod;
1887
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
1888
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
2150
1889
  }
2151
1890
  return DoSomeOne(self, b, rb_intern("div"));
2152
1891
  }
@@ -2154,48 +1893,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2154
1893
  /* div in BigDecimal sense */
2155
1894
  ix = check_int_precision(n);
2156
1895
 
2157
- pl = VpSetPrecLimit(0);
2158
- if (ix == 0) ix = pl;
2159
-
2160
- GUARD_OBJ(av, GetVpValue(self, 1));
2161
- if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) {
2162
- /* TODO: I want to refactor this precision control for a float value later
2163
- * by introducing an implicit conversion function instead of
2164
- * GetVpValueWithPrec. */
2165
- GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1));
2166
- }
2167
- else {
2168
- GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1));
2169
- }
1896
+ av = GetBDValueMust(self);
1897
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
2170
1898
 
2171
1899
  if (ix == 0) {
2172
- ssize_t a_prec, b_prec;
2173
- VpCountPrecisionAndScale(av, &a_prec, NULL);
2174
- VpCountPrecisionAndScale(bv, &b_prec, NULL);
1900
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1901
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1902
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
2175
1903
  ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
2176
1904
  if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
2177
1905
  ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1906
+ if (limit && limit < ix) ix = limit;
2178
1907
  }
2179
1908
 
2180
- // VpDivd needs 2 extra DECDIGs. One more is needed for rounding.
2181
- GUARD_OBJ(cv, NewZeroWrapLimited(1, ix + 3 * VpBaseFig()));
1909
+ // Needs to calculate 1 extra digit for rounding.
1910
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
1911
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
1912
+ VpDivd(cv.real, res.real, av.real, bv.real);
2182
1913
 
2183
- mx = bv->Prec + cv->MaxPrec - 1;
2184
- if (mx <= av->Prec) mx = av->Prec + 1;
2185
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig()));
2186
- VpDivd(cv, res, av, bv);
2187
- VpSetPrecLimit(pl);
2188
- if (!VpIsZero(res)) {
1914
+ if (!VpIsZero(res.real)) {
2189
1915
  // Remainder value affects rounding result.
2190
- // ROUND_UP cv = 0.1e0 with ix=10 will be:
1916
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
2191
1917
  // 0.1e0 if remainder == 0
2192
1918
  // 0.1000000001e0 if remainder != 0
2193
1919
  size_t idx = roomof(ix, BASE_FIG);
2194
- while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0;
2195
- if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++;
1920
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
1921
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
2196
1922
  }
2197
- VpLeftRound(cv, VpGetRoundMode(), ix);
2198
- return VpCheckGetValue(cv);
1923
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
1924
+
1925
+ RB_GC_GUARD(av.bigdecimal);
1926
+ RB_GC_GUARD(bv.bigdecimal);
1927
+ RB_GC_GUARD(res.bigdecimal);
1928
+ return CheckGetValue(cv);
2199
1929
  }
2200
1930
 
2201
1931
  /*
@@ -2271,18 +2001,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2271
2001
  static VALUE
2272
2002
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2273
2003
  {
2274
- ENTER(2);
2275
- Real *cv;
2276
- SIGNED_VALUE mx = check_int_precision(n);
2277
- if (mx == 0) return BigDecimal_add(self, b);
2278
- else {
2279
- size_t pl = VpSetPrecLimit(0);
2280
- VALUE c = BigDecimal_add(self, b);
2281
- VpSetPrecLimit(pl);
2282
- GUARD_OBJ(cv, GetVpValue(c, 1));
2283
- VpLeftRound(cv, VpGetRoundMode(), mx);
2284
- return VpCheckGetValue(cv);
2285
- }
2004
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2286
2005
  }
2287
2006
 
2288
2007
  /* call-seq:
@@ -2301,18 +2020,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2301
2020
  static VALUE
2302
2021
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2303
2022
  {
2304
- ENTER(2);
2305
- Real *cv;
2306
- SIGNED_VALUE mx = check_int_precision(n);
2307
- if (mx == 0) return BigDecimal_sub(self, b);
2308
- else {
2309
- size_t pl = VpSetPrecLimit(0);
2310
- VALUE c = BigDecimal_sub(self, b);
2311
- VpSetPrecLimit(pl);
2312
- GUARD_OBJ(cv, GetVpValue(c, 1));
2313
- VpLeftRound(cv, VpGetRoundMode(), mx);
2314
- return VpCheckGetValue(cv);
2315
- }
2023
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2316
2024
  }
2317
2025
 
2318
2026
  /*
@@ -2344,18 +2052,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2344
2052
  static VALUE
2345
2053
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2346
2054
  {
2347
- ENTER(2);
2348
- Real *cv;
2349
- SIGNED_VALUE mx = check_int_precision(n);
2350
- if (mx == 0) return BigDecimal_mult(self, b);
2351
- else {
2352
- size_t pl = VpSetPrecLimit(0);
2353
- VALUE c = BigDecimal_mult(self, b);
2354
- VpSetPrecLimit(pl);
2355
- GUARD_OBJ(cv, GetVpValue(c, 1));
2356
- VpLeftRound(cv, VpGetRoundMode(), mx);
2357
- return VpCheckGetValue(cv);
2358
- }
2055
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2359
2056
  }
2360
2057
 
2361
2058
  /*
@@ -2372,41 +2069,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2372
2069
  static VALUE
2373
2070
  BigDecimal_abs(VALUE self)
2374
2071
  {
2375
- ENTER(5);
2376
- Real *c, *a;
2377
- size_t mx;
2378
-
2379
- GUARD_OBJ(a, GetVpValue(self, 1));
2380
- mx = a->Prec *(VpBaseFig() + 1);
2381
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2382
- VpAsgn(c, a, 1);
2383
- VpChangeSign(c, 1);
2384
- return VpCheckGetValue(c);
2385
- }
2386
-
2387
- /* call-seq:
2388
- * sqrt(n)
2389
- *
2390
- * Returns the square root of the value.
2391
- *
2392
- * Result has at least n significant digits.
2393
- */
2394
- static VALUE
2395
- BigDecimal_sqrt(VALUE self, VALUE nFig)
2396
- {
2397
- ENTER(5);
2398
- Real *c, *a;
2399
- size_t mx, n;
2400
-
2401
- GUARD_OBJ(a, GetVpValue(self, 1));
2402
- mx = a->Prec * (VpBaseFig() + 1);
2403
-
2404
- n = check_int_precision(nFig);
2405
- n += VpDblFig() + VpBaseFig();
2406
- if (mx <= n) mx = n;
2407
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2408
- VpSqrt(c, a);
2409
- return VpCheckGetValue(c);
2072
+ BDVALUE a = GetBDValueMust(self);
2073
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
2074
+ VpAsgn(c.real, a.real, 10);
2075
+ VpChangeSign(c.real, 1);
2076
+ RB_GC_GUARD(a.bigdecimal);
2077
+ return CheckGetValue(c);
2410
2078
  }
2411
2079
 
2412
2080
  /* Return the integer part of the number, as a BigDecimal.
@@ -2414,15 +2082,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2414
2082
  static VALUE
2415
2083
  BigDecimal_fix(VALUE self)
2416
2084
  {
2417
- ENTER(5);
2418
- Real *c, *a;
2419
- size_t mx;
2420
-
2421
- GUARD_OBJ(a, GetVpValue(self, 1));
2422
- mx = a->Prec *(VpBaseFig() + 1);
2423
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2424
- VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2425
- return VpCheckGetValue(c);
2085
+ BDVALUE a = GetBDValueMust(self);
2086
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2087
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
2088
+ RB_GC_GUARD(a.bigdecimal);
2089
+ return CheckGetValue(c);
2426
2090
  }
2427
2091
 
2428
2092
  /* call-seq:
@@ -2454,13 +2118,12 @@ BigDecimal_fix(VALUE self)
2454
2118
  static VALUE
2455
2119
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2456
2120
  {
2457
- ENTER(5);
2458
- Real *c, *a;
2121
+ BDVALUE c, a;
2459
2122
  int iLoc = 0;
2460
2123
  VALUE vLoc;
2461
2124
  VALUE vRound;
2462
2125
  int round_to_int = 0;
2463
- size_t mx, pl;
2126
+ size_t mx;
2464
2127
 
2465
2128
  unsigned short sw = VpGetRoundMode();
2466
2129
 
@@ -2491,16 +2154,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2491
2154
  break;
2492
2155
  }
2493
2156
 
2494
- pl = VpSetPrecLimit(0);
2495
- GUARD_OBJ(a, GetVpValue(self, 1));
2496
- mx = a->Prec * (VpBaseFig() + 1);
2497
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2498
- VpSetPrecLimit(pl);
2499
- VpActiveRound(c, a, sw, iLoc);
2157
+ a = GetBDValueMust(self);
2158
+ mx = (a.real->Prec + 1) * BASE_FIG;
2159
+ c = NewZeroWrap(1, mx);
2160
+
2161
+ VpActiveRound(c.real, a.real, sw, iLoc);
2162
+
2163
+ RB_GC_GUARD(a.bigdecimal);
2164
+
2500
2165
  if (round_to_int) {
2501
- return BigDecimal_to_i(VpCheckGetValue(c));
2166
+ return BigDecimal_to_i(CheckGetValue(c));
2167
+ }
2168
+ return CheckGetValue(c);
2169
+ }
2170
+
2171
+ static VALUE
2172
+ BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
2173
+ {
2174
+ BDVALUE c, a;
2175
+ int iLoc;
2176
+ VALUE vLoc;
2177
+ size_t mx;
2178
+
2179
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2180
+ iLoc = 0;
2181
+ }
2182
+ else {
2183
+ iLoc = NUM2INT(vLoc);
2502
2184
  }
2503
- return VpCheckGetValue(c);
2185
+
2186
+ a = GetBDValueMust(self);
2187
+ mx = (a.real->Prec + 1) * BASE_FIG;
2188
+ c = NewZeroWrap(1, mx);
2189
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
2190
+
2191
+ RB_GC_GUARD(a.bigdecimal);
2192
+
2193
+ if (argc == 0) {
2194
+ return BigDecimal_to_i(CheckGetValue(c));
2195
+ }
2196
+ return CheckGetValue(c);
2504
2197
  }
2505
2198
 
2506
2199
  /* call-seq:
@@ -2525,28 +2218,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2525
2218
  static VALUE
2526
2219
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2527
2220
  {
2528
- ENTER(5);
2529
- Real *c, *a;
2530
- int iLoc;
2531
- VALUE vLoc;
2532
- size_t mx, pl = VpSetPrecLimit(0);
2533
-
2534
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2535
- iLoc = 0;
2536
- }
2537
- else {
2538
- iLoc = NUM2INT(vLoc);
2539
- }
2540
-
2541
- GUARD_OBJ(a, GetVpValue(self, 1));
2542
- mx = a->Prec * (VpBaseFig() + 1);
2543
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2544
- VpSetPrecLimit(pl);
2545
- VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2546
- if (argc == 0) {
2547
- return BigDecimal_to_i(VpCheckGetValue(c));
2548
- }
2549
- return VpCheckGetValue(c);
2221
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2550
2222
  }
2551
2223
 
2552
2224
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2554,15 +2226,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2554
2226
  static VALUE
2555
2227
  BigDecimal_frac(VALUE self)
2556
2228
  {
2557
- ENTER(5);
2558
- Real *c, *a;
2559
- size_t mx;
2560
-
2561
- GUARD_OBJ(a, GetVpValue(self, 1));
2562
- mx = a->Prec * (VpBaseFig() + 1);
2563
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2564
- VpFrac(c, a);
2565
- return VpCheckGetValue(c);
2229
+ BDVALUE a = GetBDValueMust(self);
2230
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2231
+ VpFrac(c.real, a.real);
2232
+ RB_GC_GUARD(a.bigdecimal);
2233
+ return CheckGetValue(c);
2566
2234
  }
2567
2235
 
2568
2236
  /* call-seq:
@@ -2585,31 +2253,7 @@ BigDecimal_frac(VALUE self)
2585
2253
  static VALUE
2586
2254
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2587
2255
  {
2588
- ENTER(5);
2589
- Real *c, *a;
2590
- int iLoc;
2591
- VALUE vLoc;
2592
- size_t mx, pl = VpSetPrecLimit(0);
2593
-
2594
- if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
2595
- iLoc = 0;
2596
- }
2597
- else {
2598
- iLoc = NUM2INT(vLoc);
2599
- }
2600
-
2601
- GUARD_OBJ(a, GetVpValue(self, 1));
2602
- mx = a->Prec * (VpBaseFig() + 1);
2603
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2604
- VpSetPrecLimit(pl);
2605
- VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2606
- #ifdef BIGDECIMAL_DEBUG
2607
- VPrint(stderr, "floor: c=%\n", c);
2608
- #endif
2609
- if (argc == 0) {
2610
- return BigDecimal_to_i(VpCheckGetValue(c));
2611
- }
2612
- return VpCheckGetValue(c);
2256
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2613
2257
  }
2614
2258
 
2615
2259
  /* call-seq:
@@ -2632,27 +2276,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2632
2276
  static VALUE
2633
2277
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2634
2278
  {
2635
- ENTER(5);
2636
- Real *c, *a;
2637
- int iLoc;
2638
- VALUE vLoc;
2639
- size_t mx, pl = VpSetPrecLimit(0);
2640
-
2641
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2642
- iLoc = 0;
2643
- } else {
2644
- iLoc = NUM2INT(vLoc);
2645
- }
2646
-
2647
- GUARD_OBJ(a, GetVpValue(self, 1));
2648
- mx = a->Prec * (VpBaseFig() + 1);
2649
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2650
- VpSetPrecLimit(pl);
2651
- VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2652
- if (argc == 0) {
2653
- return BigDecimal_to_i(VpCheckGetValue(c));
2654
- }
2655
- return VpCheckGetValue(c);
2279
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2656
2280
  }
2657
2281
 
2658
2282
  /* call-seq:
@@ -2673,7 +2297,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2673
2297
  * If s contains a number, a space is inserted after each group of that many
2674
2298
  * digits, starting from '.' and counting outwards.
2675
2299
  *
2676
- * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2300
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
2677
2301
  *
2678
2302
  * If s ends with an 'F', conventional floating point notation is used.
2679
2303
  *
@@ -2691,10 +2315,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2691
2315
  static VALUE
2692
2316
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2693
2317
  {
2694
- ENTER(5);
2695
2318
  int fmt = 0; /* 0: E format, 1: F format */
2696
2319
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2697
- Real *vp;
2320
+ BDVALUE v;
2698
2321
  volatile VALUE str;
2699
2322
  char *psz;
2700
2323
  char ch;
@@ -2702,7 +2325,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2702
2325
  SIGNED_VALUE m;
2703
2326
  VALUE f;
2704
2327
 
2705
- GUARD_OBJ(vp, GetVpValue(self, 1));
2328
+ v = GetBDValueMust(self);
2706
2329
 
2707
2330
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2708
2331
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2737,10 +2360,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2737
2360
  }
2738
2361
  }
2739
2362
  if (fmt) {
2740
- nc = VpNumOfChars(vp, "F");
2363
+ nc = VpNumOfChars(v.real, "F");
2741
2364
  }
2742
2365
  else {
2743
- nc = VpNumOfChars(vp, "E");
2366
+ nc = VpNumOfChars(v.real, "E");
2744
2367
  }
2745
2368
  if (mc > 0) {
2746
2369
  nc += (nc + mc - 1) / mc + 1;
@@ -2750,12 +2373,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2750
2373
  psz = RSTRING_PTR(str);
2751
2374
 
2752
2375
  if (fmt) {
2753
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2376
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
2754
2377
  }
2755
2378
  else {
2756
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2379
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
2757
2380
  }
2758
2381
  rb_str_resize(str, strlen(psz));
2382
+
2383
+ RB_GC_GUARD(v.bigdecimal);
2759
2384
  return str;
2760
2385
  }
2761
2386
 
@@ -2786,16 +2411,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2786
2411
  static VALUE
2787
2412
  BigDecimal_split(VALUE self)
2788
2413
  {
2789
- ENTER(5);
2790
- Real *vp;
2414
+ BDVALUE v;
2791
2415
  VALUE obj,str;
2792
2416
  ssize_t e, s;
2793
2417
  char *psz1;
2794
2418
 
2795
- GUARD_OBJ(vp, GetVpValue(self, 1));
2796
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2419
+ v = GetBDValueMust(self);
2420
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
2797
2421
  psz1 = RSTRING_PTR(str);
2798
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2422
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
2799
2423
  s = 1;
2800
2424
  if(psz1[0] == '-') {
2801
2425
  size_t len = strlen(psz1 + 1);
@@ -2805,13 +2429,15 @@ BigDecimal_split(VALUE self)
2805
2429
  s = -1;
2806
2430
  }
2807
2431
  if (psz1[0] == 'N') s = 0; /* NaN */
2808
- e = VpExponent10(vp);
2432
+ e = VpExponent10(v.real);
2809
2433
  obj = rb_ary_new2(4);
2810
2434
  rb_ary_push(obj, INT2FIX(s));
2811
2435
  rb_ary_push(obj, str);
2812
2436
  rb_str_resize(str, strlen(psz1));
2813
2437
  rb_ary_push(obj, INT2FIX(10));
2814
2438
  rb_ary_push(obj, SSIZET2NUM(e));
2439
+
2440
+ RB_GC_GUARD(v.bigdecimal);
2815
2441
  return obj;
2816
2442
  }
2817
2443
 
@@ -2823,7 +2449,7 @@ BigDecimal_split(VALUE self)
2823
2449
  static VALUE
2824
2450
  BigDecimal_exponent(VALUE self)
2825
2451
  {
2826
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2452
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
2827
2453
  return SSIZET2NUM(e);
2828
2454
  }
2829
2455
 
@@ -2835,49 +2461,78 @@ BigDecimal_exponent(VALUE self)
2835
2461
  static VALUE
2836
2462
  BigDecimal_inspect(VALUE self)
2837
2463
  {
2838
- ENTER(5);
2839
- Real *vp;
2464
+ BDVALUE v;
2840
2465
  volatile VALUE str;
2841
2466
  size_t nc;
2842
2467
 
2843
- GUARD_OBJ(vp, GetVpValue(self, 1));
2844
- nc = VpNumOfChars(vp, "E");
2468
+ v = GetBDValueMust(self);
2469
+ nc = VpNumOfChars(v.real, "E");
2845
2470
 
2846
2471
  str = rb_str_new(0, nc);
2847
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2472
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2848
2473
  rb_str_resize(str, strlen(RSTRING_PTR(str)));
2849
- return str;
2850
- }
2851
2474
 
2852
- static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
2853
- static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
2854
-
2855
- #define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
2856
- #define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
2857
-
2858
- inline static int
2859
- is_integer(VALUE x)
2860
- {
2861
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2475
+ RB_GC_GUARD(v.bigdecimal);
2476
+ return str;
2862
2477
  }
2863
2478
 
2864
- inline static int
2865
- is_negative(VALUE x)
2866
- {
2867
- if (FIXNUM_P(x)) {
2868
- return FIX2LONG(x) < 0;
2869
- }
2870
- else if (RB_TYPE_P(x, T_BIGNUM)) {
2871
- return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
2872
- }
2873
- else if (RB_TYPE_P(x, T_FLOAT)) {
2874
- return RFLOAT_VALUE(x) < 0.0;
2479
+ /* Returns self * 10**v without changing the precision.
2480
+ * This method is currently for internal use.
2481
+ *
2482
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2483
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2484
+ */
2485
+ static VALUE
2486
+ BigDecimal_decimal_shift(VALUE self, VALUE v)
2487
+ {
2488
+ BDVALUE a, c;
2489
+ ssize_t shift, exponentShift;
2490
+ bool shiftDown;
2491
+ size_t prec;
2492
+ DECDIG ex, iex;
2493
+
2494
+ a = GetBDValueMust(self);
2495
+ shift = NUM2SSIZET(rb_to_int(v));
2496
+
2497
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
2498
+
2499
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
2500
+ shift -= exponentShift * BASE_FIG;
2501
+ ex = 1;
2502
+ for (int i = 0; i < shift; i++) ex *= 10;
2503
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
2504
+ iex = BASE / ex;
2505
+
2506
+ prec = a.real->Prec + shiftDown;
2507
+ c = NewZeroWrap(1, prec * BASE_FIG);
2508
+ if (shift == 0) {
2509
+ VpAsgn(c.real, a.real, 1);
2510
+ } else if (shiftDown) {
2511
+ DECDIG carry = 0;
2512
+ exponentShift++;
2513
+ for (size_t i = 0; i < a.real->Prec; i++) {
2514
+ DECDIG v = a.real->frac[i];
2515
+ c.real->frac[i] = carry * ex + v / iex;
2516
+ carry = v % iex;
2517
+ }
2518
+ c.real->frac[a.real->Prec] = carry * ex;
2519
+ } else {
2520
+ DECDIG carry = 0;
2521
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
2522
+ DECDIG v = a.real->frac[i];
2523
+ c.real->frac[i] = v % iex * ex + carry;
2524
+ carry = v / iex;
2525
+ }
2875
2526
  }
2876
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2527
+ while (c.real->frac[prec - 1] == 0) prec--;
2528
+ c.real->Prec = prec;
2529
+ c.real->sign = a.real->sign;
2530
+ c.real->exponent = a.real->exponent;
2531
+ AddExponent(c.real, exponentShift);
2532
+ RB_GC_GUARD(a.bigdecimal);
2533
+ return CheckGetValue(c);
2877
2534
  }
2878
2535
 
2879
- #define is_positive(x) (!is_negative(x))
2880
-
2881
2536
  inline static int
2882
2537
  is_zero(VALUE x)
2883
2538
  {
@@ -2901,344 +2556,6 @@ is_zero(VALUE x)
2901
2556
  return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2902
2557
  }
2903
2558
 
2904
- inline static int
2905
- is_one(VALUE x)
2906
- {
2907
- VALUE num, den;
2908
-
2909
- switch (TYPE(x)) {
2910
- case T_FIXNUM:
2911
- return FIX2LONG(x) == 1;
2912
-
2913
- case T_BIGNUM:
2914
- return Qfalse;
2915
-
2916
- case T_RATIONAL:
2917
- num = rb_rational_num(x);
2918
- den = rb_rational_den(x);
2919
- return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
2920
- FIXNUM_P(num) && FIX2LONG(num) == 1;
2921
-
2922
- default:
2923
- break;
2924
- }
2925
-
2926
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
2927
- }
2928
-
2929
- inline static int
2930
- is_even(VALUE x)
2931
- {
2932
- switch (TYPE(x)) {
2933
- case T_FIXNUM:
2934
- return (FIX2LONG(x) % 2) == 0;
2935
-
2936
- case T_BIGNUM:
2937
- {
2938
- unsigned long l;
2939
- rb_big_pack(x, &l, 1);
2940
- return l % 2 == 0;
2941
- }
2942
-
2943
- default:
2944
- break;
2945
- }
2946
-
2947
- return 0;
2948
- }
2949
-
2950
- static VALUE
2951
- bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2952
- {
2953
- VALUE log_x, multiplied, y;
2954
- volatile VALUE obj = exp->obj;
2955
-
2956
- if (VpIsZero(exp)) {
2957
- return VpCheckGetValue(NewOneWrapLimited(1, n));
2958
- }
2959
-
2960
- log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
2961
- multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
2962
- y = BigMath_exp(multiplied, SSIZET2NUM(n));
2963
- RB_GC_GUARD(obj);
2964
-
2965
- return y;
2966
- }
2967
-
2968
- /* call-seq:
2969
- * power(n)
2970
- * power(n, prec)
2971
- *
2972
- * Returns the value raised to the power of n.
2973
- *
2974
- * Note that n must be an Integer.
2975
- *
2976
- * Also available as the operator **.
2977
- */
2978
- static VALUE
2979
- BigDecimal_power(int argc, VALUE*argv, VALUE self)
2980
- {
2981
- ENTER(5);
2982
- VALUE vexp, prec;
2983
- Real* exp = NULL;
2984
- Real *x, *y;
2985
- ssize_t mp, ma, n;
2986
- SIGNED_VALUE int_exp;
2987
- double d;
2988
-
2989
- rb_scan_args(argc, argv, "11", &vexp, &prec);
2990
-
2991
- GUARD_OBJ(x, GetVpValue(self, 1));
2992
- n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2993
-
2994
- if (VpIsNaN(x)) {
2995
- y = NewZeroWrapLimited(1, n);
2996
- VpSetNaN(y);
2997
- RB_GC_GUARD(y->obj);
2998
- return VpCheckGetValue(y);
2999
- }
3000
-
3001
- retry:
3002
- switch (TYPE(vexp)) {
3003
- case T_FIXNUM:
3004
- break;
3005
-
3006
- case T_BIGNUM:
3007
- break;
3008
-
3009
- case T_FLOAT:
3010
- d = RFLOAT_VALUE(vexp);
3011
- if (d == round(d)) {
3012
- if (FIXABLE(d)) {
3013
- vexp = LONG2FIX((long)d);
3014
- }
3015
- else {
3016
- vexp = rb_dbl2big(d);
3017
- }
3018
- goto retry;
3019
- }
3020
- if (NIL_P(prec)) {
3021
- n += BIGDECIMAL_DOUBLE_FIGURES;
3022
- }
3023
- exp = GetVpValueWithPrec(vexp, 0, 1);
3024
- break;
3025
-
3026
- case T_RATIONAL:
3027
- if (is_zero(rb_rational_num(vexp))) {
3028
- if (is_positive(vexp)) {
3029
- vexp = INT2FIX(0);
3030
- goto retry;
3031
- }
3032
- }
3033
- else if (is_one(rb_rational_den(vexp))) {
3034
- vexp = rb_rational_num(vexp);
3035
- goto retry;
3036
- }
3037
- exp = GetVpValueWithPrec(vexp, n, 1);
3038
- if (NIL_P(prec)) {
3039
- n += n;
3040
- }
3041
- break;
3042
-
3043
- case T_DATA:
3044
- if (is_kind_of_BigDecimal(vexp)) {
3045
- VALUE zero = INT2FIX(0);
3046
- VALUE rounded = BigDecimal_round(1, &zero, vexp);
3047
- if (RTEST(BigDecimal_eq(vexp, rounded))) {
3048
- vexp = BigDecimal_to_i(vexp);
3049
- goto retry;
3050
- }
3051
- if (NIL_P(prec)) {
3052
- GUARD_OBJ(y, GetVpValue(vexp, 1));
3053
- n += y->Prec*VpBaseFig();
3054
- }
3055
- exp = DATA_PTR(vexp);
3056
- break;
3057
- }
3058
- /* fall through */
3059
- default:
3060
- rb_raise(rb_eTypeError,
3061
- "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
3062
- RB_OBJ_CLASSNAME(vexp));
3063
- }
3064
-
3065
- if (VpIsZero(x)) {
3066
- if (is_negative(vexp)) {
3067
- y = NewZeroWrapNolimit(1, n);
3068
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3069
- if (is_integer(vexp)) {
3070
- if (is_even(vexp)) {
3071
- /* (-0) ** (-even_integer) -> Infinity */
3072
- VpSetPosInf(y);
3073
- }
3074
- else {
3075
- /* (-0) ** (-odd_integer) -> -Infinity */
3076
- VpSetNegInf(y);
3077
- }
3078
- }
3079
- else {
3080
- /* (-0) ** (-non_integer) -> Infinity */
3081
- VpSetPosInf(y);
3082
- }
3083
- }
3084
- else {
3085
- /* (+0) ** (-num) -> Infinity */
3086
- VpSetPosInf(y);
3087
- }
3088
- RB_GC_GUARD(y->obj);
3089
- return VpCheckGetValue(y);
3090
- }
3091
- else if (is_zero(vexp)) {
3092
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3093
- }
3094
- else {
3095
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3096
- }
3097
- }
3098
-
3099
- if (is_zero(vexp)) {
3100
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3101
- }
3102
- else if (is_one(vexp)) {
3103
- return self;
3104
- }
3105
-
3106
- if (VpIsInf(x)) {
3107
- if (is_negative(vexp)) {
3108
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3109
- if (is_integer(vexp)) {
3110
- if (is_even(vexp)) {
3111
- /* (-Infinity) ** (-even_integer) -> +0 */
3112
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3113
- }
3114
- else {
3115
- /* (-Infinity) ** (-odd_integer) -> -0 */
3116
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3117
- }
3118
- }
3119
- else {
3120
- /* (-Infinity) ** (-non_integer) -> -0 */
3121
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3122
- }
3123
- }
3124
- else {
3125
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3126
- }
3127
- }
3128
- else {
3129
- y = NewZeroWrapLimited(1, n);
3130
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3131
- if (is_integer(vexp)) {
3132
- if (is_even(vexp)) {
3133
- VpSetPosInf(y);
3134
- }
3135
- else {
3136
- VpSetNegInf(y);
3137
- }
3138
- }
3139
- else {
3140
- /* TODO: support complex */
3141
- rb_raise(rb_eMathDomainError,
3142
- "a non-integral exponent for a negative base");
3143
- }
3144
- }
3145
- else {
3146
- VpSetPosInf(y);
3147
- }
3148
- return VpCheckGetValue(y);
3149
- }
3150
- }
3151
-
3152
- if (exp != NULL) {
3153
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3154
- }
3155
- else if (RB_TYPE_P(vexp, T_BIGNUM)) {
3156
- VALUE abs_value = BigDecimal_abs(self);
3157
- if (is_one(abs_value)) {
3158
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3159
- }
3160
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
3161
- if (is_negative(vexp)) {
3162
- y = NewZeroWrapLimited(1, n);
3163
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3164
- return VpCheckGetValue(y);
3165
- }
3166
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3167
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3168
- }
3169
- else {
3170
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3171
- }
3172
- }
3173
- else {
3174
- if (is_positive(vexp)) {
3175
- y = NewZeroWrapLimited(1, n);
3176
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3177
- return VpCheckGetValue(y);
3178
- }
3179
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3180
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3181
- }
3182
- else {
3183
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3184
- }
3185
- }
3186
- }
3187
-
3188
- int_exp = FIX2LONG(vexp);
3189
- ma = int_exp;
3190
- if (ma < 0) ma = -ma;
3191
- if (ma == 0) ma = 1;
3192
-
3193
- if (VpIsDef(x)) {
3194
- mp = x->Prec * (VpBaseFig() + 1);
3195
- GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
3196
- }
3197
- else {
3198
- GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3199
- }
3200
- VpPowerByInt(y, x, int_exp);
3201
- if (!NIL_P(prec) && VpIsDef(y)) {
3202
- VpMidRound(y, VpGetRoundMode(), n);
3203
- }
3204
- return VpCheckGetValue(y);
3205
- }
3206
-
3207
- /* call-seq:
3208
- * self ** other -> bigdecimal
3209
- *
3210
- * Returns the \BigDecimal value of +self+ raised to power +other+:
3211
- *
3212
- * b = BigDecimal('3.14')
3213
- * b ** 2 # => 0.98596e1
3214
- * b ** 2.0 # => 0.98596e1
3215
- * b ** Rational(2, 1) # => 0.98596e1
3216
- *
3217
- * Related: BigDecimal#power.
3218
- *
3219
- */
3220
- static VALUE
3221
- BigDecimal_power_op(VALUE self, VALUE exp)
3222
- {
3223
- return BigDecimal_power(1, &exp, self);
3224
- }
3225
-
3226
- /* :nodoc:
3227
- *
3228
- * private method for dup and clone the provided BigDecimal +other+
3229
- */
3230
- static VALUE
3231
- BigDecimal_initialize_copy(VALUE self, VALUE other)
3232
- {
3233
- Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
3234
- Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
3235
-
3236
- if (self != other) {
3237
- DATA_PTR(self) = VpCopy(pv, x);
3238
- }
3239
- return self;
3240
- }
3241
-
3242
2559
  /* :nodoc: */
3243
2560
  static VALUE
3244
2561
  BigDecimal_clone(VALUE self)
@@ -3277,20 +2594,18 @@ check_exception(VALUE bd)
3277
2594
 
3278
2595
  Real *vp;
3279
2596
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3280
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2597
+ VpCheckException(vp, false);
3281
2598
 
3282
2599
  return bd;
3283
2600
  }
3284
2601
 
3285
2602
  static VALUE
3286
- rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
2603
+ rb_uint64_convert_to_BigDecimal(uint64_t uval)
3287
2604
  {
3288
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3289
-
2605
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3290
2606
  Real *vp;
3291
2607
  if (uval == 0) {
3292
2608
  vp = rbd_allocate_struct(1);
3293
- vp->MaxPrec = 1;
3294
2609
  vp->Prec = 1;
3295
2610
  vp->exponent = 1;
3296
2611
  VpSetZero(vp, 1);
@@ -3298,7 +2613,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3298
2613
  }
3299
2614
  else if (uval < BASE) {
3300
2615
  vp = rbd_allocate_struct(1);
3301
- vp->MaxPrec = 1;
3302
2616
  vp->Prec = 1;
3303
2617
  vp->exponent = 1;
3304
2618
  VpSetSign(vp, 1);
@@ -3324,21 +2638,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3324
2638
 
3325
2639
  const size_t exp = len + ntz;
3326
2640
  vp = rbd_allocate_struct(len);
3327
- vp->MaxPrec = len;
3328
2641
  vp->Prec = len;
3329
2642
  vp->exponent = exp;
3330
2643
  VpSetSign(vp, 1);
3331
2644
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3332
2645
  }
3333
2646
 
3334
- return BigDecimal_wrap_struct(obj, vp);
2647
+ return BigDecimal_wrap_struct(null_wrapped, vp);
3335
2648
  }
3336
2649
 
3337
2650
  static VALUE
3338
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2651
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3339
2652
  {
3340
2653
  const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
3341
- VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception);
2654
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3342
2655
  if (ival < 0) {
3343
2656
  Real *vp;
3344
2657
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
@@ -3348,7 +2661,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
3348
2661
  }
3349
2662
 
3350
2663
  static VALUE
3351
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2664
+ rb_big_convert_to_BigDecimal(VALUE val)
3352
2665
  {
3353
2666
  assert(RB_TYPE_P(val, T_BIGNUM));
3354
2667
 
@@ -3360,40 +2673,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3360
2673
  }
3361
2674
  if (size <= sizeof(long)) {
3362
2675
  if (sign < 0) {
3363
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2676
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3364
2677
  }
3365
2678
  else {
3366
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2679
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3367
2680
  }
3368
2681
  }
3369
2682
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3370
2683
  else if (size <= sizeof(LONG_LONG)) {
3371
2684
  if (sign < 0) {
3372
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2685
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3373
2686
  }
3374
2687
  else {
3375
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2688
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3376
2689
  }
3377
2690
  }
3378
2691
  #endif
3379
2692
  else {
3380
2693
  VALUE str = rb_big2str(val, 10);
3381
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3382
- RSTRING_PTR(str), true);
2694
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2695
+ RSTRING_PTR(str),
2696
+ rb_cBigDecimal,
2697
+ true,
2698
+ true
2699
+ ));
3383
2700
  RB_GC_GUARD(str);
3384
- return check_exception(vp->obj);
2701
+ return CheckGetValue(v);
3385
2702
  }
3386
2703
  }
3387
2704
 
3388
2705
  static VALUE
3389
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2706
+ rb_inum_convert_to_BigDecimal(VALUE val)
3390
2707
  {
3391
2708
  assert(RB_INTEGER_TYPE_P(val));
3392
2709
  if (FIXNUM_P(val)) {
3393
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2710
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3394
2711
  }
3395
2712
  else {
3396
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2713
+ return rb_big_convert_to_BigDecimal(val);
3397
2714
  }
3398
2715
  }
3399
2716
 
@@ -3428,11 +2745,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3428
2745
  }
3429
2746
 
3430
2747
  if (digs == SIZE_MAX) {
3431
- if (!raise_exception)
3432
- return Qnil;
3433
- rb_raise(rb_eArgError,
3434
- "can't omit precision for a %"PRIsVALUE".",
3435
- CLASS_OF(val));
2748
+ digs = 0;
3436
2749
  }
3437
2750
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3438
2751
  if (!raise_exception)
@@ -3547,7 +2860,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3547
2860
  exp = -exp;
3548
2861
  }
3549
2862
 
3550
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
2863
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
3551
2864
  Real *vp;
3552
2865
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3553
2866
  assert(vp->Prec == prec);
@@ -3570,28 +2883,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3570
2883
  CLASS_OF(val));
3571
2884
  }
3572
2885
 
3573
- VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
2886
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
3574
2887
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3575
2888
  return d;
3576
2889
  }
3577
2890
 
3578
2891
  static VALUE
3579
- rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
2892
+ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
3580
2893
  {
3581
- if (digs == SIZE_MAX)
3582
- digs = 0;
3583
-
3584
- Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
3585
- if (!vp)
3586
- return Qnil;
3587
- return VpCheckGetValue(vp);
2894
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
2895
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
2896
+ return CheckGetValue(bdvalue_nonnullable(v));
3588
2897
  }
3589
2898
 
3590
2899
  static inline VALUE
3591
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2900
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3592
2901
  {
3593
2902
  const char *c_str = StringValueCStr(val);
3594
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2903
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3595
2904
  }
3596
2905
 
3597
2906
  static VALUE
@@ -3619,17 +2928,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3619
2928
  if (digs == SIZE_MAX)
3620
2929
  return check_exception(val);
3621
2930
 
2931
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3622
2932
  Real *vp;
3623
2933
  TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
3624
-
3625
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3626
2934
  vp = VpCopy(NULL, vp);
2935
+ RB_GC_GUARD(val);
2936
+
2937
+ VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
3627
2938
  /* TODO: rounding */
3628
- BigDecimal_wrap_struct(copy, vp);
3629
- return VpCheckGetValue(vp);
2939
+ return check_exception(copy);
3630
2940
  }
3631
2941
  else if (RB_INTEGER_TYPE_P(val)) {
3632
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2942
+ return rb_inum_convert_to_BigDecimal(val);
3633
2943
  }
3634
2944
  else if (RB_FLOAT_TYPE_P(val)) {
3635
2945
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3647,7 +2957,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3647
2957
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3648
2958
  }
3649
2959
  else if (RB_TYPE_P(val, T_STRING)) {
3650
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2960
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3651
2961
  }
3652
2962
 
3653
2963
  /* TODO: chheck to_d */
@@ -3661,7 +2971,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3661
2971
  }
3662
2972
  return Qnil;
3663
2973
  }
3664
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2974
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3665
2975
  }
3666
2976
 
3667
2977
  /* call-seq:
@@ -3682,12 +2992,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3682
2992
  *
3683
2993
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3684
2994
  *
3685
- * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
2995
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
3686
2996
  * BigDecimal(2) # => 0.2e1
3687
2997
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3688
2998
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3689
- * # Float or Rational value requires ndigits.
3690
- * BigDecimal(2.0, 0) # => 0.2e1
2999
+ * BigDecimal(2.0) # => 0.2e1
3000
+ * # Rational value requires ndigits.
3691
3001
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3692
3002
  *
3693
3003
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3751,11 +3061,11 @@ static VALUE
3751
3061
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3752
3062
  {
3753
3063
  char const *c_str = StringValueCStr(str);
3754
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3755
- if (!vp)
3064
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3065
+ if (v.bigdecimal_or_nil == Qnil)
3756
3066
  return Qnil;
3757
3067
  else
3758
- return VpCheckGetValue(vp);
3068
+ return CheckGetValue(bdvalue_nonnullable(v));
3759
3069
  }
3760
3070
 
3761
3071
  /*
@@ -3810,7 +3120,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3810
3120
  static VALUE
3811
3121
  BigDecimal_sign(VALUE self)
3812
3122
  { /* sign */
3813
- int s = GetVpValue(self, 1)->sign;
3123
+ int s = GetSelfVpValue(self)->sign;
3814
3124
  return INT2FIX(s);
3815
3125
  }
3816
3126
 
@@ -3882,310 +3192,15 @@ BigDecimal_save_rounding_mode(VALUE self)
3882
3192
  * puts BigDecimal.limit
3883
3193
  *
3884
3194
  */
3885
- static VALUE
3886
- BigDecimal_save_limit(VALUE self)
3887
- {
3888
- size_t const limit = VpGetPrecLimit();
3889
- int state;
3890
- VALUE ret = rb_protect(rb_yield, Qnil, &state);
3891
- VpSetPrecLimit(limit);
3892
- if (state) rb_jump_tag(state);
3893
- return ret;
3894
- }
3895
-
3896
- /* call-seq:
3897
- * BigMath.exp(decimal, numeric) -> BigDecimal
3898
- *
3899
- * Computes the value of e (the base of natural logarithms) raised to the
3900
- * power of +decimal+, to the specified number of digits of precision.
3901
- *
3902
- * If +decimal+ is infinity, returns Infinity.
3903
- *
3904
- * If +decimal+ is NaN, returns NaN.
3905
- */
3906
- static VALUE
3907
- BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3908
- {
3909
- ssize_t prec, n, i;
3910
- Real* vx = NULL;
3911
- VALUE one, d, y;
3912
- int negative = 0;
3913
- int infinite = 0;
3914
- int nan = 0;
3915
- double flo;
3916
-
3917
- prec = NUM2SSIZET(vprec);
3918
- if (prec <= 0) {
3919
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
3920
- }
3921
-
3922
- /* TODO: the following switch statement is almost same as one in the
3923
- * BigDecimalCmp function. */
3924
- switch (TYPE(x)) {
3925
- case T_DATA:
3926
- if (!is_kind_of_BigDecimal(x)) break;
3927
- vx = DATA_PTR(x);
3928
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3929
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3930
- nan = VpIsNaN(vx);
3931
- break;
3932
-
3933
- case T_FIXNUM:
3934
- /* fall through */
3935
- case T_BIGNUM:
3936
- vx = GetVpValue(x, 0);
3937
- break;
3938
-
3939
- case T_FLOAT:
3940
- flo = RFLOAT_VALUE(x);
3941
- negative = flo < 0;
3942
- infinite = isinf(flo);
3943
- nan = isnan(flo);
3944
- if (!infinite && !nan) {
3945
- vx = GetVpValueWithPrec(x, 0, 0);
3946
- }
3947
- break;
3948
-
3949
- case T_RATIONAL:
3950
- vx = GetVpValueWithPrec(x, prec, 0);
3951
- break;
3952
-
3953
- default:
3954
- break;
3955
- }
3956
- if (infinite) {
3957
- if (negative) {
3958
- return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3959
- }
3960
- else {
3961
- Real* vy = NewZeroWrapNolimit(1, prec);
3962
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3963
- RB_GC_GUARD(vy->obj);
3964
- return VpCheckGetValue(vy);
3965
- }
3966
- }
3967
- else if (nan) {
3968
- Real* vy = NewZeroWrapNolimit(1, prec);
3969
- VpSetNaN(vy);
3970
- RB_GC_GUARD(vy->obj);
3971
- return VpCheckGetValue(vy);
3972
- }
3973
- else if (vx == NULL) {
3974
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
3975
- }
3976
- x = vx->obj;
3977
-
3978
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
3979
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3980
- if (negative) {
3981
- VALUE x_zero = INT2NUM(1);
3982
- VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
3983
- x = BigDecimal_initialize_copy(x_copy, x);
3984
- vx = DATA_PTR(x);
3985
- VpSetSign(vx, 1);
3986
- }
3987
-
3988
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
3989
- y = one;
3990
- d = y;
3991
- i = 1;
3992
-
3993
- while (!VpIsZero((Real*)DATA_PTR(d))) {
3994
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
3995
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
3996
- ssize_t m = n - vabs(ey - ed);
3997
-
3998
- rb_thread_check_ints();
3999
-
4000
- if (m <= 0) {
4001
- break;
4002
- }
4003
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4004
- m = BIGDECIMAL_DOUBLE_FIGURES;
4005
- }
4006
-
4007
- d = BigDecimal_mult(d, x); /* d <- d * x */
4008
- d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
4009
- y = BigDecimal_add(y, d); /* y <- y + d */
4010
- ++i; /* i <- i + 1 */
4011
- }
4012
-
4013
- if (negative) {
4014
- return BigDecimal_div2(one, y, vprec);
4015
- }
4016
- else {
4017
- vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
4018
- return BigDecimal_round(1, &vprec, y);
4019
- }
4020
-
4021
- RB_GC_GUARD(one);
4022
- RB_GC_GUARD(x);
4023
- RB_GC_GUARD(y);
4024
- RB_GC_GUARD(d);
4025
- }
4026
-
4027
- /* call-seq:
4028
- * BigMath.log(decimal, numeric) -> BigDecimal
4029
- *
4030
- * Computes the natural logarithm of +decimal+ to the specified number of
4031
- * digits of precision, +numeric+.
4032
- *
4033
- * If +decimal+ is zero or negative, raises Math::DomainError.
4034
- *
4035
- * If +decimal+ is positive infinity, returns Infinity.
4036
- *
4037
- * If +decimal+ is NaN, returns NaN.
4038
- */
4039
- static VALUE
4040
- BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
4041
- {
4042
- ssize_t prec, n, i;
4043
- SIGNED_VALUE expo;
4044
- Real* vx = NULL;
4045
- VALUE vn, one, two, w, x2, y, d;
4046
- int zero = 0;
4047
- int negative = 0;
4048
- int infinite = 0;
4049
- int nan = 0;
4050
- double flo;
4051
- long fix;
4052
-
4053
- if (!is_integer(vprec)) {
4054
- rb_raise(rb_eArgError, "precision must be an Integer");
4055
- }
4056
-
4057
- prec = NUM2SSIZET(vprec);
4058
- if (prec <= 0) {
4059
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
4060
- }
4061
-
4062
- /* TODO: the following switch statement is almost same as one in the
4063
- * BigDecimalCmp function. */
4064
- switch (TYPE(x)) {
4065
- case T_DATA:
4066
- if (!is_kind_of_BigDecimal(x)) break;
4067
- vx = DATA_PTR(x);
4068
- zero = VpIsZero(vx);
4069
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4070
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
4071
- nan = VpIsNaN(vx);
4072
- break;
4073
-
4074
- case T_FIXNUM:
4075
- fix = FIX2LONG(x);
4076
- zero = fix == 0;
4077
- negative = fix < 0;
4078
- goto get_vp_value;
4079
-
4080
- case T_BIGNUM:
4081
- i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
4082
- zero = i == 0;
4083
- negative = i < 0;
4084
- get_vp_value:
4085
- if (zero || negative) break;
4086
- vx = GetVpValue(x, 0);
4087
- break;
4088
-
4089
- case T_FLOAT:
4090
- flo = RFLOAT_VALUE(x);
4091
- zero = flo == 0;
4092
- negative = flo < 0;
4093
- infinite = isinf(flo);
4094
- nan = isnan(flo);
4095
- if (!zero && !negative && !infinite && !nan) {
4096
- vx = GetVpValueWithPrec(x, 0, 1);
4097
- }
4098
- break;
4099
-
4100
- case T_RATIONAL:
4101
- zero = RRATIONAL_ZERO_P(x);
4102
- negative = RRATIONAL_NEGATIVE_P(x);
4103
- if (zero || negative) break;
4104
- vx = GetVpValueWithPrec(x, prec, 1);
4105
- break;
4106
-
4107
- case T_COMPLEX:
4108
- rb_raise(rb_eMathDomainError,
4109
- "Complex argument for BigMath.log");
4110
-
4111
- default:
4112
- break;
4113
- }
4114
- if (infinite && !negative) {
4115
- Real *vy = NewZeroWrapNolimit(1, prec);
4116
- RB_GC_GUARD(vy->obj);
4117
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
4118
- return VpCheckGetValue(vy);
4119
- }
4120
- else if (nan) {
4121
- Real* vy = NewZeroWrapNolimit(1, prec);
4122
- RB_GC_GUARD(vy->obj);
4123
- VpSetNaN(vy);
4124
- return VpCheckGetValue(vy);
4125
- }
4126
- else if (zero || negative) {
4127
- rb_raise(rb_eMathDomainError,
4128
- "Zero or negative argument for log");
4129
- }
4130
- else if (vx == NULL) {
4131
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4132
- }
4133
- x = VpCheckGetValue(vx);
4134
-
4135
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4136
- two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4137
-
4138
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4139
- vn = SSIZET2NUM(n);
4140
- expo = VpExponent10(vx);
4141
- if (expo < 0 || expo >= 3) {
4142
- char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
4143
- snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
4144
- x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
4145
- }
4146
- else {
4147
- expo = 0;
4148
- }
4149
- w = BigDecimal_sub(x, one);
4150
- x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
4151
- x2 = BigDecimal_mult2(x, x, vn);
4152
- y = x;
4153
- d = y;
4154
- i = 1;
4155
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4156
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4157
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4158
- ssize_t m = n - vabs(ey - ed);
4159
- if (m <= 0) {
4160
- break;
4161
- }
4162
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4163
- m = BIGDECIMAL_DOUBLE_FIGURES;
4164
- }
4165
-
4166
- x = BigDecimal_mult2(x2, x, vn);
4167
- i += 2;
4168
- d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
4169
- y = BigDecimal_add(y, d);
4170
- }
4171
-
4172
- y = BigDecimal_mult(y, two);
4173
- if (expo != 0) {
4174
- VALUE log10, vexpo, dy;
4175
- log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
4176
- vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
4177
- dy = BigDecimal_mult(log10, vexpo);
4178
- y = BigDecimal_add(y, dy);
4179
- }
4180
-
4181
- RB_GC_GUARD(one);
4182
- RB_GC_GUARD(two);
4183
- RB_GC_GUARD(vn);
4184
- RB_GC_GUARD(x2);
4185
- RB_GC_GUARD(y);
4186
- RB_GC_GUARD(d);
4187
-
4188
- return y;
3195
+ static VALUE
3196
+ BigDecimal_save_limit(VALUE self)
3197
+ {
3198
+ size_t const limit = VpGetPrecLimit();
3199
+ int state;
3200
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
3201
+ VpSetPrecLimit(limit);
3202
+ if (state) rb_jump_tag(state);
3203
+ return ret;
4189
3204
  }
4190
3205
 
4191
3206
  static VALUE BIGDECIMAL_NAN = Qnil;
@@ -4239,6 +3254,34 @@ BigDecimal_literal(const char *str)
4239
3254
 
4240
3255
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4241
3256
 
3257
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3258
+ VALUE
3259
+ BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3260
+ BDVALUE a,b,c,d;
3261
+ size_t cn = NUM2INT(cprec);
3262
+ a = GetBDValueMust(self);
3263
+ b = GetBDValueMust(r);
3264
+ c = NewZeroWrap(1, cn * BASE_FIG);
3265
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3266
+ VpDivd(c.real, d.real, a.real, b.real);
3267
+ RB_GC_GUARD(a.bigdecimal);
3268
+ RB_GC_GUARD(b.bigdecimal);
3269
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3270
+ }
3271
+
3272
+ VALUE
3273
+ BigDecimal_vpmult(VALUE self, VALUE v) {
3274
+ BDVALUE a,b,c;
3275
+ a = GetBDValueMust(self);
3276
+ b = GetBDValueMust(v);
3277
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3278
+ VpMult(c.real, a.real, b.real);
3279
+ RB_GC_GUARD(a.bigdecimal);
3280
+ RB_GC_GUARD(b.bigdecimal);
3281
+ return c.bigdecimal;
3282
+ }
3283
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3284
+
4242
3285
  /* Document-class: BigDecimal
4243
3286
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4244
3287
  *
@@ -4355,14 +3398,16 @@ BigDecimal_literal(const char *str)
4355
3398
  *
4356
3399
  * When you require +bigdecimal/util+, the #to_d method will be
4357
3400
  * available on BigDecimal and the native Integer, Float, Rational,
4358
- * and String classes:
3401
+ * String, Complex, and NilClass classes:
4359
3402
  *
4360
3403
  * require 'bigdecimal/util'
4361
3404
  *
4362
- * 42.to_d # => 0.42e2
4363
- * 0.5.to_d # => 0.5e0
4364
- * (2/3r).to_d(3) # => 0.667e0
4365
- * "0.5".to_d # => 0.5e0
3405
+ * 42.to_d # => 0.42e2
3406
+ * 0.5.to_d # => 0.5e0
3407
+ * (2/3r).to_d(3) # => 0.667e0
3408
+ * "0.5".to_d # => 0.5e0
3409
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
3410
+ * nil.to_d # => 0.0
4366
3411
  *
4367
3412
  * == Methods for Working with \JSON
4368
3413
  *
@@ -4436,7 +3481,7 @@ Init_bigdecimal(void)
4436
3481
  * guarantee that two groups could always be multiplied together without
4437
3482
  * overflow.)
4438
3483
  */
4439
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3484
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4440
3485
 
4441
3486
  /* Exceptions */
4442
3487
 
@@ -4578,14 +3623,11 @@ Init_bigdecimal(void)
4578
3623
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4579
3624
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4580
3625
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4581
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4582
3626
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4583
3627
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4584
3628
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4585
3629
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4586
3630
  rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
4587
- rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
4588
- rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
4589
3631
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4590
3632
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4591
3633
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4604,11 +3646,13 @@ Init_bigdecimal(void)
4604
3646
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4605
3647
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4606
3648
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3649
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4607
3650
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4608
3651
 
4609
- rb_mBigMath = rb_define_module("BigMath");
4610
- rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4611
- rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
3652
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3653
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
3654
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3655
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
4612
3656
 
4613
3657
  #define ROUNDING_MODE(i, name, value) \
4614
3658
  id_##name = rb_intern_const(#name); \
@@ -4648,19 +3692,9 @@ Init_bigdecimal(void)
4648
3692
  */
4649
3693
  #ifdef BIGDECIMAL_DEBUG
4650
3694
  static int gfDebug = 1; /* Debug switch */
4651
- #if 0
4652
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4653
- #endif
4654
3695
  #endif /* BIGDECIMAL_DEBUG */
4655
3696
 
4656
3697
  static Real *VpConstOne; /* constant 1.0 */
4657
- static Real *VpConstPt5; /* constant 0.5 */
4658
- #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4659
- /* used in VpSqrt() */
4660
-
4661
- /* ETC */
4662
- #define MemCmp(x,y,z) memcmp(x,y,z)
4663
- #define StrCmp(x,y) strcmp(x,y)
4664
3698
 
4665
3699
  enum op_sw {
4666
3700
  OP_SW_ADD = 1, /* + */
@@ -4670,11 +3704,9 @@ enum op_sw {
4670
3704
  };
4671
3705
 
4672
3706
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4673
- static int AddExponent(Real *a, SIGNED_VALUE n);
4674
3707
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4675
3708
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4676
3709
  static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
4677
- static int VpNmlz(Real *a);
4678
3710
  static void VpFormatSt(char *psz, size_t fFmt);
4679
3711
  static int VpRdup(Real *m, size_t ind_m);
4680
3712
 
@@ -4733,10 +3765,10 @@ VpCheckException(Real *p, bool always)
4733
3765
  }
4734
3766
 
4735
3767
  static VALUE
4736
- VpCheckGetValue(Real *p)
3768
+ CheckGetValue(BDVALUE v)
4737
3769
  {
4738
- VpCheckException(p, false);
4739
- return p->obj;
3770
+ VpCheckException(v.real, false);
3771
+ return v.bigdecimal;
4740
3772
  }
4741
3773
 
4742
3774
  /*
@@ -4768,12 +3800,10 @@ VpGetPrecLimit(void)
4768
3800
  return NUM2SIZET(vlimit);
4769
3801
  }
4770
3802
 
4771
- VP_EXPORT size_t
3803
+ VP_EXPORT void
4772
3804
  VpSetPrecLimit(size_t n)
4773
3805
  {
4774
- size_t const s = VpGetPrecLimit();
4775
3806
  bigdecimal_set_thread_local_precision_limit(n);
4776
- return s;
4777
3807
  }
4778
3808
 
4779
3809
  /*
@@ -4888,15 +3918,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4888
3918
  return nzero;
4889
3919
  }
4890
3920
 
4891
- #if 0 /* unused */
4892
- VP_EXPORT int
4893
- VpIsNegDoubleZero(double v)
4894
- {
4895
- double z = VpGetDoubleNegZero();
4896
- return MemCmp(&v,&z,sizeof(v))==0;
4897
- }
4898
- #endif
4899
-
4900
3921
  VP_EXPORT int
4901
3922
  VpException(unsigned short f, const char *str,int always)
4902
3923
  {
@@ -5048,7 +4069,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5048
4069
  case 'E':
5049
4070
  /* fall through */
5050
4071
  default:
5051
- nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4072
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
5052
4073
  }
5053
4074
  return nc;
5054
4075
  }
@@ -5074,28 +4095,13 @@ VpInit(DECDIG BaseVal)
5074
4095
  VpGetDoubleNegZero();
5075
4096
 
5076
4097
  /* Const 1.0 */
5077
- VpConstOne = NewOneNolimit(1, 1);
5078
-
5079
- /* Const 0.5 */
5080
- VpConstPt5 = NewOneNolimit(1, 1);
5081
- VpConstPt5->exponent = 0;
5082
- VpConstPt5->frac[0] = 5*BASE1;
4098
+ VpConstOne = NewZero(1, 1);
4099
+ VpSetOne(VpConstOne);
5083
4100
 
5084
4101
  #ifdef BIGDECIMAL_DEBUG
5085
4102
  gnAlloc = 0;
5086
4103
  #endif /* BIGDECIMAL_DEBUG */
5087
4104
 
5088
- #ifdef BIGDECIMAL_DEBUG
5089
- if (gfDebug) {
5090
- printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
5091
- printf("\tBASE = %"PRIuDECDIG"\n", BASE);
5092
- printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
5093
- printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
5094
- printf("\tBASE_FIG = %u\n", BASE_FIG);
5095
- printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
5096
- }
5097
- #endif /* BIGDECIMAL_DEBUG */
5098
-
5099
4105
  return BIGDECIMAL_DOUBLE_FIGURES;
5100
4106
  }
5101
4107
 
@@ -5111,24 +4117,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5111
4117
  {
5112
4118
  SIGNED_VALUE e = a->exponent;
5113
4119
  SIGNED_VALUE m = e+n;
5114
- SIGNED_VALUE eb, mb;
5115
- if (e > 0) {
5116
- if (n > 0) {
5117
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5118
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5119
- goto overflow;
5120
- mb = m*(SIGNED_VALUE)BASE_FIG;
5121
- eb = e*(SIGNED_VALUE)BASE_FIG;
5122
- if (eb - mb > 0) goto overflow;
5123
- }
5124
- }
5125
- else if (n < 0) {
5126
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5127
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5128
- goto underflow;
5129
- mb = m*(SIGNED_VALUE)BASE_FIG;
5130
- eb = e*(SIGNED_VALUE)BASE_FIG;
5131
- if (mb - eb > 0) goto underflow;
4120
+ if (e > 0 && n > 0) {
4121
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
4122
+ } else if (e < 0 && n < 0) {
4123
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
4124
+ } else if (m > VP_EXPONENT_MAX) {
4125
+ goto overflow;
4126
+ } else if (m < VP_EXPONENT_MIN) {
4127
+ goto underflow;
5132
4128
  }
5133
4129
  a->exponent = m;
5134
4130
  return 1;
@@ -5169,7 +4165,6 @@ bigdecimal_parse_special_string(const char *str)
5169
4165
  while (*p && ISSPACE(*p)) ++p;
5170
4166
  if (*p == '\0') {
5171
4167
  Real *vp = rbd_allocate_struct(1);
5172
- vp->MaxPrec = 1;
5173
4168
  switch (table[i].sign) {
5174
4169
  default:
5175
4170
  UNREACHABLE; break;
@@ -5234,38 +4229,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
5234
4229
  /*
5235
4230
  * Allocates variable.
5236
4231
  * [Input]
5237
- * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5238
- * The mx will be the number of significant digits can to be stored.
5239
- * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5240
- * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5241
- * so that the full precision specified by szVal is allocated.
4232
+ * szVal ... The value assigned(char).
5242
4233
  *
5243
4234
  * [Returns]
5244
4235
  * Pointer to the newly allocated variable, or
5245
4236
  * NULL be returned if memory allocation is failed,or any error.
5246
4237
  */
5247
4238
  VP_EXPORT Real *
5248
- VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4239
+ VpAlloc(const char *szVal, int strict_p, int exc)
5249
4240
  {
5250
4241
  const char *orig_szVal = szVal;
5251
4242
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5252
- size_t len;
5253
4243
  char v, *psz;
5254
4244
  int sign=1;
5255
4245
  Real *vp = NULL;
5256
4246
  VALUE buf;
5257
4247
 
5258
- if (szVal == NULL) {
5259
- return_zero:
5260
- /* necessary to be able to store */
5261
- /* at least mx digits. */
5262
- /* szVal==NULL ==> allocate zero value. */
5263
- vp = rbd_allocate_struct(mx);
5264
- vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5265
- VpSetZero(vp, 1); /* initialize vp to zero. */
5266
- return vp;
5267
- }
5268
-
5269
4248
  /* Skipping leading spaces */
5270
4249
  while (ISSPACE(*szVal)) szVal++;
5271
4250
 
@@ -5274,14 +4253,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5274
4253
  return vp;
5275
4254
  }
5276
4255
 
5277
- /* Processing the leading one `#` */
5278
- if (*szVal != '#') {
5279
- len = rbd_calculate_internal_digits(mx, true);
5280
- }
5281
- else {
5282
- len = rbd_calculate_internal_digits(mx, false);
5283
- ++szVal;
5284
- }
4256
+ /* Skip leading `#`.
4257
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
4258
+ * but now it has no effect.
4259
+ */
4260
+ if (*szVal == '#') ++szVal;
5285
4261
 
5286
4262
  /* Scanning digits */
5287
4263
 
@@ -5428,7 +4404,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5428
4404
  VALUE str;
5429
4405
  invalid_value:
5430
4406
  if (!strict_p) {
5431
- goto return_zero;
4407
+ return NewZero(1, 1);
5432
4408
  }
5433
4409
  if (!exc) {
5434
4410
  return NULL;
@@ -5439,11 +4415,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5439
4415
 
5440
4416
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5441
4417
  /* units for szVal[] */
5442
- if (len == 0) len = 1;
5443
- nalloc = Max(nalloc, len);
5444
- len = nalloc;
5445
- vp = rbd_allocate_struct(len);
5446
- vp->MaxPrec = len; /* set max precision */
4418
+ vp = rbd_allocate_struct(nalloc);
5447
4419
  VpSetZero(vp, sign);
5448
4420
  protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
5449
4421
  rb_str_resize(buf, 0);
@@ -5483,7 +4455,7 @@ VpAsgn(Real *c, Real *a, int isw)
5483
4455
  c->Prec = n;
5484
4456
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5485
4457
  /* Needs round ? */
5486
- if (isw != 10) {
4458
+ if (isw != 10 && isw != -10) {
5487
4459
  /* Not in ActiveRound */
5488
4460
  if(c->Prec < a->Prec) {
5489
4461
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5509,19 +4481,11 @@ VpAsgn(Real *c, Real *a, int isw)
5509
4481
  VP_EXPORT size_t
5510
4482
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5511
4483
  {
5512
- short sw, isw;
4484
+ short sw, isw, sign;
5513
4485
  Real *a_ptr, *b_ptr;
5514
4486
  size_t n, na, nb, i;
5515
4487
  DECDIG mrv;
5516
4488
 
5517
- #ifdef BIGDECIMAL_DEBUG
5518
- if (gfDebug) {
5519
- VPrint(stdout, "VpAddSub(enter) a=% \n", a);
5520
- VPrint(stdout, " b=% \n", b);
5521
- printf(" operation=%d\n", operation);
5522
- }
5523
- #endif /* BIGDECIMAL_DEBUG */
5524
-
5525
4489
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5526
4490
 
5527
4491
  /* check if a or b is zero */
@@ -5610,28 +4574,21 @@ end_if:
5610
4574
  if (isw) { /* addition */
5611
4575
  VpSetSign(c, 1);
5612
4576
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5613
- VpSetSign(c, isw / 2);
4577
+ sign = isw / 2;
5614
4578
  }
5615
4579
  else { /* subtraction */
5616
4580
  VpSetSign(c, 1);
5617
4581
  mrv = VpSubAbs(a_ptr, b_ptr, c);
5618
- if (a_ptr == a) {
5619
- VpSetSign(c,VpGetSign(a));
5620
- }
5621
- else {
5622
- VpSetSign(c, VpGetSign(a_ptr) * sw);
5623
- }
4582
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5624
4583
  }
5625
- VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
5626
-
5627
- #ifdef BIGDECIMAL_DEBUG
5628
- if (gfDebug) {
5629
- VPrint(stdout, "VpAddSub(result) c=% \n", c);
5630
- VPrint(stdout, " a=% \n", a);
5631
- VPrint(stdout, " b=% \n", b);
5632
- printf(" operation=%d\n", operation);
4584
+ if (VpIsInf(c)) {
4585
+ VpSetInf(c, sign);
5633
4586
  }
5634
- #endif /* BIGDECIMAL_DEBUG */
4587
+ else {
4588
+ VpSetSign(c, sign);
4589
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4590
+ }
4591
+
5635
4592
  return c->Prec * BASE_FIG;
5636
4593
  }
5637
4594
 
@@ -5652,13 +4609,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5652
4609
  size_t c_pos;
5653
4610
  DECDIG av, bv, carry, mrv;
5654
4611
 
5655
- #ifdef BIGDECIMAL_DEBUG
5656
- if (gfDebug) {
5657
- VPrint(stdout, "VpAddAbs called: a = %\n", a);
5658
- VPrint(stdout, " b = %\n", b);
5659
- }
5660
- #endif /* BIGDECIMAL_DEBUG */
5661
-
5662
4612
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5663
4613
  a_pos = ap;
5664
4614
  b_pos = bp;
@@ -5724,11 +4674,6 @@ Assign_a:
5724
4674
 
5725
4675
  Exit:
5726
4676
 
5727
- #ifdef BIGDECIMAL_DEBUG
5728
- if (gfDebug) {
5729
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5730
- }
5731
- #endif /* BIGDECIMAL_DEBUG */
5732
4677
  return mrv;
5733
4678
  }
5734
4679
 
@@ -5747,13 +4692,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5747
4692
  size_t c_pos;
5748
4693
  DECDIG av, bv, borrow, mrv;
5749
4694
 
5750
- #ifdef BIGDECIMAL_DEBUG
5751
- if (gfDebug) {
5752
- VPrint(stdout, "VpSubAbs called: a = %\n", a);
5753
- VPrint(stdout, " b = %\n", b);
5754
- }
5755
- #endif /* BIGDECIMAL_DEBUG */
5756
-
5757
4695
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5758
4696
  a_pos = ap;
5759
4697
  b_pos = bp;
@@ -5829,11 +4767,6 @@ Assign_a:
5829
4767
  mrv = 0;
5830
4768
 
5831
4769
  Exit:
5832
- #ifdef BIGDECIMAL_DEBUG
5833
- if (gfDebug) {
5834
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5835
- }
5836
- #endif /* BIGDECIMAL_DEBUG */
5837
4770
  return mrv;
5838
4771
  }
5839
4772
 
@@ -5964,19 +4897,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5964
4897
  VP_EXPORT size_t
5965
4898
  VpMult(Real *c, Real *a, Real *b)
5966
4899
  {
5967
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
4900
+ size_t MxIndA, MxIndB, MxIndAB;
5968
4901
  size_t ind_c, i, ii, nc;
5969
4902
  size_t ind_as, ind_ae, ind_bs;
5970
4903
  DECDIG carry;
5971
4904
  DECDIG_DBL s;
5972
- Real *w;
5973
-
5974
- #ifdef BIGDECIMAL_DEBUG
5975
- if (gfDebug) {
5976
- VPrint(stdout, "VpMult(Enter): a=% \n", a);
5977
- VPrint(stdout, " b=% \n", b);
5978
- }
5979
- #endif /* BIGDECIMAL_DEBUG */
5980
4905
 
5981
4906
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
5982
4907
 
@@ -5987,39 +4912,28 @@ VpMult(Real *c, Real *a, Real *b)
5987
4912
  }
5988
4913
 
5989
4914
  if (VpIsOne(a)) {
5990
- VpAsgn(c, b, VpGetSign(a));
4915
+ VpAsgn(c, b, 10 * VpGetSign(a));
5991
4916
  goto Exit;
5992
4917
  }
5993
4918
  if (VpIsOne(b)) {
5994
- VpAsgn(c, a, VpGetSign(b));
4919
+ VpAsgn(c, a, 10 * VpGetSign(b));
5995
4920
  goto Exit;
5996
4921
  }
5997
4922
  if (b->Prec > a->Prec) {
5998
4923
  /* Adjust so that digits(a)>digits(b) */
5999
- w = a;
4924
+ Real *w = a;
6000
4925
  a = b;
6001
4926
  b = w;
6002
4927
  }
6003
- w = NULL;
6004
4928
  MxIndA = a->Prec - 1;
6005
4929
  MxIndB = b->Prec - 1;
6006
- MxIndC = c->MaxPrec - 1;
6007
4930
  MxIndAB = a->Prec + b->Prec - 1;
6008
4931
 
6009
- if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
6010
- w = c;
6011
- c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
6012
- MxIndC = MxIndAB;
6013
- }
6014
-
6015
4932
  /* set LHSV c info */
6016
4933
 
6017
4934
  c->exponent = a->exponent; /* set exponent */
6018
- if (!AddExponent(c, b->exponent)) {
6019
- if (w) rbd_free_struct(c);
6020
- return 0;
6021
- }
6022
4935
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
4936
+ if (!AddExponent(c, b->exponent)) return 0;
6023
4937
  carry = 0;
6024
4938
  nc = ind_c = MxIndAB;
6025
4939
  memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
@@ -6066,29 +4980,18 @@ VpMult(Real *c, Real *a, Real *b)
6066
4980
  }
6067
4981
  }
6068
4982
  }
6069
- if (w != NULL) { /* free work variable */
6070
- VpNmlz(c);
6071
- VpAsgn(w, c, 1);
6072
- rbd_free_struct(c);
6073
- c = w;
6074
- }
6075
- else {
6076
- VpLimitRound(c,0);
6077
- }
4983
+ VpNmlz(c);
6078
4984
 
6079
4985
  Exit:
6080
- #ifdef BIGDECIMAL_DEBUG
6081
- if (gfDebug) {
6082
- VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
6083
- VPrint(stdout, " a=% \n", a);
6084
- VPrint(stdout, " b=% \n", b);
6085
- }
6086
- #endif /*BIGDECIMAL_DEBUG */
6087
4986
  return c->Prec*BASE_FIG;
6088
4987
  }
6089
4988
 
6090
4989
  /*
6091
4990
  * c = a / b, remainder = r
4991
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
4992
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
4993
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
4994
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
6092
4995
  */
6093
4996
  VP_EXPORT size_t
6094
4997
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6097,16 +5000,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6097
5000
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6098
5001
  size_t nLoop;
6099
5002
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6100
- DECDIG borrow, borrow1, borrow2;
5003
+ DECDIG borrow1, borrow2;
6101
5004
  DECDIG_DBL qb;
6102
5005
 
6103
- #ifdef BIGDECIMAL_DEBUG
6104
- if (gfDebug) {
6105
- VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
6106
- VPrint(stdout, " b=% \n", b);
6107
- }
6108
- #endif /*BIGDECIMAL_DEBUG */
6109
-
6110
5006
  VpSetNaN(r);
6111
5007
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6112
5008
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6123,30 +5019,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6123
5019
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6124
5020
  goto Exit;
6125
5021
  }
6126
- if (VpIsOne(b)) {
6127
- /* divide by one */
6128
- VpAsgn(c, a, VpGetSign(b));
6129
- VpSetZero(r, VpGetSign(a));
6130
- goto Exit;
6131
- }
6132
5022
 
6133
5023
  word_a = a->Prec;
6134
5024
  word_b = b->Prec;
6135
5025
  word_c = c->MaxPrec;
6136
5026
  word_r = r->MaxPrec;
6137
5027
 
6138
- if (word_a >= word_r || word_b + word_c - 2 >= word_r) goto space_error;
5028
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6139
5029
 
6140
- ind_r = 1;
6141
- r->frac[0] = 0;
6142
- while (ind_r <= word_a) {
6143
- r->frac[ind_r] = a->frac[ind_r - 1];
6144
- ++ind_r;
6145
- }
6146
- while (ind_r < word_r) r->frac[ind_r++] = 0;
6147
-
6148
- ind_c = 0;
6149
- while (ind_c < word_c) c->frac[ind_c++] = 0;
5030
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
5031
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
5032
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
6150
5033
 
6151
5034
  /* initial procedure */
6152
5035
  b1 = b1p1 = b->frac[0];
@@ -6161,15 +5044,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6161
5044
 
6162
5045
  /* */
6163
5046
  /* loop start */
6164
- ind_c = word_r - 1;
6165
- nLoop = Min(word_c,ind_c);
6166
- ind_c = 1;
5047
+ nLoop = Min(word_c, word_r);
5048
+ ind_c = 0;
6167
5049
  while (ind_c < nLoop) {
6168
5050
  if (r->frac[ind_c] == 0) {
6169
5051
  ++ind_c;
6170
5052
  continue;
6171
5053
  }
6172
- r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
5054
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
6173
5055
  if (r1r2 == b1b2) {
6174
5056
  /* The first two word digits is the same */
6175
5057
  ind_b = 2;
@@ -6182,26 +5064,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6182
5064
  }
6183
5065
  /* The first few word digits of r and b is the same and */
6184
5066
  /* the first different word digit of w is greater than that */
6185
- /* of b, so quotient is 1 and just subtract b from r. */
6186
- borrow = 0; /* quotient=1, then just r-b */
6187
- ind_b = b->Prec - 1;
6188
- ind_r = ind_c + ind_b;
6189
- if (ind_r >= word_r) goto space_error;
6190
- n = ind_b;
6191
- for (i = 0; i <= n; ++i) {
6192
- if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
6193
- r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
6194
- borrow = 1;
6195
- }
6196
- else {
6197
- r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
6198
- borrow = 0;
6199
- }
6200
- --ind_r;
6201
- --ind_b;
6202
- }
5067
+ /* of b, so quotient is 1. */
5068
+ q = 1;
6203
5069
  ++c->frac[ind_c];
6204
- goto carry;
5070
+ ind_r = b->Prec + ind_c - 1;
5071
+ goto sub_mult;
6205
5072
  }
6206
5073
  /* The first two word digits is not the same, */
6207
5074
  /* then compare magnitude, and divide actually. */
@@ -6254,49 +5121,26 @@ sub_mult:
6254
5121
  }
6255
5122
 
6256
5123
  r->frac[ind_r] -= borrow2;
6257
- carry:
6258
- ind_r = ind_c;
6259
- while (c->frac[ind_r] >= BASE) {
6260
- c->frac[ind_r] -= BASE;
6261
- --ind_r;
6262
- ++c->frac[ind_r];
6263
- }
6264
5124
  }
6265
5125
  /* End of operation, now final arrangement */
6266
5126
  out_side:
6267
5127
  c->Prec = word_c;
6268
5128
  c->exponent = a->exponent;
6269
- if (!AddExponent(c, 2)) return 0;
5129
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5130
+ if (!AddExponent(c, 1)) return 0;
6270
5131
  if (!AddExponent(c, -(b->exponent))) return 0;
6271
5132
 
6272
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6273
5133
  VpNmlz(c); /* normalize c */
6274
5134
  r->Prec = word_r;
6275
5135
  r->exponent = a->exponent;
6276
- if (!AddExponent(r, 1)) return 0;
6277
5136
  VpSetSign(r, VpGetSign(a));
6278
5137
  VpNmlz(r); /* normalize r(remainder) */
6279
5138
  goto Exit;
6280
5139
 
6281
5140
  space_error:
6282
- #ifdef BIGDECIMAL_DEBUG
6283
- if (gfDebug) {
6284
- printf(" word_a=%"PRIuSIZE"\n", word_a);
6285
- printf(" word_b=%"PRIuSIZE"\n", word_b);
6286
- printf(" word_c=%"PRIuSIZE"\n", word_c);
6287
- printf(" word_r=%"PRIuSIZE"\n", word_r);
6288
- printf(" ind_r =%"PRIuSIZE"\n", ind_r);
6289
- }
6290
- #endif /* BIGDECIMAL_DEBUG */
6291
5141
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6292
5142
 
6293
5143
  Exit:
6294
- #ifdef BIGDECIMAL_DEBUG
6295
- if (gfDebug) {
6296
- VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
6297
- VPrint(stdout, " r=% \n", r);
6298
- }
6299
- #endif /* BIGDECIMAL_DEBUG */
6300
5144
  return c->Prec * BASE_FIG;
6301
5145
  }
6302
5146
 
@@ -6419,13 +5263,6 @@ Exit:
6419
5263
  if (val > 1) val = 1;
6420
5264
  else if (val < -1) val = -1;
6421
5265
 
6422
- #ifdef BIGDECIMAL_DEBUG
6423
- if (gfDebug) {
6424
- VPrint(stdout, " VpComp a=%\n", a);
6425
- VPrint(stdout, " b=%\n", b);
6426
- printf(" ans=%d\n", val);
6427
- }
6428
- #endif /* BIGDECIMAL_DEBUG */
6429
5266
  return (int)val;
6430
5267
  }
6431
5268
 
@@ -6543,25 +5380,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6543
5380
  static void
6544
5381
  VpFormatSt(char *psz, size_t fFmt)
6545
5382
  {
6546
- size_t ie, i, nf = 0;
6547
- char ch;
5383
+ size_t iend, idig = 0, iexp = 0, nspaces;
5384
+ char *p;
6548
5385
 
6549
5386
  if (fFmt == 0) return;
6550
5387
 
6551
- ie = strlen(psz);
6552
- for (i = 0; i < ie; ++i) {
6553
- ch = psz[i];
6554
- if (!ch) break;
6555
- if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
6556
- if (ch == '.') { nf = 0; continue; }
6557
- if (ch == 'E' || ch == 'e') break;
6558
-
6559
- if (++nf > fFmt) {
6560
- memmove(psz + i + 1, psz + i, ie - i + 1);
6561
- ++ie;
6562
- nf = 0;
6563
- psz[i] = ' ';
6564
- }
5388
+ iend = strlen(psz);
5389
+
5390
+ if ((p = strchr(psz, '.'))) {
5391
+ idig = (p - psz) + 1;
5392
+ }
5393
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
5394
+ iexp = p - psz;
5395
+ }
5396
+ if (idig == 0 || idig > iexp) return;
5397
+
5398
+ nspaces = (iexp - idig - 1) / fFmt;
5399
+ p = psz + iend + 1;
5400
+ for (size_t i = nspaces; i > 0; i--) {
5401
+ char *src = psz + idig + i * fFmt;
5402
+ char *dst = psz + idig + i * (fFmt + 1);
5403
+ memmove(dst, src, p - src);
5404
+ dst[-1] = ' ';
5405
+ p = src;
6565
5406
  }
6566
5407
  }
6567
5408
 
@@ -6843,7 +5684,7 @@ VP_EXPORT int
6843
5684
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6844
5685
  {
6845
5686
  size_t i, j, ind_a, ma, mi, me;
6846
- SIGNED_VALUE e, es, eb, ef;
5687
+ SIGNED_VALUE e;
6847
5688
  int sign, signe, exponent_overflow;
6848
5689
 
6849
5690
  /* get exponent part */
@@ -6866,23 +5707,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6866
5707
  ++me;
6867
5708
  }
6868
5709
  while (i < me) {
6869
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
6870
- es = e;
6871
- goto exp_overflow;
6872
- }
6873
- es = e * (SIGNED_VALUE)BASE_FIG;
6874
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
6875
- SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
6876
- goto exp_overflow;
6877
- e = e * 10 + exp_chr[i] - '0';
6878
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
6879
- goto exp_overflow;
6880
- if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
6881
- exp_overflow:
5710
+ int dig = exp_chr[i] - '0';
5711
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5712
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6882
5713
  exponent_overflow = 1;
6883
- e = es; /* keep sign */
6884
5714
  break;
6885
5715
  }
5716
+ e = e * 10 + signe * dig;
6886
5717
  ++i;
6887
5718
  }
6888
5719
  }
@@ -6901,34 +5732,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6901
5732
  ++mi;
6902
5733
  }
6903
5734
  }
5735
+ /* skip leading zeros in integer part */
5736
+ while (i < mi && int_chr[i] == '0') {
5737
+ ++i;
5738
+ --ni;
5739
+ }
6904
5740
 
6905
- e = signe * e; /* e: The value of exponent part. */
6906
- e = e + ni; /* set actual exponent size. */
6907
-
6908
- if (e > 0) signe = 1;
6909
- else signe = -1;
5741
+ /* set actual exponent size. */
5742
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5743
+ exponent_overflow = 1;
5744
+ } else {
5745
+ e += ni;
5746
+ }
6910
5747
 
6911
5748
  /* Adjust the exponent so that it is the multiple of BASE_FIG. */
6912
- j = 0;
6913
- ef = 1;
6914
- while (ef) {
6915
- if (e >= 0) eb = e;
6916
- else eb = -e;
6917
- ef = eb / (SIGNED_VALUE)BASE_FIG;
6918
- ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
6919
- if (ef) {
6920
- ++j; /* Means to add one more preceding zero */
6921
- ++e;
6922
- }
5749
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5750
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5751
+ exponent_overflow = 1;
5752
+ } else {
5753
+ e += j;
6923
5754
  }
6924
5755
 
6925
- eb = e / (SIGNED_VALUE)BASE_FIG;
6926
-
6927
- if (exponent_overflow) {
5756
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6928
5757
  int zero = 1;
6929
5758
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6930
5759
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6931
- if (!zero && signe > 0) {
5760
+ if (!zero && e > 0) {
6932
5761
  VpSetInf(a, sign);
6933
5762
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6934
5763
  }
@@ -6978,7 +5807,7 @@ Final:
6978
5807
  ++j;
6979
5808
  }
6980
5809
  a->Prec = ind_a + 1;
6981
- a->exponent = eb;
5810
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
6982
5811
  VpSetSign(a, sign);
6983
5812
  VpNmlz(a);
6984
5813
  return 1;
@@ -7050,254 +5879,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7050
5879
  *d *= VpGetSign(m);
7051
5880
 
7052
5881
  Exit:
7053
- #ifdef BIGDECIMAL_DEBUG
7054
- if (gfDebug) {
7055
- VPrint(stdout, " VpVtoD: m=%\n", m);
7056
- printf(" d=%e * 10 **%ld\n", *d, *e);
7057
- printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
7058
- }
7059
- #endif /*BIGDECIMAL_DEBUG */
7060
5882
  return f;
7061
5883
  }
7062
5884
 
7063
- /*
7064
- * m <- d
7065
- */
7066
- VP_EXPORT void
7067
- VpDtoV(Real *m, double d)
7068
- {
7069
- size_t ind_m, mm;
7070
- SIGNED_VALUE ne;
7071
- DECDIG i;
7072
- double val, val2;
7073
-
7074
- if (isnan(d)) {
7075
- VpSetNaN(m);
7076
- goto Exit;
7077
- }
7078
- if (isinf(d)) {
7079
- if (d > 0.0) VpSetPosInf(m);
7080
- else VpSetNegInf(m);
7081
- goto Exit;
7082
- }
7083
-
7084
- if (d == 0.0) {
7085
- VpSetZero(m, 1);
7086
- goto Exit;
7087
- }
7088
- val = (d > 0.) ? d : -d;
7089
- ne = 0;
7090
- if (val >= 1.0) {
7091
- while (val >= 1.0) {
7092
- val /= (double)BASE;
7093
- ++ne;
7094
- }
7095
- }
7096
- else {
7097
- val2 = 1.0 / (double)BASE;
7098
- while (val < val2) {
7099
- val *= (double)BASE;
7100
- --ne;
7101
- }
7102
- }
7103
- /* Now val = 0.xxxxx*BASE**ne */
7104
-
7105
- mm = m->MaxPrec;
7106
- memset(m->frac, 0, mm * sizeof(DECDIG));
7107
- for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
7108
- val *= (double)BASE;
7109
- i = (DECDIG)val;
7110
- val -= (double)i;
7111
- m->frac[ind_m] = i;
7112
- }
7113
- if (ind_m >= mm) ind_m = mm - 1;
7114
- VpSetSign(m, (d > 0.0) ? 1 : -1);
7115
- m->Prec = ind_m + 1;
7116
- m->exponent = ne;
7117
-
7118
- VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
7119
- (DECDIG)(val*(double)BASE));
7120
-
7121
- Exit:
7122
- #ifdef BIGDECIMAL_DEBUG
7123
- if (gfDebug) {
7124
- printf("VpDtoV d=%30.30e\n", d);
7125
- VPrint(stdout, " m=%\n", m);
7126
- }
7127
- #endif /* BIGDECIMAL_DEBUG */
7128
- return;
7129
- }
7130
-
7131
- /*
7132
- * m <- ival
7133
- */
7134
- #if 0 /* unused */
7135
- VP_EXPORT void
7136
- VpItoV(Real *m, SIGNED_VALUE ival)
7137
- {
7138
- size_t mm, ind_m;
7139
- size_t val, v1, v2, v;
7140
- int isign;
7141
- SIGNED_VALUE ne;
7142
-
7143
- if (ival == 0) {
7144
- VpSetZero(m, 1);
7145
- goto Exit;
7146
- }
7147
- isign = 1;
7148
- val = ival;
7149
- if (ival < 0) {
7150
- isign = -1;
7151
- val =(size_t)(-ival);
7152
- }
7153
- ne = 0;
7154
- ind_m = 0;
7155
- mm = m->MaxPrec;
7156
- while (ind_m < mm) {
7157
- m->frac[ind_m] = 0;
7158
- ++ind_m;
7159
- }
7160
- ind_m = 0;
7161
- while (val > 0) {
7162
- if (val) {
7163
- v1 = val;
7164
- v2 = 1;
7165
- while (v1 >= BASE) {
7166
- v1 /= BASE;
7167
- v2 *= BASE;
7168
- }
7169
- val = val - v2 * v1;
7170
- v = v1;
7171
- }
7172
- else {
7173
- v = 0;
7174
- }
7175
- m->frac[ind_m] = v;
7176
- ++ind_m;
7177
- ++ne;
7178
- }
7179
- m->Prec = ind_m - 1;
7180
- m->exponent = ne;
7181
- VpSetSign(m, isign);
7182
- VpNmlz(m);
7183
-
7184
- Exit:
7185
- #ifdef BIGDECIMAL_DEBUG
7186
- if (gfDebug) {
7187
- printf(" VpItoV i=%d\n", ival);
7188
- VPrint(stdout, " m=%\n", m);
7189
- }
7190
- #endif /* BIGDECIMAL_DEBUG */
7191
- return;
7192
- }
7193
- #endif
7194
-
7195
- /*
7196
- * y = SQRT(x), y*y - x =>0
7197
- */
7198
- VP_EXPORT int
7199
- VpSqrt(Real *y, Real *x)
7200
- {
7201
- Real *f = NULL;
7202
- Real *r = NULL;
7203
- size_t y_prec;
7204
- SIGNED_VALUE n, e;
7205
- ssize_t nr;
7206
- double val;
7207
-
7208
- /* Zero or +Infinity ? */
7209
- if (VpIsZero(x) || VpIsPosInf(x)) {
7210
- VpAsgn(y,x,1);
7211
- goto Exit;
7212
- }
7213
-
7214
- /* Negative ? */
7215
- if (BIGDECIMAL_NEGATIVE_P(x)) {
7216
- VpSetNaN(y);
7217
- return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
7218
- }
7219
-
7220
- /* NaN ? */
7221
- if (VpIsNaN(x)) {
7222
- VpSetNaN(y);
7223
- return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
7224
- }
7225
-
7226
- /* One ? */
7227
- if (VpIsOne(x)) {
7228
- VpSetOne(y);
7229
- goto Exit;
7230
- }
7231
-
7232
- n = (SIGNED_VALUE)y->MaxPrec;
7233
- if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
7234
-
7235
- /* allocate temporally variables */
7236
- /* TODO: reconsider MaxPrec of f and r */
7237
- f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7238
- r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
7239
-
7240
- nr = 0;
7241
- y_prec = y->MaxPrec;
7242
-
7243
- VpVtoD(&val, &e, x); /* val <- x */
7244
- e /= (SIGNED_VALUE)BASE_FIG;
7245
- n = e / 2;
7246
- if (e - n * 2 != 0) {
7247
- val /= BASE;
7248
- n = (e + 1) / 2;
7249
- }
7250
- VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
7251
- y->exponent += n;
7252
- n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
7253
- y->MaxPrec = Min((size_t)n , y_prec);
7254
- f->MaxPrec = y->MaxPrec + 1;
7255
- n = (SIGNED_VALUE)(y_prec * BASE_FIG);
7256
- if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7257
-
7258
- /*
7259
- * Perform: y_{n+1} = (y_n - x/y_n) / 2
7260
- */
7261
- do {
7262
- y->MaxPrec *= 2;
7263
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7264
- f->MaxPrec = y->MaxPrec;
7265
- VpDivd(f, r, x, y); /* f = x/y */
7266
- VpAddSub(r, f, y, -1); /* r = f - y */
7267
- VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7268
- if (VpIsZero(f))
7269
- goto converge;
7270
- VpAddSub(r, f, y, 1); /* r = y + f */
7271
- VpAsgn(y, r, 1); /* y = r */
7272
- } while (++nr < n);
7273
-
7274
- #ifdef BIGDECIMAL_DEBUG
7275
- if (gfDebug) {
7276
- printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
7277
- }
7278
- #endif /* BIGDECIMAL_DEBUG */
7279
- y->MaxPrec = y_prec;
7280
-
7281
- converge:
7282
- VpChangeSign(y, 1);
7283
- #ifdef BIGDECIMAL_DEBUG
7284
- if (gfDebug) {
7285
- VpMult(r, y, y);
7286
- VpAddSub(f, x, r, -1);
7287
- printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
7288
- VPrint(stdout, " y =% \n", y);
7289
- VPrint(stdout, " x =% \n", x);
7290
- VPrint(stdout, " x-y*y = % \n", f);
7291
- }
7292
- #endif /* BIGDECIMAL_DEBUG */
7293
- y->MaxPrec = y_prec;
7294
-
7295
- Exit:
7296
- rbd_free_struct(f);
7297
- rbd_free_struct(r);
7298
- return 1;
7299
- }
7300
-
7301
5885
  /*
7302
5886
  * Round relatively from the decimal point.
7303
5887
  * f: rounding mode
@@ -7474,7 +6058,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7474
6058
  DECDIG v;
7475
6059
  if (!VpHasVal(y)) return 0; /* Unable to round */
7476
6060
  v = y->frac[0];
7477
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6061
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7478
6062
  while ((v /= 10) != 0) nf--;
7479
6063
  nf += (ssize_t)BASE_FIG-1;
7480
6064
  return VpMidRound(y, f, nf);
@@ -7611,117 +6195,9 @@ VpFrac(Real *y, Real *x)
7611
6195
  VpNmlz(y);
7612
6196
 
7613
6197
  Exit:
7614
- #ifdef BIGDECIMAL_DEBUG
7615
- if (gfDebug) {
7616
- VPrint(stdout, "VpFrac y=%\n", y);
7617
- VPrint(stdout, " x=%\n", x);
7618
- }
7619
- #endif /* BIGDECIMAL_DEBUG */
7620
6198
  return;
7621
6199
  }
7622
6200
 
7623
- /*
7624
- * y = x ** n
7625
- */
7626
- VP_EXPORT int
7627
- VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7628
- {
7629
- size_t s, ss;
7630
- ssize_t sign;
7631
- Real *w1 = NULL;
7632
- Real *w2 = NULL;
7633
-
7634
- if (VpIsZero(x)) {
7635
- if (n == 0) {
7636
- VpSetOne(y);
7637
- goto Exit;
7638
- }
7639
- sign = VpGetSign(x);
7640
- if (n < 0) {
7641
- n = -n;
7642
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7643
- VpSetInf(y, sign);
7644
- }
7645
- else {
7646
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7647
- VpSetZero(y,sign);
7648
- }
7649
- goto Exit;
7650
- }
7651
- if (VpIsNaN(x)) {
7652
- VpSetNaN(y);
7653
- goto Exit;
7654
- }
7655
- if (VpIsInf(x)) {
7656
- if (n == 0) {
7657
- VpSetOne(y);
7658
- goto Exit;
7659
- }
7660
- if (n > 0) {
7661
- VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7662
- goto Exit;
7663
- }
7664
- VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7665
- goto Exit;
7666
- }
7667
-
7668
- if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
7669
- /* abs(x) = 1 */
7670
- VpSetOne(y);
7671
- if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
7672
- if ((n % 2) == 0) goto Exit;
7673
- VpSetSign(y, -1);
7674
- goto Exit;
7675
- }
7676
-
7677
- if (n > 0) sign = 1;
7678
- else if (n < 0) {
7679
- sign = -1;
7680
- n = -n;
7681
- }
7682
- else {
7683
- VpSetOne(y);
7684
- goto Exit;
7685
- }
7686
-
7687
- /* Allocate working variables */
7688
- /* TODO: reconsider MaxPrec of w1 and w2 */
7689
- w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7690
- w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7691
-
7692
- /* calculation start */
7693
-
7694
- VpAsgn(y, x, 1);
7695
- --n;
7696
- while (n > 0) {
7697
- VpAsgn(w1, x, 1);
7698
- s = 1;
7699
- while (ss = s, (s += s) <= (size_t)n) {
7700
- VpMult(w2, w1, w1);
7701
- VpAsgn(w1, w2, 1);
7702
- }
7703
- n -= (SIGNED_VALUE)ss;
7704
- VpMult(w2, y, w1);
7705
- VpAsgn(y, w2, 1);
7706
- }
7707
- if (sign < 0) {
7708
- VpDivd(w1, w2, VpConstOne, y);
7709
- VpAsgn(y, w1, 1);
7710
- }
7711
-
7712
- Exit:
7713
- #ifdef BIGDECIMAL_DEBUG
7714
- if (gfDebug) {
7715
- VPrint(stdout, "VpPowerByInt y=%\n", y);
7716
- VPrint(stdout, "VpPowerByInt x=%\n", x);
7717
- printf(" n=%"PRIdVALUE"\n", n);
7718
- }
7719
- #endif /* BIGDECIMAL_DEBUG */
7720
- rbd_free_struct(w2);
7721
- rbd_free_struct(w1);
7722
- return 1;
7723
- }
7724
-
7725
6201
  #ifdef BIGDECIMAL_DEBUG
7726
6202
  int
7727
6203
  VpVarCheck(Real * v)