bigdecimal 3.1.9 → 3.2.3

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.1.9"
34
+ #define BIGDECIMAL_VERSION "3.2.3"
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,21 @@ 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)
351
- {
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;
358
- }
359
-
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)
255
+ static VALUE
256
+ BigDecimal_wrap_struct(VALUE klass, Real *real)
364
257
  {
365
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
258
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, real);
259
+ RB_OBJ_FREEZE(obj);
260
+ return obj;
366
261
  }
367
262
 
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)
263
+ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
264
+ #define NewZeroWrap rbd_allocate_struct_zero_wrap
265
+ static BDVALUE
266
+ rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
372
267
  {
373
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
268
+ Real *real = rbd_allocate_struct_zero(sign, digits);
269
+ return (BDVALUE) { BigDecimal_wrap_struct(rb_cBigDecimal, real), real };
374
270
  }
375
271
 
376
272
  static inline int
@@ -398,24 +294,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
398
294
  }
399
295
 
400
296
  static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
401
- static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
297
+ static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
402
298
  static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
403
299
  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);
300
+ static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
405
301
  static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
406
302
 
407
- static Real*
408
- GetVpValueWithPrec(VALUE v, long prec, int must)
303
+ static NULLABLE_BDVALUE
304
+ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
409
305
  {
410
- const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
411
-
412
306
  switch(TYPE(v)) {
413
307
  case T_FLOAT:
414
- v = rb_float_convert_to_BigDecimal(v, digs, must);
308
+ v = rb_float_convert_to_BigDecimal(v, 0, true);
415
309
  break;
416
310
 
417
311
  case T_RATIONAL:
418
- v = rb_rational_convert_to_BigDecimal(v, digs, must);
312
+ v = rb_rational_convert_to_BigDecimal(v, prec, true);
419
313
  break;
420
314
 
421
315
  case T_DATA:
@@ -424,47 +318,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
424
318
  }
425
319
  break;
426
320
 
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);
321
+ case T_FIXNUM:
322
+ case T_BIGNUM: {
323
+ v = rb_inum_convert_to_BigDecimal(v);
431
324
  break;
432
325
  }
433
326
 
434
327
  #ifdef ENABLE_NUMERIC_STRING
435
328
  case T_STRING: {
436
329
  const char *c_str = StringValueCStr(v);
437
- v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
330
+ v = rb_cstr_convert_to_BigDecimal(c_str, must);
438
331
  break;
439
332
  }
440
333
  #endif /* ENABLE_NUMERIC_STRING */
441
334
 
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
335
  default:
450
336
  goto SomeOneMayDoIt;
451
337
  }
452
338
 
453
339
  Real *vp;
454
340
  TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
455
- return vp;
341
+ return (NULLABLE_BDVALUE) { v, vp };
456
342
 
457
343
  SomeOneMayDoIt:
458
344
  if (must) {
459
345
  cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
460
346
  }
461
- return NULL; /* NULL means to coerce */
347
+ return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
348
+ }
349
+
350
+ static inline NULLABLE_BDVALUE
351
+ GetBDValueWithPrec(VALUE v, size_t prec)
352
+ {
353
+ return GetBDValueWithPrecInternal(v, prec, 0);
354
+ }
355
+
356
+
357
+ static inline BDVALUE
358
+ GetBDValueWithPrecMust(VALUE v, size_t prec)
359
+ {
360
+ return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
462
361
  }
463
362
 
363
+ // self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
464
364
  static inline Real*
465
- GetVpValue(VALUE v, int must)
365
+ GetSelfVpValue(VALUE self)
366
+ {
367
+ return GetBDValueWithPrecMust(self, 0).real;
368
+ }
369
+
370
+ static inline BDVALUE
371
+ GetBDValueMust(VALUE v)
466
372
  {
467
- return GetVpValueWithPrec(v, -1, must);
373
+ return GetBDValueWithPrecMust(v, 0);
468
374
  }
469
375
 
470
376
  /* call-seq:
@@ -479,7 +385,7 @@ GetVpValue(VALUE v, int must)
479
385
  static inline VALUE
480
386
  BigDecimal_double_fig(VALUE self)
481
387
  {
482
- return INT2FIX(VpDblFig());
388
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
483
389
  }
484
390
 
485
391
  /* call-seq:
@@ -498,30 +404,26 @@ BigDecimal_double_fig(VALUE self)
498
404
  static VALUE
499
405
  BigDecimal_prec(VALUE self)
500
406
  {
501
- ENTER(1);
502
- Real *p;
407
+ BDVALUE v;
503
408
  VALUE obj;
504
409
 
505
410
  rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
506
411
  "BigDecimal#precs is deprecated and will be removed in the future; "
507
412
  "use BigDecimal#precision instead.");
508
413
 
509
- GUARD_OBJ(p, GetVpValue(self, 1));
510
- obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
511
- SIZET2NUM(p->MaxPrec*VpBaseFig()));
414
+ v = GetBDValueMust(self);
415
+ obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
416
+ SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
417
+
418
+ RB_GC_GUARD(v.bigdecimal);
512
419
  return obj;
513
420
  }
514
421
 
515
422
  static void
516
- BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
423
+ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
517
424
  {
518
- ENTER(1);
519
-
520
425
  if (out_precision == NULL && out_scale == NULL)
521
426
  return;
522
-
523
- Real *p;
524
- GUARD_OBJ(p, GetVpValue(self, 1));
525
427
  if (VpIsZero(p) || !VpIsDef(p)) {
526
428
  zero:
527
429
  if (out_precision) *out_precision = 0;
@@ -625,6 +527,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
625
527
  }
626
528
  }
627
529
 
530
+ static void
531
+ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
532
+ {
533
+ BDVALUE v = GetBDValueMust(self);
534
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
535
+ RB_GC_GUARD(v.bigdecimal);
536
+ }
537
+
628
538
  /*
629
539
  * call-seq:
630
540
  * precision -> integer
@@ -660,8 +570,8 @@ BigDecimal_precision(VALUE self)
660
570
  * BigDecimal("1").scale # => 0
661
571
  * BigDecimal("1.1").scale # => 1
662
572
  * BigDecimal("3.1415").scale # => 4
663
- * BigDecimal("-1e20").precision # => 0
664
- * BigDecimal("1e-20").precision # => 20
573
+ * BigDecimal("-1e20").scale # => 0
574
+ * BigDecimal("1e-20").scale # => 20
665
575
  * BigDecimal("Infinity").scale # => 0
666
576
  * BigDecimal("-Infinity").scale # => 0
667
577
  * BigDecimal("NaN").scale # => 0
@@ -711,25 +621,23 @@ BigDecimal_precision_scale(VALUE self)
711
621
  static VALUE
712
622
  BigDecimal_n_significant_digits(VALUE self)
713
623
  {
714
- ENTER(1);
715
-
716
- Real *p;
717
- GUARD_OBJ(p, GetVpValue(self, 1));
718
- if (VpIsZero(p) || !VpIsDef(p)) {
624
+ BDVALUE v = GetBDValueMust(self);
625
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
719
626
  return INT2FIX(0);
720
627
  }
721
628
 
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);
629
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
630
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
724
631
  if (n == 0) return INT2FIX(0);
725
632
 
726
633
  DECDIG x;
727
634
  int nlz = BASE_FIG;
728
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
635
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
729
636
 
730
637
  int ntz = 0;
731
- for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
638
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
732
639
 
640
+ RB_GC_GUARD(v.bigdecimal);
733
641
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
734
642
  return SSIZET2NUM(n_significant_digits);
735
643
  }
@@ -751,17 +659,14 @@ BigDecimal_n_significant_digits(VALUE self)
751
659
  static VALUE
752
660
  BigDecimal_hash(VALUE self)
753
661
  {
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;
662
+ BDVALUE v = GetBDValueMust(self);
663
+ st_index_t hash = (st_index_t)v.real->sign;
760
664
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
761
665
  if(hash == 2 || hash == (st_index_t)-2) {
762
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
763
- hash += p->exponent;
666
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
667
+ hash += v.real->exponent;
764
668
  }
669
+ RB_GC_GUARD(v.bigdecimal);
765
670
  return ST2FIX(hash);
766
671
  }
767
672
 
@@ -780,21 +685,22 @@ BigDecimal_hash(VALUE self)
780
685
  static VALUE
781
686
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
782
687
  {
783
- ENTER(5);
784
- Real *vp;
688
+ BDVALUE v;
785
689
  char *psz;
786
690
  VALUE dummy;
787
691
  volatile VALUE dump;
788
692
  size_t len;
789
693
 
790
694
  rb_scan_args(argc, argv, "01", &dummy);
791
- GUARD_OBJ(vp,GetVpValue(self, 1));
792
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
695
+ v = GetBDValueMust(self);
696
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
793
697
  psz = RSTRING_PTR(dump);
794
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
698
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
795
699
  len = strlen(psz);
796
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
700
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
797
701
  rb_str_resize(dump, strlen(psz));
702
+
703
+ RB_GC_GUARD(v.bigdecimal);
798
704
  return dump;
799
705
  }
800
706
 
@@ -804,27 +710,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
804
710
  static VALUE
805
711
  BigDecimal_load(VALUE self, VALUE str)
806
712
  {
807
- ENTER(2);
808
- Real *pv;
713
+ BDVALUE v;
809
714
  unsigned char *pch;
810
715
  unsigned char ch;
811
- unsigned long m=0;
812
716
 
813
717
  pch = (unsigned char *)StringValueCStr(str);
814
- /* First get max prec */
718
+ /* First skip max prec. Don't trust the value. */
815
719
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
816
720
  if(!ISDIGIT(ch)) {
817
721
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
818
722
  }
819
- m = m*10 + (unsigned long)(ch-'0');
820
723
  }
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);
724
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
725
+ return CheckGetValue(v);
828
726
  }
829
727
 
830
728
  static unsigned short
@@ -1117,22 +1015,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1117
1015
  static size_t
1118
1016
  GetAddSubPrec(Real *a, Real *b)
1119
1017
  {
1120
- size_t mxs;
1121
- size_t mx = a->Prec;
1122
- SIGNED_VALUE d;
1123
-
1124
1018
  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;
1019
+ ssize_t min_a = a->exponent - a->Prec;
1020
+ ssize_t min_b = b->exponent - b->Prec;
1021
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
1136
1022
  }
1137
1023
 
1138
1024
  static inline SIGNED_VALUE
@@ -1152,39 +1038,12 @@ check_int_precision(VALUE v)
1152
1038
  return n;
1153
1039
  }
1154
1040
 
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)
1041
+ static NULLABLE_BDVALUE
1042
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1186
1043
  {
1187
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
1044
+ Real *pv = VpAlloc(str, strict_p, raise_exception);
1045
+ if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
1046
+ return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(klass, pv), pv };
1188
1047
  }
1189
1048
 
1190
1049
  static Real *
@@ -1192,7 +1051,7 @@ VpCopy(Real *pv, Real const* const x)
1192
1051
  {
1193
1052
  assert(x != NULL);
1194
1053
 
1195
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1054
+ pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
1196
1055
  pv->MaxPrec = x->MaxPrec;
1197
1056
  pv->Prec = x->Prec;
1198
1057
  pv->exponent = x->exponent;
@@ -1207,7 +1066,7 @@ VpCopy(Real *pv, Real const* const x)
1207
1066
  static VALUE
1208
1067
  BigDecimal_IsNaN(VALUE self)
1209
1068
  {
1210
- Real *p = GetVpValue(self, 1);
1069
+ Real *p = GetSelfVpValue(self);
1211
1070
  if (VpIsNaN(p)) return Qtrue;
1212
1071
  return Qfalse;
1213
1072
  }
@@ -1218,7 +1077,7 @@ BigDecimal_IsNaN(VALUE self)
1218
1077
  static VALUE
1219
1078
  BigDecimal_IsInfinite(VALUE self)
1220
1079
  {
1221
- Real *p = GetVpValue(self, 1);
1080
+ Real *p = GetSelfVpValue(self);
1222
1081
  if (VpIsPosInf(p)) return INT2FIX(1);
1223
1082
  if (VpIsNegInf(p)) return INT2FIX(-1);
1224
1083
  return Qnil;
@@ -1228,7 +1087,7 @@ BigDecimal_IsInfinite(VALUE self)
1228
1087
  static VALUE
1229
1088
  BigDecimal_IsFinite(VALUE self)
1230
1089
  {
1231
- Real *p = GetVpValue(self, 1);
1090
+ Real *p = GetSelfVpValue(self);
1232
1091
  if (VpIsNaN(p)) return Qfalse;
1233
1092
  if (VpIsInf(p)) return Qfalse;
1234
1093
  return Qtrue;
@@ -1240,6 +1099,7 @@ BigDecimal_check_num(Real *p)
1240
1099
  VpCheckException(p, true);
1241
1100
  }
1242
1101
 
1102
+ static VALUE BigDecimal_fix(VALUE self);
1243
1103
  static VALUE BigDecimal_split(VALUE self);
1244
1104
 
1245
1105
  /* Returns the value as an Integer.
@@ -1249,44 +1109,36 @@ static VALUE BigDecimal_split(VALUE self);
1249
1109
  static VALUE
1250
1110
  BigDecimal_to_i(VALUE self)
1251
1111
  {
1252
- ENTER(5);
1253
- ssize_t e, nf;
1254
- Real *p;
1112
+ BDVALUE v;
1113
+ VALUE ret;
1255
1114
 
1256
- GUARD_OBJ(p, GetVpValue(self, 1));
1257
- BigDecimal_check_num(p);
1115
+ v = GetBDValueMust(self);
1116
+ BigDecimal_check_num(v.real);
1258
1117
 
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]));
1118
+ if (v.real->exponent <= 0) return INT2FIX(0);
1119
+ if (v.real->exponent == 1) {
1120
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
1264
1121
  }
1265
1122
  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;
1123
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
1124
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
1125
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
1126
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
1127
+
1128
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
1129
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
1130
+ }
1131
+ if (dpower) {
1132
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
1133
+ // In Ruby < 3.4, int**int may return Float::INFINITY
1134
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
1135
+
1136
+ ret = rb_funcall(ret, '*', 1, pow10);
1137
+ }
1289
1138
  }
1139
+
1140
+ RB_GC_GUARD(v.bigdecimal);
1141
+ return ret;
1290
1142
  }
1291
1143
 
1292
1144
  /* Returns a new Float object having approximately the same value as the
@@ -1296,24 +1148,26 @@ BigDecimal_to_i(VALUE self)
1296
1148
  static VALUE
1297
1149
  BigDecimal_to_f(VALUE self)
1298
1150
  {
1299
- ENTER(1);
1300
- Real *p;
1301
1151
  double d;
1302
1152
  SIGNED_VALUE e;
1303
1153
  char *buf;
1304
1154
  volatile VALUE str;
1155
+ BDVALUE v = GetBDValueMust(self);
1156
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1305
1157
 
1306
- GUARD_OBJ(p, GetVpValue(self, 1));
1307
- if (VpVtoD(&d, &e, p) != 1)
1158
+ if (VpVtoD(&d, &e, v.real) != 1)
1308
1159
  return rb_float_new(d);
1309
1160
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1310
1161
  goto overflow;
1311
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1162
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1312
1163
  goto underflow;
1313
1164
 
1314
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1165
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1315
1166
  buf = RSTRING_PTR(str);
1316
- VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1167
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
1168
+
1169
+ RB_GC_GUARD(v.bigdecimal);
1170
+
1317
1171
  errno = 0;
1318
1172
  d = strtod(buf, 0);
1319
1173
  if (errno == ERANGE) {
@@ -1324,14 +1178,14 @@ BigDecimal_to_f(VALUE self)
1324
1178
 
1325
1179
  overflow:
1326
1180
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1327
- if (BIGDECIMAL_NEGATIVE_P(p))
1181
+ if (negative)
1328
1182
  return rb_float_new(VpGetDoubleNegInf());
1329
1183
  else
1330
1184
  return rb_float_new(VpGetDoublePosInf());
1331
1185
 
1332
1186
  underflow:
1333
1187
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1334
- if (BIGDECIMAL_NEGATIVE_P(p))
1188
+ if (negative)
1335
1189
  return rb_float_new(-0.0);
1336
1190
  else
1337
1191
  return rb_float_new(0.0);
@@ -1343,15 +1197,16 @@ underflow:
1343
1197
  static VALUE
1344
1198
  BigDecimal_to_r(VALUE self)
1345
1199
  {
1346
- Real *p;
1200
+ BDVALUE v;
1347
1201
  ssize_t sign, power, denomi_power;
1348
1202
  VALUE a, digits, numerator;
1349
1203
 
1350
- p = GetVpValue(self, 1);
1351
- BigDecimal_check_num(p);
1204
+ v = GetBDValueMust(self);
1205
+ BigDecimal_check_num(v.real);
1206
+ sign = VpGetSign(v.real);
1207
+ power = VpExponent10(v.real);
1208
+ RB_GC_GUARD(v.bigdecimal);
1352
1209
 
1353
- sign = VpGetSign(p);
1354
- power = VpExponent10(p);
1355
1210
  a = BigDecimal_split(self);
1356
1211
  digits = RARRAY_AREF(a, 1);
1357
1212
  denomi_power = power - RSTRING_LEN(digits);
@@ -1372,6 +1227,14 @@ BigDecimal_to_r(VALUE self)
1372
1227
  }
1373
1228
  }
1374
1229
 
1230
+ static size_t
1231
+ GetCoercePrec(Real *a, size_t prec)
1232
+ {
1233
+ if (prec == 0) prec = a->Prec * BASE_FIG;
1234
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1235
+ return prec;
1236
+ }
1237
+
1375
1238
  /* The coerce method provides support for Ruby type coercion. It is not
1376
1239
  * enabled by default.
1377
1240
  *
@@ -1389,26 +1252,9 @@ BigDecimal_to_r(VALUE self)
1389
1252
  static VALUE
1390
1253
  BigDecimal_coerce(VALUE self, VALUE other)
1391
1254
  {
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;
1255
+ Real* pv = DATA_PTR(self);
1256
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1257
+ return rb_assoc_new(CheckGetValue(b), self);
1412
1258
  }
1413
1259
 
1414
1260
  /*
@@ -1428,6 +1274,15 @@ BigDecimal_uplus(VALUE self)
1428
1274
  return self;
1429
1275
  }
1430
1276
 
1277
+ static bool
1278
+ is_coerceable_to_BigDecimal(VALUE r)
1279
+ {
1280
+ return is_kind_of_BigDecimal(r) ||
1281
+ RB_INTEGER_TYPE_P(r) ||
1282
+ RB_TYPE_P(r, T_FLOAT) ||
1283
+ RB_TYPE_P(r, T_RATIONAL);
1284
+ }
1285
+
1431
1286
  /*
1432
1287
  * call-seq:
1433
1288
  * self + value -> bigdecimal
@@ -1447,45 +1302,44 @@ BigDecimal_uplus(VALUE self)
1447
1302
  static VALUE
1448
1303
  BigDecimal_add(VALUE self, VALUE r)
1449
1304
  {
1450
- ENTER(5);
1451
- Real *c, *a, *b;
1452
- size_t mx;
1305
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
1306
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
1307
+ }
1453
1308
 
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
- }
1309
+ static VALUE
1310
+ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1311
+ {
1312
+ BDVALUE a, b, c;
1313
+ size_t mx;
1464
1314
 
1465
- if (!b) return DoSomeOne(self,r,'+');
1466
- SAVE(b);
1315
+ a = GetBDValueMust(self);
1316
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1467
1317
 
1468
- if (VpIsNaN(b)) return b->obj;
1469
- if (VpIsNaN(a)) return a->obj;
1318
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1319
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1470
1320
 
1471
- mx = GetAddSubPrec(a, b);
1321
+ mx = GetAddSubPrec(a.real, b.real);
1472
1322
  if (mx == (size_t)-1L) {
1473
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1474
- VpAddSub(c, a, b, 1);
1323
+ /* a or b is inf */
1324
+ c = NewZeroWrap(1, BASE_FIG);
1325
+ VpAddSub(c.real, a.real, b.real, operation);
1475
1326
  }
1476
1327
  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
- }
1328
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1329
+ size_t pl = VpGetPrecLimit();
1330
+ if (prec) VpSetPrecLimit(prec);
1331
+ // Let VpAddSub round the result
1332
+ VpAddSub(c.real, a.real, b.real, operation);
1333
+ if (prec) VpSetPrecLimit(pl);
1484
1334
  }
