bigdecimal 3.2.2 → 4.0.1

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 "4.0.1"
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,37 +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());
483
- }
484
-
485
- /* call-seq:
486
- * precs -> array
487
- *
488
- * Returns an Array of two Integer values that represent platform-dependent
489
- * internal storage properties.
490
- *
491
- * This method is deprecated and will be removed in the future.
492
- * Instead, use BigDecimal#n_significant_digits for obtaining the number of
493
- * significant digits in scientific notation, and BigDecimal#precision for
494
- * obtaining the number of digits in decimal notation.
495
- *
496
- */
497
-
498
- static VALUE
499
- BigDecimal_prec(VALUE self)
500
- {
501
- ENTER(1);
502
- Real *p;
503
- VALUE obj;
504
-
505
- rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
506
- "BigDecimal#precs is deprecated and will be removed in the future; "
507
- "use BigDecimal#precision instead.");
508
-
509
- GUARD_OBJ(p, GetVpValue(self, 1));
510
- obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
511
- SIZET2NUM(p->MaxPrec*VpBaseFig()));
512
- return obj;
400
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
513
401
  }
514
402
 
515
403
  static void
@@ -623,10 +511,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
623
511
  static void
624
512
  BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
625
513
  {
626
- ENTER(1);
627
- Real *p;
628
- GUARD_OBJ(p, GetVpValue(self, 1));
629
- VpCountPrecisionAndScale(p, out_precision, out_scale);
514
+ BDVALUE v = GetBDValueMust(self);
515
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
516
+ RB_GC_GUARD(v.bigdecimal);
630
517
  }
631
518
 
632
519
  /*
@@ -664,8 +551,8 @@ BigDecimal_precision(VALUE self)
664
551
  * BigDecimal("1").scale # => 0
665
552
  * BigDecimal("1.1").scale # => 1
666
553
  * BigDecimal("3.1415").scale # => 4
667
- * BigDecimal("-1e20").precision # => 0
668
- * BigDecimal("1e-20").precision # => 20
554
+ * BigDecimal("-1e20").scale # => 0
555
+ * BigDecimal("1e-20").scale # => 20
669
556
  * BigDecimal("Infinity").scale # => 0
670
557
  * BigDecimal("-Infinity").scale # => 0
671
558
  * BigDecimal("NaN").scale # => 0
@@ -715,25 +602,23 @@ BigDecimal_precision_scale(VALUE self)
715
602
  static VALUE
716
603
  BigDecimal_n_significant_digits(VALUE self)
717
604
  {
718
- ENTER(1);
719
-
720
- Real *p;
721
- GUARD_OBJ(p, GetVpValue(self, 1));
722
- if (VpIsZero(p) || !VpIsDef(p)) {
605
+ BDVALUE v = GetBDValueMust(self);
606
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
723
607
  return INT2FIX(0);
724
608
  }
725
609
 
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);
610
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
611
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
728
612
  if (n == 0) return INT2FIX(0);
729
613
 
730
614
  DECDIG x;
731
615
  int nlz = BASE_FIG;
732
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
616
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
733
617
 
734
618
  int ntz = 0;
735
- for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
619
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
736
620
 
621
+ RB_GC_GUARD(v.bigdecimal);
737
622
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
738
623
  return SSIZET2NUM(n_significant_digits);
739
624
  }
@@ -755,17 +640,14 @@ BigDecimal_n_significant_digits(VALUE self)
755
640
  static VALUE
756
641
  BigDecimal_hash(VALUE self)
757
642
  {
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;
643
+ BDVALUE v = GetBDValueMust(self);
644
+ st_index_t hash = (st_index_t)v.real->sign;
764
645
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
765
646
  if(hash == 2 || hash == (st_index_t)-2) {
766
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
767
- hash += p->exponent;
647
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
648
+ hash += v.real->exponent;
768
649
  }
650
+ RB_GC_GUARD(v.bigdecimal);
769
651
  return ST2FIX(hash);
770
652
  }
771
653
 
@@ -784,21 +666,22 @@ BigDecimal_hash(VALUE self)
784
666
  static VALUE
785
667
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
786
668
  {
787
- ENTER(5);
788
- Real *vp;
669
+ BDVALUE v;
789
670
  char *psz;
790
671
  VALUE dummy;
791
672
  volatile VALUE dump;
792
673
  size_t len;
793
674
 
794
675
  rb_scan_args(argc, argv, "01", &dummy);
795
- GUARD_OBJ(vp,GetVpValue(self, 1));
796
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
676
+ v = GetBDValueMust(self);
677
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
797
678
  psz = RSTRING_PTR(dump);
798
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
679
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
799
680
  len = strlen(psz);
800
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
681
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
801
682
  rb_str_resize(dump, strlen(psz));
683
+
684
+ RB_GC_GUARD(v.bigdecimal);
802
685
  return dump;
803
686
  }
804
687
 
@@ -808,27 +691,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
808
691
  static VALUE
809
692
  BigDecimal_load(VALUE self, VALUE str)
810
693
  {
811
- ENTER(2);
812
- Real *pv;
694
+ BDVALUE v;
813
695
  unsigned char *pch;
814
696
  unsigned char ch;
815
- unsigned long m=0;
816
697
 
817
698
  pch = (unsigned char *)StringValueCStr(str);
818
- /* First get max prec */
699
+ /* First skip max prec. Don't trust the value. */
819
700
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
820
701
  if(!ISDIGIT(ch)) {
821
702
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
822
703
  }
823
- m = m*10 + (unsigned long)(ch-'0');
824
704
  }
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);
705
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
706
+ return CheckGetValue(v);
832
707
  }
833
708
 
834
709
  static unsigned short
@@ -1121,22 +996,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1121
996
  static size_t
1122
997
  GetAddSubPrec(Real *a, Real *b)
1123
998
  {
1124
- size_t mxs;
1125
- size_t mx = a->Prec;
1126
- SIGNED_VALUE d;
1127
-
1128
999
  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;
1000
+ ssize_t min_a = a->exponent - a->Prec;
1001
+ ssize_t min_b = b->exponent - b->Prec;
1002
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
1140
1003
  }
1141
1004
 
1142
1005
  static inline SIGNED_VALUE
@@ -1156,39 +1019,13 @@ check_int_precision(VALUE v)
1156
1019
  return n;
1157
1020
  }
1158
1021
 
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)
1022
+ static NULLABLE_BDVALUE
1023
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1190
1024
  {
1191
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
1025
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
1026
+ Real *pv = VpAlloc(str, strict_p, raise_exception);
1027
+ if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
1028
+ return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
1192
1029
  }
1193
1030
 
1194
1031
  static Real *
