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