1485
- return VpCheckGetValue(c);
1335
+
1336
+ RB_GC_GUARD(a.bigdecimal);
1337
+ RB_GC_GUARD(b.bigdecimal);
1338
+ return CheckGetValue(c);
1486
1339
  }
1487
1340
 
1488
- /* call-seq:
1341
+ /*
1342
+ * call-seq:
1489
1343
  * self - value -> bigdecimal
1490
1344
  *
1491
1345
  * Returns the \BigDecimal difference of +self+ and +value+:
@@ -1502,73 +1356,18 @@ BigDecimal_add(VALUE self, VALUE r)
1502
1356
  static VALUE
1503
1357
  BigDecimal_sub(VALUE self, VALUE r)
1504
1358
  {
1505
- ENTER(5);
1506
- Real *c, *a, *b;
1507
- size_t mx;
1508
-
1509
- GUARD_OBJ(a, GetVpValue(self,1));
1510
- if (RB_TYPE_P(r, T_FLOAT)) {
1511
- b = GetVpValueWithPrec(r, 0, 1);
1512
- }
1513
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1514
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1515
- }
1516
- else {
1517
- b = GetVpValue(r,0);
1518
- }
1519
-
1520
- if (!b) return DoSomeOne(self,r,'-');
1521
- SAVE(b);
1522
-
1523
- if (VpIsNaN(b)) return b->obj;
1524
- if (VpIsNaN(a)) return a->obj;
1525
-
1526
- mx = GetAddSubPrec(a,b);
1527
- if (mx == (size_t)-1L) {
1528
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1529
- VpAddSub(c, a, b, -1);
1530
- }
1531
- else {
1532
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
1533
- if (!mx) {
1534
- VpSetInf(c,VpGetSign(a));
1535
- }
1536
- else {
1537
- VpAddSub(c, a, b, -1);
1538
- }
1539
- }
1540
- return VpCheckGetValue(c);
1359
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1360
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1541
1361
  }
1542
1362
 
1543
1363
  static VALUE
1544
1364
  BigDecimalCmp(VALUE self, VALUE r,char op)
1545
1365
  {
1546
- ENTER(5);
1547
1366
  SIGNED_VALUE e;
1548
- Real *a, *b=0;
1549
- GUARD_OBJ(a, GetVpValue(self, 1));
1550
- switch (TYPE(r)) {
1551
- case T_DATA:
1552
- if (!is_kind_of_BigDecimal(r)) break;
1553
- /* fall through */
1554
- case T_FIXNUM:
1555
- /* fall through */
1556
- case T_BIGNUM:
1557
- GUARD_OBJ(b, GetVpValue(r, 0));
1558
- break;
1559
-
1560
- case T_FLOAT:
1561
- GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
1562
- break;
1563
-
1564
- case T_RATIONAL:
1565
- GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
1566
- break;
1367
+ BDVALUE a = GetBDValueMust(self);
1368
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1567
1369
 
1568
- default:
1569
- break;
1570
- }
1571
- if (b == NULL) {
1370
+ if (b.real_or_null == NULL) {
1572
1371
  ID f = 0;
1573
1372
 
1574
1373
  switch (op) {
@@ -1597,8 +1396,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1597
1396
  }
1598
1397
  return rb_num_coerce_relop(self, r, f);
1599
1398
  }
1600
- SAVE(b);
1601
- e = VpComp(a, b);
1399
+ e = VpComp(a.real, b.real_or_null);
1400
+
1401
+ RB_GC_GUARD(a.bigdecimal);
1402
+ RB_GC_GUARD(b.bigdecimal_or_nil);
1403
+
1602
1404
  if (e == 999)
1603
1405
  return (op == '*') ? Qnil : Qfalse;
1604
1406
  switch (op) {
@@ -1638,7 +1440,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1638
1440
  static VALUE
1639
1441
  BigDecimal_zero(VALUE self)
1640
1442
  {
1641
- Real *a = GetVpValue(self, 1);
1443
+ Real *a = GetSelfVpValue(self);
1642
1444
  return VpIsZero(a) ? Qtrue : Qfalse;
1643
1445
  }
1644
1446
 
@@ -1646,7 +1448,7 @@ BigDecimal_zero(VALUE self)
1646
1448
  static VALUE
1647
1449
  BigDecimal_nonzero(VALUE self)
1648
1450
  {
1649
- Real *a = GetVpValue(self, 1);
1451
+ Real *a = GetSelfVpValue(self);
1650
1452
  return VpIsZero(a) ? Qnil : self;
1651
1453
  }
1652
1454
 
@@ -1772,12 +1574,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1772
1574
  static VALUE
1773
1575
  BigDecimal_neg(VALUE self)
1774
1576
  {
1775
- ENTER(5);
1776
- Real *c, *a;
1777
- GUARD_OBJ(a, GetVpValue(self, 1));
1778
- GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
1779
- VpAsgn(c, a, -1);
1780
- return VpCheckGetValue(c);
1577
+ BDVALUE a = GetBDValueMust(self);
1578
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
1579
+ VpAsgn(c.real, a.real, -10);
1580
+ RB_GC_GUARD(a.bigdecimal);
1581
+ return CheckGetValue(c);
1781
1582
  }
1782
1583
 
1783
1584
  /*
@@ -1790,84 +1591,36 @@ BigDecimal_neg(VALUE self)
1790
1591
  *
1791
1592
  * See BigDecimal#mult.
1792
1593
  */
1793
-
1794
1594
  static VALUE
1795
1595
  BigDecimal_mult(VALUE self, VALUE r)
1796
1596
  {
1797
- ENTER(5);
1798
- Real *c, *a, *b;
1799
- size_t mx;
1800
-
1801
- GUARD_OBJ(a, GetVpValue(self, 1));
1802
- if (RB_TYPE_P(r, T_FLOAT)) {
1803
- b = GetVpValueWithPrec(r, 0, 1);
1804
- }
1805
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1806
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1807
- }
1808
- else {
1809
- b = GetVpValue(r,0);
1810
- }
1811
-
1812
- if (!b) return DoSomeOne(self, r, '*');
1813
- SAVE(b);
1814
-
1815
- mx = a->Prec + b->Prec;
1816
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1817
- VpMult(c, a, b);
1818
- return VpCheckGetValue(c);
1597
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1598
+ return BigDecimal_mult_with_coerce(self, r, 0);
1819
1599
  }
1820
1600
 
1821
1601
  static VALUE
1822
- BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1823
- /* For c = self.div(r): with round operation */
1602
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1824
1603
  {
1825
- ENTER(5);
1826
- Real *a, *b;
1827
- ssize_t a_prec, b_prec;
1828
- size_t mx;
1604
+ BDVALUE a, b, c;
1829
1605
 
1830
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1831
- SAVE(a);
1606
+ a = GetBDValueMust(self);
1607
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1832
1608
 
1833
- VALUE rr = r;
1834
- if (is_kind_of_BigDecimal(rr)) {
1835
- /* do nothing */
1836
- }
1837
- else if (RB_INTEGER_TYPE_P(r)) {
1838
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
1839
- }
1840
- else if (RB_TYPE_P(r, T_FLOAT)) {
1841
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1609
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
1610
+ VpMult(c.real, a.real, b.real);
1611
+ if (prec) {
1612
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
1842
1613
  }
1843
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1844
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1845
- }
1846
-
1847
- if (!is_kind_of_BigDecimal(rr)) {
1848
- return DoSomeOne(self, r, '/');
1614
+ else {
1615
+ VpLimitRound(c.real, 0);
1849
1616
  }
1850
1617
 
1851
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1852
- SAVE(b);
1853
- *div = b;
1854
-
1855
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
1856
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
1857
- mx = (a_prec > b_prec) ? a_prec : b_prec;
1858
- mx *= 2;
1859
-
1860
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1861
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1862
-
1863
- GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
1864
- GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
1865
- VpDivd(*c, *res, a, b);
1866
-
1867
- return Qnil;
1618
+ RB_GC_GUARD(a.bigdecimal);
1619
+ RB_GC_GUARD(b.bigdecimal);
1620
+ return CheckGetValue(c);
1868
1621
  }
1869
1622
 
1870
- static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1623
+ static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
1871
1624
 
1872
1625
  /* call-seq:
1873
1626
  * a / b -> bigdecimal
@@ -1884,20 +1637,8 @@ static VALUE
1884
1637
  BigDecimal_div(VALUE self, VALUE r)
1885
1638
  /* For c = self/r: with round operation */
1886
1639
  {
1887
- ENTER(5);
1888
- Real *c=NULL, *res=NULL, *div = NULL;
1889
- r = BigDecimal_divide(self, r, &c, &res, &div);
1890
- if (!NIL_P(r)) return r; /* coerced by other */
1891
- SAVE(c); SAVE(res); SAVE(div);
1892
- /* a/b = c + r/b */
1893
- /* c xxxxx
1894
- r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
1895
- */
1896
- /* Round */
1897
- if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
1898
- VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
1899
- }
1900
- return VpCheckGetValue(c);
1640
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1641
+ return BigDecimal_div2(self, r, INT2FIX(0));
1901
1642
  }
1902
1643
 
1903
1644
  static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
@@ -1942,119 +1683,105 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1942
1683
  /*
1943
1684
  * %: mod = a%b = a - (a.to_f/b).floor * b
1944
1685
  * div = (a.to_f/b).floor
1686
+ * In truncate mode, use truncate instead of floor.
1945
1687
  */
1946
- static VALUE
1947
- BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1688
+ static bool
1689
+ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
1948
1690
  {
1949
- ENTER(8);
1950
- Real *c=NULL, *d=NULL, *res=NULL;
1951
- Real *a, *b;
1952
- ssize_t a_prec, b_prec;
1953
- size_t mx;
1691
+ BDVALUE a, b, dv, md, res;
1692
+ NULLABLE_BDVALUE b2;
1693
+ ssize_t a_exponent, b_exponent;
1694
+ size_t mx, rx, pl;
1954
1695
 
1955
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1956
- SAVE(a);
1696
+ a = GetBDValueMust(self);
1957
1697
 
1958
- VALUE rr = r;
1959
- if (is_kind_of_BigDecimal(rr)) {
1960
- /* do nothing */
1961
- }
1962
- else if (RB_INTEGER_TYPE_P(r)) {
1963
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
1964
- }
1965
- else if (RB_TYPE_P(r, T_FLOAT)) {
1966
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1967
- }
1968
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1969
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1970
- }
1698
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1699
+ if (!b2.real_or_null) return false;
1700
+ b = bdvalue_nonnullable(b2);
1971
1701
 
1972
- if (!is_kind_of_BigDecimal(rr)) {
1973
- return Qfalse;
1702
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1703
+ VALUE nan = BigDecimal_nan();
1704
+ *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1705
+ goto Done;
1974
1706
  }
1975
-
1976
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1977
- SAVE(b);
1978
-
1979
- if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
1980
- if (VpIsInf(a) && VpIsInf(b)) goto NaN;
1981
- if (VpIsZero(b)) {
1707
+ if (VpIsZero(b.real)) {
1982
1708
  rb_raise(rb_eZeroDivError, "divided by 0");
1983
1709
  }
1984
- if (VpIsInf(a)) {
1985
- if (VpGetSign(a) == VpGetSign(b)) {
1710
+ if (VpIsInf(a.real)) {
1711
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1986
1712
  VALUE inf = BigDecimal_positive_infinity();
1987
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1713
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1988
1714
  }
1989
1715
  else {
1990
1716
  VALUE inf = BigDecimal_negative_infinity();
1991
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1717
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1992
1718
  }
1993
1719
  VALUE nan = BigDecimal_nan();
1994
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
1995
- return Qtrue;
1720
+ *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1721
+ goto Done;
1996
1722
  }
1997
- if (VpIsInf(b)) {
1723
+ if (VpIsInf(b.real)) {
1998
1724
  VALUE zero = BigDecimal_positive_zero();
1999
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
2000
- *mod = a;
2001
- return Qtrue;
1725
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1726
+ *mod = bdvalue_nullable(a);
1727
+ goto Done;
2002
1728
  }
2003
- if (VpIsZero(a)) {
1729
+ if (VpIsZero(a.real)) {
2004
1730
  VALUE zero = BigDecimal_positive_zero();
2005
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
2006
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
2007
- return Qtrue;
2008
- }
2009
-
2010
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
2011
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
2012
-
2013
- mx = (a_prec > b_prec) ? a_prec : b_prec;
2014
- mx *= 2;
2015
-
2016
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
2017
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
2018
-
2019
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
2020
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
2021
- VpDivd(c, res, a, b);
2022
-
2023
- mx = c->Prec * BASE_FIG;
2024
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2025
- VpActiveRound(d, c, VP_ROUND_DOWN, 0);
2026
-
2027
- VpMult(res, d, b);
2028
- VpAddSub(c, a, res, -1);
1731
+ *div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1732
+ goto Done;
1733
+ }
1734
+
1735
+ a_exponent = VpExponent10(a.real);
1736
+ b_exponent = VpExponent10(b.real);
1737
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
1738
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
1739
+
1740
+ /* res is reused for VpDivd remainder and VpMult result */
1741
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
1742
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
1743
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
1744
+ /* AddSub needs one more prec */
1745
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
1746
+
1747
+ VpDivd(dv.real, res.real, a.real, b.real);
1748
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
1749
+ VpMult(res.real, dv.real, b.real);
1750
+ pl = VpGetPrecLimit();
1751
+ VpSetPrecLimit(0);
1752
+ VpAddSub(md.real, a.real, res.real, -1);
1753
+ VpSetPrecLimit(pl);
2029
1754
 
2030
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1755
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
2031
1756
  /* result adjustment for negative case */
2032
- res = rbd_reallocate_struct(res, d->MaxPrec);
2033
- res->MaxPrec = d->MaxPrec;
2034
- VpAddSub(res, d, VpOne(), -1);
2035
- GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
2036
- VpAddSub(d, c, b, 1);
2037
- *div = res;
2038
- *mod = d;
1757
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
1758
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
1759
+ VpSetPrecLimit(0);
1760
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
1761
+ VpAddSub(md2.real, md.real, b.real, 1);
1762
+ VpSetPrecLimit(pl);
1763
+ *div = bdvalue_nullable(dv2);
1764
+ *mod = bdvalue_nullable(md2);
1765
+ RB_GC_GUARD(dv2.bigdecimal);
1766
+ RB_GC_GUARD(md2.bigdecimal);
2039
1767
  }
2040
1768
  else {
2041
- *div = d;
2042
- *mod = c;
1769
+ *div = bdvalue_nullable(dv);
1770
+ *mod = bdvalue_nullable(md);
2043
1771
  }
2044
- return Qtrue;
2045
1772
 
2046
- NaN:
2047
- {
2048
- VALUE nan = BigDecimal_nan();
2049
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
2050
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
2051
- }
2052
- return Qtrue;
1773
+ Done:
1774
+ RB_GC_GUARD(a.bigdecimal);
1775
+ RB_GC_GUARD(b.bigdecimal);
1776
+ RB_GC_GUARD(dv.bigdecimal);
1777
+ RB_GC_GUARD(md.bigdecimal);
1778
+ RB_GC_GUARD(res.bigdecimal);
1779
+ return true;
2053
1780
  }
2054
1781
 
2055
1782
  /* call-seq:
2056
- * a % b
2057
- * a.modulo(b)
1783
+ * a % b
1784
+ * a.modulo(b)
2058
1785
  *
2059
1786
  * Returns the modulus from dividing by b.
2060
1787
  *
@@ -2063,71 +1790,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2063
1790
  static VALUE
2064
1791
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2065
1792
  {
2066
- ENTER(3);
2067
- Real *div = NULL, *mod = NULL;
1793
+ NULLABLE_BDVALUE div, mod;
2068
1794
 
2069
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2070
- SAVE(div); SAVE(mod);
2071
- return VpCheckGetValue(mod);
1795
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1796
+ return CheckGetValue(bdvalue_nonnullable(mod));
2072
1797
  }
2073
1798
  return DoSomeOne(self, r, '%');
2074
1799
  }
2075
1800
 
2076
- static VALUE
2077
- BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2078
- {
2079
- ENTER(10);
2080
- size_t mx;
2081
- Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
2082
- Real *f = NULL;
2083
-
2084
- GUARD_OBJ(a, GetVpValue(self, 1));
2085
- if (RB_TYPE_P(r, T_FLOAT)) {
2086
- b = GetVpValueWithPrec(r, 0, 1);
2087
- }
2088
- else if (RB_TYPE_P(r, T_RATIONAL)) {
2089
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
2090
- }
2091
- else {
2092
- b = GetVpValue(r, 0);
2093
- }
2094
-
2095
- if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
2096
- SAVE(b);
2097
-
2098
- if (VpIsPosInf(b) || VpIsNegInf(b)) {
2099
- GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2100
- VpSetZero(*dv, 1);
2101
- *rv = a;
2102
- return Qnil;
2103
- }
2104
-
2105
- mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
2106
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2107
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2108
- GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2109
- GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2110
-
2111
- VpDivd(c, res, a, b);
2112
-
2113
- mx = c->Prec *(VpBaseFig() + 1);
2114
-
2115
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2116
- GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
2117
-
2118
- VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
2119
-
2120
- VpFrac(f, c);
2121
- VpMult(rr, f, b);
2122
- VpAddSub(ff, res, rr, 1);
2123
-
2124
- *dv = d;
2125
- *rv = ff;
2126
- return Qnil;
2127
- }
2128
-
2129
1801
  /* call-seq:
2130
- * remainder(value)
1802
+ * remainder(value)
2131
1803
  *
2132
1804
  * Returns the remainder from dividing by the value.
2133
1805
  *
@@ -2136,15 +1808,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2136
1808
  static VALUE
2137
1809
  BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2138
1810
  {
2139
- VALUE f;
2140
- Real *d, *rv = 0;
2141
- f = BigDecimal_divremain(self, r, &d, &rv);
2142
- if (!NIL_P(f)) return f;
2143
- return VpCheckGetValue(rv);
1811
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
1812
+
1813
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
1814
+ return CheckGetValue(bdvalue_nonnullable(mod));
1815
+ }
1816
+ return DoSomeOne(self, r, rb_intern("remainder"));
2144
1817
  }
2145
1818
 
2146
1819
  /* call-seq:
2147
- * divmod(value)
1820
+ * divmod(value)
2148
1821
  *
2149
1822
  * Divides by the specified value, and returns the quotient and modulus
2150
1823
  * as BigDecimal numbers. The quotient is rounded towards negative infinity.
@@ -2168,12 +1841,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2168
1841
  static VALUE
2169
1842
  BigDecimal_divmod(VALUE self, VALUE r)
2170
1843
  {
2171
- ENTER(5);
2172
- Real *div = NULL, *mod = NULL;
1844
+ NULLABLE_BDVALUE div, mod;
2173
1845
 
2174
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2175
- SAVE(div); SAVE(mod);
2176
- return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
1846
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1847
+ return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
2177
1848
  }
2178
1849
  return DoSomeOne(self,r,rb_intern("divmod"));
2179
1850
  }
@@ -2185,47 +1856,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
2185
1856
  static inline VALUE
2186
1857
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2187
1858
  {
2188
- ENTER(5);
2189
1859
  SIGNED_VALUE ix;
1860
+ BDVALUE av, bv, cv, res;
2190
1861
 
2191
1862
  if (NIL_P(n)) { /* div in Float sense */
2192
- Real *div = NULL;
2193
- Real *mod;
2194
- if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
2195
- return BigDecimal_to_i(VpCheckGetValue(div));
1863
+ NULLABLE_BDVALUE div;
1864
+ NULLABLE_BDVALUE mod;
1865
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
1866
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
2196
1867
  }
2197
1868
  return DoSomeOne(self, b, rb_intern("div"));
2198
1869
  }