@@ -1196,7 +1033,7 @@ VpCopy(Real *pv, Real const* const x)
1196
1033
  {
1197
1034
  assert(x != NULL);
1198
1035
 
1199
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1036
+ pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
1200
1037
  pv->MaxPrec = x->MaxPrec;
1201
1038
  pv->Prec = x->Prec;
1202
1039
  pv->exponent = x->exponent;
@@ -1211,7 +1048,7 @@ VpCopy(Real *pv, Real const* const x)
1211
1048
  static VALUE
1212
1049
  BigDecimal_IsNaN(VALUE self)
1213
1050
  {
1214
- Real *p = GetVpValue(self, 1);
1051
+ Real *p = GetSelfVpValue(self);
1215
1052
  if (VpIsNaN(p)) return Qtrue;
1216
1053
  return Qfalse;
1217
1054
  }
@@ -1222,7 +1059,7 @@ BigDecimal_IsNaN(VALUE self)
1222
1059
  static VALUE
1223
1060
  BigDecimal_IsInfinite(VALUE self)
1224
1061
  {
1225
- Real *p = GetVpValue(self, 1);
1062
+ Real *p = GetSelfVpValue(self);
1226
1063
  if (VpIsPosInf(p)) return INT2FIX(1);
1227
1064
  if (VpIsNegInf(p)) return INT2FIX(-1);
1228
1065
  return Qnil;
@@ -1232,7 +1069,7 @@ BigDecimal_IsInfinite(VALUE self)
1232
1069
  static VALUE
1233
1070
  BigDecimal_IsFinite(VALUE self)
1234
1071
  {
1235
- Real *p = GetVpValue(self, 1);
1072
+ Real *p = GetSelfVpValue(self);
1236
1073
  if (VpIsNaN(p)) return Qfalse;
1237
1074
  if (VpIsInf(p)) return Qfalse;
1238
1075
  return Qtrue;
@@ -1244,6 +1081,7 @@ BigDecimal_check_num(Real *p)
1244
1081
  VpCheckException(p, true);
1245
1082
  }
1246
1083
 
1084
+ static VALUE BigDecimal_fix(VALUE self);
1247
1085
  static VALUE BigDecimal_split(VALUE self);
1248
1086
 
1249
1087
  /* Returns the value as an Integer.
@@ -1253,44 +1091,36 @@ static VALUE BigDecimal_split(VALUE self);
1253
1091
  static VALUE
1254
1092
  BigDecimal_to_i(VALUE self)
1255
1093
  {
1256
- ENTER(5);
1257
- ssize_t e, nf;
1258
- Real *p;
1094
+ BDVALUE v;
1095
+ VALUE ret;
1259
1096
 
1260
- GUARD_OBJ(p, GetVpValue(self, 1));
1261
- BigDecimal_check_num(p);
1097
+ v = GetBDValueMust(self);
1098
+ BigDecimal_check_num(v.real);
1262
1099
 
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]));
1100
+ if (v.real->exponent <= 0) return INT2FIX(0);
1101
+ if (v.real->exponent == 1) {
1102
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
1268
1103
  }
1269
1104
  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;
1105
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
1106
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
1107
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
1108
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
1109
+
1110
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
1111
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
1112
+ }
1113
+ if (dpower) {
1114
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
1115
+ // In Ruby < 3.4, int**int may return Float::INFINITY
1116
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
1117
+
1118
+ ret = rb_funcall(ret, '*', 1, pow10);
1119
+ }
1293
1120
  }
1121
+
1122
+ RB_GC_GUARD(v.bigdecimal);
1123
+ return ret;
1294
1124
  }
1295
1125
 
1296
1126
  /* Returns a new Float object having approximately the same value as the
@@ -1300,24 +1130,26 @@ BigDecimal_to_i(VALUE self)
1300
1130
  static VALUE
1301
1131
  BigDecimal_to_f(VALUE self)
1302
1132
  {
1303
- ENTER(1);
1304
- Real *p;
1305
1133
  double d;
1306
1134
  SIGNED_VALUE e;
1307
1135
  char *buf;
1308
1136
  volatile VALUE str;
1137
+ BDVALUE v = GetBDValueMust(self);
1138
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1309
1139
 
1310
- GUARD_OBJ(p, GetVpValue(self, 1));
1311
- if (VpVtoD(&d, &e, p) != 1)
1140
+ if (VpVtoD(&d, &e, v.real) != 1)
1312
1141
  return rb_float_new(d);
1313
1142
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1314
1143
  goto overflow;
1315
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1144
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1316
1145
  goto underflow;
1317
1146
 
1318
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1147
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1319
1148
  buf = RSTRING_PTR(str);
1320
- VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1149
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
1150
+
1151
+ RB_GC_GUARD(v.bigdecimal);
1152
+
1321
1153
  errno = 0;
1322
1154
  d = strtod(buf, 0);
1323
1155
  if (errno == ERANGE) {
@@ -1328,14 +1160,14 @@ BigDecimal_to_f(VALUE self)
1328
1160
 
1329
1161
  overflow:
1330
1162
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1331
- if (BIGDECIMAL_NEGATIVE_P(p))
1163
+ if (negative)
1332
1164
  return rb_float_new(VpGetDoubleNegInf());
1333
1165
  else
1334
1166
  return rb_float_new(VpGetDoublePosInf());
1335
1167
 
1336
1168
  underflow:
1337
1169
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1338
- if (BIGDECIMAL_NEGATIVE_P(p))
1170
+ if (negative)
1339
1171
  return rb_float_new(-0.0);
1340
1172
  else
1341
1173
  return rb_float_new(0.0);
@@ -1347,15 +1179,16 @@ underflow:
1347
1179
  static VALUE
1348
1180
  BigDecimal_to_r(VALUE self)
1349
1181
  {
1350
- Real *p;
1182
+ BDVALUE v;
1351
1183
  ssize_t sign, power, denomi_power;
1352
1184
  VALUE a, digits, numerator;
1353
1185
 
1354
- p = GetVpValue(self, 1);
1355
- BigDecimal_check_num(p);
1186
+ v = GetBDValueMust(self);
1187
+ BigDecimal_check_num(v.real);
1188
+ sign = VpGetSign(v.real);
1189
+ power = VpExponent10(v.real);
1190
+ RB_GC_GUARD(v.bigdecimal);
1356
1191
 
1357
- sign = VpGetSign(p);
1358
- power = VpExponent10(p);
1359
1192
  a = BigDecimal_split(self);
1360
1193
  digits = RARRAY_AREF(a, 1);
1361
1194
  denomi_power = power - RSTRING_LEN(digits);
@@ -1376,6 +1209,14 @@ BigDecimal_to_r(VALUE self)
1376
1209
  }
1377
1210
  }
1378
1211
 
1212
+ static size_t
1213
+ GetCoercePrec(Real *a, size_t prec)
1214
+ {
1215
+ if (prec == 0) prec = a->Prec * BASE_FIG;
1216
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1217
+ return prec;
1218
+ }
1219
+
1379
1220
  /* The coerce method provides support for Ruby type coercion. It is not
1380
1221
  * enabled by default.
1381
1222
  *
@@ -1393,26 +1234,9 @@ BigDecimal_to_r(VALUE self)
1393
1234
  static VALUE
1394
1235
  BigDecimal_coerce(VALUE self, VALUE other)
1395
1236
  {
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;
1237
+ Real* pv = DATA_PTR(self);
1238
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1239
+ return rb_assoc_new(CheckGetValue(b), self);
1416
1240
  }
1417
1241
 
1418
1242
  /*
@@ -1432,6 +1256,15 @@ BigDecimal_uplus(VALUE self)
1432
1256
  return self;
1433
1257
  }
1434
1258
 
1259
+ static bool
1260
+ is_coerceable_to_BigDecimal(VALUE r)
1261
+ {
1262
+ return is_kind_of_BigDecimal(r) ||
1263
+ RB_INTEGER_TYPE_P(r) ||
1264
+ RB_TYPE_P(r, T_FLOAT) ||
1265
+ RB_TYPE_P(r, T_RATIONAL);
1266
+ }
1267
+
1435
1268
  /*
1436
1269
  * call-seq:
1437
1270
  * self + value -> bigdecimal
@@ -1451,42 +1284,40 @@ BigDecimal_uplus(VALUE self)
1451
1284
  static VALUE
1452
1285
  BigDecimal_add(VALUE self, VALUE r)
1453
1286
  {
1454
- ENTER(5);
1455
- Real *c, *a, *b;
1456
- size_t mx;
1287
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
1288
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
1289
+ }
1457
1290
 
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
- }
1291
+ static VALUE
1292
+ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1293
+ {
1294
+ BDVALUE a, b, c;
1295
+ size_t mx;
1468
1296
 
1469
- if (!b) return DoSomeOne(self,r,'+');
1470
- SAVE(b);
1297
+ a = GetBDValueMust(self);
1298
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1471
1299
 
1472
- if (VpIsNaN(b)) return b->obj;
1473
- if (VpIsNaN(a)) return a->obj;
1300
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1301
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1474
1302
 
1475
- mx = GetAddSubPrec(a, b);
1303
+ mx = GetAddSubPrec(a.real, b.real);
1476
1304
  if (mx == (size_t)-1L) {
1477
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1478
- VpAddSub(c, a, b, 1);
1305
+ /* a or b is inf */
1306
+ c = NewZeroWrap(1, BASE_FIG);
1307
+ VpAddSub(c.real, a.real, b.real, operation);
1479
1308
  }
1480
1309
  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
- }
1310
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1311
+ size_t pl = VpGetPrecLimit();
1312
+ if (prec) VpSetPrecLimit(prec);
1313
+ // Let VpAddSub round the result
1314
+ VpAddSub(c.real, a.real, b.real, operation);
1315
+ if (prec) VpSetPrecLimit(pl);
1488
1316
  }
1489
- return VpCheckGetValue(c);
1317
+
1318
+ RB_GC_GUARD(a.bigdecimal);
1319
+ RB_GC_GUARD(b.bigdecimal);
1320
+ return CheckGetValue(c);
1490
1321
  }
1491
1322
 
1492
1323
  /*
@@ -1507,73 +1338,18 @@ BigDecimal_add(VALUE self, VALUE r)
1507
1338
  static VALUE
1508
1339
  BigDecimal_sub(VALUE self, VALUE r)
1509
1340
  {
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);
1341
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1342
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1546
1343
  }
1547
1344
 
1548
1345
  static VALUE
1549
1346
  BigDecimalCmp(VALUE self, VALUE r,char op)
1550
1347
  {
1551
- ENTER(5);
1552
1348
  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;
1564
-
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;
1349
+ BDVALUE a = GetBDValueMust(self);
1350
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1572
1351
 
1573
- default:
1574
- break;
1575
- }
1576
- if (b == NULL) {
1352
+ if (b.real_or_null == NULL) {
1577
1353
  ID f = 0;
1578
1354
 
1579
1355
  switch (op) {
@@ -1602,8 +1378,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1602
1378
  }
1603
1379
  return rb_num_coerce_relop(self, r, f);
1604
1380
  }
1605
- SAVE(b);
1606
- e = VpComp(a, b);
1381
+ e = VpComp(a.real, b.real_or_null);
1382
+
1383
+ RB_GC_GUARD(a.bigdecimal);
1384
+ RB_GC_GUARD(b.bigdecimal_or_nil);
1385
+
1607
1386
  if (e == 999)
1608
1387
  return (op == '*') ? Qnil : Qfalse;
1609
1388
  switch (op) {
@@ -1643,7 +1422,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1643
1422
  static VALUE
1644
1423
  BigDecimal_zero(VALUE self)
1645
1424
  {
1646
- Real *a = GetVpValue(self, 1);
1425
+ Real *a = GetSelfVpValue(self);
1647
1426
  return VpIsZero(a) ? Qtrue : Qfalse;
1648
1427
  }
1649
1428
 
@@ -1651,7 +1430,7 @@ BigDecimal_zero(VALUE self)
1651
1430
  static VALUE
1652
1431
  BigDecimal_nonzero(VALUE self)
1653
1432
  {
1654
- Real *a = GetVpValue(self, 1);
1433
+ Real *a = GetSelfVpValue(self);
1655
1434
  return VpIsZero(a) ? Qnil : self;
1656
1435
  }
1657
1436
 
@@ -1777,12 +1556,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1777
1556
  static VALUE
1778
1557
  BigDecimal_neg(VALUE self)
1779
1558
  {
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);
1559
+ BDVALUE a = GetBDValueMust(self);
1560
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
1561
+ VpAsgn(c.real, a.real, -10);
1562
+ RB_GC_GUARD(a.bigdecimal);
1563
+ return CheckGetValue(c);
1786
1564
  }
1787
1565
 
1788
1566
  /*
@@ -1795,35 +1573,36 @@ BigDecimal_neg(VALUE self)
1795
1573
  *
1796
1574
  * See BigDecimal#mult.
1797
1575
  */
1798
-
1799
1576
  static VALUE
1800
1577
  BigDecimal_mult(VALUE self, VALUE r)
1801
1578
  {
1802
- ENTER(5);
1803
- Real *c, *a, *b;
1804
- size_t mx;
1579
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1580
+ return BigDecimal_mult_with_coerce(self, r, 0);
1581
+ }
1805
1582
 
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);
1583
+ static VALUE
1584
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1585
+ {
1586
+ BDVALUE a, b, c;
1587
+
1588
+ a = GetBDValueMust(self);
1589
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1590
+
1591
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
1592
+ VpMult(c.real, a.real, b.real);
1593
+ if (prec) {
1594
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
1812
1595
  }
1813
1596
  else {
1814
- b = GetVpValue(r,0);
1597
+ VpLimitRound(c.real, 0);
1815
1598
  }
1816
1599
 
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);
1600
+ RB_GC_GUARD(a.bigdecimal);
1601
+ RB_GC_GUARD(b.bigdecimal);
1602
+ return CheckGetValue(c);
1824
1603
  }
1825
1604
 
1826
- static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1605
+ static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
1827
1606
 
1828
1607
  /* call-seq:
1829
1608
  * a / b -> bigdecimal
@@ -1840,14 +1619,7 @@ static VALUE
1840
1619
  BigDecimal_div(VALUE self, VALUE r)
1841
1620
  /* For c = self/r: with round operation */
1842
1621
  {
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
- }
1622
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1851
1623
  return BigDecimal_div2(self, r, INT2FIX(0));
1852
1624
  }
1853
1625
 
@@ -1893,114 +1665,110 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1893
1665
  /*
1894
1666
  * %: mod = a%b = a - (a.to_f/b).floor * b
1895
1667
  * div = (a.to_f/b).floor
1668
+ * In truncate mode, use truncate instead of floor.
1896
1669
  */
1897
- static VALUE
1898
- BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1670
+ static bool
1671
+ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
1899
1672
  {
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;
1673
+ BDVALUE a, b, dv, md, res;
1674
+ NULLABLE_BDVALUE b2;
1675
+ ssize_t a_exponent, b_exponent;
1676
+ size_t mx, rx, pl;
1905
1677
 
1906
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1907
- SAVE(a);
1678
+ a = GetBDValueMust(self);
1908
1679
 
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
- }
1680
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1681
+ if (!b2.real_or_null) return false;
1682
+ b = bdvalue_nonnullable(b2);
1922
1683
 
1923
- if (!is_kind_of_BigDecimal(rr)) {
1924
- return Qfalse;
1684
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1685
+ VALUE nan = BigDecimal_nan();
1686
+ *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1687
+ goto Done;
1925
1688
  }
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)) {
1689
+ if (VpIsZero(b.real)) {
1933
1690
  rb_raise(rb_eZeroDivError, "divided by 0");
1934
1691
  }
1935
- if (VpIsInf(a)) {
1936
- if (VpGetSign(a) == VpGetSign(b)) {
1692
+ if (VpIsInf(a.real)) {
1693
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1937
1694
  VALUE inf = BigDecimal_positive_infinity();
1938
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1695
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1939
1696
  }
1940
1697
  else {
1941
1698
  VALUE inf = BigDecimal_negative_infinity();
1942
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1699
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1943
1700
  }
1944
1701
  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;
1702
+ *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1703
+ goto Done;
1953
1704
  }
1954
- if (VpIsZero(a)) {
1705
+ if (VpIsZero(a.real)) {
1955
1706
  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);
1707
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1708
+ *mod = bdvalue_nullable(a);
1709
+ goto Done;
1710
+ }
1711
+ if (VpIsInf(b.real)) {
1712
+ if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
1713
+ BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
1714
+ VpSetOne(minus_one.real);
1715
+ VpSetSign(minus_one.real, -1);
1716
+ RB_GC_GUARD(minus_one.bigdecimal);
1717
+ *div = bdvalue_nullable(minus_one);
1718
+ *mod = bdvalue_nullable(b);
1719
+ } else {
1720
+ VALUE zero = BigDecimal_positive_zero();
1721
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1722
+ *mod = bdvalue_nullable(a);
1723
+ }
1724
+ goto Done;
1725
+ }
1726
+
1727
+ a_exponent = VpExponent10(a.real);
1728
+ b_exponent = VpExponent10(b.real);
1729
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
1730
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
1731
+
1732
+ /* res is reused for VpDivd remainder and VpMult result */
1733
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
1734
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
1735
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
1736
+ /* AddSub needs one more prec */
1737
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
1738
+
1739
+ VpDivd(dv.real, res.real, a.real, b.real);
1740
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
1741
+ VpMult(res.real, dv.real, b.real);
1742
+ pl = VpGetPrecLimit();
1743
+ VpSetPrecLimit(0);
1744
+ VpAddSub(md.real, a.real, res.real, -1);
1745
+ VpSetPrecLimit(pl);
1980
1746
 
1981
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1747
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
1982
1748
  /* 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;
1749
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
1750
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
1751
+ VpSetPrecLimit(0);
1752
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
1753
+ VpAddSub(md2.real, md.real, b.real, 1);
1754
+ VpSetPrecLimit(pl);
1755
+ *div = bdvalue_nullable(dv2);
1756
+ *mod = bdvalue_nullable(md2);
1757
+ RB_GC_GUARD(dv2.bigdecimal);
1758
+ RB_GC_GUARD(md2.bigdecimal);
1990
1759
  }
1991
1760
  else {
1992
- *div = d;
1993
- *mod = c;
1761
+ *div = bdvalue_nullable(dv);
1762
+ *mod = bdvalue_nullable(md);
1994
1763
  }
1995
- return Qtrue;
1996
1764
 
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;
1765
+ Done:
1766
+ RB_GC_GUARD(a.bigdecimal);
1767
+ RB_GC_GUARD(b.bigdecimal);
1768
+ RB_GC_GUARD(dv.bigdecimal);
1769
+ RB_GC_GUARD(md.bigdecimal);
1770
+ RB_GC_GUARD(res.bigdecimal);
1771
+ return true;
2004
1772
  }
2005
1773
 
2006
1774
  /* call-seq:
@@ -2014,69 +1782,14 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2014
1782
  static VALUE
2015
1783
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2016
1784
  {
2017
- ENTER(3);
2018
- Real *div = NULL, *mod = NULL;
1785
+ NULLABLE_BDVALUE div, mod;
2019
1786
 
2020
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2021
- SAVE(div); SAVE(mod);
2022
- return VpCheckGetValue(mod);
1787
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1788
+ return CheckGetValue(bdvalue_nonnullable(mod));
2023
1789
  }
2024
1790
  return DoSomeOne(self, r, '%');
2025
1791
  }
2026
1792
 
2027
- static VALUE
2028
- BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2029
- {
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;
2034
-
2035
- GUARD_OBJ(a, GetVpValue(self, 1));
2036
- if (RB_TYPE_P(r, T_FLOAT)) {
2037
- b = GetVpValueWithPrec(r, 0, 1);
2038
- }
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
1793
  /* call-seq:
2081
1794
  * remainder(value)
2082
1795
  *
@@ -2087,11 +1800,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2087
1800
  static VALUE
2088
1801
  BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2089
1802
  {
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);
1803
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
1804
+
1805
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
1806
+ return CheckGetValue(bdvalue_nonnullable(mod));
1807
+ }
1808
+ return DoSomeOne(self, r, rb_intern("remainder"));
2095
1809
  }
2096
1810
 
2097
1811
  /* call-seq:
@@ -2119,12 +1833,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2119
1833
  static VALUE
2120
1834
  BigDecimal_divmod(VALUE self, VALUE r)
2121
1835
  {
2122
- ENTER(5);
2123
- Real *div = NULL, *mod = NULL;
1836
+ NULLABLE_BDVALUE div, mod;
2124
1837
 
2125
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2126
- SAVE(div); SAVE(mod);
2127
- return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
1838
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1839
+ return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
2128
1840
  }
2129
1841
  return DoSomeOne(self,r,rb_intern("divmod"));
2130
1842
  }
@@ -2136,17 +1848,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
2136
1848
  static inline VALUE
2137
1849
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2138
1850
  {
2139
- ENTER(5);
2140
1851
  SIGNED_VALUE ix;
2141
- Real *res = NULL;
2142
- Real *av = NULL, *bv = NULL, *cv = NULL;
2143
- size_t mx, pl;
1852
+ BDVALUE av, bv, cv, res;
2144
1853
 
2145
1854
  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));
1855
+ NULLABLE_BDVALUE div;
1856
+ NULLABLE_BDVALUE mod;
1857
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
1858
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
2150
1859
  }
2151
1860
  return DoSomeOne(self, b, rb_intern("div"));
2152
1861
  }
@@ -2154,48 +1863,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2154
1863
  /* div in BigDecimal sense */
2155
1864
  ix = check_int_precision(n);
2156
1865
 
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
- }
1866
+ av = GetBDValueMust(self);
1867
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
2170
1868
 