2199
1870
 
2200
1871
  /* div in BigDecimal sense */
2201
1872
  ix = check_int_precision(n);
1873
+
1874
+ av = GetBDValueMust(self);
1875
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
1876
+
2202
1877
  if (ix == 0) {
2203
- return BigDecimal_div(self, b);
1878
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1879
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1880
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
1881
+ ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
1882
+ if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
1883
+ ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1884
+ if (limit && limit < ix) ix = limit;
2204
1885
  }
2205
- else {
2206
- Real *res = NULL;
2207
- Real *av = NULL, *bv = NULL, *cv = NULL;
2208
- size_t mx = ix + VpBaseFig()*2;
2209
- size_t b_prec = ix;
2210
- size_t pl = VpSetPrecLimit(0);
2211
-
2212
- GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig()));
2213
- GUARD_OBJ(av, GetVpValue(self, 1));
2214
- /* TODO: I want to refactor this precision control for a float value later
2215
- * by introducing an implicit conversion function instead of
2216
- * GetVpValueWithPrec. */
2217
- if (RB_FLOAT_TYPE_P(b) && b_prec > BIGDECIMAL_DOUBLE_FIGURES) {
2218
- b_prec = BIGDECIMAL_DOUBLE_FIGURES;
2219
- }
2220
- GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
2221
- mx = av->Prec + bv->Prec + 2;
2222
- if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
2223
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
2224
- VpDivd(cv, res, av, bv);
2225
- VpSetPrecLimit(pl);
2226
- VpLeftRound(cv, VpGetRoundMode(), ix);
2227
- return VpCheckGetValue(cv);
1886
+
1887
+ // Needs to calculate 1 extra digit for rounding.
1888
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
1889
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
1890
+ VpDivd(cv.real, res.real, av.real, bv.real);
1891
+
1892
+ if (!VpIsZero(res.real)) {
1893
+ // Remainder value affects rounding result.
1894
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
1895
+ // 0.1e0 if remainder == 0
1896
+ // 0.1000000001e0 if remainder != 0
1897
+ size_t idx = roomof(ix, BASE_FIG);
1898
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
1899
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
2228
1900
  }
1901
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
1902
+
1903
+ RB_GC_GUARD(av.bigdecimal);
1904
+ RB_GC_GUARD(bv.bigdecimal);
1905
+ RB_GC_GUARD(res.bigdecimal);
1906
+ return CheckGetValue(cv);
2229
1907
  }
2230
1908
 
2231
1909
  /*
@@ -2301,22 +1979,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2301
1979
  static VALUE
2302
1980
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2303
1981
  {
2304
- ENTER(2);
2305
- Real *cv;
2306
- SIGNED_VALUE mx = check_int_precision(n);
2307
- if (mx == 0) return BigDecimal_add(self, b);
2308
- else {
2309
- size_t pl = VpSetPrecLimit(0);
2310
- VALUE c = BigDecimal_add(self, b);
2311
- VpSetPrecLimit(pl);
2312
- GUARD_OBJ(cv, GetVpValue(c, 1));
2313
- VpLeftRound(cv, VpGetRoundMode(), mx);
2314
- return VpCheckGetValue(cv);
2315
- }
1982
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2316
1983
  }
2317
1984
 
2318
1985
  /* call-seq:
2319
- * sub(value, digits) -> bigdecimal
1986
+ * sub(value, digits) -> bigdecimal
2320
1987
  *
2321
1988
  * Subtract the specified value.
2322
1989
  *
@@ -2331,18 +1998,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2331
1998
  static VALUE
2332
1999
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2333
2000
  {
2334
- ENTER(2);
2335
- Real *cv;
2336
- SIGNED_VALUE mx = check_int_precision(n);
2337
- if (mx == 0) return BigDecimal_sub(self, b);
2338
- else {
2339
- size_t pl = VpSetPrecLimit(0);
2340
- VALUE c = BigDecimal_sub(self, b);
2341
- VpSetPrecLimit(pl);
2342
- GUARD_OBJ(cv, GetVpValue(c, 1));
2343
- VpLeftRound(cv, VpGetRoundMode(), mx);
2344
- return VpCheckGetValue(cv);
2345
- }
2001
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2346
2002
  }
2347
2003
 
2348
2004
  /*
@@ -2374,18 +2030,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2374
2030
  static VALUE
2375
2031
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2376
2032
  {
2377
- ENTER(2);
2378
- Real *cv;
2379
- SIGNED_VALUE mx = check_int_precision(n);
2380
- if (mx == 0) return BigDecimal_mult(self, b);
2381
- else {
2382
- size_t pl = VpSetPrecLimit(0);
2383
- VALUE c = BigDecimal_mult(self, b);
2384
- VpSetPrecLimit(pl);
2385
- GUARD_OBJ(cv, GetVpValue(c, 1));
2386
- VpLeftRound(cv, VpGetRoundMode(), mx);
2387
- return VpCheckGetValue(cv);
2388
- }
2033
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2389
2034
  }
2390
2035
 
2391
2036
  /*
@@ -2402,41 +2047,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2402
2047
  static VALUE
2403
2048
  BigDecimal_abs(VALUE self)
2404
2049
  {
2405
- ENTER(5);
2406
- Real *c, *a;
2407
- size_t mx;
2408
-
2409
- GUARD_OBJ(a, GetVpValue(self, 1));
2410
- mx = a->Prec *(VpBaseFig() + 1);
2411
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2412
- VpAsgn(c, a, 1);
2413
- VpChangeSign(c, 1);
2414
- return VpCheckGetValue(c);
2415
- }
2416
-
2417
- /* call-seq:
2418
- * sqrt(n)
2419
- *
2420
- * Returns the square root of the value.
2421
- *
2422
- * Result has at least n significant digits.
2423
- */
2424
- static VALUE
2425
- BigDecimal_sqrt(VALUE self, VALUE nFig)
2426
- {
2427
- ENTER(5);
2428
- Real *c, *a;
2429
- size_t mx, n;
2430
-
2431
- GUARD_OBJ(a, GetVpValue(self, 1));
2432
- mx = a->Prec * (VpBaseFig() + 1);
2433
-
2434
- n = check_int_precision(nFig);
2435
- n += VpDblFig() + VpBaseFig();
2436
- if (mx <= n) mx = n;
2437
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2438
- VpSqrt(c, a);
2439
- return VpCheckGetValue(c);
2050
+ BDVALUE a = GetBDValueMust(self);
2051
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
2052
+ VpAsgn(c.real, a.real, 10);
2053
+ VpChangeSign(c.real, 1);
2054
+ RB_GC_GUARD(a.bigdecimal);
2055
+ return CheckGetValue(c);
2440
2056
  }
2441
2057
 
2442
2058
  /* Return the integer part of the number, as a BigDecimal.
@@ -2444,19 +2060,15 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2444
2060
  static VALUE
2445
2061
  BigDecimal_fix(VALUE self)
2446
2062
  {
2447
- ENTER(5);
2448
- Real *c, *a;
2449
- size_t mx;
2450
-
2451
- GUARD_OBJ(a, GetVpValue(self, 1));
2452
- mx = a->Prec *(VpBaseFig() + 1);
2453
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2454
- VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2455
- return VpCheckGetValue(c);
2063
+ BDVALUE a = GetBDValueMust(self);
2064
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2065
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
2066
+ RB_GC_GUARD(a.bigdecimal);
2067
+ return CheckGetValue(c);
2456
2068
  }
2457
2069
 
2458
2070
  /* call-seq:
2459
- * round(n, mode)
2071
+ * round(n, mode)
2460
2072
  *
2461
2073
  * Round to the nearest integer (by default), returning the result as a
2462
2074
  * BigDecimal if n is specified and positive, or as an Integer if it isn't.
@@ -2484,13 +2096,12 @@ BigDecimal_fix(VALUE self)
2484
2096
  static VALUE
2485
2097
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2486
2098
  {
2487
- ENTER(5);
2488
- Real *c, *a;
2099
+ BDVALUE c, a;
2489
2100
  int iLoc = 0;
2490
2101
  VALUE vLoc;
2491
2102
  VALUE vRound;
2492
2103
  int round_to_int = 0;
2493
- size_t mx, pl;
2104
+ size_t mx;
2494
2105
 
2495
2106
  unsigned short sw = VpGetRoundMode();
2496
2107
 
@@ -2521,20 +2132,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2521
2132
  break;
2522
2133
  }
2523
2134
 
2524
- pl = VpSetPrecLimit(0);
2525
- GUARD_OBJ(a, GetVpValue(self, 1));
2526
- mx = a->Prec * (VpBaseFig() + 1);
2527
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2528
- VpSetPrecLimit(pl);
2529
- VpActiveRound(c, a, sw, iLoc);
2135
+ a = GetBDValueMust(self);
2136
+ mx = (a.real->Prec + 1) * BASE_FIG;
2137
+ c = NewZeroWrap(1, mx);
2138
+
2139
+ VpActiveRound(c.real, a.real, sw, iLoc);
2140
+
2141
+ RB_GC_GUARD(a.bigdecimal);
2142
+
2530
2143
  if (round_to_int) {
2531
- return BigDecimal_to_i(VpCheckGetValue(c));
2144
+ return BigDecimal_to_i(CheckGetValue(c));
2532
2145
  }
2533
- return VpCheckGetValue(c);
2146
+ return CheckGetValue(c);
2147
+ }
2148
+
2149
+ static VALUE
2150
+ BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
2151
+ {
2152
+ BDVALUE c, a;
2153
+ int iLoc;
2154
+ VALUE vLoc;
2155
+ size_t mx;
2156
+
2157
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2158
+ iLoc = 0;
2159
+ }
2160
+ else {
2161
+ iLoc = NUM2INT(vLoc);
2162
+ }
2163
+
2164
+ a = GetBDValueMust(self);
2165
+ mx = (a.real->Prec + 1) * BASE_FIG;
2166
+ c = NewZeroWrap(1, mx);
2167
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
2168
+
2169
+ RB_GC_GUARD(a.bigdecimal);
2170
+
2171
+ if (argc == 0) {
2172
+ return BigDecimal_to_i(CheckGetValue(c));
2173
+ }
2174
+ return CheckGetValue(c);
2534
2175
  }
2535
2176
 
2536
2177
  /* call-seq:
2537
- * truncate(n)
2178
+ * truncate(n)
2538
2179
  *
2539
2180
  * Truncate to the nearest integer (by default), returning the result as a
2540
2181
  * BigDecimal.
@@ -2555,28 +2196,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2555
2196
  static VALUE
2556
2197
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2557
2198
  {
2558
- ENTER(5);
2559
- Real *c, *a;
2560
- int iLoc;
2561
- VALUE vLoc;
2562
- size_t mx, pl = VpSetPrecLimit(0);
2563
-
2564
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2565
- iLoc = 0;
2566
- }
2567
- else {
2568
- iLoc = NUM2INT(vLoc);
2569
- }
2570
-
2571
- GUARD_OBJ(a, GetVpValue(self, 1));
2572
- mx = a->Prec * (VpBaseFig() + 1);
2573
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2574
- VpSetPrecLimit(pl);
2575
- VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2576
- if (argc == 0) {
2577
- return BigDecimal_to_i(VpCheckGetValue(c));
2578
- }
2579
- return VpCheckGetValue(c);
2199
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2580
2200
  }
2581
2201
 
2582
2202
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2584,19 +2204,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2584
2204
  static VALUE
2585
2205
  BigDecimal_frac(VALUE self)
2586
2206
  {
2587
- ENTER(5);
2588
- Real *c, *a;
2589
- size_t mx;
2590
-
2591
- GUARD_OBJ(a, GetVpValue(self, 1));
2592
- mx = a->Prec * (VpBaseFig() + 1);
2593
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2594
- VpFrac(c, a);
2595
- return VpCheckGetValue(c);
2207
+ BDVALUE a = GetBDValueMust(self);
2208
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2209
+ VpFrac(c.real, a.real);
2210
+ RB_GC_GUARD(a.bigdecimal);
2211
+ return CheckGetValue(c);
2596
2212
  }
2597
2213
 
2598
2214
  /* call-seq:
2599
- * floor(n)
2215
+ * floor(n)
2600
2216
  *
2601
2217
  * Return the largest integer less than or equal to the value, as a BigDecimal.
2602
2218
  *
@@ -2615,35 +2231,11 @@ BigDecimal_frac(VALUE self)
2615
2231
  static VALUE
2616
2232
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2617
2233
  {
2618
- ENTER(5);
2619
- Real *c, *a;
2620
- int iLoc;
2621
- VALUE vLoc;
2622
- size_t mx, pl = VpSetPrecLimit(0);
2623
-
2624
- if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
2625
- iLoc = 0;
2626
- }
2627
- else {
2628
- iLoc = NUM2INT(vLoc);
2629
- }
2630
-
2631
- GUARD_OBJ(a, GetVpValue(self, 1));
2632
- mx = a->Prec * (VpBaseFig() + 1);
2633
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2634
- VpSetPrecLimit(pl);
2635
- VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2636
- #ifdef BIGDECIMAL_DEBUG
2637
- VPrint(stderr, "floor: c=%\n", c);
2638
- #endif
2639
- if (argc == 0) {
2640
- return BigDecimal_to_i(VpCheckGetValue(c));
2641
- }
2642
- return VpCheckGetValue(c);
2234
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2643
2235
  }
2644
2236
 
2645
2237
  /* call-seq:
2646
- * ceil(n)
2238
+ * ceil(n)
2647
2239
  *
2648
2240
  * Return the smallest integer greater than or equal to the value, as a BigDecimal.
2649
2241
  *
@@ -2662,31 +2254,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2662
2254
  static VALUE
2663
2255
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2664
2256
  {
2665
- ENTER(5);
2666
- Real *c, *a;
2667
- int iLoc;
2668
- VALUE vLoc;
2669
- size_t mx, pl = VpSetPrecLimit(0);
2670
-
2671
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2672
- iLoc = 0;
2673
- } else {
2674
- iLoc = NUM2INT(vLoc);
2675
- }
2676
-
2677
- GUARD_OBJ(a, GetVpValue(self, 1));
2678
- mx = a->Prec * (VpBaseFig() + 1);
2679
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2680
- VpSetPrecLimit(pl);
2681
- VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2682
- if (argc == 0) {
2683
- return BigDecimal_to_i(VpCheckGetValue(c));
2684
- }
2685
- return VpCheckGetValue(c);
2257
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2686
2258
  }
2687
2259
 
2688
2260
  /* call-seq:
2689
- * to_s(s)
2261
+ * to_s(s)
2690
2262
  *
2691
2263
  * Converts the value to a string.
2692
2264
  *
@@ -2703,7 +2275,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2703
2275
  * If s contains a number, a space is inserted after each group of that many
2704
2276
  * digits, starting from '.' and counting outwards.
2705
2277
  *
2706
- * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2278
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
2707
2279
  *
2708
2280
  * If s ends with an 'F', conventional floating point notation is used.
2709
2281
  *
@@ -2721,10 +2293,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2721
2293
  static VALUE
2722
2294
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2723
2295
  {
2724
- ENTER(5);
2725
2296
  int fmt = 0; /* 0: E format, 1: F format */