2171
1869
  if (ix == 0) {
2172
- ssize_t a_prec, b_prec;
2173
- VpCountPrecisionAndScale(av, &a_prec, NULL);
2174
- VpCountPrecisionAndScale(bv, &b_prec, NULL);
1870
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1871
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1872
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
2175
1873
  ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
2176
1874
  if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
2177
1875
  ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1876
+ if (limit && limit < ix) ix = limit;
2178
1877
  }
2179
1878
 
2180
- // VpDivd needs 2 extra DECDIGs. One more is needed for rounding.
2181
- GUARD_OBJ(cv, NewZeroWrapLimited(1, ix + 3 * VpBaseFig()));
1879
+ // Needs to calculate 1 extra digit for rounding.
1880
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
1881
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
1882
+ VpDivd(cv.real, res.real, av.real, bv.real);
2182
1883
 
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)) {
1884
+ if (!VpIsZero(res.real)) {
2189
1885
  // Remainder value affects rounding result.
2190
- // ROUND_UP cv = 0.1e0 with ix=10 will be:
1886
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
2191
1887
  // 0.1e0 if remainder == 0
2192
1888
  // 0.1000000001e0 if remainder != 0
2193
1889
  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]++;
1890
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
1891
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
2196
1892
  }
2197
- VpLeftRound(cv, VpGetRoundMode(), ix);
2198
- return VpCheckGetValue(cv);
1893
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
1894
+
1895
+ RB_GC_GUARD(av.bigdecimal);
1896
+ RB_GC_GUARD(bv.bigdecimal);
1897
+ RB_GC_GUARD(res.bigdecimal);
1898
+ return CheckGetValue(cv);
2199
1899
  }
2200
1900
 
2201
1901
  /*
@@ -2271,18 +1971,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2271
1971
  static VALUE
2272
1972
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2273
1973
  {
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
- }
1974
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2286
1975
  }
2287
1976
 
2288
1977
  /* call-seq:
@@ -2301,18 +1990,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2301
1990
  static VALUE
2302
1991
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2303
1992
  {
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
- }
1993
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2316
1994
  }
2317
1995
 
2318
1996
  /*
@@ -2344,18 +2022,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2344
2022
  static VALUE
2345
2023
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2346
2024
  {
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
- }
2025
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2359
2026
  }
2360
2027
 
2361
2028
  /*
@@ -2372,41 +2039,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2372
2039
  static VALUE
2373
2040
  BigDecimal_abs(VALUE self)
2374
2041
  {
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);
2042
+ BDVALUE a = GetBDValueMust(self);
2043
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
2044
+ VpAsgn(c.real, a.real, 10);
2045
+ VpChangeSign(c.real, 1);
2046
+ RB_GC_GUARD(a.bigdecimal);
2047
+ return CheckGetValue(c);
2410
2048
  }
2411
2049
 
2412
2050
  /* Return the integer part of the number, as a BigDecimal.
@@ -2414,15 +2052,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2414
2052
  static VALUE
2415
2053
  BigDecimal_fix(VALUE self)
2416
2054
  {
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);
2055
+ BDVALUE a = GetBDValueMust(self);
2056
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2057
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
2058
+ RB_GC_GUARD(a.bigdecimal);
2059
+ return CheckGetValue(c);
2426
2060
  }
2427
2061
 
2428
2062
  /* call-seq:
@@ -2454,13 +2088,12 @@ BigDecimal_fix(VALUE self)
2454
2088
  static VALUE
2455
2089
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2456
2090
  {
2457
- ENTER(5);
2458
- Real *c, *a;
2091
+ BDVALUE c, a;
2459
2092
  int iLoc = 0;
2460
2093
  VALUE vLoc;
2461
2094
  VALUE vRound;
2462
2095
  int round_to_int = 0;
2463
- size_t mx, pl;
2096
+ size_t mx;
2464
2097
 
2465
2098
  unsigned short sw = VpGetRoundMode();
2466
2099
 
@@ -2491,16 +2124,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2491
2124
  break;
2492
2125
  }
2493
2126
 
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);
2127
+ a = GetBDValueMust(self);
2128
+ mx = (a.real->Prec + 1) * BASE_FIG;
2129
+ c = NewZeroWrap(1, mx);
2130
+
2131
+ VpActiveRound(c.real, a.real, sw, iLoc);
2132
+
2133
+ RB_GC_GUARD(a.bigdecimal);
2134
+
2500
2135
  if (round_to_int) {
2501
- return BigDecimal_to_i(VpCheckGetValue(c));
2136
+ return BigDecimal_to_i(CheckGetValue(c));
2502
2137
  }
2503
- return VpCheckGetValue(c);
2138
+ return CheckGetValue(c);
2139
+ }
2140
+
2141
+ static VALUE
2142
+ BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
2143
+ {
2144
+ BDVALUE c, a;
2145
+ int iLoc;
2146
+ VALUE vLoc;
2147
+ size_t mx;
2148
+
2149
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2150
+ iLoc = 0;
2151
+ }
2152
+ else {
2153
+ iLoc = NUM2INT(vLoc);
2154
+ }
2155
+
2156
+ a = GetBDValueMust(self);
2157
+ mx = (a.real->Prec + 1) * BASE_FIG;
2158
+ c = NewZeroWrap(1, mx);
2159
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
2160
+
2161
+ RB_GC_GUARD(a.bigdecimal);
2162
+
2163
+ if (argc == 0) {
2164
+ return BigDecimal_to_i(CheckGetValue(c));
2165
+ }
2166
+ return CheckGetValue(c);
2504
2167
  }
2505
2168
 
2506
2169
  /* call-seq:
@@ -2525,28 +2188,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2525
2188
  static VALUE
2526
2189
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2527
2190
  {
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);
2191
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2550
2192
  }
2551
2193
 
2552
2194
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2554,15 +2196,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2554
2196
  static VALUE
2555
2197
  BigDecimal_frac(VALUE self)
2556
2198
  {
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);
2199
+ BDVALUE a = GetBDValueMust(self);
2200
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2201
+ VpFrac(c.real, a.real);
2202
+ RB_GC_GUARD(a.bigdecimal);
2203
+ return CheckGetValue(c);
2566
2204
  }
2567
2205
 
2568
2206
  /* call-seq:
@@ -2585,31 +2223,7 @@ BigDecimal_frac(VALUE self)
2585
2223
  static VALUE
2586
2224
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2587
2225
  {
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);
2226
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2613
2227
  }
2614
2228
 
2615
2229
  /* call-seq:
@@ -2632,27 +2246,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2632
2246
  static VALUE
2633
2247
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2634
2248
  {
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);
2249
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2656
2250
  }
2657
2251
 
2658
2252
  /* call-seq:
@@ -2673,7 +2267,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2673
2267
  * If s contains a number, a space is inserted after each group of that many
2674
2268
  * digits, starting from '.' and counting outwards.
2675
2269
  *
2676
- * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2270
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
2677
2271
  *
2678
2272
  * If s ends with an 'F', conventional floating point notation is used.
2679
2273
  *
@@ -2691,10 +2285,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2691
2285
  static VALUE
2692
2286
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2693
2287
  {
2694
- ENTER(5);
2695
2288
  int fmt = 0; /* 0: E format, 1: F format */
2696
2289
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2697
- Real *vp;
2290
+ BDVALUE v;
2698
2291
  volatile VALUE str;
2699
2292
  char *psz;
2700
2293
  char ch;
@@ -2702,7 +2295,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2702
2295
  SIGNED_VALUE m;
2703
2296
  VALUE f;
2704
2297
 
2705
- GUARD_OBJ(vp, GetVpValue(self, 1));
2298
+ v = GetBDValueMust(self);
2706
2299
 
2707
2300
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2708
2301
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2737,10 +2330,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2737
2330
  }
2738
2331
  }
2739
2332
  if (fmt) {
2740
- nc = VpNumOfChars(vp, "F");
2333
+ nc = VpNumOfChars(v.real, "F");
2741
2334
  }
2742
2335
  else {
2743
- nc = VpNumOfChars(vp, "E");
2336
+ nc = VpNumOfChars(v.real, "E");
2744
2337
  }
2745
2338
  if (mc > 0) {
2746
2339
  nc += (nc + mc - 1) / mc + 1;
@@ -2750,12 +2343,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2750
2343
  psz = RSTRING_PTR(str);
2751
2344
 
2752
2345
  if (fmt) {
2753
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2346
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
2754
2347
  }
2755
2348
  else {
2756
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2349
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
2757
2350
  }
2758
2351
  rb_str_resize(str, strlen(psz));
2352
+
2353
+ RB_GC_GUARD(v.bigdecimal);
2759
2354
  return str;
2760
2355
  }
2761
2356
 
@@ -2786,16 +2381,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2786
2381
  static VALUE
2787
2382
  BigDecimal_split(VALUE self)