2726
2297
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2727
- Real *vp;
2298
+ BDVALUE v;
2728
2299
  volatile VALUE str;
2729
2300
  char *psz;
2730
2301
  char ch;
@@ -2732,7 +2303,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2732
2303
  SIGNED_VALUE m;
2733
2304
  VALUE f;
2734
2305
 
2735
- GUARD_OBJ(vp, GetVpValue(self, 1));
2306
+ v = GetBDValueMust(self);
2736
2307
 
2737
2308
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2738
2309
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2767,10 +2338,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2767
2338
  }
2768
2339
  }
2769
2340
  if (fmt) {
2770
- nc = VpNumOfChars(vp, "F");
2341
+ nc = VpNumOfChars(v.real, "F");
2771
2342
  }
2772
2343
  else {
2773
- nc = VpNumOfChars(vp, "E");
2344
+ nc = VpNumOfChars(v.real, "E");
2774
2345
  }
2775
2346
  if (mc > 0) {
2776
2347
  nc += (nc + mc - 1) / mc + 1;
@@ -2780,12 +2351,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2780
2351
  psz = RSTRING_PTR(str);
2781
2352
 
2782
2353
  if (fmt) {
2783
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2354
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
2784
2355
  }
2785
2356
  else {
2786
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2357
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
2787
2358
  }
2788
2359
  rb_str_resize(str, strlen(psz));
2360
+
2361
+ RB_GC_GUARD(v.bigdecimal);
2789
2362
  return str;
2790
2363
  }
2791
2364
 
@@ -2816,16 +2389,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2816
2389
  static VALUE
2817
2390
  BigDecimal_split(VALUE self)
2818
2391
  {
2819
- ENTER(5);
2820
- Real *vp;
2392
+ BDVALUE v;
2821
2393
  VALUE obj,str;
2822
2394
  ssize_t e, s;
2823
2395
  char *psz1;
2824
2396
 
2825
- GUARD_OBJ(vp, GetVpValue(self, 1));
2826
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2397
+ v = GetBDValueMust(self);
2398
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
2827
2399
  psz1 = RSTRING_PTR(str);
2828
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2400
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
2829
2401
  s = 1;
2830
2402
  if(psz1[0] == '-') {
2831
2403
  size_t len = strlen(psz1 + 1);
@@ -2835,13 +2407,15 @@ BigDecimal_split(VALUE self)
2835
2407
  s = -1;
2836
2408
  }
2837
2409
  if (psz1[0] == 'N') s = 0; /* NaN */
2838
- e = VpExponent10(vp);
2410
+ e = VpExponent10(v.real);
2839
2411
  obj = rb_ary_new2(4);
2840
2412
  rb_ary_push(obj, INT2FIX(s));
2841
2413
  rb_ary_push(obj, str);
2842
2414
  rb_str_resize(str, strlen(psz1));
2843
2415
  rb_ary_push(obj, INT2FIX(10));
2844
2416
  rb_ary_push(obj, SSIZET2NUM(e));
2417
+
2418
+ RB_GC_GUARD(v.bigdecimal);
2845
2419
  return obj;
2846
2420
  }
2847
2421
 
@@ -2853,7 +2427,7 @@ BigDecimal_split(VALUE self)
2853
2427
  static VALUE
2854
2428
  BigDecimal_exponent(VALUE self)
2855
2429
  {
2856
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2430
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
2857
2431
  return SSIZET2NUM(e);
2858
2432
  }
2859
2433
 
@@ -2865,49 +2439,78 @@ BigDecimal_exponent(VALUE self)
2865
2439
  static VALUE
2866
2440
  BigDecimal_inspect(VALUE self)
2867
2441
  {
2868
- ENTER(5);
2869
- Real *vp;
2442
+ BDVALUE v;
2870
2443
  volatile VALUE str;
2871
2444
  size_t nc;
2872
2445
 
2873
- GUARD_OBJ(vp, GetVpValue(self, 1));
2874
- nc = VpNumOfChars(vp, "E");
2446
+ v = GetBDValueMust(self);
2447
+ nc = VpNumOfChars(v.real, "E");
2875
2448
 
2876
2449
  str = rb_str_new(0, nc);
2877
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2450
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2878
2451
  rb_str_resize(str, strlen(RSTRING_PTR(str)));
2879
- return str;
2880
- }
2881
-
2882
- static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
2883
- static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
2884
-
2885
- #define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
2886
- #define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
2887
2452
 
2888
- inline static int
2889
- is_integer(VALUE x)
2890
- {
2891
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2453
+ RB_GC_GUARD(v.bigdecimal);
2454
+ return str;
2892
2455
  }
2893
2456
 
2894
- inline static int
2895
- is_negative(VALUE x)
2896
- {
2897
- if (FIXNUM_P(x)) {
2898
- return FIX2LONG(x) < 0;
2899
- }
2900
- else if (RB_TYPE_P(x, T_BIGNUM)) {
2901
- return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
2902
- }
2903
- else if (RB_TYPE_P(x, T_FLOAT)) {
2904
- return RFLOAT_VALUE(x) < 0.0;
2457
+ /* Returns self * 10**v without changing the precision.
2458
+ * This method is currently for internal use.
2459
+ *
2460
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2461
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2462
+ */
2463
+ static VALUE
2464
+ BigDecimal_decimal_shift(VALUE self, VALUE v)
2465
+ {
2466
+ BDVALUE a, c;
2467
+ ssize_t shift, exponentShift;
2468
+ bool shiftDown;
2469
+ size_t prec;
2470
+ DECDIG ex, iex;
2471
+
2472
+ a = GetBDValueMust(self);
2473
+ shift = NUM2SSIZET(rb_to_int(v));
2474
+
2475
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
2476
+
2477
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
2478
+ shift -= exponentShift * BASE_FIG;
2479
+ ex = 1;
2480
+ for (int i = 0; i < shift; i++) ex *= 10;
2481
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
2482
+ iex = BASE / ex;
2483
+
2484
+ prec = a.real->Prec + shiftDown;
2485
+ c = NewZeroWrap(1, prec * BASE_FIG);
2486
+ if (shift == 0) {
2487
+ VpAsgn(c.real, a.real, 1);
2488
+ } else if (shiftDown) {
2489
+ DECDIG carry = 0;
2490
+ exponentShift++;
2491
+ for (size_t i = 0; i < a.real->Prec; i++) {
2492
+ DECDIG v = a.real->frac[i];
2493
+ c.real->frac[i] = carry * ex + v / iex;
2494
+ carry = v % iex;
2495
+ }
2496
+ c.real->frac[a.real->Prec] = carry * ex;
2497
+ } else {
2498
+ DECDIG carry = 0;
2499
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
2500
+ DECDIG v = a.real->frac[i];
2501
+ c.real->frac[i] = v % iex * ex + carry;
2502
+ carry = v / iex;
2503
+ }
2905
2504
  }
2906
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2505
+ while (c.real->frac[prec - 1] == 0) prec--;
2506
+ c.real->Prec = prec;
2507
+ c.real->sign = a.real->sign;
2508
+ c.real->exponent = a.real->exponent;
2509
+ AddExponent(c.real, exponentShift);
2510
+ RB_GC_GUARD(a.bigdecimal);
2511
+ return CheckGetValue(c);
2907
2512
  }
2908
2513
 
2909
- #define is_positive(x) (!is_negative(x))
2910
-
2911
2514
  inline static int
2912
2515
  is_zero(VALUE x)
2913
2516
  {
@@ -2931,344 +2534,6 @@ is_zero(VALUE x)
2931
2534
  return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2932
2535
  }
2933
2536
 
2934
- inline static int
2935
- is_one(VALUE x)
2936
- {
2937
- VALUE num, den;
2938
-
2939
- switch (TYPE(x)) {
2940
- case T_FIXNUM:
2941
- return FIX2LONG(x) == 1;
2942
-
2943
- case T_BIGNUM:
2944
- return Qfalse;
2945
-
2946
- case T_RATIONAL:
2947
- num = rb_rational_num(x);
2948
- den = rb_rational_den(x);
2949
- return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
2950
- FIXNUM_P(num) && FIX2LONG(num) == 1;
2951
-
2952
- default:
2953
- break;
2954
- }
2955
-
2956
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
2957
- }
2958
-
2959
- inline static int
2960
- is_even(VALUE x)
2961
- {
2962
- switch (TYPE(x)) {
2963
- case T_FIXNUM:
2964
- return (FIX2LONG(x) % 2) == 0;
2965
-
2966
- case T_BIGNUM:
2967
- {
2968
- unsigned long l;
2969
- rb_big_pack(x, &l, 1);
2970
- return l % 2 == 0;
2971
- }
2972
-
2973
- default:
2974
- break;
2975
- }
2976
-
2977
- return 0;
2978
- }
2979
-
2980
- static VALUE
2981
- bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2982
- {
2983
- VALUE log_x, multiplied, y;
2984
- volatile VALUE obj = exp->obj;
2985
-
2986
- if (VpIsZero(exp)) {
2987
- return VpCheckGetValue(NewOneWrapLimited(1, n));
2988
- }
2989
-
2990
- log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
2991
- multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
2992
- y = BigMath_exp(multiplied, SSIZET2NUM(n));
2993
- RB_GC_GUARD(obj);
2994
-
2995
- return y;
2996
- }
2997
-
2998
- /* call-seq:
2999
- * power(n)
3000
- * power(n, prec)
3001
- *
3002
- * Returns the value raised to the power of n.
3003
- *
3004
- * Note that n must be an Integer.
3005
- *
3006
- * Also available as the operator **.
3007
- */
3008
- static VALUE
3009
- BigDecimal_power(int argc, VALUE*argv, VALUE self)
3010
- {
3011
- ENTER(5);
3012
- VALUE vexp, prec;
3013
- Real* exp = NULL;
3014
- Real *x, *y;
3015
- ssize_t mp, ma, n;
3016
- SIGNED_VALUE int_exp;
3017
- double d;
3018
-
3019
- rb_scan_args(argc, argv, "11", &vexp, &prec);
3020
-
3021
- GUARD_OBJ(x, GetVpValue(self, 1));
3022
- n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
3023
-
3024
- if (VpIsNaN(x)) {
3025
- y = NewZeroWrapLimited(1, n);
3026
- VpSetNaN(y);
3027
- RB_GC_GUARD(y->obj);
3028
- return VpCheckGetValue(y);
3029
- }
3030
-
3031
- retry:
3032
- switch (TYPE(vexp)) {
3033
- case T_FIXNUM:
3034
- break;
3035
-
3036
- case T_BIGNUM:
3037
- break;
3038
-
3039
- case T_FLOAT:
3040
- d = RFLOAT_VALUE(vexp);
3041
- if (d == round(d)) {
3042
- if (FIXABLE(d)) {
3043
- vexp = LONG2FIX((long)d);
3044
- }
3045
- else {
3046
- vexp = rb_dbl2big(d);
3047
- }
3048
- goto retry;
3049
- }
3050
- if (NIL_P(prec)) {
3051
- n += BIGDECIMAL_DOUBLE_FIGURES;
3052
- }
3053
- exp = GetVpValueWithPrec(vexp, 0, 1);
3054
- break;
3055
-
3056
- case T_RATIONAL:
3057
- if (is_zero(rb_rational_num(vexp))) {
3058
- if (is_positive(vexp)) {
3059
- vexp = INT2FIX(0);
3060
- goto retry;
3061
- }
3062
- }
3063
- else if (is_one(rb_rational_den(vexp))) {
3064
- vexp = rb_rational_num(vexp);
3065
- goto retry;
3066
- }
3067
- exp = GetVpValueWithPrec(vexp, n, 1);
3068
- if (NIL_P(prec)) {
3069
- n += n;
3070
- }
3071
- break;
3072
-
3073
- case T_DATA:
3074
- if (is_kind_of_BigDecimal(vexp)) {
3075
- VALUE zero = INT2FIX(0);
3076
- VALUE rounded = BigDecimal_round(1, &zero, vexp);
3077
- if (RTEST(BigDecimal_eq(vexp, rounded))) {
3078
- vexp = BigDecimal_to_i(vexp);
3079
- goto retry;
3080
- }
3081
- if (NIL_P(prec)) {
3082
- GUARD_OBJ(y, GetVpValue(vexp, 1));
3083
- n += y->Prec*VpBaseFig();
3084
- }
3085
- exp = DATA_PTR(vexp);
3086
- break;
3087
- }
3088
- /* fall through */
3089
- default:
3090
- rb_raise(rb_eTypeError,
3091
- "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
3092
- RB_OBJ_CLASSNAME(vexp));
3093
- }
3094
-
3095
- if (VpIsZero(x)) {
3096
- if (is_negative(vexp)) {
3097
- y = NewZeroWrapNolimit(1, n);
3098
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3099
- if (is_integer(vexp)) {
3100
- if (is_even(vexp)) {
3101
- /* (-0) ** (-even_integer) -> Infinity */
3102
- VpSetPosInf(y);
3103
- }
3104
- else {
3105
- /* (-0) ** (-odd_integer) -> -Infinity */
3106
- VpSetNegInf(y);
3107
- }
3108
- }
3109
- else {
3110
- /* (-0) ** (-non_integer) -> Infinity */
3111
- VpSetPosInf(y);
3112
- }
3113
- }
3114
- else {
3115
- /* (+0) ** (-num) -> Infinity */
3116
- VpSetPosInf(y);
3117
- }
3118
- RB_GC_GUARD(y->obj);
3119
- return VpCheckGetValue(y);
3120
- }
3121
- else if (is_zero(vexp)) {
3122
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3123
- }
3124
- else {
3125
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3126
- }
3127
- }
3128
-
3129
- if (is_zero(vexp)) {
3130
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3131
- }
3132
- else if (is_one(vexp)) {
3133
- return self;
3134
- }
3135
-
3136
- if (VpIsInf(x)) {
3137
- if (is_negative(vexp)) {
3138
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3139
- if (is_integer(vexp)) {
3140
- if (is_even(vexp)) {
3141
- /* (-Infinity) ** (-even_integer) -> +0 */
3142
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3143
- }
3144
- else {
3145
- /* (-Infinity) ** (-odd_integer) -> -0 */
3146
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3147
- }
3148
- }
3149
- else {
3150
- /* (-Infinity) ** (-non_integer) -> -0 */
3151
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3152
- }
3153
- }
3154
- else {
3155
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3156
- }
3157
- }
3158
- else {
3159
- y = NewZeroWrapLimited(1, n);
3160
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3161
- if (is_integer(vexp)) {
3162
- if (is_even(vexp)) {
3163
- VpSetPosInf(y);
3164
- }
3165
- else {
3166
- VpSetNegInf(y);
3167
- }
3168
- }
3169
- else {
3170
- /* TODO: support complex */
3171
- rb_raise(rb_eMathDomainError,
3172
- "a non-integral exponent for a negative base");
3173
- }
3174
- }
3175
- else {
3176
- VpSetPosInf(y);
3177
- }
3178
- return VpCheckGetValue(y);
3179
- }
3180
- }
3181
-
3182
- if (exp != NULL) {
3183
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3184
- }
3185
- else if (RB_TYPE_P(vexp, T_BIGNUM)) {
3186
- VALUE abs_value = BigDecimal_abs(self);
3187
- if (is_one(abs_value)) {
3188
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3189
- }
3190
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
3191
- if (is_negative(vexp)) {
3192
- y = NewZeroWrapLimited(1, n);
3193
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3194
- return VpCheckGetValue(y);
3195
- }
3196
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3197
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3198
- }
3199
- else {
3200
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3201
- }
3202
- }
3203
- else {
3204
- if (is_positive(vexp)) {
3205
- y = NewZeroWrapLimited(1, n);
3206
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3207
- return VpCheckGetValue(y);
3208
- }
3209
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3210
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3211
- }
3212
- else {
3213
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3214
- }
3215
- }
3216
- }
3217
-
3218
- int_exp = FIX2LONG(vexp);
3219
- ma = int_exp;
3220
- if (ma < 0) ma = -ma;
3221
- if (ma == 0) ma = 1;
3222
-
3223
- if (VpIsDef(x)) {
3224
- mp = x->Prec * (VpBaseFig() + 1);
3225
- GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
3226
- }
3227
- else {
3228
- GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3229
- }
3230
- VpPowerByInt(y, x, int_exp);
3231
- if (!NIL_P(prec) && VpIsDef(y)) {
3232
- VpMidRound(y, VpGetRoundMode(), n);
3233
- }
3234
- return VpCheckGetValue(y);
3235
- }
3236
-
3237
- /* call-seq:
3238
- * self ** other -> bigdecimal
3239
- *
3240
- * Returns the \BigDecimal value of +self+ raised to power +other+:
3241
- *
3242
- * b = BigDecimal('3.14')
3243
- * b ** 2 # => 0.98596e1
3244
- * b ** 2.0 # => 0.98596e1
3245
- * b ** Rational(2, 1) # => 0.98596e1
3246
- *
3247
- * Related: BigDecimal#power.
3248
- *
3249
- */
3250
- static VALUE
3251
- BigDecimal_power_op(VALUE self, VALUE exp)
3252
- {
3253
- return BigDecimal_power(1, &exp, self);
3254
- }
3255
-
3256
- /* :nodoc:
3257
- *
3258
- * private method for dup and clone the provided BigDecimal +other+
3259
- */
3260
- static VALUE
3261
- BigDecimal_initialize_copy(VALUE self, VALUE other)
3262
- {
3263
- Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
3264
- Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
3265
-
3266
- if (self != other) {
3267
- DATA_PTR(self) = VpCopy(pv, x);
3268
- }
3269
- return self;
3270
- }
3271
-
3272
2537
  /* :nodoc: */
3273
2538
  static VALUE
3274
2539
  BigDecimal_clone(VALUE self)
@@ -3307,20 +2572,17 @@ check_exception(VALUE bd)
3307
2572
 
3308
2573
  Real *vp;
3309
2574
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3310
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2575
+ VpCheckException(vp, false);
3311
2576
 
3312
2577
  return bd;
3313
2578
  }
3314
2579
 
3315
2580
  static VALUE
3316
- rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
2581
+ rb_uint64_convert_to_BigDecimal(uint64_t uval)
3317
2582
  {
3318
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3319
-
3320
2583
  Real *vp;
3321
2584
  if (uval == 0) {
3322
2585
  vp = rbd_allocate_struct(1);
3323
- vp->MaxPrec = 1;
3324
2586
  vp->Prec = 1;
3325
2587
  vp->exponent = 1;
3326
2588
  VpSetZero(vp, 1);
@@ -3328,7 +2590,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3328
2590
  }
3329
2591
  else if (uval < BASE) {
3330
2592
  vp = rbd_allocate_struct(1);
3331
- vp->MaxPrec = 1;
3332
2593
  vp->Prec = 1;
3333
2594
  vp->exponent = 1;
3334
2595
  VpSetSign(vp, 1);
@@ -3354,21 +2615,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3354
2615
 
3355
2616
  const size_t exp = len + ntz;
3356
2617
  vp = rbd_allocate_struct(len);
3357
- vp->MaxPrec = len;
3358
2618
  vp->Prec = len;
3359
2619
  vp->exponent = exp;
3360
2620
  VpSetSign(vp, 1);
3361
2621
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3362
2622
  }
3363
2623
 
3364
- return BigDecimal_wrap_struct(obj, vp);
2624
+ return BigDecimal_wrap_struct(rb_cBigDecimal, vp);
3365
2625
  }
3366
2626
 
3367
2627
  static VALUE
3368
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2628
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3369
2629
  {
3370
2630
  const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
3371
- VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception);
2631
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3372
2632
  if (ival < 0) {
3373
2633
  Real *vp;
3374
2634
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
@@ -3378,7 +2638,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
3378
2638
  }
3379
2639
 
3380
2640
  static VALUE
3381
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2641
+ rb_big_convert_to_BigDecimal(VALUE val)
3382
2642
  {
3383
2643
  assert(RB_TYPE_P(val, T_BIGNUM));
3384
2644
 
@@ -3390,40 +2650,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3390
2650
  }
3391
2651
  if (size <= sizeof(long)) {
3392
2652
  if (sign < 0) {
3393
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2653
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3394
2654
  }
3395
2655
  else {
3396
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2656
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3397
2657
  }
3398
2658
  }
3399
2659
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3400
2660
  else if (size <= sizeof(LONG_LONG)) {
3401
2661
  if (sign < 0) {
3402
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2662
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3403
2663
  }
3404
2664
  else {
3405
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2665
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3406
2666
  }
3407
2667
  }
3408
2668
  #endif
3409
2669
  else {
3410
2670
  VALUE str = rb_big2str(val, 10);
3411
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3412
- RSTRING_PTR(str), true);
2671
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2672
+ RSTRING_PTR(str),
2673
+ rb_cBigDecimal,
2674
+ true,
2675
+ true
2676
+ ));
3413
2677
  RB_GC_GUARD(str);
3414
- return check_exception(vp->obj);
2678
+ return CheckGetValue(v);
3415
2679
  }
3416
2680
  }
3417
2681
 
3418
2682
  static VALUE
3419
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2683
+ rb_inum_convert_to_BigDecimal(VALUE val)
3420
2684
  {
3421
2685
  assert(RB_INTEGER_TYPE_P(val));
3422
2686
  if (FIXNUM_P(val)) {
3423
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2687
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3424
2688
  }
3425
2689
  else {
3426
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2690
+ return rb_big_convert_to_BigDecimal(val);
3427
2691
  }
3428
2692
  }
3429
2693
 
@@ -3458,11 +2722,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3458
2722
  }
3459
2723
 
3460
2724
  if (digs == SIZE_MAX) {
3461
- if (!raise_exception)
3462
- return Qnil;
3463
- rb_raise(rb_eArgError,
3464
- "can't omit precision for a %"PRIsVALUE".",
3465
- CLASS_OF(val));
2725
+ digs = 0;
3466
2726
  }
3467
2727
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3468
2728
  if (!raise_exception)
@@ -3577,7 +2837,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3577
2837
  exp = -exp;
3578
2838
  }
3579
2839
 
3580
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
2840
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
3581
2841
  Real *vp;
3582
2842
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3583
2843
  assert(vp->Prec == prec);
@@ -3600,28 +2860,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3600
2860
  CLASS_OF(val));
3601
2861
  }
3602
2862
 
3603
- VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
2863
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
3604
2864
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3605
2865
  return d;
3606
2866
  }
3607
2867
 
3608
2868
  static VALUE
3609
- rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
2869
+ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
3610
2870
  {
3611
- if (digs == SIZE_MAX)
3612
- digs = 0;
3613
-
3614
- Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
3615
- if (!vp)
3616
- return Qnil;
3617
- return VpCheckGetValue(vp);
2871
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
2872
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
2873
+ return CheckGetValue(bdvalue_nonnullable(v));
3618
2874
  }
3619
2875
 
3620
2876
  static inline VALUE
3621
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2877
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3622
2878
  {
3623
2879
  const char *c_str = StringValueCStr(val);
3624
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2880
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3625
2881
  }
3626
2882
 
3627
2883
  static VALUE
@@ -3651,15 +2907,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3651
2907
 
3652
2908
  Real *vp;
3653
2909
  TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
3654
-
3655
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3656
2910
  vp = VpCopy(NULL, vp);
2911
+ RB_GC_GUARD(val);
2912
+
2913
+ VALUE copy = BigDecimal_wrap_struct(rb_cBigDecimal, vp);
3657
2914
  /* TODO: rounding */
3658
- BigDecimal_wrap_struct(copy, vp);
3659
- return VpCheckGetValue(vp);
2915
+ return check_exception(copy);
3660
2916
  }
3661
2917
  else if (RB_INTEGER_TYPE_P(val)) {
3662
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2918
+ return rb_inum_convert_to_BigDecimal(val);
3663
2919
  }
3664
2920
  else if (RB_FLOAT_TYPE_P(val)) {
3665
2921
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3677,7 +2933,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3677
2933
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3678
2934
  }
3679
2935
  else if (RB_TYPE_P(val, T_STRING)) {
3680
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2936
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3681
2937
  }
3682
2938
 
3683
2939
  /* TODO: chheck to_d */
@@ -3691,7 +2947,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3691
2947
  }
3692
2948
  return Qnil;
3693
2949
  }
3694
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2950
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3695
2951
  }
3696
2952
 
3697
2953
  /* call-seq:
@@ -3712,12 +2968,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3712
2968
  *
3713
2969
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3714
2970
  *
3715
- * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
2971
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
3716
2972
  * BigDecimal(2) # => 0.2e1
3717
2973
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3718
2974
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3719
- * # Float or Rational value requires ndigits.
3720
- * BigDecimal(2.0, 0) # => 0.2e1
2975
+ * BigDecimal(2.0) # => 0.2e1
2976
+ * # Rational value requires ndigits.
3721
2977
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3722
2978
  *
3723
2979
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3781,15 +3037,16 @@ static VALUE
3781
3037
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3782
3038
  {
3783
3039
  char const *c_str = StringValueCStr(str);
3784
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3785
- if (!vp)
3040
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3041
+ if (v.bigdecimal_or_nil == Qnil)
3786
3042
  return Qnil;
3787
3043
  else
3788
- return VpCheckGetValue(vp);
3044
+ return CheckGetValue(bdvalue_nonnullable(v));
3789
3045
  }
3790
3046
 
3791
- /* call-seq:
3792
- * BigDecimal.limit(digits)
3047
+ /*
3048
+ * call-seq:
3049
+ * BigDecimal.limit(digits)
3793
3050
  *
3794
3051
  * Limit the number of significant digits in newly created BigDecimal
3795
3052
  * numbers to the specified value. Rounding is performed as necessary,
@@ -3839,7 +3096,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3839
3096
  static VALUE
3840
3097
  BigDecimal_sign(VALUE self)
3841
3098
  { /* sign */
3842
- int s = GetVpValue(self, 1)->sign;
3099
+ int s = GetSelfVpValue(self)->sign;
3843
3100
  return INT2FIX(s);
3844
3101
  }
3845
3102
 
@@ -3911,310 +3168,15 @@ BigDecimal_save_rounding_mode(VALUE self)
3911
3168
  * puts BigDecimal.limit
3912
3169
  *
3913
3170
  */