2788
2383
  {
2789
- ENTER(5);
2790
- Real *vp;
2384
+ BDVALUE v;
2791
2385
  VALUE obj,str;
2792
2386
  ssize_t e, s;
2793
2387
  char *psz1;
2794
2388
 
2795
- GUARD_OBJ(vp, GetVpValue(self, 1));
2796
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2389
+ v = GetBDValueMust(self);
2390
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
2797
2391
  psz1 = RSTRING_PTR(str);
2798
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2392
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
2799
2393
  s = 1;
2800
2394
  if(psz1[0] == '-') {
2801
2395
  size_t len = strlen(psz1 + 1);
@@ -2805,13 +2399,15 @@ BigDecimal_split(VALUE self)
2805
2399
  s = -1;
2806
2400
  }
2807
2401
  if (psz1[0] == 'N') s = 0; /* NaN */
2808
- e = VpExponent10(vp);
2402
+ e = VpExponent10(v.real);
2809
2403
  obj = rb_ary_new2(4);
2810
2404
  rb_ary_push(obj, INT2FIX(s));
2811
2405
  rb_ary_push(obj, str);
2812
2406
  rb_str_resize(str, strlen(psz1));
2813
2407
  rb_ary_push(obj, INT2FIX(10));
2814
2408
  rb_ary_push(obj, SSIZET2NUM(e));
2409
+
2410
+ RB_GC_GUARD(v.bigdecimal);
2815
2411
  return obj;
2816
2412
  }
2817
2413
 
@@ -2823,7 +2419,7 @@ BigDecimal_split(VALUE self)
2823
2419
  static VALUE
2824
2420
  BigDecimal_exponent(VALUE self)
2825
2421
  {
2826
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2422
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
2827
2423
  return SSIZET2NUM(e);
2828
2424
  }
2829
2425
 
@@ -2835,49 +2431,78 @@ BigDecimal_exponent(VALUE self)
2835
2431
  static VALUE
2836
2432
  BigDecimal_inspect(VALUE self)
2837
2433
  {
2838
- ENTER(5);
2839
- Real *vp;
2434
+ BDVALUE v;
2840
2435
  volatile VALUE str;
2841
2436
  size_t nc;
2842
2437
 
2843
- GUARD_OBJ(vp, GetVpValue(self, 1));
2844
- nc = VpNumOfChars(vp, "E");
2438
+ v = GetBDValueMust(self);
2439
+ nc = VpNumOfChars(v.real, "E");
2845
2440
 
2846
2441
  str = rb_str_new(0, nc);
2847
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2442
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2848
2443
  rb_str_resize(str, strlen(RSTRING_PTR(str)));
2849
- return str;
2850
- }
2851
-
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
2444
 
2858
- inline static int
2859
- is_integer(VALUE x)
2860
- {
2861
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2445
+ RB_GC_GUARD(v.bigdecimal);
2446
+ return str;
2862
2447
  }
2863
2448
 
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;
2449
+ /* Returns self * 10**v without changing the precision.
2450
+ * This method is currently for internal use.
2451
+ *
2452
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2453
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2454
+ */
2455
+ static VALUE
2456
+ BigDecimal_decimal_shift(VALUE self, VALUE v)
2457
+ {
2458
+ BDVALUE a, c;
2459
+ ssize_t shift, exponentShift;
2460
+ bool shiftDown;
2461
+ size_t prec;
2462
+ DECDIG ex, iex;
2463
+
2464
+ a = GetBDValueMust(self);
2465
+ shift = NUM2SSIZET(rb_to_int(v));
2466
+
2467
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
2468
+
2469
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
2470
+ shift -= exponentShift * BASE_FIG;
2471
+ ex = 1;
2472
+ for (int i = 0; i < shift; i++) ex *= 10;
2473
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
2474
+ iex = BASE / ex;
2475
+
2476
+ prec = a.real->Prec + shiftDown;
2477
+ c = NewZeroWrap(1, prec * BASE_FIG);
2478
+ if (shift == 0) {
2479
+ VpAsgn(c.real, a.real, 10);
2480
+ } else if (shiftDown) {
2481
+ DECDIG carry = 0;
2482
+ exponentShift++;
2483
+ for (size_t i = 0; i < a.real->Prec; i++) {
2484
+ DECDIG v = a.real->frac[i];
2485
+ c.real->frac[i] = carry * ex + v / iex;
2486
+ carry = v % iex;
2487
+ }
2488
+ c.real->frac[a.real->Prec] = carry * ex;
2489
+ } else {
2490
+ DECDIG carry = 0;
2491
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
2492
+ DECDIG v = a.real->frac[i];
2493
+ c.real->frac[i] = v % iex * ex + carry;
2494
+ carry = v / iex;
2495
+ }
2875
2496
  }
2876
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2497
+ while (c.real->frac[prec - 1] == 0) prec--;
2498
+ c.real->Prec = prec;
2499
+ c.real->sign = a.real->sign;
2500
+ c.real->exponent = a.real->exponent;
2501
+ AddExponent(c.real, exponentShift);
2502
+ RB_GC_GUARD(a.bigdecimal);
2503
+ return CheckGetValue(c);
2877
2504
  }
2878
2505
 
2879
- #define is_positive(x) (!is_negative(x))
2880
-
2881
2506
  inline static int
2882
2507
  is_zero(VALUE x)
2883
2508
  {
@@ -2901,344 +2526,6 @@ is_zero(VALUE x)
2901
2526
  return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2902
2527
  }
2903
2528
 
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
2529
  /* :nodoc: */
3243
2530
  static VALUE
3244
2531
  BigDecimal_clone(VALUE self)
@@ -3277,20 +2564,18 @@ check_exception(VALUE bd)
3277
2564
 
3278
2565
  Real *vp;
3279
2566
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3280
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2567
+ VpCheckException(vp, false);
3281
2568
 
3282
2569
  return bd;
3283
2570
  }
3284
2571
 
3285
2572
  static VALUE
3286
- rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
2573
+ rb_uint64_convert_to_BigDecimal(uint64_t uval)
3287
2574
  {
3288
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3289
-
2575
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3290
2576
  Real *vp;
3291
2577
  if (uval == 0) {
3292
2578
  vp = rbd_allocate_struct(1);
3293
- vp->MaxPrec = 1;
3294
2579
  vp->Prec = 1;
3295
2580
  vp->exponent = 1;
3296
2581
  VpSetZero(vp, 1);
@@ -3298,7 +2583,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3298
2583
  }
3299
2584
  else if (uval < BASE) {
3300
2585
  vp = rbd_allocate_struct(1);
3301
- vp->MaxPrec = 1;
3302
2586
  vp->Prec = 1;
3303
2587
  vp->exponent = 1;
3304
2588
  VpSetSign(vp, 1);
@@ -3324,21 +2608,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3324
2608
 
3325
2609
  const size_t exp = len + ntz;
3326
2610
  vp = rbd_allocate_struct(len);
3327
- vp->MaxPrec = len;
3328
2611
  vp->Prec = len;
3329
2612
  vp->exponent = exp;
3330
2613
  VpSetSign(vp, 1);
3331
2614
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3332
2615
  }
3333
2616
 
3334
- return BigDecimal_wrap_struct(obj, vp);
2617
+ return BigDecimal_wrap_struct(null_wrapped, vp);
3335
2618
  }
3336
2619
 
3337
2620
  static VALUE
3338
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2621
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3339
2622
  {
3340
2623
  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);
2624
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3342
2625
  if (ival < 0) {
3343
2626
  Real *vp;
3344
2627
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
@@ -3348,7 +2631,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
3348
2631
  }
3349
2632
 
3350
2633
  static VALUE
3351
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2634
+ rb_big_convert_to_BigDecimal(VALUE val)
3352
2635
  {
3353
2636
  assert(RB_TYPE_P(val, T_BIGNUM));
3354
2637
 
@@ -3360,40 +2643,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3360
2643
  }
3361
2644
  if (size <= sizeof(long)) {
3362
2645
  if (sign < 0) {
3363
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2646
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3364
2647
  }
3365
2648
  else {
3366
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2649
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3367
2650
  }
3368
2651
  }
3369
2652
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3370
2653
  else if (size <= sizeof(LONG_LONG)) {
3371
2654
  if (sign < 0) {
3372
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2655
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3373
2656
  }
3374
2657
  else {
3375
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2658
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3376
2659
  }
3377
2660
  }
3378
2661
  #endif
3379
2662
  else {
3380
2663
  VALUE str = rb_big2str(val, 10);
3381
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3382
- RSTRING_PTR(str), true);
2664
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2665
+ RSTRING_PTR(str),
2666
+ rb_cBigDecimal,
2667
+ true,
2668
+ true
2669
+ ));
3383
2670
  RB_GC_GUARD(str);
3384
- return check_exception(vp->obj);
2671
+ return CheckGetValue(v);
3385
2672
  }
3386
2673
  }
3387
2674
 
3388
2675
  static VALUE
3389
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2676
+ rb_inum_convert_to_BigDecimal(VALUE val)
3390
2677
  {
3391
2678
  assert(RB_INTEGER_TYPE_P(val));
3392
2679
  if (FIXNUM_P(val)) {
3393
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2680
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3394
2681
  }
3395
2682
  else {
3396
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2683
+ return rb_big_convert_to_BigDecimal(val);
3397
2684
  }
3398
2685
  }
3399
2686
 
@@ -3428,11 +2715,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3428
2715
  }
3429
2716
 
3430
2717
  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));
2718
+ digs = 0;
3436
2719
  }
3437
2720
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3438
2721
  if (!raise_exception)
@@ -3547,7 +2830,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3547
2830
  exp = -exp;
3548
2831
  }
3549
2832
 
3550
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
2833
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
3551
2834
  Real *vp;
3552
2835
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3553
2836
  assert(vp->Prec == prec);