3914
- static VALUE
3915
- BigDecimal_save_limit(VALUE self)
3916
- {
3917
- size_t const limit = VpGetPrecLimit();
3918
- int state;
3919
- VALUE ret = rb_protect(rb_yield, Qnil, &state);
3920
- VpSetPrecLimit(limit);
3921
- if (state) rb_jump_tag(state);
3922
- return ret;
3923
- }
3924
-
3925
- /* call-seq:
3926
- * BigMath.exp(decimal, numeric) -> BigDecimal
3927
- *
3928
- * Computes the value of e (the base of natural logarithms) raised to the
3929
- * power of +decimal+, to the specified number of digits of precision.
3930
- *
3931
- * If +decimal+ is infinity, returns Infinity.
3932
- *
3933
- * If +decimal+ is NaN, returns NaN.
3934
- */
3935
- static VALUE
3936
- BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3937
- {
3938
- ssize_t prec, n, i;
3939
- Real* vx = NULL;
3940
- VALUE one, d, y;
3941
- int negative = 0;
3942
- int infinite = 0;
3943
- int nan = 0;
3944
- double flo;
3945
-
3946
- prec = NUM2SSIZET(vprec);
3947
- if (prec <= 0) {
3948
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
3949
- }
3950
-
3951
- /* TODO: the following switch statement is almost same as one in the
3952
- * BigDecimalCmp function. */
3953
- switch (TYPE(x)) {
3954
- case T_DATA:
3955
- if (!is_kind_of_BigDecimal(x)) break;
3956
- vx = DATA_PTR(x);
3957
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3958
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3959
- nan = VpIsNaN(vx);
3960
- break;
3961
-
3962
- case T_FIXNUM:
3963
- /* fall through */
3964
- case T_BIGNUM:
3965
- vx = GetVpValue(x, 0);
3966
- break;
3967
-
3968
- case T_FLOAT:
3969
- flo = RFLOAT_VALUE(x);
3970
- negative = flo < 0;
3971
- infinite = isinf(flo);
3972
- nan = isnan(flo);
3973
- if (!infinite && !nan) {
3974
- vx = GetVpValueWithPrec(x, 0, 0);
3975
- }
3976
- break;
3977
-
3978
- case T_RATIONAL:
3979
- vx = GetVpValueWithPrec(x, prec, 0);
3980
- break;
3981
-
3982
- default:
3983
- break;
3984
- }
3985
- if (infinite) {
3986
- if (negative) {
3987
- return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3988
- }
3989
- else {
3990
- Real* vy = NewZeroWrapNolimit(1, prec);
3991
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3992
- RB_GC_GUARD(vy->obj);
3993
- return VpCheckGetValue(vy);
3994
- }
3995
- }
3996
- else if (nan) {
3997
- Real* vy = NewZeroWrapNolimit(1, prec);
3998
- VpSetNaN(vy);
3999
- RB_GC_GUARD(vy->obj);
4000
- return VpCheckGetValue(vy);
4001
- }
4002
- else if (vx == NULL) {
4003
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4004
- }
4005
- x = vx->obj;
4006
-
4007
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4008
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4009
- if (negative) {
4010
- VALUE x_zero = INT2NUM(1);
4011
- VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
4012
- x = BigDecimal_initialize_copy(x_copy, x);
4013
- vx = DATA_PTR(x);
4014
- VpSetSign(vx, 1);
4015
- }
4016
-
4017
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4018
- y = one;
4019
- d = y;
4020
- i = 1;
4021
-
4022
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4023
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4024
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4025
- ssize_t m = n - vabs(ey - ed);
4026
-
4027
- rb_thread_check_ints();
4028
-
4029
- if (m <= 0) {
4030
- break;
4031
- }
4032
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4033
- m = BIGDECIMAL_DOUBLE_FIGURES;
4034
- }
4035
-
4036
- d = BigDecimal_mult(d, x); /* d <- d * x */
4037
- d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
4038
- y = BigDecimal_add(y, d); /* y <- y + d */
4039
- ++i; /* i <- i + 1 */
4040
- }
4041
-
4042
- if (negative) {
4043
- return BigDecimal_div2(one, y, vprec);
4044
- }
4045
- else {
4046
- vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
4047
- return BigDecimal_round(1, &vprec, y);
4048
- }
4049
-
4050
- RB_GC_GUARD(one);
4051
- RB_GC_GUARD(x);
4052
- RB_GC_GUARD(y);
4053
- RB_GC_GUARD(d);
4054
- }
4055
-
4056
- /* call-seq:
4057
- * BigMath.log(decimal, numeric) -> BigDecimal
4058
- *
4059
- * Computes the natural logarithm of +decimal+ to the specified number of
4060
- * digits of precision, +numeric+.
4061
- *
4062
- * If +decimal+ is zero or negative, raises Math::DomainError.
4063
- *
4064
- * If +decimal+ is positive infinity, returns Infinity.
4065
- *
4066
- * If +decimal+ is NaN, returns NaN.
4067
- */
4068
- static VALUE
4069
- BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
4070
- {
4071
- ssize_t prec, n, i;
4072
- SIGNED_VALUE expo;
4073
- Real* vx = NULL;
4074
- VALUE vn, one, two, w, x2, y, d;
4075
- int zero = 0;
4076
- int negative = 0;
4077
- int infinite = 0;
4078
- int nan = 0;
4079
- double flo;
4080
- long fix;
4081
-
4082
- if (!is_integer(vprec)) {
4083
- rb_raise(rb_eArgError, "precision must be an Integer");
4084
- }
4085
-
4086
- prec = NUM2SSIZET(vprec);
4087
- if (prec <= 0) {
4088
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
4089
- }
4090
-
4091
- /* TODO: the following switch statement is almost same as one in the
4092
- * BigDecimalCmp function. */
4093
- switch (TYPE(x)) {
4094
- case T_DATA:
4095
- if (!is_kind_of_BigDecimal(x)) break;
4096
- vx = DATA_PTR(x);
4097
- zero = VpIsZero(vx);
4098
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4099
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
4100
- nan = VpIsNaN(vx);
4101
- break;
4102
-
4103
- case T_FIXNUM:
4104
- fix = FIX2LONG(x);
4105
- zero = fix == 0;
4106
- negative = fix < 0;
4107
- goto get_vp_value;
4108
-
4109
- case T_BIGNUM:
4110
- i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
4111
- zero = i == 0;
4112
- negative = i < 0;
4113
- get_vp_value:
4114
- if (zero || negative) break;
4115
- vx = GetVpValue(x, 0);
4116
- break;
4117
-
4118
- case T_FLOAT:
4119
- flo = RFLOAT_VALUE(x);
4120
- zero = flo == 0;
4121
- negative = flo < 0;
4122
- infinite = isinf(flo);
4123
- nan = isnan(flo);
4124
- if (!zero && !negative && !infinite && !nan) {
4125
- vx = GetVpValueWithPrec(x, 0, 1);
4126
- }
4127
- break;
4128
-
4129
- case T_RATIONAL:
4130
- zero = RRATIONAL_ZERO_P(x);
4131
- negative = RRATIONAL_NEGATIVE_P(x);
4132
- if (zero || negative) break;
4133
- vx = GetVpValueWithPrec(x, prec, 1);
4134
- break;
4135
-
4136
- case T_COMPLEX:
4137
- rb_raise(rb_eMathDomainError,
4138
- "Complex argument for BigMath.log");
4139
-
4140
- default:
4141
- break;
4142
- }
4143
- if (infinite && !negative) {
4144
- Real *vy = NewZeroWrapNolimit(1, prec);
4145
- RB_GC_GUARD(vy->obj);
4146
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
4147
- return VpCheckGetValue(vy);
4148
- }
4149
- else if (nan) {
4150
- Real* vy = NewZeroWrapNolimit(1, prec);
4151
- RB_GC_GUARD(vy->obj);
4152
- VpSetNaN(vy);
4153
- return VpCheckGetValue(vy);
4154
- }
4155
- else if (zero || negative) {
4156
- rb_raise(rb_eMathDomainError,
4157
- "Zero or negative argument for log");
4158
- }
4159
- else if (vx == NULL) {
4160
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4161
- }
4162
- x = VpCheckGetValue(vx);
4163
-
4164
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4165
- two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4166
-
4167
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4168
- vn = SSIZET2NUM(n);
4169
- expo = VpExponent10(vx);
4170
- if (expo < 0 || expo >= 3) {
4171
- char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
4172
- snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
4173
- x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
4174
- }
4175
- else {
4176
- expo = 0;
4177
- }
4178
- w = BigDecimal_sub(x, one);
4179
- x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
4180
- x2 = BigDecimal_mult2(x, x, vn);
4181
- y = x;
4182
- d = y;
4183
- i = 1;
4184
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4185
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4186
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4187
- ssize_t m = n - vabs(ey - ed);
4188
- if (m <= 0) {
4189
- break;
4190
- }
4191
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4192
- m = BIGDECIMAL_DOUBLE_FIGURES;
4193
- }
4194
-
4195
- x = BigDecimal_mult2(x2, x, vn);
4196
- i += 2;
4197
- d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
4198
- y = BigDecimal_add(y, d);
4199
- }
4200
-
4201
- y = BigDecimal_mult(y, two);
4202
- if (expo != 0) {
4203
- VALUE log10, vexpo, dy;
4204
- log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
4205
- vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
4206
- dy = BigDecimal_mult(log10, vexpo);
4207
- y = BigDecimal_add(y, dy);
4208
- }
4209
-
4210
- RB_GC_GUARD(one);
4211
- RB_GC_GUARD(two);
4212
- RB_GC_GUARD(vn);
4213
- RB_GC_GUARD(x2);
4214
- RB_GC_GUARD(y);
4215
- RB_GC_GUARD(d);
4216
-
4217
- return y;
3171
+ static VALUE
3172
+ BigDecimal_save_limit(VALUE self)
3173
+ {
3174
+ size_t const limit = VpGetPrecLimit();
3175
+ int state;
3176
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
3177
+ VpSetPrecLimit(limit);
3178
+ if (state) rb_jump_tag(state);
3179
+ return ret;
4218
3180
  }
4219
3181
 
4220
3182
  static VALUE BIGDECIMAL_NAN = Qnil;
@@ -4268,6 +3230,34 @@ BigDecimal_literal(const char *str)
4268
3230
 
4269
3231
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4270
3232
 
3233
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3234
+ VALUE
3235
+ BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3236
+ BDVALUE a,b,c,d;
3237
+ size_t cn = NUM2INT(cprec);
3238
+ a = GetBDValueMust(self);
3239
+ b = GetBDValueMust(r);
3240
+ c = NewZeroWrap(1, cn * BASE_FIG);
3241
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3242
+ VpDivd(c.real, d.real, a.real, b.real);
3243
+ RB_GC_GUARD(a.bigdecimal);
3244
+ RB_GC_GUARD(b.bigdecimal);
3245
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3246
+ }
3247
+
3248
+ VALUE
3249
+ BigDecimal_vpmult(VALUE self, VALUE v) {
3250
+ BDVALUE a,b,c;
3251
+ a = GetBDValueMust(self);
3252
+ b = GetBDValueMust(v);
3253
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3254
+ VpMult(c.real, a.real, b.real);
3255
+ RB_GC_GUARD(a.bigdecimal);
3256
+ RB_GC_GUARD(b.bigdecimal);
3257
+ return c.bigdecimal;
3258
+ }
3259
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3260
+
4271
3261
  /* Document-class: BigDecimal
4272
3262
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4273
3263
  *
@@ -4384,14 +3374,16 @@ BigDecimal_literal(const char *str)
4384
3374
  *
4385
3375
  * When you require +bigdecimal/util+, the #to_d method will be
4386
3376
  * available on BigDecimal and the native Integer, Float, Rational,
4387
- * and String classes:
3377
+ * String, Complex, and NilClass classes:
4388
3378
  *
4389
3379
  * require 'bigdecimal/util'
4390
3380
  *
4391
- * 42.to_d # => 0.42e2
4392
- * 0.5.to_d # => 0.5e0
4393
- * (2/3r).to_d(3) # => 0.667e0
4394
- * "0.5".to_d # => 0.5e0
3381
+ * 42.to_d # => 0.42e2
3382
+ * 0.5.to_d # => 0.5e0
3383
+ * (2/3r).to_d(3) # => 0.667e0
3384
+ * "0.5".to_d # => 0.5e0
3385
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
3386
+ * nil.to_d # => 0.0
4395
3387
  *
4396
3388
  * == Methods for Working with \JSON
4397
3389
  *
@@ -4465,7 +3457,7 @@ Init_bigdecimal(void)
4465
3457
  * guarantee that two groups could always be multiplied together without
4466
3458
  * overflow.)
4467
3459
  */
4468
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3460
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4469
3461
 
4470
3462
  /* Exceptions */
4471
3463
 
@@ -4607,14 +3599,11 @@ Init_bigdecimal(void)
4607
3599
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4608
3600
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4609
3601
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4610
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4611
3602
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4612
3603
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4613
3604
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4614
3605
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4615
3606
  rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
4616
- rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
4617
- rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
4618
3607
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4619
3608
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4620
3609
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4633,11 +3622,13 @@ Init_bigdecimal(void)
4633
3622
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4634
3623
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4635
3624
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3625
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4636
3626
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4637
3627
 
4638
- rb_mBigMath = rb_define_module("BigMath");
4639
- rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4640
- rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
3628
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3629
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
3630
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3631
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
4641
3632
 
4642
3633
  #define ROUNDING_MODE(i, name, value) \
4643
3634
  id_##name = rb_intern_const(#name); \
@@ -4677,19 +3668,9 @@ Init_bigdecimal(void)
4677
3668
  */
4678
3669
  #ifdef BIGDECIMAL_DEBUG
4679
3670
  static int gfDebug = 1; /* Debug switch */
4680
- #if 0
4681
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4682
- #endif
4683
3671
  #endif /* BIGDECIMAL_DEBUG */
4684
3672
 
4685
3673
  static Real *VpConstOne; /* constant 1.0 */
4686
- static Real *VpConstPt5; /* constant 0.5 */
4687
- #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4688
- /* used in VpSqrt() */
4689
-
4690
- /* ETC */
4691
- #define MemCmp(x,y,z) memcmp(x,y,z)
4692
- #define StrCmp(x,y) strcmp(x,y)
4693
3674
 
4694
3675
  enum op_sw {
4695
3676
  OP_SW_ADD = 1, /* + */
@@ -4699,11 +3680,9 @@ enum op_sw {
4699
3680
  };
4700
3681
 
4701
3682
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4702
- static int AddExponent(Real *a, SIGNED_VALUE n);
4703
3683
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4704
3684
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4705
3685
  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);
4706
- static int VpNmlz(Real *a);
4707
3686
  static void VpFormatSt(char *psz, size_t fFmt);
4708
3687
  static int VpRdup(Real *m, size_t ind_m);
4709
3688
 
@@ -4762,10 +3741,10 @@ VpCheckException(Real *p, bool always)
4762
3741
  }
4763
3742
 
4764
3743
  static VALUE
4765
- VpCheckGetValue(Real *p)
3744
+ CheckGetValue(BDVALUE v)
4766
3745
  {
4767
- VpCheckException(p, false);
4768
- return p->obj;
3746
+ VpCheckException(v.real, false);
3747
+ return v.bigdecimal;
4769
3748
  }
4770
3749
 
4771
3750
  /*
@@ -4797,12 +3776,10 @@ VpGetPrecLimit(void)
4797
3776
  return NUM2SIZET(vlimit);
4798
3777
  }
4799
3778
 
4800
- VP_EXPORT size_t
3779
+ VP_EXPORT void
4801
3780
  VpSetPrecLimit(size_t n)
4802
3781
  {
4803
- size_t const s = VpGetPrecLimit();
4804
3782
  bigdecimal_set_thread_local_precision_limit(n);
4805
- return s;
4806
3783
  }
4807
3784
 
4808
3785
  /*
@@ -4917,15 +3894,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4917
3894
  return nzero;
4918
3895
  }
4919
3896
 
4920
- #if 0 /* unused */
4921
- VP_EXPORT int
4922
- VpIsNegDoubleZero(double v)
4923
- {
4924
- double z = VpGetDoubleNegZero();
4925
- return MemCmp(&v,&z,sizeof(v))==0;
4926
- }
4927
- #endif
4928
-
4929
3897
  VP_EXPORT int
4930
3898
  VpException(unsigned short f, const char *str,int always)
4931
3899
  {
@@ -5077,7 +4045,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5077
4045
  case 'E':
5078
4046
  /* fall through */
5079
4047
  default:
5080
- nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4048
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
5081
4049
  }
5082
4050
  return nc;
5083
4051
  }
@@ -5103,28 +4071,13 @@ VpInit(DECDIG BaseVal)
5103
4071
  VpGetDoubleNegZero();
5104
4072
 
5105
4073
  /* Const 1.0 */
5106
- VpConstOne = NewOneNolimit(1, 1);
5107
-
5108
- /* Const 0.5 */
5109
- VpConstPt5 = NewOneNolimit(1, 1);
5110
- VpConstPt5->exponent = 0;
5111
- VpConstPt5->frac[0] = 5*BASE1;
4074
+ VpConstOne = NewZero(1, 1);
4075
+ VpSetOne(VpConstOne);
5112
4076
 
5113
4077
  #ifdef BIGDECIMAL_DEBUG
5114
4078
  gnAlloc = 0;
5115
4079
  #endif /* BIGDECIMAL_DEBUG */
5116
4080
 
5117
- #ifdef BIGDECIMAL_DEBUG
5118
- if (gfDebug) {
5119
- printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
5120
- printf("\tBASE = %"PRIuDECDIG"\n", BASE);
5121
- printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
5122
- printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
5123
- printf("\tBASE_FIG = %u\n", BASE_FIG);
5124
- printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
5125
- }
5126
- #endif /* BIGDECIMAL_DEBUG */
5127
-
5128
4081
  return BIGDECIMAL_DOUBLE_FIGURES;
5129
4082
  }
5130
4083
 
@@ -5140,24 +4093,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5140
4093
  {
5141
4094
  SIGNED_VALUE e = a->exponent;
5142
4095
  SIGNED_VALUE m = e+n;
5143
- SIGNED_VALUE eb, mb;
5144
- if (e > 0) {
5145
- if (n > 0) {
5146
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5147
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5148
- goto overflow;
5149
- mb = m*(SIGNED_VALUE)BASE_FIG;
5150
- eb = e*(SIGNED_VALUE)BASE_FIG;
5151
- if (eb - mb > 0) goto overflow;
5152
- }
5153
- }
5154
- else if (n < 0) {
5155
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5156
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5157
- goto underflow;
5158
- mb = m*(SIGNED_VALUE)BASE_FIG;
5159
- eb = e*(SIGNED_VALUE)BASE_FIG;
5160
- if (mb - eb > 0) goto underflow;
4096
+ if (e > 0 && n > 0) {
4097
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
4098
+ } else if (e < 0 && n < 0) {
4099
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
4100
+ } else if (m > VP_EXPONENT_MAX) {
4101
+ goto overflow;
4102
+ } else if (m < VP_EXPONENT_MIN) {
4103
+ goto underflow;
5161
4104
  }
5162
4105
  a->exponent = m;
5163
4106
  return 1;
@@ -5198,7 +4141,6 @@ bigdecimal_parse_special_string(const char *str)
5198
4141
  while (*p && ISSPACE(*p)) ++p;
5199
4142
  if (*p == '\0') {
5200
4143
  Real *vp = rbd_allocate_struct(1);
5201
- vp->MaxPrec = 1;
5202
4144
  switch (table[i].sign) {
5203
4145
  default:
5204
4146
  UNREACHABLE; break;
@@ -5263,38 +4205,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
5263
4205
  /*
5264
4206
  * Allocates variable.
5265
4207
  * [Input]
5266
- * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5267
- * The mx will be the number of significant digits can to be stored.
5268
- * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5269
- * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5270
- * so that the full precision specified by szVal is allocated.
4208
+ * szVal ... The value assigned(char).
5271
4209
  *
5272
4210
  * [Returns]
5273
4211
  * Pointer to the newly allocated variable, or
5274
4212
  * NULL be returned if memory allocation is failed,or any error.
5275
4213
  */
5276
4214
  VP_EXPORT Real *
5277
- VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4215
+ VpAlloc(const char *szVal, int strict_p, int exc)
5278
4216
  {
5279
4217
  const char *orig_szVal = szVal;
5280
4218
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5281
- size_t len;
5282
4219
  char v, *psz;
5283
4220
  int sign=1;
5284
4221
  Real *vp = NULL;
5285
4222
  VALUE buf;
5286
4223
 
5287
- if (szVal == NULL) {
5288
- return_zero:
5289
- /* necessary to be able to store */
5290
- /* at least mx digits. */
5291
- /* szVal==NULL ==> allocate zero value. */
5292
- vp = rbd_allocate_struct(mx);
5293
- vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5294
- VpSetZero(vp, 1); /* initialize vp to zero. */
5295
- return vp;
5296
- }
5297
-
5298
4224
  /* Skipping leading spaces */
5299
4225
  while (ISSPACE(*szVal)) szVal++;
5300
4226
 
@@ -5303,14 +4229,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5303
4229
  return vp;
5304
4230
  }
5305
4231
 
5306
- /* Processing the leading one `#` */
5307
- if (*szVal != '#') {
5308
- len = rbd_calculate_internal_digits(mx, true);
5309
- }
5310
- else {
5311
- len = rbd_calculate_internal_digits(mx, false);
5312
- ++szVal;
5313
- }
4232
+ /* Skip leading `#`.
4233
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
4234
+ * but now it has no effect.
4235
+ */
4236
+ if (*szVal == '#') ++szVal;
5314
4237
 
5315
4238
  /* Scanning digits */
5316
4239
 
@@ -5457,7 +4380,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5457
4380
  VALUE str;
5458
4381
  invalid_value:
5459
4382
  if (!strict_p) {
5460
- goto return_zero;
4383
+ return NewZero(1, 1);
5461
4384
  }
5462
4385
  if (!exc) {
5463
4386
  return NULL;
@@ -5468,11 +4391,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5468
4391
 
5469
4392
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5470
4393
  /* units for szVal[] */
5471
- if (len == 0) len = 1;
5472
- nalloc = Max(nalloc, len);
5473
- len = nalloc;
5474
- vp = rbd_allocate_struct(len);
5475
- vp->MaxPrec = len; /* set max precision */
4394
+ vp = rbd_allocate_struct(nalloc);
5476
4395
  VpSetZero(vp, sign);
5477
4396
  protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
5478
4397
  rb_str_resize(buf, 0);
@@ -5512,7 +4431,7 @@ VpAsgn(Real *c, Real *a, int isw)
5512
4431
  c->Prec = n;
5513
4432
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5514
4433
  /* Needs round ? */
5515
- if (isw != 10) {
4434
+ if (isw != 10 && isw != -10) {
5516
4435
  /* Not in ActiveRound */
5517
4436
  if(c->Prec < a->Prec) {
5518
4437
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5538,19 +4457,11 @@ VpAsgn(Real *c, Real *a, int isw)
5538
4457
  VP_EXPORT size_t
5539
4458
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5540
4459
  {
5541
- short sw, isw;
4460
+ short sw, isw, sign;
5542
4461
  Real *a_ptr, *b_ptr;
5543
4462
  size_t n, na, nb, i;
5544
4463
  DECDIG mrv;
5545
4464
 
5546
- #ifdef BIGDECIMAL_DEBUG
5547
- if (gfDebug) {
5548
- VPrint(stdout, "VpAddSub(enter) a=% \n", a);
5549
- VPrint(stdout, " b=% \n", b);
5550
- printf(" operation=%d\n", operation);
5551
- }
5552
- #endif /* BIGDECIMAL_DEBUG */
5553
-
5554
4465
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5555
4466
 
5556
4467
  /* check if a or b is zero */
@@ -5639,28 +4550,21 @@ end_if:
5639
4550
  if (isw) { /* addition */
5640
4551
  VpSetSign(c, 1);
5641
4552
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5642
- VpSetSign(c, isw / 2);
4553
+ sign = isw / 2;
5643
4554
  }
5644
4555
  else { /* subtraction */
5645
4556
  VpSetSign(c, 1);
5646
4557
  mrv = VpSubAbs(a_ptr, b_ptr, c);
5647
- if (a_ptr == a) {
5648
- VpSetSign(c,VpGetSign(a));
5649
- }
5650
- else {
5651
- VpSetSign(c, VpGetSign(a_ptr) * sw);
5652
- }
4558
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5653
4559
  }
5654
- VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
5655
-
5656
- #ifdef BIGDECIMAL_DEBUG
5657
- if (gfDebug) {
5658
- VPrint(stdout, "VpAddSub(result) c=% \n", c);
5659
- VPrint(stdout, " a=% \n", a);
5660
- VPrint(stdout, " b=% \n", b);
5661
- printf(" operation=%d\n", operation);
4560
+ if (VpIsInf(c)) {
4561
+ VpSetInf(c, sign);
5662
4562
  }
5663
- #endif /* BIGDECIMAL_DEBUG */
4563
+ else {
4564
+ VpSetSign(c, sign);
4565
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4566
+ }
4567
+
5664
4568
  return c->Prec * BASE_FIG;
5665
4569
  }
5666
4570
 
@@ -5681,13 +4585,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5681
4585
  size_t c_pos;
5682
4586
  DECDIG av, bv, carry, mrv;
5683
4587
 
5684
- #ifdef BIGDECIMAL_DEBUG
5685
- if (gfDebug) {
5686
- VPrint(stdout, "VpAddAbs called: a = %\n", a);
5687
- VPrint(stdout, " b = %\n", b);
5688
- }
5689
- #endif /* BIGDECIMAL_DEBUG */
5690
-
5691
4588
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5692
4589
  a_pos = ap;
5693
4590
  b_pos = bp;
@@ -5753,11 +4650,6 @@ Assign_a:
5753
4650
 
5754
4651
  Exit:
5755
4652
 
5756
- #ifdef BIGDECIMAL_DEBUG
5757
- if (gfDebug) {
5758
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5759
- }
5760
- #endif /* BIGDECIMAL_DEBUG */
5761
4653
  return mrv;
5762
4654
  }
5763
4655
 
@@ -5776,13 +4668,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5776
4668
  size_t c_pos;
5777
4669
  DECDIG av, bv, borrow, mrv;
5778
4670
 
5779
- #ifdef BIGDECIMAL_DEBUG
5780
- if (gfDebug) {
5781
- VPrint(stdout, "VpSubAbs called: a = %\n", a);
5782
- VPrint(stdout, " b = %\n", b);
5783
- }
5784
- #endif /* BIGDECIMAL_DEBUG */
5785
-
5786
4671
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5787
4672
  a_pos = ap;
5788
4673
  b_pos = bp;
@@ -5858,11 +4743,6 @@ Assign_a:
5858
4743
  mrv = 0;
5859
4744
 
5860
4745
  Exit:
5861
- #ifdef BIGDECIMAL_DEBUG
5862
- if (gfDebug) {
5863
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5864
- }
5865
- #endif /* BIGDECIMAL_DEBUG */
5866
4746
  return mrv;
5867
4747
  }
5868
4748
 
@@ -5993,19 +4873,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5993
4873
  VP_EXPORT size_t
5994
4874
  VpMult(Real *c, Real *a, Real *b)
5995
4875
  {
5996
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
4876
+ size_t MxIndA, MxIndB, MxIndAB;
5997
4877
  size_t ind_c, i, ii, nc;
5998
4878
  size_t ind_as, ind_ae, ind_bs;
5999
4879
  DECDIG carry;
6000
4880
  DECDIG_DBL s;
6001
- Real *w;
6002
-
6003
- #ifdef BIGDECIMAL_DEBUG
6004
- if (gfDebug) {
6005
- VPrint(stdout, "VpMult(Enter): a=% \n", a);
6006
- VPrint(stdout, " b=% \n", b);
6007
- }
6008
- #endif /* BIGDECIMAL_DEBUG */
6009
4881
 
6010
4882
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
6011
4883
 
@@ -6016,39 +4888,28 @@ VpMult(Real *c, Real *a, Real *b)
6016
4888
  }
6017
4889
 
6018
4890
  if (VpIsOne(a)) {
6019
- VpAsgn(c, b, VpGetSign(a));
4891
+ VpAsgn(c, b, 10 * VpGetSign(a));
6020
4892
  goto Exit;
6021
4893
  }
6022
4894
  if (VpIsOne(b)) {
6023
- VpAsgn(c, a, VpGetSign(b));
4895
+ VpAsgn(c, a, 10 * VpGetSign(b));
6024
4896
  goto Exit;
6025
4897
  }
6026
4898
  if (b->Prec > a->Prec) {
6027
4899
  /* Adjust so that digits(a)>digits(b) */
6028
- w = a;
4900
+ Real *w = a;
6029
4901
  a = b;
6030
4902
  b = w;
6031
4903
  }
6032
- w = NULL;
6033
4904
  MxIndA = a->Prec - 1;
6034
4905
  MxIndB = b->Prec - 1;
6035
- MxIndC = c->MaxPrec - 1;
6036
4906
  MxIndAB = a->Prec + b->Prec - 1;
6037
4907
 
6038
- if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
6039
- w = c;
6040
- c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
6041
- MxIndC = MxIndAB;
6042
- }
6043
-
6044
4908
  /* set LHSV c info */
6045
4909
 
6046
4910
  c->exponent = a->exponent; /* set exponent */
6047
- if (!AddExponent(c, b->exponent)) {
6048
- if (w) rbd_free_struct(c);
6049
- return 0;
6050
- }
6051
4911
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
4912
+ if (!AddExponent(c, b->exponent)) return 0;
6052
4913
  carry = 0;
6053
4914
  nc = ind_c = MxIndAB;
6054
4915
  memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
@@ -6095,29 +4956,18 @@ VpMult(Real *c, Real *a, Real *b)
6095
4956
  }
6096
4957
  }
6097
4958
  }
6098
- if (w != NULL) { /* free work variable */
6099
- VpNmlz(c);
6100
- VpAsgn(w, c, 1);
6101
- rbd_free_struct(c);
6102
- c = w;
6103
- }
6104
- else {
6105
- VpLimitRound(c,0);
6106
- }
4959
+ VpNmlz(c);
6107
4960
 
6108
4961
  Exit:
6109
- #ifdef BIGDECIMAL_DEBUG
6110
- if (gfDebug) {
6111
- VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
6112
- VPrint(stdout, " a=% \n", a);
6113
- VPrint(stdout, " b=% \n", b);
6114
- }
6115
- #endif /*BIGDECIMAL_DEBUG */
6116
4962
  return c->Prec*BASE_FIG;
6117
4963
  }
6118
4964
 
6119
4965
  /*
6120
4966
  * c = a / b, remainder = r
4967
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
4968
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
4969
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
4970
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
6121
4971
  */
6122
4972
  VP_EXPORT size_t
6123
4973
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6126,16 +4976,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6126
4976
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6127
4977
  size_t nLoop;
6128
4978
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6129
- DECDIG borrow, borrow1, borrow2;
4979
+ DECDIG borrow1, borrow2;
6130
4980
  DECDIG_DBL qb;
6131
4981
 
6132
- #ifdef BIGDECIMAL_DEBUG
6133
- if (gfDebug) {
6134
- VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
6135
- VPrint(stdout, " b=% \n", b);
6136
- }
6137
- #endif /*BIGDECIMAL_DEBUG */
6138
-
6139
4982
  VpSetNaN(r);
6140
4983
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6141
4984
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6152,30 +4995,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6152
4995
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6153
4996
  goto Exit;
6154
4997
  }
6155
- if (VpIsOne(b)) {
6156
- /* divide by one */
6157
- VpAsgn(c, a, VpGetSign(b));
6158
- VpSetZero(r, VpGetSign(a));
6159
- goto Exit;
6160
- }
6161
4998
 
6162
4999
  word_a = a->Prec;
6163
5000
  word_b = b->Prec;
6164
5001
  word_c = c->MaxPrec;
6165
5002
  word_r = r->MaxPrec;
6166
5003
 
6167
- if (word_a >= word_r) goto space_error;
5004
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6168
5005
 
6169
- ind_r = 1;
6170
- r->frac[0] = 0;
6171
- while (ind_r <= word_a) {
6172
- r->frac[ind_r] = a->frac[ind_r - 1];
6173
- ++ind_r;
6174
- }
6175
- while (ind_r < word_r) r->frac[ind_r++] = 0;
6176
-
6177
- ind_c = 0;
6178
- while (ind_c < word_c) c->frac[ind_c++] = 0;
5006
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
5007
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
5008
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
6179
5009
 
6180
5010
  /* initial procedure */
6181
5011
  b1 = b1p1 = b->frac[0];
@@ -6190,15 +5020,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6190
5020
 
6191
5021
  /* */
6192
5022
  /* loop start */
6193
- ind_c = word_r - 1;
6194
- nLoop = Min(word_c,ind_c);
6195
- ind_c = 1;
5023
+ nLoop = Min(word_c, word_r);
5024
+ ind_c = 0;
6196
5025
  while (ind_c < nLoop) {
6197
5026
  if (r->frac[ind_c] == 0) {
6198
5027
  ++ind_c;
6199
5028
  continue;
6200
5029
  }
6201
- r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
5030
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
6202
5031
  if (r1r2 == b1b2) {
6203
5032
  /* The first two word digits is the same */
6204
5033
  ind_b = 2;
@@ -6211,26 +5040,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6211
5040
  }
6212
5041
  /* The first few word digits of r and b is the same and */
6213
5042
  /* the first different word digit of w is greater than that */
6214
- /* of b, so quotient is 1 and just subtract b from r. */
6215
- borrow = 0; /* quotient=1, then just r-b */
6216
- ind_b = b->Prec - 1;
6217
- ind_r = ind_c + ind_b;
6218
- if (ind_r >= word_r) goto space_error;
6219
- n = ind_b;
6220
- for (i = 0; i <= n; ++i) {
6221
- if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
6222
- r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
6223
- borrow = 1;
6224
- }
6225
- else {
6226
- r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
6227
- borrow = 0;
6228
- }
6229
- --ind_r;
6230
- --ind_b;
6231
- }
5043
+ /* of b, so quotient is 1. */
5044
+ q = 1;
6232
5045
  ++c->frac[ind_c];
6233
- goto carry;
5046
+ ind_r = b->Prec + ind_c - 1;
5047
+ goto sub_mult;
6234
5048
  }
6235
5049
  /* The first two word digits is not the same, */
6236
5050
  /* then compare magnitude, and divide actually. */
@@ -6283,49 +5097,26 @@ sub_mult:
6283
5097
  }
6284
5098
 
6285
5099
  r->frac[ind_r] -= borrow2;
6286
- carry:
6287
- ind_r = ind_c;
6288
- while (c->frac[ind_r] >= BASE) {
6289
- c->frac[ind_r] -= BASE;
6290
- --ind_r;
6291
- ++c->frac[ind_r];
6292
- }
6293
5100
  }
6294
5101
  /* End of operation, now final arrangement */
6295
5102
  out_side:
6296
5103
  c->Prec = word_c;
6297
5104
  c->exponent = a->exponent;
6298
- if (!AddExponent(c, 2)) return 0;
5105
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5106
+ if (!AddExponent(c, 1)) return 0;
6299
5107
  if (!AddExponent(c, -(b->exponent))) return 0;
6300
5108
 
6301
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6302
5109
  VpNmlz(c); /* normalize c */
6303
5110
  r->Prec = word_r;
6304
5111
  r->exponent = a->exponent;
6305
- if (!AddExponent(r, 1)) return 0;
6306
5112
  VpSetSign(r, VpGetSign(a));
6307
5113
  VpNmlz(r); /* normalize r(remainder) */
6308
5114
  goto Exit;
6309
5115
 
6310
5116
  space_error:
6311
- #ifdef BIGDECIMAL_DEBUG
6312
- if (gfDebug) {
6313
- printf(" word_a=%"PRIuSIZE"\n", word_a);
6314
- printf(" word_b=%"PRIuSIZE"\n", word_b);
6315
- printf(" word_c=%"PRIuSIZE"\n", word_c);
6316
- printf(" word_r=%"PRIuSIZE"\n", word_r);
6317
- printf(" ind_r =%"PRIuSIZE"\n", ind_r);
6318
- }
6319
- #endif /* BIGDECIMAL_DEBUG */
6320
5117
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6321
5118
 
6322
5119
  Exit:
6323
- #ifdef BIGDECIMAL_DEBUG
6324
- if (gfDebug) {
6325
- VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
6326
- VPrint(stdout, " r=% \n", r);
6327
- }
6328
- #endif /* BIGDECIMAL_DEBUG */
6329
5120
  return c->Prec * BASE_FIG;
6330
5121
  }
6331
5122
 
@@ -6448,13 +5239,6 @@ Exit:
6448
5239
  if (val > 1) val = 1;
6449
5240
  else if (val < -1) val = -1;
6450
5241
 
6451
- #ifdef BIGDECIMAL_DEBUG
6452
- if (gfDebug) {
6453
- VPrint(stdout, " VpComp a=%\n", a);
6454
- VPrint(stdout, " b=%\n", b);
6455
- printf(" ans=%d\n", val);
6456
- }
6457
- #endif /* BIGDECIMAL_DEBUG */
6458
5242
  return (int)val;
6459
5243
  }
6460
5244
 
@@ -6572,25 +5356,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6572
5356
  static void
6573
5357
  VpFormatSt(char *psz, size_t fFmt)