@@ -3570,28 +2853,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3570
2853
  CLASS_OF(val));
3571
2854
  }
3572
2855
 
3573
- VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
2856
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
3574
2857
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3575
2858
  return d;
3576
2859
  }
3577
2860
 
3578
2861
  static VALUE
3579
- rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
2862
+ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
3580
2863
  {
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);
2864
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
2865
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
2866
+ return CheckGetValue(bdvalue_nonnullable(v));
3588
2867
  }
3589
2868
 
3590
2869
  static inline VALUE
3591
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2870
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3592
2871
  {
3593
2872
  const char *c_str = StringValueCStr(val);
3594
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2873
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3595
2874
  }
3596
2875
 
3597
2876
  static VALUE
@@ -3619,17 +2898,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3619
2898
  if (digs == SIZE_MAX)
3620
2899
  return check_exception(val);
3621
2900
 
2901
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3622
2902
  Real *vp;
3623
2903
  TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
3624
-
3625
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3626
2904
  vp = VpCopy(NULL, vp);
2905
+ RB_GC_GUARD(val);
2906
+
2907
+ VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
3627
2908
  /* TODO: rounding */
3628
- BigDecimal_wrap_struct(copy, vp);
3629
- return VpCheckGetValue(vp);
2909
+ return check_exception(copy);
3630
2910
  }
3631
2911
  else if (RB_INTEGER_TYPE_P(val)) {
3632
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2912
+ return rb_inum_convert_to_BigDecimal(val);
3633
2913
  }
3634
2914
  else if (RB_FLOAT_TYPE_P(val)) {
3635
2915
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3647,7 +2927,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3647
2927
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3648
2928
  }
3649
2929
  else if (RB_TYPE_P(val, T_STRING)) {
3650
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2930
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3651
2931
  }
3652
2932
 
3653
2933
  /* TODO: chheck to_d */
@@ -3661,7 +2941,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3661
2941
  }
3662
2942
  return Qnil;
3663
2943
  }
3664
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2944
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3665
2945
  }
3666
2946
 
3667
2947
  /* call-seq:
@@ -3682,12 +2962,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3682
2962
  *
3683
2963
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3684
2964
  *
3685
- * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
2965
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
3686
2966
  * BigDecimal(2) # => 0.2e1
3687
2967
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3688
2968
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3689
- * # Float or Rational value requires ndigits.
3690
- * BigDecimal(2.0, 0) # => 0.2e1
2969
+ * BigDecimal(2.0) # => 0.2e1
2970
+ * # Rational value requires ndigits.
3691
2971
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3692
2972
  *
3693
2973
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3751,11 +3031,11 @@ static VALUE
3751
3031
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3752
3032
  {
3753
3033
  char const *c_str = StringValueCStr(str);
3754
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3755
- if (!vp)
3034
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3035
+ if (v.bigdecimal_or_nil == Qnil)
3756
3036
  return Qnil;
3757
3037
  else
3758
- return VpCheckGetValue(vp);
3038
+ return CheckGetValue(bdvalue_nonnullable(v));
3759
3039
  }
3760
3040
 
3761
3041
  /*
@@ -3810,7 +3090,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3810
3090
  static VALUE
3811
3091
  BigDecimal_sign(VALUE self)
3812
3092
  { /* sign */
3813
- int s = GetVpValue(self, 1)->sign;
3093
+ int s = GetSelfVpValue(self)->sign;
3814
3094
  return INT2FIX(s);
3815
3095
  }
3816
3096
 
@@ -3882,310 +3162,15 @@ BigDecimal_save_rounding_mode(VALUE self)
3882
3162
  * puts BigDecimal.limit
3883
3163
  *
3884
3164
  */
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;
3165
+ static VALUE
3166
+ BigDecimal_save_limit(VALUE self)
3167
+ {
3168
+ size_t const limit = VpGetPrecLimit();
3169
+ int state;
3170
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
3171
+ VpSetPrecLimit(limit);
3172
+ if (state) rb_jump_tag(state);
3173
+ return ret;
4189
3174
  }
4190
3175
 
4191
3176
  static VALUE BIGDECIMAL_NAN = Qnil;
@@ -4239,6 +3224,34 @@ BigDecimal_literal(const char *str)
4239
3224
 
4240
3225
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4241
3226
 
3227
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3228
+ VALUE
3229
+ BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3230
+ BDVALUE a,b,c,d;
3231
+ size_t cn = NUM2INT(cprec);
3232
+ a = GetBDValueMust(self);
3233
+ b = GetBDValueMust(r);
3234
+ c = NewZeroWrap(1, cn * BASE_FIG);
3235
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3236
+ VpDivd(c.real, d.real, a.real, b.real);
3237
+ RB_GC_GUARD(a.bigdecimal);
3238
+ RB_GC_GUARD(b.bigdecimal);
3239
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3240
+ }
3241
+
3242
+ VALUE
3243
+ BigDecimal_vpmult(VALUE self, VALUE v) {
3244
+ BDVALUE a,b,c;
3245
+ a = GetBDValueMust(self);
3246
+ b = GetBDValueMust(v);
3247
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3248
+ VpMult(c.real, a.real, b.real);
3249
+ RB_GC_GUARD(a.bigdecimal);
3250
+ RB_GC_GUARD(b.bigdecimal);
3251
+ return c.bigdecimal;
3252
+ }
3253
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3254
+
4242
3255
  /* Document-class: BigDecimal
4243
3256
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4244
3257
  *
@@ -4355,14 +3368,16 @@ BigDecimal_literal(const char *str)
4355
3368
  *
4356
3369
  * When you require +bigdecimal/util+, the #to_d method will be
4357
3370
  * available on BigDecimal and the native Integer, Float, Rational,
4358
- * and String classes:
3371
+ * String, Complex, and NilClass classes:
4359
3372
  *
4360
3373
  * require 'bigdecimal/util'
4361
3374
  *
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
3375
+ * 42.to_d # => 0.42e2
3376
+ * 0.5.to_d # => 0.5e0
3377
+ * (2/3r).to_d(3) # => 0.667e0
3378
+ * "0.5".to_d # => 0.5e0
3379
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
3380
+ * nil.to_d # => 0.0
4366
3381
  *
4367
3382
  * == Methods for Working with \JSON
4368
3383
  *
@@ -4436,7 +3451,7 @@ Init_bigdecimal(void)
4436
3451
  * guarantee that two groups could always be multiplied together without
4437
3452
  * overflow.)
4438
3453
  */
4439
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3454
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4440
3455
 
4441
3456
  /* Exceptions */
4442
3457
 
@@ -4547,7 +3562,6 @@ Init_bigdecimal(void)
4547
3562
  rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
4548
3563
 
4549
3564
  /* instance methods */
4550
- rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
4551
3565
  rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
4552
3566
  rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
4553
3567
  rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
@@ -4578,14 +3592,11 @@ Init_bigdecimal(void)
4578
3592
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4579
3593
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4580
3594
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4581
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4582
3595
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4583
3596
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4584
3597
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4585
3598
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4586
3599
  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
3600
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4590
3601
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4591
3602
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4604,11 +3615,13 @@ Init_bigdecimal(void)
4604
3615
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4605
3616
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4606
3617
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3618
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4607
3619
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4608
3620
 
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);
3621
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3622
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
3623
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3624
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
4612
3625
 
4613
3626
  #define ROUNDING_MODE(i, name, value) \
4614
3627
  id_##name = rb_intern_const(#name); \
@@ -4648,19 +3661,9 @@ Init_bigdecimal(void)
4648
3661
  */
4649
3662
  #ifdef BIGDECIMAL_DEBUG
4650
3663
  static int gfDebug = 1; /* Debug switch */
4651
- #if 0
4652
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4653
- #endif
4654
3664
  #endif /* BIGDECIMAL_DEBUG */
4655
3665
 
4656
3666
  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
3667
 
4665
3668
  enum op_sw {
4666
3669
  OP_SW_ADD = 1, /* + */
@@ -4670,11 +3673,9 @@ enum op_sw {
4670
3673
  };
4671
3674
 
4672
3675
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4673
- static int AddExponent(Real *a, SIGNED_VALUE n);
4674
3676
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4675
3677
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4676
3678
  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
3679
  static void VpFormatSt(char *psz, size_t fFmt);
4679
3680
  static int VpRdup(Real *m, size_t ind_m);
4680
3681
 
@@ -4733,10 +3734,10 @@ VpCheckException(Real *p, bool always)
4733
3734
  }
4734
3735
 
4735
3736
  static VALUE
4736
- VpCheckGetValue(Real *p)
3737
+ CheckGetValue(BDVALUE v)
4737
3738
  {
4738
- VpCheckException(p, false);
4739
- return p->obj;
3739
+ VpCheckException(v.real, false);
3740
+ return v.bigdecimal;
4740
3741
  }
4741
3742
 
4742
3743
  /*
@@ -4768,12 +3769,10 @@ VpGetPrecLimit(void)
4768
3769
  return NUM2SIZET(vlimit);
4769
3770
  }
4770
3771
 
4771
- VP_EXPORT size_t
3772
+ VP_EXPORT void
4772
3773
  VpSetPrecLimit(size_t n)
4773
3774
  {
4774
- size_t const s = VpGetPrecLimit();
4775
3775
  bigdecimal_set_thread_local_precision_limit(n);
4776
- return s;
4777
3776
  }
4778
3777
 
4779
3778
  /*
@@ -4888,15 +3887,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4888
3887
  return nzero;
4889
3888
  }
4890
3889
 
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
3890
  VP_EXPORT int
4901
3891
  VpException(unsigned short f, const char *str,int always)
4902
3892
  {
@@ -5048,7 +4038,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5048
4038
  case 'E':
5049
4039
  /* fall through */