6574
5358
  {
6575
- size_t ie, i, nf = 0;
6576
- char ch;
5359
+ size_t iend, idig = 0, iexp = 0, nspaces;
5360
+ char *p;
6577
5361
 
6578
5362
  if (fFmt == 0) return;
6579
5363
 
6580
- ie = strlen(psz);
6581
- for (i = 0; i < ie; ++i) {
6582
- ch = psz[i];
6583
- if (!ch) break;
6584
- if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
6585
- if (ch == '.') { nf = 0; continue; }
6586
- if (ch == 'E' || ch == 'e') break;
6587
-
6588
- if (++nf > fFmt) {
6589
- memmove(psz + i + 1, psz + i, ie - i + 1);
6590
- ++ie;
6591
- nf = 0;
6592
- psz[i] = ' ';
6593
- }
5364
+ iend = strlen(psz);
5365
+
5366
+ if ((p = strchr(psz, '.'))) {
5367
+ idig = (p - psz) + 1;
5368
+ }
5369
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
5370
+ iexp = p - psz;
5371
+ }
5372
+ if (idig == 0 || idig > iexp) return;
5373
+
5374
+ nspaces = (iexp - idig - 1) / fFmt;
5375
+ p = psz + iend + 1;
5376
+ for (size_t i = nspaces; i > 0; i--) {
5377
+ char *src = psz + idig + i * fFmt;
5378
+ char *dst = psz + idig + i * (fFmt + 1);
5379
+ memmove(dst, src, p - src);
5380
+ dst[-1] = ' ';
5381
+ p = src;
6594
5382
  }
6595
5383
  }
6596
5384
 
@@ -6872,7 +5660,7 @@ VP_EXPORT int
6872
5660
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6873
5661
  {
6874
5662
  size_t i, j, ind_a, ma, mi, me;
6875
- SIGNED_VALUE e, es, eb, ef;
5663
+ SIGNED_VALUE e;
6876
5664
  int sign, signe, exponent_overflow;
6877
5665
 
6878
5666
  /* get exponent part */
@@ -6895,23 +5683,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6895
5683
  ++me;
6896
5684
  }
6897
5685
  while (i < me) {
6898
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
6899
- es = e;
6900
- goto exp_overflow;
6901
- }
6902
- es = e * (SIGNED_VALUE)BASE_FIG;
6903
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
6904
- SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
6905
- goto exp_overflow;
6906
- e = e * 10 + exp_chr[i] - '0';
6907
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
6908
- goto exp_overflow;
6909
- if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
6910
- exp_overflow:
5686
+ int dig = exp_chr[i] - '0';
5687
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5688
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6911
5689
  exponent_overflow = 1;
6912
- e = es; /* keep sign */
6913
5690
  break;
6914
5691
  }
5692
+ e = e * 10 + signe * dig;
6915
5693
  ++i;
6916
5694
  }
6917
5695
  }
@@ -6930,34 +5708,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6930
5708
  ++mi;
6931
5709
  }
6932
5710
  }
5711
+ /* skip leading zeros in integer part */
5712
+ while (i < mi && int_chr[i] == '0') {
5713
+ ++i;
5714
+ --ni;
5715
+ }
6933
5716
 
6934
- e = signe * e; /* e: The value of exponent part. */
6935
- e = e + ni; /* set actual exponent size. */
6936
-
6937
- if (e > 0) signe = 1;
6938
- else signe = -1;
5717
+ /* set actual exponent size. */
5718
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5719
+ exponent_overflow = 1;
5720
+ } else {
5721
+ e += ni;
5722
+ }
6939
5723
 
6940
5724
  /* Adjust the exponent so that it is the multiple of BASE_FIG. */
6941
- j = 0;
6942
- ef = 1;
6943
- while (ef) {
6944
- if (e >= 0) eb = e;
6945
- else eb = -e;
6946
- ef = eb / (SIGNED_VALUE)BASE_FIG;
6947
- ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
6948
- if (ef) {
6949
- ++j; /* Means to add one more preceding zero */
6950
- ++e;
6951
- }
5725
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5726
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5727
+ exponent_overflow = 1;
5728
+ } else {
5729
+ e += j;
6952
5730
  }
6953
5731
 
6954
- eb = e / (SIGNED_VALUE)BASE_FIG;
6955
-
6956
- if (exponent_overflow) {
5732
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6957
5733
  int zero = 1;
6958
5734
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6959
5735
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6960
- if (!zero && signe > 0) {
5736
+ if (!zero && e > 0) {
6961
5737
  VpSetInf(a, sign);
6962
5738
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6963
5739
  }
@@ -7007,7 +5783,7 @@ Final:
7007
5783
  ++j;
7008
5784
  }
7009
5785
  a->Prec = ind_a + 1;
7010
- a->exponent = eb;
5786
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
7011
5787
  VpSetSign(a, sign);
7012
5788
  VpNmlz(a);
7013
5789
  return 1;
@@ -7079,254 +5855,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7079
5855
  *d *= VpGetSign(m);
7080
5856
 
7081
5857
  Exit:
7082
- #ifdef BIGDECIMAL_DEBUG
7083
- if (gfDebug) {
7084
- VPrint(stdout, " VpVtoD: m=%\n", m);
7085
- printf(" d=%e * 10 **%ld\n", *d, *e);
7086
- printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
7087
- }
7088
- #endif /*BIGDECIMAL_DEBUG */
7089
5858
  return f;
7090
5859
  }
7091
5860
 
7092
- /*
7093
- * m <- d
7094
- */
7095
- VP_EXPORT void
7096
- VpDtoV(Real *m, double d)
7097
- {
7098
- size_t ind_m, mm;
7099
- SIGNED_VALUE ne;
7100
- DECDIG i;
7101
- double val, val2;
7102
-
7103
- if (isnan(d)) {
7104
- VpSetNaN(m);
7105
- goto Exit;
7106
- }
7107
- if (isinf(d)) {
7108
- if (d > 0.0) VpSetPosInf(m);
7109
- else VpSetNegInf(m);
7110
- goto Exit;
7111
- }
7112
-
7113
- if (d == 0.0) {
7114
- VpSetZero(m, 1);
7115
- goto Exit;
7116
- }
7117
- val = (d > 0.) ? d : -d;
7118
- ne = 0;
7119
- if (val >= 1.0) {
7120
- while (val >= 1.0) {
7121
- val /= (double)BASE;
7122
- ++ne;
7123
- }
7124
- }
7125
- else {
7126
- val2 = 1.0 / (double)BASE;
7127
- while (val < val2) {
7128
- val *= (double)BASE;
7129
- --ne;
7130
- }
7131
- }
7132
- /* Now val = 0.xxxxx*BASE**ne */
7133
-
7134
- mm = m->MaxPrec;
7135
- memset(m->frac, 0, mm * sizeof(DECDIG));
7136
- for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
7137
- val *= (double)BASE;
7138
- i = (DECDIG)val;
7139
- val -= (double)i;
7140
- m->frac[ind_m] = i;
7141
- }
7142
- if (ind_m >= mm) ind_m = mm - 1;
7143
- VpSetSign(m, (d > 0.0) ? 1 : -1);
7144
- m->Prec = ind_m + 1;
7145
- m->exponent = ne;
7146
-
7147
- VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
7148
- (DECDIG)(val*(double)BASE));
7149
-
7150
- Exit:
7151
- #ifdef BIGDECIMAL_DEBUG
7152
- if (gfDebug) {
7153
- printf("VpDtoV d=%30.30e\n", d);
7154
- VPrint(stdout, " m=%\n", m);
7155
- }
7156
- #endif /* BIGDECIMAL_DEBUG */
7157
- return;
7158
- }
7159
-
7160
- /*
7161
- * m <- ival
7162
- */
7163
- #if 0 /* unused */
7164
- VP_EXPORT void
7165
- VpItoV(Real *m, SIGNED_VALUE ival)
7166
- {
7167
- size_t mm, ind_m;
7168
- size_t val, v1, v2, v;
7169
- int isign;
7170
- SIGNED_VALUE ne;
7171
-
7172
- if (ival == 0) {
7173
- VpSetZero(m, 1);
7174
- goto Exit;
7175
- }
7176
- isign = 1;
7177
- val = ival;
7178
- if (ival < 0) {
7179
- isign = -1;
7180
- val =(size_t)(-ival);
7181
- }
7182
- ne = 0;
7183
- ind_m = 0;
7184
- mm = m->MaxPrec;
7185
- while (ind_m < mm) {
7186
- m->frac[ind_m] = 0;
7187
- ++ind_m;
7188
- }
7189
- ind_m = 0;
7190
- while (val > 0) {
7191
- if (val) {
7192
- v1 = val;
7193
- v2 = 1;
7194
- while (v1 >= BASE) {
7195
- v1 /= BASE;
7196
- v2 *= BASE;
7197
- }
7198
- val = val - v2 * v1;
7199
- v = v1;
7200
- }
7201
- else {
7202
- v = 0;
7203
- }
7204
- m->frac[ind_m] = v;
7205
- ++ind_m;
7206
- ++ne;
7207
- }
7208
- m->Prec = ind_m - 1;
7209
- m->exponent = ne;
7210
- VpSetSign(m, isign);
7211
- VpNmlz(m);
7212
-
7213
- Exit:
7214
- #ifdef BIGDECIMAL_DEBUG
7215
- if (gfDebug) {
7216
- printf(" VpItoV i=%d\n", ival);
7217
- VPrint(stdout, " m=%\n", m);
7218
- }
7219
- #endif /* BIGDECIMAL_DEBUG */
7220
- return;
7221
- }
7222
- #endif
7223
-
7224
- /*
7225
- * y = SQRT(x), y*y - x =>0
7226
- */
7227
- VP_EXPORT int
7228
- VpSqrt(Real *y, Real *x)
7229
- {
7230
- Real *f = NULL;
7231
- Real *r = NULL;
7232
- size_t y_prec;
7233
- SIGNED_VALUE n, e;
7234
- ssize_t nr;
7235
- double val;
7236
-
7237
- /* Zero or +Infinity ? */
7238
- if (VpIsZero(x) || VpIsPosInf(x)) {
7239
- VpAsgn(y,x,1);
7240
- goto Exit;
7241
- }
7242
-
7243
- /* Negative ? */
7244
- if (BIGDECIMAL_NEGATIVE_P(x)) {
7245
- VpSetNaN(y);
7246
- return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
7247
- }
7248
-
7249
- /* NaN ? */
7250
- if (VpIsNaN(x)) {
7251
- VpSetNaN(y);
7252
- return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
7253
- }
7254
-
7255
- /* One ? */
7256
- if (VpIsOne(x)) {
7257
- VpSetOne(y);
7258
- goto Exit;
7259
- }
7260
-
7261
- n = (SIGNED_VALUE)y->MaxPrec;
7262
- if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
7263
-
7264
- /* allocate temporally variables */
7265
- /* TODO: reconsider MaxPrec of f and r */
7266
- f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7267
- r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
7268
-
7269
- nr = 0;
7270
- y_prec = y->MaxPrec;
7271
-
7272
- VpVtoD(&val, &e, x); /* val <- x */
7273
- e /= (SIGNED_VALUE)BASE_FIG;
7274
- n = e / 2;
7275
- if (e - n * 2 != 0) {
7276
- val /= BASE;
7277
- n = (e + 1) / 2;
7278
- }
7279
- VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
7280
- y->exponent += n;
7281
- n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
7282
- y->MaxPrec = Min((size_t)n , y_prec);
7283
- f->MaxPrec = y->MaxPrec + 1;
7284
- n = (SIGNED_VALUE)(y_prec * BASE_FIG);
7285
- if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7286
-
7287
- /*
7288
- * Perform: y_{n+1} = (y_n - x/y_n) / 2
7289
- */
7290
- do {
7291
- y->MaxPrec *= 2;
7292
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7293
- f->MaxPrec = y->MaxPrec;
7294
- VpDivd(f, r, x, y); /* f = x/y */
7295
- VpAddSub(r, f, y, -1); /* r = f - y */
7296
- VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7297
- if (VpIsZero(f))
7298
- goto converge;
7299
- VpAddSub(r, f, y, 1); /* r = y + f */
7300
- VpAsgn(y, r, 1); /* y = r */
7301
- } while (++nr < n);
7302
-
7303
- #ifdef BIGDECIMAL_DEBUG
7304
- if (gfDebug) {
7305
- printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
7306
- }
7307
- #endif /* BIGDECIMAL_DEBUG */
7308
- y->MaxPrec = y_prec;
7309
-
7310
- converge:
7311
- VpChangeSign(y, 1);
7312
- #ifdef BIGDECIMAL_DEBUG
7313
- if (gfDebug) {
7314
- VpMult(r, y, y);
7315
- VpAddSub(f, x, r, -1);
7316
- printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
7317
- VPrint(stdout, " y =% \n", y);
7318
- VPrint(stdout, " x =% \n", x);
7319
- VPrint(stdout, " x-y*y = % \n", f);
7320
- }
7321
- #endif /* BIGDECIMAL_DEBUG */
7322
- y->MaxPrec = y_prec;
7323
-
7324
- Exit:
7325
- rbd_free_struct(f);
7326
- rbd_free_struct(r);
7327
- return 1;
7328
- }
7329
-
7330
5861
  /*
7331
5862
  * Round relatively from the decimal point.
7332
5863
  * f: rounding mode
@@ -7503,7 +6034,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7503
6034
  DECDIG v;
7504
6035
  if (!VpHasVal(y)) return 0; /* Unable to round */
7505
6036
  v = y->frac[0];
7506
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6037
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7507
6038
  while ((v /= 10) != 0) nf--;
7508
6039
  nf += (ssize_t)BASE_FIG-1;
7509
6040
  return VpMidRound(y, f, nf);
@@ -7640,117 +6171,9 @@ VpFrac(Real *y, Real *x)
7640
6171
  VpNmlz(y);
7641
6172
 
7642
6173
  Exit:
7643
- #ifdef BIGDECIMAL_DEBUG
7644
- if (gfDebug) {
7645
- VPrint(stdout, "VpFrac y=%\n", y);
7646
- VPrint(stdout, " x=%\n", x);
7647
- }
7648
- #endif /* BIGDECIMAL_DEBUG */
7649
6174
  return;
7650
6175
  }
7651
6176
 
7652
- /*
7653
- * y = x ** n
7654
- */
7655
- VP_EXPORT int
7656
- VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7657
- {
7658
- size_t s, ss;
7659
- ssize_t sign;
7660
- Real *w1 = NULL;
7661
- Real *w2 = NULL;
7662
-
7663
- if (VpIsZero(x)) {
7664
- if (n == 0) {
7665
- VpSetOne(y);
7666
- goto Exit;
7667
- }
7668
- sign = VpGetSign(x);
7669
- if (n < 0) {
7670
- n = -n;
7671
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7672
- VpSetInf(y, sign);
7673
- }
7674
- else {
7675
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7676
- VpSetZero(y,sign);
7677
- }
7678
- goto Exit;
7679
- }
7680
- if (VpIsNaN(x)) {
7681
- VpSetNaN(y);
7682
- goto Exit;
7683
- }
7684
- if (VpIsInf(x)) {
7685
- if (n == 0) {
7686
- VpSetOne(y);
7687
- goto Exit;
7688
- }
7689
- if (n > 0) {
7690
- VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7691
- goto Exit;
7692
- }
7693
- VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7694
- goto Exit;
7695
- }
7696
-
7697
- if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
7698
- /* abs(x) = 1 */
7699
- VpSetOne(y);
7700
- if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
7701
- if ((n % 2) == 0) goto Exit;
7702
- VpSetSign(y, -1);
7703
- goto Exit;
7704
- }
7705
-
7706
- if (n > 0) sign = 1;
7707
- else if (n < 0) {
7708
- sign = -1;
7709
- n = -n;
7710
- }
7711
- else {
7712
- VpSetOne(y);
7713
- goto Exit;
7714
- }
7715
-
7716
- /* Allocate working variables */
7717
- /* TODO: reconsider MaxPrec of w1 and w2 */
7718
- w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7719
- w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7720
-
7721
- /* calculation start */
7722
-
7723
- VpAsgn(y, x, 1);
7724
- --n;
7725
- while (n > 0) {
7726
- VpAsgn(w1, x, 1);
7727
- s = 1;
7728
- while (ss = s, (s += s) <= (size_t)n) {
7729
- VpMult(w2, w1, w1);
7730
- VpAsgn(w1, w2, 1);
7731
- }
7732
- n -= (SIGNED_VALUE)ss;
7733
- VpMult(w2, y, w1);
7734
- VpAsgn(y, w2, 1);
7735
- }
7736
- if (sign < 0) {
7737
- VpDivd(w1, w2, VpConstOne, y);
7738
- VpAsgn(y, w1, 1);
7739
- }
7740
-
7741
- Exit:
7742
- #ifdef BIGDECIMAL_DEBUG
7743
- if (gfDebug) {
7744
- VPrint(stdout, "VpPowerByInt y=%\n", y);
7745
- VPrint(stdout, "VpPowerByInt x=%\n", x);
7746
- printf(" n=%"PRIdVALUE"\n", n);
7747
- }
7748
- #endif /* BIGDECIMAL_DEBUG */
7749
- rbd_free_struct(w2);
7750
- rbd_free_struct(w1);
7751
- return 1;
7752
- }
7753
-
7754
6177
  #ifdef BIGDECIMAL_DEBUG
7755
6178
  int
7756
6179
  VpVarCheck(Real * v)