5050
4040
  default:
5051
- nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4041
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
5052
4042
  }
5053
4043
  return nc;
5054
4044
  }
@@ -5074,28 +4064,13 @@ VpInit(DECDIG BaseVal)
5074
4064
  VpGetDoubleNegZero();
5075
4065
 
5076
4066
  /* 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;
4067
+ VpConstOne = NewZero(1, 1);
4068
+ VpSetOne(VpConstOne);
5083
4069
 
5084
4070
  #ifdef BIGDECIMAL_DEBUG
5085
4071
  gnAlloc = 0;
5086
4072
  #endif /* BIGDECIMAL_DEBUG */
5087
4073
 
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
4074
  return BIGDECIMAL_DOUBLE_FIGURES;
5100
4075
  }
5101
4076
 
@@ -5111,24 +4086,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5111
4086
  {
5112
4087
  SIGNED_VALUE e = a->exponent;
5113
4088
  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;
4089
+ if (e > 0 && n > 0) {
4090
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
4091
+ } else if (e < 0 && n < 0) {
4092
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
4093
+ } else if (m > VP_EXPONENT_MAX) {
4094
+ goto overflow;
4095
+ } else if (m < VP_EXPONENT_MIN) {
4096
+ goto underflow;
5132
4097
  }
5133
4098
  a->exponent = m;
5134
4099
  return 1;
@@ -5169,7 +4134,6 @@ bigdecimal_parse_special_string(const char *str)
5169
4134
  while (*p && ISSPACE(*p)) ++p;
5170
4135
  if (*p == '\0') {
5171
4136
  Real *vp = rbd_allocate_struct(1);
5172
- vp->MaxPrec = 1;
5173
4137
  switch (table[i].sign) {
5174
4138
  default:
5175
4139
  UNREACHABLE; break;
@@ -5234,38 +4198,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
5234
4198
  /*
5235
4199
  * Allocates variable.
5236
4200
  * [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.
4201
+ * szVal ... The value assigned(char).
5242
4202
  *
5243
4203
  * [Returns]
5244
4204
  * Pointer to the newly allocated variable, or
5245
4205
  * NULL be returned if memory allocation is failed,or any error.
5246
4206
  */
5247
4207
  VP_EXPORT Real *
5248
- VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4208
+ VpAlloc(const char *szVal, int strict_p, int exc)
5249
4209
  {
5250
4210
  const char *orig_szVal = szVal;
5251
4211
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5252
- size_t len;
5253
4212
  char v, *psz;
5254
4213
  int sign=1;
5255
4214
  Real *vp = NULL;
5256
4215
  VALUE buf;
5257
4216
 
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
4217
  /* Skipping leading spaces */
5270
4218
  while (ISSPACE(*szVal)) szVal++;
5271
4219
 
@@ -5274,14 +4222,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5274
4222
  return vp;
5275
4223
  }
5276
4224
 
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
- }
4225
+ /* Skip leading `#`.
4226
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
4227
+ * but now it has no effect.
4228
+ */
4229
+ if (*szVal == '#') ++szVal;
5285
4230
 
5286
4231
  /* Scanning digits */
5287
4232
 
@@ -5428,7 +4373,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5428
4373
  VALUE str;
5429
4374
  invalid_value:
5430
4375
  if (!strict_p) {
5431
- goto return_zero;
4376
+ return NewZero(1, 1);
5432
4377
  }
5433
4378
  if (!exc) {
5434
4379
  return NULL;
@@ -5439,11 +4384,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5439
4384
 
5440
4385
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5441
4386
  /* 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 */
4387
+ vp = rbd_allocate_struct(nalloc);
5447
4388
  VpSetZero(vp, sign);
5448
4389
  protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
5449
4390
  rb_str_resize(buf, 0);
@@ -5483,7 +4424,7 @@ VpAsgn(Real *c, Real *a, int isw)
5483
4424
  c->Prec = n;
5484
4425
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5485
4426
  /* Needs round ? */
5486
- if (isw != 10) {
4427
+ if (isw != 10 && isw != -10) {
5487
4428
  /* Not in ActiveRound */
5488
4429
  if(c->Prec < a->Prec) {
5489
4430
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5509,19 +4450,11 @@ VpAsgn(Real *c, Real *a, int isw)
5509
4450
  VP_EXPORT size_t
5510
4451
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5511
4452
  {
5512
- short sw, isw;
4453
+ short sw, isw, sign;
5513
4454
  Real *a_ptr, *b_ptr;
5514
4455
  size_t n, na, nb, i;
5515
4456
  DECDIG mrv;
5516
4457
 
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
4458
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5526
4459
 
5527
4460
  /* check if a or b is zero */
@@ -5610,28 +4543,21 @@ end_if:
5610
4543
  if (isw) { /* addition */
5611
4544
  VpSetSign(c, 1);
5612
4545
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5613
- VpSetSign(c, isw / 2);
4546
+ sign = isw / 2;
5614
4547
  }
5615
4548
  else { /* subtraction */
5616
4549
  VpSetSign(c, 1);
5617
4550
  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
- }
4551
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5624
4552
  }
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);
4553
+ if (VpIsInf(c)) {
4554
+ VpSetInf(c, sign);
5633
4555
  }
5634
- #endif /* BIGDECIMAL_DEBUG */
4556
+ else {
4557
+ VpSetSign(c, sign);
4558
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4559
+ }
4560
+
5635
4561
  return c->Prec * BASE_FIG;
5636
4562
  }
5637
4563
 
@@ -5652,13 +4578,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5652
4578
  size_t c_pos;
5653
4579
  DECDIG av, bv, carry, mrv;
5654
4580
 
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
4581
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5663
4582
  a_pos = ap;
5664
4583
  b_pos = bp;
@@ -5724,11 +4643,6 @@ Assign_a:
5724
4643
 
5725
4644
  Exit:
5726
4645
 
5727
- #ifdef BIGDECIMAL_DEBUG
5728
- if (gfDebug) {
5729
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5730
- }
5731
- #endif /* BIGDECIMAL_DEBUG */
5732
4646
  return mrv;
5733
4647
  }
5734
4648
 
@@ -5747,13 +4661,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5747
4661
  size_t c_pos;
5748
4662
  DECDIG av, bv, borrow, mrv;
5749
4663
 
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
4664
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5758
4665
  a_pos = ap;
5759
4666
  b_pos = bp;
@@ -5829,11 +4736,6 @@ Assign_a:
5829
4736
  mrv = 0;
5830
4737
 
5831
4738
  Exit:
5832
- #ifdef BIGDECIMAL_DEBUG
5833
- if (gfDebug) {
5834
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5835
- }
5836
- #endif /* BIGDECIMAL_DEBUG */
5837
4739
  return mrv;
5838
4740
  }
5839
4741
 
@@ -5964,19 +4866,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5964
4866
  VP_EXPORT size_t
5965
4867
  VpMult(Real *c, Real *a, Real *b)
5966
4868
  {
5967
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
4869
+ size_t MxIndA, MxIndB, MxIndAB;
5968
4870
  size_t ind_c, i, ii, nc;
5969
4871
  size_t ind_as, ind_ae, ind_bs;
5970
4872
  DECDIG carry;
5971
4873
  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
4874
 
5981
4875
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
5982
4876
 
@@ -5987,39 +4881,28 @@ VpMult(Real *c, Real *a, Real *b)
5987
4881
  }
5988
4882
 
5989
4883
  if (VpIsOne(a)) {
5990
- VpAsgn(c, b, VpGetSign(a));
4884
+ VpAsgn(c, b, 10 * VpGetSign(a));
5991
4885
  goto Exit;
5992
4886
  }
5993
4887
  if (VpIsOne(b)) {
5994
- VpAsgn(c, a, VpGetSign(b));
4888
+ VpAsgn(c, a, 10 * VpGetSign(b));
5995
4889
  goto Exit;
5996
4890
  }
5997
4891
  if (b->Prec > a->Prec) {
5998
4892
  /* Adjust so that digits(a)>digits(b) */
5999
- w = a;
4893
+ Real *w = a;
6000
4894
  a = b;
6001
4895
  b = w;
6002
4896
  }
6003
- w = NULL;
6004
4897
  MxIndA = a->Prec - 1;
6005
4898
  MxIndB = b->Prec - 1;
6006
- MxIndC = c->MaxPrec - 1;
6007
4899
  MxIndAB = a->Prec + b->Prec - 1;
6008
4900
 
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
4901
  /* set LHSV c info */
6016
4902
 
6017
4903
  c->exponent = a->exponent; /* set exponent */
6018
- if (!AddExponent(c, b->exponent)) {
6019
- if (w) rbd_free_struct(c);
6020
- return 0;
6021
- }
6022
4904
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
4905
+ if (!AddExponent(c, b->exponent)) return 0;
6023
4906
  carry = 0;
6024
4907
  nc = ind_c = MxIndAB;
6025
4908
  memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
@@ -6066,29 +4949,18 @@ VpMult(Real *c, Real *a, Real *b)
6066
4949
  }
6067
4950
  }
6068
4951
  }
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
- }
4952
+ VpNmlz(c);
6078
4953
 
6079
4954
  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
4955
  return c->Prec*BASE_FIG;
6088
4956
  }
6089
4957
 
6090
4958
  /*
6091
4959
  * c = a / b, remainder = r
4960
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
4961
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
4962
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
4963
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
6092
4964
  */
6093
4965
  VP_EXPORT size_t
6094
4966
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6097,16 +4969,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6097
4969
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6098
4970
  size_t nLoop;
6099
4971
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6100
- DECDIG borrow, borrow1, borrow2;
4972
+ DECDIG borrow1, borrow2;
6101
4973
  DECDIG_DBL qb;
6102
4974
 
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
4975
  VpSetNaN(r);
6111
4976
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6112
4977
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6123,30 +4988,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6123
4988
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6124
4989
  goto Exit;
6125
4990
  }
6126
- if (VpIsOne(b)) {
6127
- /* divide by one */
6128
- VpAsgn(c, a, VpGetSign(b));
6129
- VpSetZero(r, VpGetSign(a));
6130
- goto Exit;
6131
- }
6132
4991
 
6133
4992
  word_a = a->Prec;
6134
4993
  word_b = b->Prec;
6135
4994
  word_c = c->MaxPrec;
6136
4995
  word_r = r->MaxPrec;
6137
4996
 
6138
- if (word_a >= word_r || word_b + word_c - 2 >= word_r) goto space_error;
4997
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6139
4998
 
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;
4999
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
5000
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
5001
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
6150
5002
 
6151
5003
  /* initial procedure */
6152
5004
  b1 = b1p1 = b->frac[0];
@@ -6161,15 +5013,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6161
5013
 
6162
5014
  /* */
6163
5015
  /* loop start */
6164
- ind_c = word_r - 1;
6165
- nLoop = Min(word_c,ind_c);
6166
- ind_c = 1;
5016
+ nLoop = Min(word_c, word_r);
5017
+ ind_c = 0;
6167
5018
  while (ind_c < nLoop) {
6168
5019
  if (r->frac[ind_c] == 0) {
6169
5020
  ++ind_c;
6170
5021
  continue;
6171
5022
  }
6172
- r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
5023
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
6173
5024
  if (r1r2 == b1b2) {
6174
5025
  /* The first two word digits is the same */
6175
5026
  ind_b = 2;
@@ -6182,26 +5033,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6182
5033
  }
6183
5034
  /* The first few word digits of r and b is the same and */
6184
5035
  /* 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
- }
5036
+ /* of b, so quotient is 1. */
5037
+ q = 1;
6203
5038
  ++c->frac[ind_c];
6204
- goto carry;
5039
+ ind_r = b->Prec + ind_c - 1;
5040
+ goto sub_mult;
6205
5041
  }
6206
5042
  /* The first two word digits is not the same, */
6207
5043
  /* then compare magnitude, and divide actually. */
@@ -6254,49 +5090,26 @@ sub_mult:
6254
5090
  }
6255
5091
 
6256
5092
  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
5093
  }
6265
5094
  /* End of operation, now final arrangement */
6266
5095
  out_side:
6267
5096
  c->Prec = word_c;
6268
5097
  c->exponent = a->exponent;
6269
- if (!AddExponent(c, 2)) return 0;
5098
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5099
+ if (!AddExponent(c, 1)) return 0;
6270
5100
  if (!AddExponent(c, -(b->exponent))) return 0;
6271
5101
 
6272
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6273
5102
  VpNmlz(c); /* normalize c */
6274
5103
  r->Prec = word_r;
6275
5104
  r->exponent = a->exponent;
6276
- if (!AddExponent(r, 1)) return 0;
6277
5105
  VpSetSign(r, VpGetSign(a));
6278
5106
  VpNmlz(r); /* normalize r(remainder) */
6279
5107
  goto Exit;
6280
5108
 
6281
5109
  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
5110
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6292
5111
 
6293
5112
  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
5113
  return c->Prec * BASE_FIG;
6301
5114
  }
6302
5115
 
@@ -6419,13 +5232,6 @@ Exit:
6419
5232
  if (val > 1) val = 1;
6420
5233
  else if (val < -1) val = -1;
6421
5234
 
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
5235
  return (int)val;
6430
5236
  }
6431
5237
 
@@ -6543,25 +5349,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6543
5349
  static void
6544
5350
  VpFormatSt(char *psz, size_t fFmt)
6545
5351
  {
6546
- size_t ie, i, nf = 0;
6547
- char ch;
5352
+ size_t iend, idig = 0, iexp = 0, nspaces;
5353
+ char *p;
6548
5354
 
6549
5355
  if (fFmt == 0) return;
6550
5356
 
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
- }
5357
+ iend = strlen(psz);
5358
+
5359
+ if ((p = strchr(psz, '.'))) {
5360
+ idig = (p - psz) + 1;
5361
+ }
5362
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
5363
+ iexp = p - psz;
5364
+ }
5365
+ if (idig == 0 || idig > iexp) return;
5366
+
5367
+ nspaces = (iexp - idig - 1) / fFmt;
5368
+ p = psz + iend + 1;
5369
+ for (size_t i = nspaces; i > 0; i--) {
5370
+ char *src = psz + idig + i * fFmt;
5371
+ char *dst = psz + idig + i * (fFmt + 1);
5372
+ memmove(dst, src, p - src);
5373
+ dst[-1] = ' ';
5374
+ p = src;
6565
5375
  }
6566
5376
  }
6567
5377
 
@@ -6843,7 +5653,7 @@ VP_EXPORT int
6843
5653
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6844
5654
  {
6845
5655
  size_t i, j, ind_a, ma, mi, me;
6846
- SIGNED_VALUE e, es, eb, ef;
5656
+ SIGNED_VALUE e;
6847
5657
  int sign, signe, exponent_overflow;
6848
5658
 
6849
5659
  /* get exponent part */
@@ -6866,23 +5676,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6866
5676
  ++me;
6867
5677
  }
6868
5678
  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:
5679
+ int dig = exp_chr[i] - '0';
5680
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5681
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6882
5682
  exponent_overflow = 1;
6883
- e = es; /* keep sign */
6884
5683
  break;
6885
5684
  }
5685
+ e = e * 10 + signe * dig;
6886
5686
  ++i;
6887
5687
  }
6888
5688
  }
@@ -6901,34 +5701,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6901
5701
  ++mi;
6902
5702
  }
6903
5703
  }
5704
+ /* skip leading zeros in integer part */
5705
+ while (i < mi && int_chr[i] == '0') {
5706
+ ++i;
5707
+ --ni;
5708
+ }
6904
5709
 
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;
5710
+ /* set actual exponent size. */
5711
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5712
+ exponent_overflow = 1;
5713
+ } else {
5714
+ e += ni;
5715
+ }
6910
5716
 
6911
5717
  /* 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
- }
5718
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5719
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5720
+ exponent_overflow = 1;
5721
+ } else {
5722
+ e += j;
6923
5723
  }
6924
5724
 
6925
- eb = e / (SIGNED_VALUE)BASE_FIG;
6926
-
6927
- if (exponent_overflow) {
5725
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6928
5726
  int zero = 1;
6929
5727
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6930
5728
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6931
- if (!zero && signe > 0) {
5729
+ if (!zero && e > 0) {
6932
5730
  VpSetInf(a, sign);
6933
5731
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6934
5732
  }
@@ -6978,7 +5776,7 @@ Final:
6978
5776
  ++j;
6979
5777
  }
6980
5778
  a->Prec = ind_a + 1;
6981
- a->exponent = eb;
5779
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
6982
5780
  VpSetSign(a, sign);
6983
5781
  VpNmlz(a);
6984
5782
  return 1;
@@ -7050,254 +5848,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7050
5848
  *d *= VpGetSign(m);
7051
5849
 
7052
5850
  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
5851
  return f;
7061
5852
  }
7062
5853
 
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
5854
  /*
7302
5855
  * Round relatively from the decimal point.
7303
5856
  * f: rounding mode
@@ -7474,7 +6027,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7474
6027
  DECDIG v;
7475
6028
  if (!VpHasVal(y)) return 0; /* Unable to round */
7476
6029
  v = y->frac[0];
7477
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6030
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7478
6031
  while ((v /= 10) != 0) nf--;
7479
6032
  nf += (ssize_t)BASE_FIG-1;
7480
6033
  return VpMidRound(y, f, nf);
@@ -7581,7 +6134,7 @@ VpFrac(Real *y, Real *x)
7581
6134
  size_t my, ind_y, ind_x;
7582
6135
 
7583
6136
  if (!VpHasVal(x)) {
7584
- VpAsgn(y, x, 1);
6137
+ VpAsgn(y, x, 10);
7585
6138
  goto Exit;
7586
6139
  }
7587
6140
 
@@ -7590,7 +6143,7 @@ VpFrac(Real *y, Real *x)
7590
6143
  goto Exit;
7591
6144
  }
7592
6145
  else if (x->exponent <= 0) {
7593
- VpAsgn(y, x, 1);
6146
+ VpAsgn(y, x, 10);
7594
6147
  goto Exit;
7595
6148
  }
7596
6149
 
@@ -7611,117 +6164,9 @@ VpFrac(Real *y, Real *x)
7611
6164
  VpNmlz(y);
7612
6165
 
7613
6166
  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
6167
  return;
7621
6168
  }
7622
6169
 
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
6170
  #ifdef BIGDECIMAL_DEBUG
7726
6171
  int
7727
6172
  VpVarCheck(Real * v)