bigdecimal 3.1.9 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,16 +31,23 @@
31
31
  #include "bits.h"
32
32
  #include "static_assert.h"
33
33
 
34
- #define BIGDECIMAL_VERSION "3.1.9"
34
+ #define BIGDECIMAL_VERSION "4.0.1"
35
35
 
36
36
  /* #define ENABLE_NUMERIC_STRING */
37
37
 
38
38
  #define SIGNED_VALUE_MAX INTPTR_MAX
39
39
  #define SIGNED_VALUE_MIN INTPTR_MIN
40
40
  #define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
41
+ #define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
42
+
43
+ /* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
44
+ #define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
45
+ /* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
46
+ #define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
47
+ #define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
48
+ #define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
41
49
 
42
50
  VALUE rb_cBigDecimal;
43
- VALUE rb_mBigMath;
44
51
 
45
52
  static ID id_BigDecimal_exception_mode;
46
53
  static ID id_BigDecimal_rounding_mode;
@@ -68,15 +75,28 @@ static struct {
68
75
  uint8_t mode;
69
76
  } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
70
77
 
71
- /* MACRO's to guard objects from GC by keeping them in stack */
72
- #ifdef RBIMPL_ATTR_MAYBE_UNUSED
73
- #define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0
74
- #else
75
- #define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
76
- #endif
77
- #define PUSH(x) (vStack[iStack++] = (VALUE)(x))
78
- #define SAVE(p) PUSH((p)->obj)
79
- #define GUARD_OBJ(p,y) ((p)=(y), SAVE(p))
78
+ typedef struct {
79
+ VALUE bigdecimal;
80
+ Real *real;
81
+ } BDVALUE;
82
+
83
+ typedef struct {
84
+ VALUE bigdecimal_or_nil;
85
+ Real *real_or_null;
86
+ } NULLABLE_BDVALUE;
87
+
88
+ static inline BDVALUE
89
+ bdvalue_nonnullable(NULLABLE_BDVALUE v)
90
+ {
91
+ assert(v.real_or_null != NULL);
92
+ return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
93
+ }
94
+
95
+ static inline NULLABLE_BDVALUE
96
+ bdvalue_nullable(BDVALUE v)
97
+ {
98
+ return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
99
+ }
80
100
 
81
101
  #define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
82
102
  #define BASE BIGDECIMAL_BASE
@@ -84,31 +104,6 @@ static struct {
84
104
  #define HALF_BASE (BASE/2)
85
105
  #define BASE1 (BASE/10)
86
106
 
87
- #define LOG10_2 0.3010299956639812
88
-
89
- #ifndef RRATIONAL_ZERO_P
90
- # define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
91
- FIX2LONG(rb_rational_num(x)) == 0)
92
- #endif
93
-
94
- #ifndef RRATIONAL_NEGATIVE_P
95
- # define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
96
- #endif
97
-
98
- #ifndef DECIMAL_SIZE_OF_BITS
99
- #define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
100
- /* an approximation of ceil(n * log10(2)), upto 65536 at least */
101
- #endif
102
-
103
- #ifdef PRIsVALUE
104
- # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
105
- # define RB_OBJ_STRING(obj) (obj)
106
- #else
107
- # define PRIsVALUE "s"
108
- # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
109
- # define RB_OBJ_STRING(obj) StringValueCStr(obj)
110
- #endif
111
-
112
107
  #ifndef MAYBE_UNUSED
113
108
  # define MAYBE_UNUSED(x) x
114
109
  #endif
@@ -145,6 +140,17 @@ check_allocation_count_nonzero(void)
145
140
  # define check_allocation_count_nonzero() /* nothing */
146
141
  #endif /* BIGDECIMAL_DEBUG */
147
142
 
143
+ /* VpMult VpDivd helpers */
144
+ #define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
145
+ /* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
146
+ /* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
147
+ #define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
148
+ /* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
149
+ #define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
150
+
151
+ static NULLABLE_BDVALUE
152
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
153
+
148
154
  PUREFUNC(static inline size_t rbd_struct_size(size_t const));
149
155
 
150
156
  static inline size_t
@@ -164,44 +170,10 @@ rbd_allocate_struct(size_t const internal_digits)
164
170
  return real;
165
171
  }
166
172
 
167
- static size_t
168
- rbd_calculate_internal_digits(size_t const digits, bool limit_precision)
169
- {
170
- size_t const len = roomof(digits, BASE_FIG);
171
- if (limit_precision) {
172
- size_t const prec_limit = VpGetPrecLimit();
173
- if (prec_limit > 0) {
174
- /* NOTE: 2 more digits for rounding and division */
175
- size_t const max_len = roomof(prec_limit, BASE_FIG) + 2;
176
- if (len > max_len)
177
- return max_len;
178
- }
179
- }
180
-
181
- return len;
182
- }
183
-
184
173
  static inline Real *
185
- rbd_allocate_struct_decimal_digits(size_t const decimal_digits, bool limit_precision)
186
- {
187
- size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision);
188
- return rbd_allocate_struct(internal_digits);
189
- }
190
-
191
- static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp);
192
-
193
- static Real *
194
- rbd_reallocate_struct(Real *real, size_t const internal_digits)
174
+ rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
195
175
  {
196
- size_t const size = rbd_struct_size(internal_digits);
197
- VALUE obj = real ? real->obj : 0;
198
- Real *new_real = (Real *)ruby_xrealloc(real, size);
199
- new_real->MaxPrec = internal_digits;
200
- if (obj) {
201
- new_real->obj = 0;
202
- BigDecimal_wrap_struct(obj, new_real);
203
- }
204
- return new_real;
176
+ return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
205
177
  }
206
178
 
207
179
  static void
@@ -214,58 +186,16 @@ rbd_free_struct(Real *real)
214
186
  }
215
187
  }
216
188
 
189
+ MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
217
190
  #define NewZero rbd_allocate_struct_zero
218
- static Real *
219
- rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision)
220
- {
221
- Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
222
- VpSetZero(real, sign);
223
- return real;
224
- }
225
-
226
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits));
227
- #define NewZeroLimited rbd_allocate_struct_zero_limited
228
- static inline Real *
229
- rbd_allocate_struct_zero_limited(int sign, size_t const digits)
230
- {
231
- return rbd_allocate_struct_zero(sign, digits, true);
232
- }
233
-
234
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits));
235
- #define NewZeroNolimit rbd_allocate_struct_zero_nolimit
236
191
  static inline Real *
237
- rbd_allocate_struct_zero_nolimit(int sign, size_t const digits)
238
- {
239
- return rbd_allocate_struct_zero(sign, digits, false);
240
- }
241
-
242
- #define NewOne rbd_allocate_struct_one
243
- static Real *
244
- rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision)
192
+ rbd_allocate_struct_zero(int sign, size_t const digits)
245
193
  {
246
- Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
247
- VpSetOne(real);
248
- if (sign < 0)
249
- VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
194
+ Real *real = rbd_allocate_struct_decimal_digits(digits);
195
+ VpSetZero(real, sign);
250
196
  return real;
251
197
  }
252
198
 
253
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits));
254
- #define NewOneLimited rbd_allocate_struct_one_limited
255
- static inline Real *
256
- rbd_allocate_struct_one_limited(int sign, size_t const digits)
257
- {
258
- return rbd_allocate_struct_one(sign, digits, true);
259
- }
260
-
261
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits));
262
- #define NewOneNolimit rbd_allocate_struct_one_nolimit
263
- static inline Real *
264
- rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
265
- {
266
- return rbd_allocate_struct_one(sign, digits, false);
267
- }
268
-
269
199
  /*
270
200
  * ================== Ruby Interface part ==========================
271
201
  */
@@ -277,7 +207,8 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
277
207
  static unsigned short VpGetException(void);
278
208
  static void VpSetException(unsigned short f);
279
209
  static void VpCheckException(Real *p, bool always);
280
- static VALUE VpCheckGetValue(Real *p);
210
+ static int AddExponent(Real *a, SIGNED_VALUE n);
211
+ static VALUE CheckGetValue(BDVALUE v);
281
212
  static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
282
213
  static int VpLimitRound(Real *c, size_t ixDigit);
283
214
  static Real *VpCopy(Real *pv, Real const* const x);
@@ -292,6 +223,8 @@ static VALUE BigDecimal_positive_infinity(void);
292
223
  static VALUE BigDecimal_negative_infinity(void);
293
224
  static VALUE BigDecimal_positive_zero(void);
294
225
  static VALUE BigDecimal_negative_zero(void);
226
+ static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
227
+ static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
295
228
 
296
229
  static void
297
230
  BigDecimal_delete(void *pv)
@@ -319,58 +252,33 @@ static const rb_data_type_t BigDecimal_data_type = {
319
252
  #endif
320
253
  };
321
254
 
322
- static Real *
323
- rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
324
- {
325
- Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision);
326
- if (real != NULL) {
327
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
328
- BigDecimal_wrap_struct(obj, real);
329
- }
330
- return real;
331
- }
332
-
333
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
334
- #define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
335
- static inline Real *
336
- rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
337
- {
338
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
339
- }
340
-
341
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
342
- #define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
343
- static inline Real *
344
- rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
345
- {
346
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
347
- }
348
-
349
- static Real *
350
- rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
255
+ // TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
256
+ // We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
257
+ typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
258
+ static NULL_WRAPPED_VALUE
259
+ BigDecimal_alloc_empty_struct(VALUE klass)
351
260
  {
352
- Real *real = rbd_allocate_struct_one(sign, digits, limit_precision);
353
- if (real != NULL) {
354
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
355
- BigDecimal_wrap_struct(obj, real);
356
- }
357
- return real;
261
+ return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
358
262
  }
359
263
 
360
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits));
361
- #define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap
362
- static inline Real *
363
- rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
264
+ static VALUE
265
+ BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
364
266
  {
365
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
267
+ VALUE obj = v._obj;
268
+ assert(RTYPEDDATA_DATA(obj) == NULL);
269
+ RTYPEDDATA_DATA(obj) = real;
270
+ RB_OBJ_FREEZE(obj);
271
+ return obj;
366
272
  }
367
273
 
368
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits));
369
- #define NewOneWrapNolimit rbd_allocate_struct_one_nolimit_wrap
370
- static inline Real *
371
- rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)
274
+ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
275
+ #define NewZeroWrap rbd_allocate_struct_zero_wrap
276
+ static BDVALUE
277
+ rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
372
278
  {
373
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
279
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
280
+ Real *real = rbd_allocate_struct_zero(sign, digits);
281
+ return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
374
282
  }
375
283
 
376
284
  static inline int
@@ -398,24 +306,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
398
306
  }
399
307
 
400
308
  static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
401
- static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
309
+ static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
402
310
  static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
403
311
  static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
404
- static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception);
312
+ static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
405
313
  static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
406
314
 
407
- static Real*
408
- GetVpValueWithPrec(VALUE v, long prec, int must)
315
+ static NULLABLE_BDVALUE
316
+ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
409
317
  {
410
- const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
411
-
412
318
  switch(TYPE(v)) {
413
319
  case T_FLOAT:
414
- v = rb_float_convert_to_BigDecimal(v, digs, must);
320
+ v = rb_float_convert_to_BigDecimal(v, 0, true);
415
321
  break;
416
322
 
417
323
  case T_RATIONAL:
418
- v = rb_rational_convert_to_BigDecimal(v, digs, must);
324
+ v = rb_rational_convert_to_BigDecimal(v, prec, true);
419
325
  break;
420
326
 
421
327
  case T_DATA:
@@ -424,47 +330,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
424
330
  }
425
331
  break;
426
332
 
427
- case T_FIXNUM: {
428
- char szD[128];
429
- snprintf(szD, 128, "%ld", FIX2LONG(v));
430
- v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
333
+ case T_FIXNUM:
334
+ case T_BIGNUM: {
335
+ v = rb_inum_convert_to_BigDecimal(v);
431
336
  break;
432
337
  }
433
338
 
434
339
  #ifdef ENABLE_NUMERIC_STRING
435
340
  case T_STRING: {
436
341
  const char *c_str = StringValueCStr(v);
437
- v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
342
+ v = rb_cstr_convert_to_BigDecimal(c_str, must);
438
343
  break;
439
344
  }
440
345
  #endif /* ENABLE_NUMERIC_STRING */
441
346
 
442
- case T_BIGNUM: {
443
- VALUE bg = rb_big2str(v, 10);
444
- v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
445
- RB_GC_GUARD(bg);
446
- break;
447
- }
448
-
449
347
  default:
450
348
  goto SomeOneMayDoIt;
451
349
  }
452
350
 
453
351
  Real *vp;
454
352
  TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
455
- return vp;
353
+ return (NULLABLE_BDVALUE) { v, vp };
456
354
 
457
355
  SomeOneMayDoIt:
458
356
  if (must) {
459
357
  cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
460
358
  }
461
- return NULL; /* NULL means to coerce */
359
+ return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
360
+ }
361
+
362
+ static inline NULLABLE_BDVALUE
363
+ GetBDValueWithPrec(VALUE v, size_t prec)
364
+ {
365
+ return GetBDValueWithPrecInternal(v, prec, 0);
366
+ }
367
+
368
+
369
+ static inline BDVALUE
370
+ GetBDValueWithPrecMust(VALUE v, size_t prec)
371
+ {
372
+ return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
462
373
  }
463
374
 
375
+ // self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
464
376
  static inline Real*
465
- GetVpValue(VALUE v, int must)
377
+ GetSelfVpValue(VALUE self)
378
+ {
379
+ return GetBDValueWithPrecMust(self, 0).real;
380
+ }
381
+
382
+ static inline BDVALUE
383
+ GetBDValueMust(VALUE v)
466
384
  {
467
- return GetVpValueWithPrec(v, -1, must);
385
+ return GetBDValueWithPrecMust(v, 0);
468
386
  }
469
387
 
470
388
  /* call-seq:
@@ -479,49 +397,14 @@ GetVpValue(VALUE v, int must)
479
397
  static inline VALUE
480
398
  BigDecimal_double_fig(VALUE self)
481
399
  {
482
- return INT2FIX(VpDblFig());
483
- }
484
-
485
- /* call-seq:
486
- * precs -> array
487
- *
488
- * Returns an Array of two Integer values that represent platform-dependent
489
- * internal storage properties.
490
- *
491
- * This method is deprecated and will be removed in the future.
492
- * Instead, use BigDecimal#n_significant_digits for obtaining the number of
493
- * significant digits in scientific notation, and BigDecimal#precision for
494
- * obtaining the number of digits in decimal notation.
495
- *
496
- */
497
-
498
- static VALUE
499
- BigDecimal_prec(VALUE self)
500
- {
501
- ENTER(1);
502
- Real *p;
503
- VALUE obj;
504
-
505
- rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
506
- "BigDecimal#precs is deprecated and will be removed in the future; "
507
- "use BigDecimal#precision instead.");
508
-
509
- GUARD_OBJ(p, GetVpValue(self, 1));
510
- obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
511
- SIZET2NUM(p->MaxPrec*VpBaseFig()));
512
- return obj;
400
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
513
401
  }
514
402
 
515
403
  static void
516
- BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
404
+ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
517
405
  {
518
- ENTER(1);
519
-
520
406
  if (out_precision == NULL && out_scale == NULL)
521
407
  return;
522
-
523
- Real *p;
524
- GUARD_OBJ(p, GetVpValue(self, 1));
525
408
  if (VpIsZero(p) || !VpIsDef(p)) {
526
409
  zero:
527
410
  if (out_precision) *out_precision = 0;
@@ -625,6 +508,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
625
508
  }
626
509
  }
627
510
 
511
+ static void
512
+ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
513
+ {
514
+ BDVALUE v = GetBDValueMust(self);
515
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
516
+ RB_GC_GUARD(v.bigdecimal);
517
+ }
518
+
628
519
  /*
629
520
  * call-seq:
630
521
  * precision -> integer
@@ -660,8 +551,8 @@ BigDecimal_precision(VALUE self)
660
551
  * BigDecimal("1").scale # => 0
661
552
  * BigDecimal("1.1").scale # => 1
662
553
  * BigDecimal("3.1415").scale # => 4
663
- * BigDecimal("-1e20").precision # => 0
664
- * BigDecimal("1e-20").precision # => 20
554
+ * BigDecimal("-1e20").scale # => 0
555
+ * BigDecimal("1e-20").scale # => 20
665
556
  * BigDecimal("Infinity").scale # => 0
666
557
  * BigDecimal("-Infinity").scale # => 0
667
558
  * BigDecimal("NaN").scale # => 0
@@ -711,25 +602,23 @@ BigDecimal_precision_scale(VALUE self)
711
602
  static VALUE
712
603
  BigDecimal_n_significant_digits(VALUE self)
713
604
  {
714
- ENTER(1);
715
-
716
- Real *p;
717
- GUARD_OBJ(p, GetVpValue(self, 1));
718
- if (VpIsZero(p) || !VpIsDef(p)) {
605
+ BDVALUE v = GetBDValueMust(self);
606
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
719
607
  return INT2FIX(0);
720
608
  }
721
609
 
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);
610
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
611
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
724
612
  if (n == 0) return INT2FIX(0);
725
613
 
726
614
  DECDIG x;
727
615
  int nlz = BASE_FIG;
728
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
616
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
729
617
 
730
618
  int ntz = 0;
731
- for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
619
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
732
620
 
621
+ RB_GC_GUARD(v.bigdecimal);
733
622
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
734
623
  return SSIZET2NUM(n_significant_digits);
735
624
  }
@@ -751,17 +640,14 @@ BigDecimal_n_significant_digits(VALUE self)
751
640
  static VALUE
752
641
  BigDecimal_hash(VALUE self)
753
642
  {
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;
643
+ BDVALUE v = GetBDValueMust(self);
644
+ st_index_t hash = (st_index_t)v.real->sign;
760
645
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
761
646
  if(hash == 2 || hash == (st_index_t)-2) {
762
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
763
- hash += p->exponent;
647
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
648
+ hash += v.real->exponent;
764
649
  }
650
+ RB_GC_GUARD(v.bigdecimal);
765
651
  return ST2FIX(hash);
766
652
  }
767
653
 
@@ -780,21 +666,22 @@ BigDecimal_hash(VALUE self)
780
666
  static VALUE
781
667
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
782
668
  {
783
- ENTER(5);
784
- Real *vp;
669
+ BDVALUE v;
785
670
  char *psz;
786
671
  VALUE dummy;
787
672
  volatile VALUE dump;
788
673
  size_t len;
789
674
 
790
675
  rb_scan_args(argc, argv, "01", &dummy);
791
- GUARD_OBJ(vp,GetVpValue(self, 1));
792
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
676
+ v = GetBDValueMust(self);
677
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
793
678
  psz = RSTRING_PTR(dump);
794
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
679
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
795
680
  len = strlen(psz);
796
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
681
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
797
682
  rb_str_resize(dump, strlen(psz));
683
+
684
+ RB_GC_GUARD(v.bigdecimal);
798
685
  return dump;
799
686
  }
800
687
 
@@ -804,27 +691,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
804
691
  static VALUE
805
692
  BigDecimal_load(VALUE self, VALUE str)
806
693
  {
807
- ENTER(2);
808
- Real *pv;
694
+ BDVALUE v;
809
695
  unsigned char *pch;
810
696
  unsigned char ch;
811
- unsigned long m=0;
812
697
 
813
698
  pch = (unsigned char *)StringValueCStr(str);
814
- /* First get max prec */
699
+ /* First skip max prec. Don't trust the value. */
815
700
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
816
701
  if(!ISDIGIT(ch)) {
817
702
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
818
703
  }
819
- m = m*10 + (unsigned long)(ch-'0');
820
704
  }
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);
705
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
706
+ return CheckGetValue(v);
828
707
  }
829
708
 
830
709
  static unsigned short
@@ -1117,22 +996,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1117
996
  static size_t
1118
997
  GetAddSubPrec(Real *a, Real *b)
1119
998
  {
1120
- size_t mxs;
1121
- size_t mx = a->Prec;
1122
- SIGNED_VALUE d;
1123
-
1124
999
  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;
1000
+ ssize_t min_a = a->exponent - a->Prec;
1001
+ ssize_t min_b = b->exponent - b->Prec;
1002
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
1136
1003
  }
1137
1004
 
1138
1005
  static inline SIGNED_VALUE
@@ -1152,39 +1019,13 @@ check_int_precision(VALUE v)
1152
1019
  return n;
1153
1020
  }
1154
1021
 
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)
1022
+ static NULLABLE_BDVALUE
1023
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1186
1024
  {
1187
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
1025
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
1026
+ Real *pv = VpAlloc(str, strict_p, raise_exception);
1027
+ if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
1028
+ return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
1188
1029
  }
1189
1030
 
1190
1031
  static Real *
@@ -1192,7 +1033,7 @@ VpCopy(Real *pv, Real const* const x)
1192
1033
  {
1193
1034
  assert(x != NULL);
1194
1035
 
1195
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1036
+ pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
1196
1037
  pv->MaxPrec = x->MaxPrec;
1197
1038
  pv->Prec = x->Prec;
1198
1039
  pv->exponent = x->exponent;
@@ -1207,7 +1048,7 @@ VpCopy(Real *pv, Real const* const x)
1207
1048
  static VALUE
1208
1049
  BigDecimal_IsNaN(VALUE self)
1209
1050
  {
1210
- Real *p = GetVpValue(self, 1);
1051
+ Real *p = GetSelfVpValue(self);
1211
1052
  if (VpIsNaN(p)) return Qtrue;
1212
1053
  return Qfalse;
1213
1054
  }
@@ -1218,7 +1059,7 @@ BigDecimal_IsNaN(VALUE self)
1218
1059
  static VALUE
1219
1060
  BigDecimal_IsInfinite(VALUE self)
1220
1061
  {
1221
- Real *p = GetVpValue(self, 1);
1062
+ Real *p = GetSelfVpValue(self);
1222
1063
  if (VpIsPosInf(p)) return INT2FIX(1);
1223
1064
  if (VpIsNegInf(p)) return INT2FIX(-1);
1224
1065
  return Qnil;
@@ -1228,7 +1069,7 @@ BigDecimal_IsInfinite(VALUE self)
1228
1069
  static VALUE
1229
1070
  BigDecimal_IsFinite(VALUE self)
1230
1071
  {
1231
- Real *p = GetVpValue(self, 1);
1072
+ Real *p = GetSelfVpValue(self);
1232
1073
  if (VpIsNaN(p)) return Qfalse;
1233
1074
  if (VpIsInf(p)) return Qfalse;
1234
1075
  return Qtrue;
@@ -1240,6 +1081,7 @@ BigDecimal_check_num(Real *p)
1240
1081
  VpCheckException(p, true);
1241
1082
  }
1242
1083
 
1084
+ static VALUE BigDecimal_fix(VALUE self);
1243
1085
  static VALUE BigDecimal_split(VALUE self);
1244
1086
 
1245
1087
  /* Returns the value as an Integer.
@@ -1249,44 +1091,36 @@ static VALUE BigDecimal_split(VALUE self);
1249
1091
  static VALUE
1250
1092
  BigDecimal_to_i(VALUE self)
1251
1093
  {
1252
- ENTER(5);
1253
- ssize_t e, nf;
1254
- Real *p;
1094
+ BDVALUE v;
1095
+ VALUE ret;
1255
1096
 
1256
- GUARD_OBJ(p, GetVpValue(self, 1));
1257
- BigDecimal_check_num(p);
1097
+ v = GetBDValueMust(self);
1098
+ BigDecimal_check_num(v.real);
1258
1099
 
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]));
1100
+ if (v.real->exponent <= 0) return INT2FIX(0);
1101
+ if (v.real->exponent == 1) {
1102
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
1264
1103
  }
1265
1104
  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;
1105
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
1106
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
1107
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
1108
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
1109
+
1110
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
1111
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
1112
+ }
1113
+ if (dpower) {
1114
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
1115
+ // In Ruby < 3.4, int**int may return Float::INFINITY
1116
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
1117
+
1118
+ ret = rb_funcall(ret, '*', 1, pow10);
1119
+ }
1289
1120
  }
1121
+
1122
+ RB_GC_GUARD(v.bigdecimal);
1123
+ return ret;
1290
1124
  }
1291
1125
 
1292
1126
  /* Returns a new Float object having approximately the same value as the
@@ -1296,24 +1130,26 @@ BigDecimal_to_i(VALUE self)
1296
1130
  static VALUE
1297
1131
  BigDecimal_to_f(VALUE self)
1298
1132
  {
1299
- ENTER(1);
1300
- Real *p;
1301
1133
  double d;
1302
1134
  SIGNED_VALUE e;
1303
1135
  char *buf;
1304
1136
  volatile VALUE str;
1137
+ BDVALUE v = GetBDValueMust(self);
1138
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1305
1139
 
1306
- GUARD_OBJ(p, GetVpValue(self, 1));
1307
- if (VpVtoD(&d, &e, p) != 1)
1140
+ if (VpVtoD(&d, &e, v.real) != 1)
1308
1141
  return rb_float_new(d);
1309
1142
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1310
1143
  goto overflow;
1311
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1144
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1312
1145
  goto underflow;
1313
1146
 
1314
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1147
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1315
1148
  buf = RSTRING_PTR(str);
1316
- VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1149
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
1150
+
1151
+ RB_GC_GUARD(v.bigdecimal);
1152
+
1317
1153
  errno = 0;
1318
1154
  d = strtod(buf, 0);
1319
1155
  if (errno == ERANGE) {
@@ -1324,14 +1160,14 @@ BigDecimal_to_f(VALUE self)
1324
1160
 
1325
1161
  overflow:
1326
1162
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1327
- if (BIGDECIMAL_NEGATIVE_P(p))
1163
+ if (negative)
1328
1164
  return rb_float_new(VpGetDoubleNegInf());
1329
1165
  else
1330
1166
  return rb_float_new(VpGetDoublePosInf());
1331
1167
 
1332
1168
  underflow:
1333
1169
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1334
- if (BIGDECIMAL_NEGATIVE_P(p))
1170
+ if (negative)
1335
1171
  return rb_float_new(-0.0);
1336
1172
  else
1337
1173
  return rb_float_new(0.0);
@@ -1343,15 +1179,16 @@ underflow:
1343
1179
  static VALUE
1344
1180
  BigDecimal_to_r(VALUE self)
1345
1181
  {
1346
- Real *p;
1182
+ BDVALUE v;
1347
1183
  ssize_t sign, power, denomi_power;
1348
1184
  VALUE a, digits, numerator;
1349
1185
 
1350
- p = GetVpValue(self, 1);
1351
- BigDecimal_check_num(p);
1186
+ v = GetBDValueMust(self);
1187
+ BigDecimal_check_num(v.real);
1188
+ sign = VpGetSign(v.real);
1189
+ power = VpExponent10(v.real);
1190
+ RB_GC_GUARD(v.bigdecimal);
1352
1191
 
1353
- sign = VpGetSign(p);
1354
- power = VpExponent10(p);
1355
1192
  a = BigDecimal_split(self);
1356
1193
  digits = RARRAY_AREF(a, 1);
1357
1194
  denomi_power = power - RSTRING_LEN(digits);
@@ -1372,6 +1209,14 @@ BigDecimal_to_r(VALUE self)
1372
1209
  }
1373
1210
  }
1374
1211
 
1212
+ static size_t
1213
+ GetCoercePrec(Real *a, size_t prec)
1214
+ {
1215
+ if (prec == 0) prec = a->Prec * BASE_FIG;
1216
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1217
+ return prec;
1218
+ }
1219
+
1375
1220
  /* The coerce method provides support for Ruby type coercion. It is not
1376
1221
  * enabled by default.
1377
1222
  *
@@ -1389,26 +1234,9 @@ BigDecimal_to_r(VALUE self)
1389
1234
  static VALUE
1390
1235
  BigDecimal_coerce(VALUE self, VALUE other)
1391
1236
  {
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;
1237
+ Real* pv = DATA_PTR(self);
1238
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1239
+ return rb_assoc_new(CheckGetValue(b), self);
1412
1240
  }
1413
1241
 
1414
1242
  /*
@@ -1428,6 +1256,15 @@ BigDecimal_uplus(VALUE self)
1428
1256
  return self;
1429
1257
  }
1430
1258
 
1259
+ static bool
1260
+ is_coerceable_to_BigDecimal(VALUE r)
1261
+ {
1262
+ return is_kind_of_BigDecimal(r) ||
1263
+ RB_INTEGER_TYPE_P(r) ||
1264
+ RB_TYPE_P(r, T_FLOAT) ||
1265
+ RB_TYPE_P(r, T_RATIONAL);
1266
+ }
1267
+
1431
1268
  /*
1432
1269
  * call-seq:
1433
1270
  * self + value -> bigdecimal
@@ -1447,45 +1284,44 @@ BigDecimal_uplus(VALUE self)
1447
1284
  static VALUE
1448
1285
  BigDecimal_add(VALUE self, VALUE r)
1449
1286
  {
1450
- ENTER(5);
1451
- Real *c, *a, *b;
1452
- size_t mx;
1287
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
1288
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
1289
+ }
1453
1290
 
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
- }
1291
+ static VALUE
1292
+ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1293
+ {
1294
+ BDVALUE a, b, c;
1295
+ size_t mx;
1464
1296
 
1465
- if (!b) return DoSomeOne(self,r,'+');
1466
- SAVE(b);
1297
+ a = GetBDValueMust(self);
1298
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1467
1299
 
1468
- if (VpIsNaN(b)) return b->obj;
1469
- if (VpIsNaN(a)) return a->obj;
1300
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1301
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1470
1302
 
1471
- mx = GetAddSubPrec(a, b);
1303
+ mx = GetAddSubPrec(a.real, b.real);
1472
1304
  if (mx == (size_t)-1L) {
1473
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1474
- VpAddSub(c, a, b, 1);
1305
+ /* a or b is inf */
1306
+ c = NewZeroWrap(1, BASE_FIG);
1307
+ VpAddSub(c.real, a.real, b.real, operation);
1475
1308
  }
1476
1309
  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
- }
1310
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1311
+ size_t pl = VpGetPrecLimit();
1312
+ if (prec) VpSetPrecLimit(prec);
1313
+ // Let VpAddSub round the result
1314
+ VpAddSub(c.real, a.real, b.real, operation);
1315
+ if (prec) VpSetPrecLimit(pl);
1484
1316
  }
1485
- return VpCheckGetValue(c);
1317
+
1318
+ RB_GC_GUARD(a.bigdecimal);
1319
+ RB_GC_GUARD(b.bigdecimal);
1320
+ return CheckGetValue(c);
1486
1321
  }
1487
1322
 
1488
- /* call-seq:
1323
+ /*
1324
+ * call-seq:
1489
1325
  * self - value -> bigdecimal
1490
1326
  *
1491
1327
  * Returns the \BigDecimal difference of +self+ and +value+:
@@ -1502,73 +1338,18 @@ BigDecimal_add(VALUE self, VALUE r)
1502
1338
  static VALUE
1503
1339
  BigDecimal_sub(VALUE self, VALUE r)
1504
1340
  {
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);
1341
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1342
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1541
1343
  }
1542
1344
 
1543
1345
  static VALUE
1544
1346
  BigDecimalCmp(VALUE self, VALUE r,char op)
1545
1347
  {
1546
- ENTER(5);
1547
1348
  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;
1349
+ BDVALUE a = GetBDValueMust(self);
1350
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1567
1351
 
1568
- default:
1569
- break;
1570
- }
1571
- if (b == NULL) {
1352
+ if (b.real_or_null == NULL) {
1572
1353
  ID f = 0;
1573
1354
 
1574
1355
  switch (op) {
@@ -1597,8 +1378,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1597
1378
  }
1598
1379
  return rb_num_coerce_relop(self, r, f);
1599
1380
  }
1600
- SAVE(b);
1601
- e = VpComp(a, b);
1381
+ e = VpComp(a.real, b.real_or_null);
1382
+
1383
+ RB_GC_GUARD(a.bigdecimal);
1384
+ RB_GC_GUARD(b.bigdecimal_or_nil);
1385
+
1602
1386
  if (e == 999)
1603
1387
  return (op == '*') ? Qnil : Qfalse;
1604
1388
  switch (op) {
@@ -1638,7 +1422,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1638
1422
  static VALUE
1639
1423
  BigDecimal_zero(VALUE self)
1640
1424
  {
1641
- Real *a = GetVpValue(self, 1);
1425
+ Real *a = GetSelfVpValue(self);
1642
1426
  return VpIsZero(a) ? Qtrue : Qfalse;
1643
1427
  }
1644
1428
 
@@ -1646,7 +1430,7 @@ BigDecimal_zero(VALUE self)
1646
1430
  static VALUE
1647
1431
  BigDecimal_nonzero(VALUE self)
1648
1432
  {
1649
- Real *a = GetVpValue(self, 1);
1433
+ Real *a = GetSelfVpValue(self);
1650
1434
  return VpIsZero(a) ? Qnil : self;
1651
1435
  }
1652
1436
 
@@ -1772,12 +1556,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1772
1556
  static VALUE
1773
1557
  BigDecimal_neg(VALUE self)
1774
1558
  {
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);
1559
+ BDVALUE a = GetBDValueMust(self);
1560
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
1561
+ VpAsgn(c.real, a.real, -10);
1562
+ RB_GC_GUARD(a.bigdecimal);
1563
+ return CheckGetValue(c);
1781
1564
  }
1782
1565
 
1783
1566
  /*
@@ -1790,84 +1573,36 @@ BigDecimal_neg(VALUE self)
1790
1573
  *
1791
1574
  * See BigDecimal#mult.
1792
1575
  */
1793
-
1794
1576
  static VALUE
1795
1577
  BigDecimal_mult(VALUE self, VALUE r)
1796
1578
  {
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);
1579
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1580
+ return BigDecimal_mult_with_coerce(self, r, 0);
1819
1581
  }
1820
1582
 
1821
1583
  static VALUE
1822
- BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1823
- /* For c = self.div(r): with round operation */
1584
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1824
1585
  {
1825
- ENTER(5);
1826
- Real *a, *b;
1827
- ssize_t a_prec, b_prec;
1828
- size_t mx;
1586
+ BDVALUE a, b, c;
1829
1587
 
1830
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1831
- SAVE(a);
1588
+ a = GetBDValueMust(self);
1589
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1832
1590
 
1833
- VALUE rr = r;
1834
- if (is_kind_of_BigDecimal(rr)) {
1835
- /* do nothing */
1591
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
1592
+ VpMult(c.real, a.real, b.real);
1593
+ if (prec) {
1594
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
1836
1595
  }
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);
1842
- }
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, '/');
1596
+ else {
1597
+ VpLimitRound(c.real, 0);
1849
1598
  }
1850
1599
 
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;
1600
+ RB_GC_GUARD(a.bigdecimal);
1601
+ RB_GC_GUARD(b.bigdecimal);
1602
+ return CheckGetValue(c);
1868
1603
  }
1869
1604
 
1870
- static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1605
+ static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
1871
1606
 
1872
1607
  /* call-seq:
1873
1608
  * a / b -> bigdecimal
@@ -1884,20 +1619,8 @@ static VALUE
1884
1619
  BigDecimal_div(VALUE self, VALUE r)
1885
1620
  /* For c = self/r: with round operation */
1886
1621
  {
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);
1622
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1623
+ return BigDecimal_div2(self, r, INT2FIX(0));
1901
1624
  }
1902
1625
 
1903
1626
  static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
@@ -1942,119 +1665,115 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1942
1665
  /*
1943
1666
  * %: mod = a%b = a - (a.to_f/b).floor * b
1944
1667
  * div = (a.to_f/b).floor
1668
+ * In truncate mode, use truncate instead of floor.
1945
1669
  */
1946
- static VALUE
1947
- BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1670
+ static bool
1671
+ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
1948
1672
  {
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;
1673
+ BDVALUE a, b, dv, md, res;
1674
+ NULLABLE_BDVALUE b2;
1675
+ ssize_t a_exponent, b_exponent;
1676
+ size_t mx, rx, pl;
1954
1677
 
1955
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1956
- SAVE(a);
1678
+ a = GetBDValueMust(self);
1957
1679
 
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
- }
1680
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1681
+ if (!b2.real_or_null) return false;
1682
+ b = bdvalue_nonnullable(b2);
1971
1683
 
1972
- if (!is_kind_of_BigDecimal(rr)) {
1973
- return Qfalse;
1684
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1685
+ VALUE nan = BigDecimal_nan();
1686
+ *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1687
+ goto Done;
1974
1688
  }
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)) {
1689
+ if (VpIsZero(b.real)) {
1982
1690
  rb_raise(rb_eZeroDivError, "divided by 0");
1983
1691
  }
1984
- if (VpIsInf(a)) {
1985
- if (VpGetSign(a) == VpGetSign(b)) {
1692
+ if (VpIsInf(a.real)) {
1693
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1986
1694
  VALUE inf = BigDecimal_positive_infinity();
1987
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1695
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1988
1696
  }
1989
1697
  else {
1990
1698
  VALUE inf = BigDecimal_negative_infinity();
1991
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1699
+ *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1992
1700
  }
1993
1701
  VALUE nan = BigDecimal_nan();
1994
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
1995
- return Qtrue;
1702
+ *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1703
+ goto Done;
1996
1704
  }
1997
- if (VpIsInf(b)) {
1705
+ if (VpIsZero(a.real)) {
1998
1706
  VALUE zero = BigDecimal_positive_zero();
1999
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
2000
- *mod = a;
2001
- return Qtrue;
2002
- }
2003
- if (VpIsZero(a)) {
2004
- 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);
1707
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1708
+ *mod = bdvalue_nullable(a);
1709
+ goto Done;
1710
+ }
1711
+ if (VpIsInf(b.real)) {
1712
+ if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
1713
+ BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
1714
+ VpSetOne(minus_one.real);
1715
+ VpSetSign(minus_one.real, -1);
1716
+ RB_GC_GUARD(minus_one.bigdecimal);
1717
+ *div = bdvalue_nullable(minus_one);
1718
+ *mod = bdvalue_nullable(b);
1719
+ } else {
1720
+ VALUE zero = BigDecimal_positive_zero();
1721
+ *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1722
+ *mod = bdvalue_nullable(a);
1723
+ }
1724
+ goto Done;
1725
+ }
1726
+
1727
+ a_exponent = VpExponent10(a.real);
1728
+ b_exponent = VpExponent10(b.real);
1729
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
1730
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
1731
+
1732
+ /* res is reused for VpDivd remainder and VpMult result */
1733
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
1734
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
1735
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
1736
+ /* AddSub needs one more prec */
1737
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
1738
+
1739
+ VpDivd(dv.real, res.real, a.real, b.real);
1740
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
1741
+ VpMult(res.real, dv.real, b.real);
1742
+ pl = VpGetPrecLimit();
1743
+ VpSetPrecLimit(0);
1744
+ VpAddSub(md.real, a.real, res.real, -1);
1745
+ VpSetPrecLimit(pl);
2029
1746
 
2030
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1747
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
2031
1748
  /* 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;
1749
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
1750
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
1751
+ VpSetPrecLimit(0);
1752
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
1753
+ VpAddSub(md2.real, md.real, b.real, 1);
1754
+ VpSetPrecLimit(pl);
1755
+ *div = bdvalue_nullable(dv2);
1756
+ *mod = bdvalue_nullable(md2);
1757
+ RB_GC_GUARD(dv2.bigdecimal);
1758
+ RB_GC_GUARD(md2.bigdecimal);
2039
1759
  }
2040
1760
  else {
2041
- *div = d;
2042
- *mod = c;
1761
+ *div = bdvalue_nullable(dv);
1762
+ *mod = bdvalue_nullable(md);
2043
1763
  }
2044
- return Qtrue;
2045
1764
 
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;
1765
+ Done:
1766
+ RB_GC_GUARD(a.bigdecimal);
1767
+ RB_GC_GUARD(b.bigdecimal);
1768
+ RB_GC_GUARD(dv.bigdecimal);
1769
+ RB_GC_GUARD(md.bigdecimal);
1770
+ RB_GC_GUARD(res.bigdecimal);
1771
+ return true;
2053
1772
  }
2054
1773
 
2055
1774
  /* call-seq:
2056
- * a % b
2057
- * a.modulo(b)
1775
+ * a % b
1776
+ * a.modulo(b)
2058
1777
  *
2059
1778
  * Returns the modulus from dividing by b.
2060
1779
  *
@@ -2063,71 +1782,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2063
1782
  static VALUE
2064
1783
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2065
1784
  {
2066
- ENTER(3);
2067
- Real *div = NULL, *mod = NULL;
1785
+ NULLABLE_BDVALUE div, mod;
2068
1786
 
2069
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2070
- SAVE(div); SAVE(mod);
2071
- return VpCheckGetValue(mod);
1787
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1788
+ return CheckGetValue(bdvalue_nonnullable(mod));
2072
1789
  }
2073
1790
  return DoSomeOne(self, r, '%');
2074
1791
  }
2075
1792
 
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
1793
  /* call-seq:
2130
- * remainder(value)
1794
+ * remainder(value)
2131
1795
  *
2132
1796
  * Returns the remainder from dividing by the value.
2133
1797
  *
@@ -2136,15 +1800,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2136
1800
  static VALUE
2137
1801
  BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2138
1802
  {
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);
1803
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
1804
+
1805
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
1806
+ return CheckGetValue(bdvalue_nonnullable(mod));
1807
+ }
1808
+ return DoSomeOne(self, r, rb_intern("remainder"));
2144
1809
  }
2145
1810
 
2146
1811
  /* call-seq:
2147
- * divmod(value)
1812
+ * divmod(value)
2148
1813
  *
2149
1814
  * Divides by the specified value, and returns the quotient and modulus
2150
1815
  * as BigDecimal numbers. The quotient is rounded towards negative infinity.
@@ -2168,12 +1833,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2168
1833
  static VALUE
2169
1834
  BigDecimal_divmod(VALUE self, VALUE r)
2170
1835
  {
2171
- ENTER(5);
2172
- Real *div = NULL, *mod = NULL;
1836
+ NULLABLE_BDVALUE div, mod;
2173
1837
 
2174
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2175
- SAVE(div); SAVE(mod);
2176
- return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
1838
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1839
+ return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
2177
1840
  }
2178
1841
  return DoSomeOne(self,r,rb_intern("divmod"));
2179
1842
  }
@@ -2185,47 +1848,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
2185
1848
  static inline VALUE
2186
1849
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2187
1850
  {
2188
- ENTER(5);
2189
1851
  SIGNED_VALUE ix;
1852
+ BDVALUE av, bv, cv, res;
2190
1853
 
2191
1854
  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));
1855
+ NULLABLE_BDVALUE div;
1856
+ NULLABLE_BDVALUE mod;
1857
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
1858
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
2196
1859
  }
2197
1860
  return DoSomeOne(self, b, rb_intern("div"));
2198
1861
  }
2199
1862
 
2200
1863
  /* div in BigDecimal sense */
2201
1864
  ix = check_int_precision(n);
1865
+
1866
+ av = GetBDValueMust(self);
1867
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
1868
+
2202
1869
  if (ix == 0) {
2203
- return BigDecimal_div(self, b);
1870
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1871
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1872
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
1873
+ ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
1874
+ if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
1875
+ ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1876
+ if (limit && limit < ix) ix = limit;
2204
1877
  }
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);
1878
+
1879
+ // Needs to calculate 1 extra digit for rounding.
1880
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
1881
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
1882
+ VpDivd(cv.real, res.real, av.real, bv.real);
1883
+
1884
+ if (!VpIsZero(res.real)) {
1885
+ // Remainder value affects rounding result.
1886
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
1887
+ // 0.1e0 if remainder == 0
1888
+ // 0.1000000001e0 if remainder != 0
1889
+ size_t idx = roomof(ix, BASE_FIG);
1890
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
1891
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
2228
1892
  }
1893
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
1894
+
1895
+ RB_GC_GUARD(av.bigdecimal);
1896
+ RB_GC_GUARD(bv.bigdecimal);
1897
+ RB_GC_GUARD(res.bigdecimal);
1898
+ return CheckGetValue(cv);
2229
1899
  }
2230
1900
 
2231
1901
  /*
@@ -2301,22 +1971,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2301
1971
  static VALUE
2302
1972
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2303
1973
  {
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
- }
1974
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2316
1975
  }
2317
1976
 
2318
1977
  /* call-seq:
2319
- * sub(value, digits) -> bigdecimal
1978
+ * sub(value, digits) -> bigdecimal
2320
1979
  *
2321
1980
  * Subtract the specified value.
2322
1981
  *
@@ -2331,18 +1990,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2331
1990
  static VALUE
2332
1991
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2333
1992
  {
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
- }
1993
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2346
1994
  }
2347
1995
 
2348
1996
  /*
@@ -2374,18 +2022,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2374
2022
  static VALUE
2375
2023
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2376
2024
  {
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
- }
2025
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2389
2026
  }
2390
2027
 
2391
2028
  /*
@@ -2402,41 +2039,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2402
2039
  static VALUE
2403
2040
  BigDecimal_abs(VALUE self)
2404
2041
  {
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);
2042
+ BDVALUE a = GetBDValueMust(self);
2043
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
2044
+ VpAsgn(c.real, a.real, 10);
2045
+ VpChangeSign(c.real, 1);
2046
+ RB_GC_GUARD(a.bigdecimal);
2047
+ return CheckGetValue(c);
2440
2048
  }
2441
2049
 
2442
2050
  /* Return the integer part of the number, as a BigDecimal.
@@ -2444,19 +2052,15 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2444
2052
  static VALUE
2445
2053
  BigDecimal_fix(VALUE self)
2446
2054
  {
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);
2055
+ BDVALUE a = GetBDValueMust(self);
2056
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2057
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
2058
+ RB_GC_GUARD(a.bigdecimal);
2059
+ return CheckGetValue(c);
2456
2060
  }
2457
2061
 
2458
2062
  /* call-seq:
2459
- * round(n, mode)
2063
+ * round(n, mode)
2460
2064
  *
2461
2065
  * Round to the nearest integer (by default), returning the result as a
2462
2066
  * BigDecimal if n is specified and positive, or as an Integer if it isn't.
@@ -2484,13 +2088,12 @@ BigDecimal_fix(VALUE self)
2484
2088
  static VALUE
2485
2089
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2486
2090
  {
2487
- ENTER(5);
2488
- Real *c, *a;
2091
+ BDVALUE c, a;
2489
2092
  int iLoc = 0;
2490
2093
  VALUE vLoc;
2491
2094
  VALUE vRound;
2492
2095
  int round_to_int = 0;
2493
- size_t mx, pl;
2096
+ size_t mx;
2494
2097
 
2495
2098
  unsigned short sw = VpGetRoundMode();
2496
2099
 
@@ -2521,20 +2124,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2521
2124
  break;
2522
2125
  }
2523
2126
 
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);
2127
+ a = GetBDValueMust(self);
2128
+ mx = (a.real->Prec + 1) * BASE_FIG;
2129
+ c = NewZeroWrap(1, mx);
2130
+
2131
+ VpActiveRound(c.real, a.real, sw, iLoc);
2132
+
2133
+ RB_GC_GUARD(a.bigdecimal);
2134
+
2530
2135
  if (round_to_int) {
2531
- return BigDecimal_to_i(VpCheckGetValue(c));
2136
+ return BigDecimal_to_i(CheckGetValue(c));
2532
2137
  }
2533
- return VpCheckGetValue(c);
2138
+ return CheckGetValue(c);
2139
+ }
2140
+
2141
+ static VALUE
2142
+ BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
2143
+ {
2144
+ BDVALUE c, a;
2145
+ int iLoc;
2146
+ VALUE vLoc;
2147
+ size_t mx;
2148
+
2149
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2150
+ iLoc = 0;
2151
+ }
2152
+ else {
2153
+ iLoc = NUM2INT(vLoc);
2154
+ }
2155
+
2156
+ a = GetBDValueMust(self);
2157
+ mx = (a.real->Prec + 1) * BASE_FIG;
2158
+ c = NewZeroWrap(1, mx);
2159
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
2160
+
2161
+ RB_GC_GUARD(a.bigdecimal);
2162
+
2163
+ if (argc == 0) {
2164
+ return BigDecimal_to_i(CheckGetValue(c));
2165
+ }
2166
+ return CheckGetValue(c);
2534
2167
  }
2535
2168
 
2536
2169
  /* call-seq:
2537
- * truncate(n)
2170
+ * truncate(n)
2538
2171
  *
2539
2172
  * Truncate to the nearest integer (by default), returning the result as a
2540
2173
  * BigDecimal.
@@ -2555,28 +2188,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2555
2188
  static VALUE
2556
2189
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2557
2190
  {
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);
2191
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2580
2192
  }
2581
2193
 
2582
2194
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2584,19 +2196,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2584
2196
  static VALUE
2585
2197
  BigDecimal_frac(VALUE self)
2586
2198
  {
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);
2199
+ BDVALUE a = GetBDValueMust(self);
2200
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2201
+ VpFrac(c.real, a.real);
2202
+ RB_GC_GUARD(a.bigdecimal);
2203
+ return CheckGetValue(c);
2596
2204
  }
2597
2205
 
2598
2206
  /* call-seq:
2599
- * floor(n)
2207
+ * floor(n)
2600
2208
  *
2601
2209
  * Return the largest integer less than or equal to the value, as a BigDecimal.
2602
2210
  *
@@ -2615,35 +2223,11 @@ BigDecimal_frac(VALUE self)
2615
2223
  static VALUE
2616
2224
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2617
2225
  {
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);
2226
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2643
2227
  }
2644
2228
 
2645
2229
  /* call-seq:
2646
- * ceil(n)
2230
+ * ceil(n)
2647
2231
  *
2648
2232
  * Return the smallest integer greater than or equal to the value, as a BigDecimal.
2649
2233
  *
@@ -2662,31 +2246,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2662
2246
  static VALUE
2663
2247
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2664
2248
  {
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);
2249
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2686
2250
  }
2687
2251
 
2688
2252
  /* call-seq:
2689
- * to_s(s)
2253
+ * to_s(s)
2690
2254
  *
2691
2255
  * Converts the value to a string.
2692
2256
  *
@@ -2703,7 +2267,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2703
2267
  * If s contains a number, a space is inserted after each group of that many
2704
2268
  * digits, starting from '.' and counting outwards.
2705
2269
  *
2706
- * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2270
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
2707
2271
  *
2708
2272
  * If s ends with an 'F', conventional floating point notation is used.
2709
2273
  *
@@ -2721,10 +2285,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2721
2285
  static VALUE
2722
2286
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2723
2287
  {
2724
- ENTER(5);
2725
2288
  int fmt = 0; /* 0: E format, 1: F format */
2726
2289
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2727
- Real *vp;
2290
+ BDVALUE v;
2728
2291
  volatile VALUE str;
2729
2292
  char *psz;
2730
2293
  char ch;
@@ -2732,7 +2295,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2732
2295
  SIGNED_VALUE m;
2733
2296
  VALUE f;
2734
2297
 
2735
- GUARD_OBJ(vp, GetVpValue(self, 1));
2298
+ v = GetBDValueMust(self);
2736
2299
 
2737
2300
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2738
2301
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2767,10 +2330,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2767
2330
  }
2768
2331
  }
2769
2332
  if (fmt) {
2770
- nc = VpNumOfChars(vp, "F");
2333
+ nc = VpNumOfChars(v.real, "F");
2771
2334
  }
2772
2335
  else {
2773
- nc = VpNumOfChars(vp, "E");
2336
+ nc = VpNumOfChars(v.real, "E");
2774
2337
  }
2775
2338
  if (mc > 0) {
2776
2339
  nc += (nc + mc - 1) / mc + 1;
@@ -2780,12 +2343,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2780
2343
  psz = RSTRING_PTR(str);
2781
2344
 
2782
2345
  if (fmt) {
2783
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2346
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
2784
2347
  }
2785
2348
  else {
2786
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2349
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
2787
2350
  }
2788
2351
  rb_str_resize(str, strlen(psz));
2352
+
2353
+ RB_GC_GUARD(v.bigdecimal);
2789
2354
  return str;
2790
2355
  }
2791
2356
 
@@ -2816,16 +2381,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2816
2381
  static VALUE
2817
2382
  BigDecimal_split(VALUE self)
2818
2383
  {
2819
- ENTER(5);
2820
- Real *vp;
2384
+ BDVALUE v;
2821
2385
  VALUE obj,str;
2822
2386
  ssize_t e, s;
2823
2387
  char *psz1;
2824
2388
 
2825
- GUARD_OBJ(vp, GetVpValue(self, 1));
2826
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2389
+ v = GetBDValueMust(self);
2390
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
2827
2391
  psz1 = RSTRING_PTR(str);
2828
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2392
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
2829
2393
  s = 1;
2830
2394
  if(psz1[0] == '-') {
2831
2395
  size_t len = strlen(psz1 + 1);
@@ -2835,13 +2399,15 @@ BigDecimal_split(VALUE self)
2835
2399
  s = -1;
2836
2400
  }
2837
2401
  if (psz1[0] == 'N') s = 0; /* NaN */
2838
- e = VpExponent10(vp);
2402
+ e = VpExponent10(v.real);
2839
2403
  obj = rb_ary_new2(4);
2840
2404
  rb_ary_push(obj, INT2FIX(s));
2841
2405
  rb_ary_push(obj, str);
2842
2406
  rb_str_resize(str, strlen(psz1));
2843
2407
  rb_ary_push(obj, INT2FIX(10));
2844
2408
  rb_ary_push(obj, SSIZET2NUM(e));
2409
+
2410
+ RB_GC_GUARD(v.bigdecimal);
2845
2411
  return obj;
2846
2412
  }
2847
2413
 
@@ -2853,7 +2419,7 @@ BigDecimal_split(VALUE self)
2853
2419
  static VALUE
2854
2420
  BigDecimal_exponent(VALUE self)
2855
2421
  {
2856
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2422
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
2857
2423
  return SSIZET2NUM(e);
2858
2424
  }
2859
2425
 
@@ -2865,49 +2431,78 @@ BigDecimal_exponent(VALUE self)
2865
2431
  static VALUE
2866
2432
  BigDecimal_inspect(VALUE self)
2867
2433
  {
2868
- ENTER(5);
2869
- Real *vp;
2434
+ BDVALUE v;
2870
2435
  volatile VALUE str;
2871
2436
  size_t nc;
2872
2437
 
2873
- GUARD_OBJ(vp, GetVpValue(self, 1));
2874
- nc = VpNumOfChars(vp, "E");
2438
+ v = GetBDValueMust(self);
2439
+ nc = VpNumOfChars(v.real, "E");
2875
2440
 
2876
2441
  str = rb_str_new(0, nc);
2877
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2442
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2878
2443
  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
2444
 
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
-
2888
- inline static int
2889
- is_integer(VALUE x)
2890
- {
2891
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2445
+ RB_GC_GUARD(v.bigdecimal);
2446
+ return str;
2892
2447
  }
2893
2448
 
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;
2449
+ /* Returns self * 10**v without changing the precision.
2450
+ * This method is currently for internal use.
2451
+ *
2452
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2453
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
2454
+ */
2455
+ static VALUE
2456
+ BigDecimal_decimal_shift(VALUE self, VALUE v)
2457
+ {
2458
+ BDVALUE a, c;
2459
+ ssize_t shift, exponentShift;
2460
+ bool shiftDown;
2461
+ size_t prec;
2462
+ DECDIG ex, iex;
2463
+
2464
+ a = GetBDValueMust(self);
2465
+ shift = NUM2SSIZET(rb_to_int(v));
2466
+
2467
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
2468
+
2469
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
2470
+ shift -= exponentShift * BASE_FIG;
2471
+ ex = 1;
2472
+ for (int i = 0; i < shift; i++) ex *= 10;
2473
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
2474
+ iex = BASE / ex;
2475
+
2476
+ prec = a.real->Prec + shiftDown;
2477
+ c = NewZeroWrap(1, prec * BASE_FIG);
2478
+ if (shift == 0) {
2479
+ VpAsgn(c.real, a.real, 10);
2480
+ } else if (shiftDown) {
2481
+ DECDIG carry = 0;
2482
+ exponentShift++;
2483
+ for (size_t i = 0; i < a.real->Prec; i++) {
2484
+ DECDIG v = a.real->frac[i];
2485
+ c.real->frac[i] = carry * ex + v / iex;
2486
+ carry = v % iex;
2487
+ }
2488
+ c.real->frac[a.real->Prec] = carry * ex;
2489
+ } else {
2490
+ DECDIG carry = 0;
2491
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
2492
+ DECDIG v = a.real->frac[i];
2493
+ c.real->frac[i] = v % iex * ex + carry;
2494
+ carry = v / iex;
2495
+ }
2905
2496
  }
2906
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2497
+ while (c.real->frac[prec - 1] == 0) prec--;
2498
+ c.real->Prec = prec;
2499
+ c.real->sign = a.real->sign;
2500
+ c.real->exponent = a.real->exponent;
2501
+ AddExponent(c.real, exponentShift);
2502
+ RB_GC_GUARD(a.bigdecimal);
2503
+ return CheckGetValue(c);
2907
2504
  }
2908
2505
 
2909
- #define is_positive(x) (!is_negative(x))
2910
-
2911
2506
  inline static int
2912
2507
  is_zero(VALUE x)
2913
2508
  {
@@ -2931,344 +2526,6 @@ is_zero(VALUE x)
2931
2526
  return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2932
2527
  }
2933
2528
 
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
2529
  /* :nodoc: */
3273
2530
  static VALUE
3274
2531
  BigDecimal_clone(VALUE self)
@@ -3307,20 +2564,18 @@ check_exception(VALUE bd)
3307
2564
 
3308
2565
  Real *vp;
3309
2566
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3310
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2567
+ VpCheckException(vp, false);
3311
2568
 
3312
2569
  return bd;
3313
2570
  }
3314
2571
 
3315
2572
  static VALUE
3316
- rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
2573
+ rb_uint64_convert_to_BigDecimal(uint64_t uval)
3317
2574
  {
3318
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3319
-
2575
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3320
2576
  Real *vp;
3321
2577
  if (uval == 0) {
3322
2578
  vp = rbd_allocate_struct(1);
3323
- vp->MaxPrec = 1;
3324
2579
  vp->Prec = 1;
3325
2580
  vp->exponent = 1;
3326
2581
  VpSetZero(vp, 1);
@@ -3328,7 +2583,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3328
2583
  }
3329
2584
  else if (uval < BASE) {
3330
2585
  vp = rbd_allocate_struct(1);
3331
- vp->MaxPrec = 1;
3332
2586
  vp->Prec = 1;
3333
2587
  vp->exponent = 1;
3334
2588
  VpSetSign(vp, 1);
@@ -3354,21 +2608,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3354
2608
 
3355
2609
  const size_t exp = len + ntz;
3356
2610
  vp = rbd_allocate_struct(len);
3357
- vp->MaxPrec = len;
3358
2611
  vp->Prec = len;
3359
2612
  vp->exponent = exp;
3360
2613
  VpSetSign(vp, 1);
3361
2614
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3362
2615
  }
3363
2616
 
3364
- return BigDecimal_wrap_struct(obj, vp);
2617
+ return BigDecimal_wrap_struct(null_wrapped, vp);
3365
2618
  }
3366
2619
 
3367
2620
  static VALUE
3368
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2621
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3369
2622
  {
3370
2623
  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);
2624
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3372
2625
  if (ival < 0) {
3373
2626
  Real *vp;
3374
2627
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
@@ -3378,7 +2631,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
3378
2631
  }
3379
2632
 
3380
2633
  static VALUE
3381
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2634
+ rb_big_convert_to_BigDecimal(VALUE val)
3382
2635
  {
3383
2636
  assert(RB_TYPE_P(val, T_BIGNUM));
3384
2637
 
@@ -3390,40 +2643,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3390
2643
  }
3391
2644
  if (size <= sizeof(long)) {
3392
2645
  if (sign < 0) {
3393
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2646
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3394
2647
  }
3395
2648
  else {
3396
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2649
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3397
2650
  }
3398
2651
  }
3399
2652
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3400
2653
  else if (size <= sizeof(LONG_LONG)) {
3401
2654
  if (sign < 0) {
3402
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2655
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3403
2656
  }
3404
2657
  else {
3405
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2658
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3406
2659
  }
3407
2660
  }
3408
2661
  #endif
3409
2662
  else {
3410
2663
  VALUE str = rb_big2str(val, 10);
3411
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3412
- RSTRING_PTR(str), true);
2664
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2665
+ RSTRING_PTR(str),
2666
+ rb_cBigDecimal,
2667
+ true,
2668
+ true
2669
+ ));
3413
2670
  RB_GC_GUARD(str);
3414
- return check_exception(vp->obj);
2671
+ return CheckGetValue(v);
3415
2672
  }
3416
2673
  }
3417
2674
 
3418
2675
  static VALUE
3419
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2676
+ rb_inum_convert_to_BigDecimal(VALUE val)
3420
2677
  {
3421
2678
  assert(RB_INTEGER_TYPE_P(val));
3422
2679
  if (FIXNUM_P(val)) {
3423
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2680
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3424
2681
  }
3425
2682
  else {
3426
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2683
+ return rb_big_convert_to_BigDecimal(val);
3427
2684
  }
3428
2685
  }
3429
2686
 
@@ -3458,11 +2715,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3458
2715
  }
3459
2716
 
3460
2717
  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));
2718
+ digs = 0;
3466
2719
  }
3467
2720
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3468
2721
  if (!raise_exception)
@@ -3577,7 +2830,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3577
2830
  exp = -exp;
3578
2831
  }
3579
2832
 
3580
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
2833
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
3581
2834
  Real *vp;
3582
2835
  TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3583
2836
  assert(vp->Prec == prec);
@@ -3600,28 +2853,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3600
2853
  CLASS_OF(val));
3601
2854
  }
3602
2855
 
3603
- VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
2856
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
3604
2857
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3605
2858
  return d;
3606
2859
  }
3607
2860
 
3608
2861
  static VALUE
3609
- rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
2862
+ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
3610
2863
  {
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);
2864
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
2865
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
2866
+ return CheckGetValue(bdvalue_nonnullable(v));
3618
2867
  }
3619
2868
 
3620
2869
  static inline VALUE
3621
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2870
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3622
2871
  {
3623
2872
  const char *c_str = StringValueCStr(val);
3624
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2873
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3625
2874
  }
3626
2875
 
3627
2876
  static VALUE
@@ -3649,17 +2898,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3649
2898
  if (digs == SIZE_MAX)
3650
2899
  return check_exception(val);
3651
2900
 
2901
+ NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
3652
2902
  Real *vp;
3653
2903
  TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
3654
-
3655
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3656
2904
  vp = VpCopy(NULL, vp);
2905
+ RB_GC_GUARD(val);
2906
+
2907
+ VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
3657
2908
  /* TODO: rounding */
3658
- BigDecimal_wrap_struct(copy, vp);
3659
- return VpCheckGetValue(vp);
2909
+ return check_exception(copy);
3660
2910
  }
3661
2911
  else if (RB_INTEGER_TYPE_P(val)) {
3662
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2912
+ return rb_inum_convert_to_BigDecimal(val);
3663
2913
  }
3664
2914
  else if (RB_FLOAT_TYPE_P(val)) {
3665
2915
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3677,7 +2927,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3677
2927
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3678
2928
  }
3679
2929
  else if (RB_TYPE_P(val, T_STRING)) {
3680
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2930
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3681
2931
  }
3682
2932
 
3683
2933
  /* TODO: chheck to_d */
@@ -3691,7 +2941,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3691
2941
  }
3692
2942
  return Qnil;
3693
2943
  }
3694
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2944
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3695
2945
  }
3696
2946
 
3697
2947
  /* call-seq:
@@ -3712,12 +2962,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3712
2962
  *
3713
2963
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3714
2964
  *
3715
- * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
2965
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
3716
2966
  * BigDecimal(2) # => 0.2e1
3717
2967
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3718
2968
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3719
- * # Float or Rational value requires ndigits.
3720
- * BigDecimal(2.0, 0) # => 0.2e1
2969
+ * BigDecimal(2.0) # => 0.2e1
2970
+ * # Rational value requires ndigits.
3721
2971
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3722
2972
  *
3723
2973
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3781,15 +3031,16 @@ static VALUE
3781
3031
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3782
3032
  {
3783
3033
  char const *c_str = StringValueCStr(str);
3784
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3785
- if (!vp)
3034
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3035
+ if (v.bigdecimal_or_nil == Qnil)
3786
3036
  return Qnil;
3787
3037
  else
3788
- return VpCheckGetValue(vp);
3038
+ return CheckGetValue(bdvalue_nonnullable(v));
3789
3039
  }
3790
3040
 
3791
- /* call-seq:
3792
- * BigDecimal.limit(digits)
3041
+ /*
3042
+ * call-seq:
3043
+ * BigDecimal.limit(digits)
3793
3044
  *
3794
3045
  * Limit the number of significant digits in newly created BigDecimal
3795
3046
  * numbers to the specified value. Rounding is performed as necessary,
@@ -3839,7 +3090,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3839
3090
  static VALUE
3840
3091
  BigDecimal_sign(VALUE self)
3841
3092
  { /* sign */
3842
- int s = GetVpValue(self, 1)->sign;
3093
+ int s = GetSelfVpValue(self)->sign;
3843
3094
  return INT2FIX(s);
3844
3095
  }
3845
3096
 
@@ -3911,310 +3162,15 @@ BigDecimal_save_rounding_mode(VALUE self)
3911
3162
  * puts BigDecimal.limit
3912
3163
  *
3913
3164
  */
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;
3165
+ static VALUE
3166
+ BigDecimal_save_limit(VALUE self)
3167
+ {
3168
+ size_t const limit = VpGetPrecLimit();
3169
+ int state;
3170
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
3171
+ VpSetPrecLimit(limit);
3172
+ if (state) rb_jump_tag(state);
3173
+ return ret;
4218
3174
  }
4219
3175
 
4220
3176
  static VALUE BIGDECIMAL_NAN = Qnil;
@@ -4268,6 +3224,34 @@ BigDecimal_literal(const char *str)
4268
3224
 
4269
3225
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4270
3226
 
3227
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3228
+ VALUE
3229
+ BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3230
+ BDVALUE a,b,c,d;
3231
+ size_t cn = NUM2INT(cprec);
3232
+ a = GetBDValueMust(self);
3233
+ b = GetBDValueMust(r);
3234
+ c = NewZeroWrap(1, cn * BASE_FIG);
3235
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3236
+ VpDivd(c.real, d.real, a.real, b.real);
3237
+ RB_GC_GUARD(a.bigdecimal);
3238
+ RB_GC_GUARD(b.bigdecimal);
3239
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3240
+ }
3241
+
3242
+ VALUE
3243
+ BigDecimal_vpmult(VALUE self, VALUE v) {
3244
+ BDVALUE a,b,c;
3245
+ a = GetBDValueMust(self);
3246
+ b = GetBDValueMust(v);
3247
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3248
+ VpMult(c.real, a.real, b.real);
3249
+ RB_GC_GUARD(a.bigdecimal);
3250
+ RB_GC_GUARD(b.bigdecimal);
3251
+ return c.bigdecimal;
3252
+ }
3253
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3254
+
4271
3255
  /* Document-class: BigDecimal
4272
3256
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4273
3257
  *
@@ -4384,14 +3368,16 @@ BigDecimal_literal(const char *str)
4384
3368
  *
4385
3369
  * When you require +bigdecimal/util+, the #to_d method will be
4386
3370
  * available on BigDecimal and the native Integer, Float, Rational,
4387
- * and String classes:
3371
+ * String, Complex, and NilClass classes:
4388
3372
  *
4389
3373
  * require 'bigdecimal/util'
4390
3374
  *
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
3375
+ * 42.to_d # => 0.42e2
3376
+ * 0.5.to_d # => 0.5e0
3377
+ * (2/3r).to_d(3) # => 0.667e0
3378
+ * "0.5".to_d # => 0.5e0
3379
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
3380
+ * nil.to_d # => 0.0
4395
3381
  *
4396
3382
  * == Methods for Working with \JSON
4397
3383
  *
@@ -4465,7 +3451,7 @@ Init_bigdecimal(void)
4465
3451
  * guarantee that two groups could always be multiplied together without
4466
3452
  * overflow.)
4467
3453
  */
4468
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3454
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4469
3455
 
4470
3456
  /* Exceptions */
4471
3457
 
@@ -4576,7 +3562,6 @@ Init_bigdecimal(void)
4576
3562
  rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
4577
3563
 
4578
3564
  /* instance methods */
4579
- rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
4580
3565
  rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
4581
3566
  rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
4582
3567
  rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
@@ -4607,14 +3592,11 @@ Init_bigdecimal(void)
4607
3592
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4608
3593
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4609
3594
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4610
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4611
3595
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4612
3596
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4613
3597
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4614
3598
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4615
3599
  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
3600
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4619
3601
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4620
3602
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4633,11 +3615,13 @@ Init_bigdecimal(void)
4633
3615
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4634
3616
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4635
3617
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3618
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4636
3619
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4637
3620
 
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);
3621
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3622
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
3623
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3624
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
4641
3625
 
4642
3626
  #define ROUNDING_MODE(i, name, value) \
4643
3627
  id_##name = rb_intern_const(#name); \
@@ -4677,19 +3661,9 @@ Init_bigdecimal(void)
4677
3661
  */
4678
3662
  #ifdef BIGDECIMAL_DEBUG
4679
3663
  static int gfDebug = 1; /* Debug switch */
4680
- #if 0
4681
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4682
- #endif
4683
3664
  #endif /* BIGDECIMAL_DEBUG */
4684
3665
 
4685
3666
  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
3667
 
4694
3668
  enum op_sw {
4695
3669
  OP_SW_ADD = 1, /* + */
@@ -4699,11 +3673,9 @@ enum op_sw {
4699
3673
  };
4700
3674
 
4701
3675
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4702
- static int AddExponent(Real *a, SIGNED_VALUE n);
4703
3676
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4704
3677
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4705
3678
  static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
4706
- static int VpNmlz(Real *a);
4707
3679
  static void VpFormatSt(char *psz, size_t fFmt);
4708
3680
  static int VpRdup(Real *m, size_t ind_m);
4709
3681
 
@@ -4762,10 +3734,10 @@ VpCheckException(Real *p, bool always)
4762
3734
  }
4763
3735
 
4764
3736
  static VALUE
4765
- VpCheckGetValue(Real *p)
3737
+ CheckGetValue(BDVALUE v)
4766
3738
  {
4767
- VpCheckException(p, false);
4768
- return p->obj;
3739
+ VpCheckException(v.real, false);
3740
+ return v.bigdecimal;
4769
3741
  }
4770
3742
 
4771
3743
  /*
@@ -4797,12 +3769,10 @@ VpGetPrecLimit(void)
4797
3769
  return NUM2SIZET(vlimit);
4798
3770
  }
4799
3771
 
4800
- VP_EXPORT size_t
3772
+ VP_EXPORT void
4801
3773
  VpSetPrecLimit(size_t n)
4802
3774
  {
4803
- size_t const s = VpGetPrecLimit();
4804
3775
  bigdecimal_set_thread_local_precision_limit(n);
4805
- return s;
4806
3776
  }
4807
3777
 
4808
3778
  /*
@@ -4917,15 +3887,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4917
3887
  return nzero;
4918
3888
  }
4919
3889
 
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
3890
  VP_EXPORT int
4930
3891
  VpException(unsigned short f, const char *str,int always)
4931
3892
  {
@@ -5077,7 +4038,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5077
4038
  case 'E':
5078
4039
  /* fall through */
5079
4040
  default:
5080
- nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4041
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
5081
4042
  }
5082
4043
  return nc;
5083
4044
  }
@@ -5103,28 +4064,13 @@ VpInit(DECDIG BaseVal)
5103
4064
  VpGetDoubleNegZero();
5104
4065
 
5105
4066
  /* 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;
4067
+ VpConstOne = NewZero(1, 1);
4068
+ VpSetOne(VpConstOne);
5112
4069
 
5113
4070
  #ifdef BIGDECIMAL_DEBUG
5114
4071
  gnAlloc = 0;
5115
4072
  #endif /* BIGDECIMAL_DEBUG */
5116
4073
 
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
4074
  return BIGDECIMAL_DOUBLE_FIGURES;
5129
4075
  }
5130
4076
 
@@ -5140,24 +4086,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5140
4086
  {
5141
4087
  SIGNED_VALUE e = a->exponent;
5142
4088
  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;
4089
+ if (e > 0 && n > 0) {
4090
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
4091
+ } else if (e < 0 && n < 0) {
4092
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
4093
+ } else if (m > VP_EXPONENT_MAX) {
4094
+ goto overflow;
4095
+ } else if (m < VP_EXPONENT_MIN) {
4096
+ goto underflow;
5161
4097
  }
5162
4098
  a->exponent = m;
5163
4099
  return 1;
@@ -5198,7 +4134,6 @@ bigdecimal_parse_special_string(const char *str)
5198
4134
  while (*p && ISSPACE(*p)) ++p;
5199
4135
  if (*p == '\0') {
5200
4136
  Real *vp = rbd_allocate_struct(1);
5201
- vp->MaxPrec = 1;
5202
4137
  switch (table[i].sign) {
5203
4138
  default:
5204
4139
  UNREACHABLE; break;
@@ -5263,38 +4198,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
5263
4198
  /*
5264
4199
  * Allocates variable.
5265
4200
  * [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.
4201
+ * szVal ... The value assigned(char).
5271
4202
  *
5272
4203
  * [Returns]
5273
4204
  * Pointer to the newly allocated variable, or
5274
4205
  * NULL be returned if memory allocation is failed,or any error.
5275
4206
  */
5276
4207
  VP_EXPORT Real *
5277
- VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4208
+ VpAlloc(const char *szVal, int strict_p, int exc)
5278
4209
  {
5279
4210
  const char *orig_szVal = szVal;
5280
4211
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5281
- size_t len;
5282
4212
  char v, *psz;
5283
4213
  int sign=1;
5284
4214
  Real *vp = NULL;
5285
4215
  VALUE buf;
5286
4216
 
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
4217
  /* Skipping leading spaces */
5299
4218
  while (ISSPACE(*szVal)) szVal++;
5300
4219
 
@@ -5303,14 +4222,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5303
4222
  return vp;
5304
4223
  }
5305
4224
 
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
- }
4225
+ /* Skip leading `#`.
4226
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
4227
+ * but now it has no effect.
4228
+ */
4229
+ if (*szVal == '#') ++szVal;
5314
4230
 
5315
4231
  /* Scanning digits */
5316
4232
 
@@ -5457,7 +4373,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5457
4373
  VALUE str;
5458
4374
  invalid_value:
5459
4375
  if (!strict_p) {
5460
- goto return_zero;
4376
+ return NewZero(1, 1);
5461
4377
  }
5462
4378
  if (!exc) {
5463
4379
  return NULL;
@@ -5468,11 +4384,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5468
4384
 
5469
4385
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5470
4386
  /* 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 */
4387
+ vp = rbd_allocate_struct(nalloc);
5476
4388
  VpSetZero(vp, sign);
5477
4389
  protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
5478
4390
  rb_str_resize(buf, 0);
@@ -5512,7 +4424,7 @@ VpAsgn(Real *c, Real *a, int isw)
5512
4424
  c->Prec = n;
5513
4425
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5514
4426
  /* Needs round ? */
5515
- if (isw != 10) {
4427
+ if (isw != 10 && isw != -10) {
5516
4428
  /* Not in ActiveRound */
5517
4429
  if(c->Prec < a->Prec) {
5518
4430
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5538,19 +4450,11 @@ VpAsgn(Real *c, Real *a, int isw)
5538
4450
  VP_EXPORT size_t
5539
4451
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5540
4452
  {
5541
- short sw, isw;
4453
+ short sw, isw, sign;
5542
4454
  Real *a_ptr, *b_ptr;
5543
4455
  size_t n, na, nb, i;
5544
4456
  DECDIG mrv;
5545
4457
 
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
4458
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5555
4459
 
5556
4460
  /* check if a or b is zero */
@@ -5639,28 +4543,21 @@ end_if:
5639
4543
  if (isw) { /* addition */
5640
4544
  VpSetSign(c, 1);
5641
4545
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5642
- VpSetSign(c, isw / 2);
4546
+ sign = isw / 2;
5643
4547
  }
5644
4548
  else { /* subtraction */
5645
4549
  VpSetSign(c, 1);
5646
4550
  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
- }
4551
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5653
4552
  }
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);
4553
+ if (VpIsInf(c)) {
4554
+ VpSetInf(c, sign);
5662
4555
  }
5663
- #endif /* BIGDECIMAL_DEBUG */
4556
+ else {
4557
+ VpSetSign(c, sign);
4558
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4559
+ }
4560
+
5664
4561
  return c->Prec * BASE_FIG;
5665
4562
  }
5666
4563
 
@@ -5681,13 +4578,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5681
4578
  size_t c_pos;
5682
4579
  DECDIG av, bv, carry, mrv;
5683
4580
 
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
4581
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5692
4582
  a_pos = ap;
5693
4583
  b_pos = bp;
@@ -5753,11 +4643,6 @@ Assign_a:
5753
4643
 
5754
4644
  Exit:
5755
4645
 
5756
- #ifdef BIGDECIMAL_DEBUG
5757
- if (gfDebug) {
5758
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5759
- }
5760
- #endif /* BIGDECIMAL_DEBUG */
5761
4646
  return mrv;
5762
4647
  }
5763
4648
 
@@ -5776,13 +4661,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5776
4661
  size_t c_pos;
5777
4662
  DECDIG av, bv, borrow, mrv;
5778
4663
 
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
4664
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5787
4665
  a_pos = ap;
5788
4666
  b_pos = bp;
@@ -5858,11 +4736,6 @@ Assign_a:
5858
4736
  mrv = 0;
5859
4737
 
5860
4738
  Exit:
5861
- #ifdef BIGDECIMAL_DEBUG
5862
- if (gfDebug) {
5863
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5864
- }
5865
- #endif /* BIGDECIMAL_DEBUG */
5866
4739
  return mrv;
5867
4740
  }
5868
4741
 
@@ -5993,19 +4866,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5993
4866
  VP_EXPORT size_t
5994
4867
  VpMult(Real *c, Real *a, Real *b)
5995
4868
  {
5996
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
4869
+ size_t MxIndA, MxIndB, MxIndAB;
5997
4870
  size_t ind_c, i, ii, nc;
5998
4871
  size_t ind_as, ind_ae, ind_bs;
5999
4872
  DECDIG carry;
6000
4873
  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
4874
 
6010
4875
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
6011
4876
 
@@ -6016,39 +4881,28 @@ VpMult(Real *c, Real *a, Real *b)
6016
4881
  }
6017
4882
 
6018
4883
  if (VpIsOne(a)) {
6019
- VpAsgn(c, b, VpGetSign(a));
4884
+ VpAsgn(c, b, 10 * VpGetSign(a));
6020
4885
  goto Exit;
6021
4886
  }
6022
4887
  if (VpIsOne(b)) {
6023
- VpAsgn(c, a, VpGetSign(b));
4888
+ VpAsgn(c, a, 10 * VpGetSign(b));
6024
4889
  goto Exit;
6025
4890
  }
6026
4891
  if (b->Prec > a->Prec) {
6027
4892
  /* Adjust so that digits(a)>digits(b) */
6028
- w = a;
4893
+ Real *w = a;
6029
4894
  a = b;
6030
4895
  b = w;
6031
4896
  }
6032
- w = NULL;
6033
4897
  MxIndA = a->Prec - 1;
6034
4898
  MxIndB = b->Prec - 1;
6035
- MxIndC = c->MaxPrec - 1;
6036
4899
  MxIndAB = a->Prec + b->Prec - 1;
6037
4900
 
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
4901
  /* set LHSV c info */
6045
4902
 
6046
4903
  c->exponent = a->exponent; /* set exponent */
6047
- if (!AddExponent(c, b->exponent)) {
6048
- if (w) rbd_free_struct(c);
6049
- return 0;
6050
- }
6051
4904
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
4905
+ if (!AddExponent(c, b->exponent)) return 0;
6052
4906
  carry = 0;
6053
4907
  nc = ind_c = MxIndAB;
6054
4908
  memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
@@ -6095,29 +4949,18 @@ VpMult(Real *c, Real *a, Real *b)
6095
4949
  }
6096
4950
  }
6097
4951
  }
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
- }
4952
+ VpNmlz(c);
6107
4953
 
6108
4954
  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
4955
  return c->Prec*BASE_FIG;
6117
4956
  }
6118
4957
 
6119
4958
  /*
6120
4959
  * c = a / b, remainder = r
4960
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
4961
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
4962
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
4963
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
6121
4964
  */
6122
4965
  VP_EXPORT size_t
6123
4966
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6126,16 +4969,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6126
4969
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6127
4970
  size_t nLoop;
6128
4971
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6129
- DECDIG borrow, borrow1, borrow2;
4972
+ DECDIG borrow1, borrow2;
6130
4973
  DECDIG_DBL qb;
6131
4974
 
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
4975
  VpSetNaN(r);
6140
4976
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6141
4977
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6152,30 +4988,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6152
4988
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6153
4989
  goto Exit;
6154
4990
  }
6155
- if (VpIsOne(b)) {
6156
- /* divide by one */
6157
- VpAsgn(c, a, VpGetSign(b));
6158
- VpSetZero(r, VpGetSign(a));
6159
- goto Exit;
6160
- }
6161
4991
 
6162
4992
  word_a = a->Prec;
6163
4993
  word_b = b->Prec;
6164
4994
  word_c = c->MaxPrec;
6165
4995
  word_r = r->MaxPrec;
6166
4996
 
6167
- if (word_a >= word_r) goto space_error;
4997
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6168
4998
 
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;
4999
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
5000
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
5001
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
6179
5002
 
6180
5003
  /* initial procedure */
6181
5004
  b1 = b1p1 = b->frac[0];
@@ -6190,15 +5013,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6190
5013
 
6191
5014
  /* */
6192
5015
  /* loop start */
6193
- ind_c = word_r - 1;
6194
- nLoop = Min(word_c,ind_c);
6195
- ind_c = 1;
5016
+ nLoop = Min(word_c, word_r);
5017
+ ind_c = 0;
6196
5018
  while (ind_c < nLoop) {
6197
5019
  if (r->frac[ind_c] == 0) {
6198
5020
  ++ind_c;
6199
5021
  continue;
6200
5022
  }
6201
- r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
5023
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
6202
5024
  if (r1r2 == b1b2) {
6203
5025
  /* The first two word digits is the same */
6204
5026
  ind_b = 2;
@@ -6211,26 +5033,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6211
5033
  }
6212
5034
  /* The first few word digits of r and b is the same and */
6213
5035
  /* 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
- }
5036
+ /* of b, so quotient is 1. */
5037
+ q = 1;
6232
5038
  ++c->frac[ind_c];
6233
- goto carry;
5039
+ ind_r = b->Prec + ind_c - 1;
5040
+ goto sub_mult;
6234
5041
  }
6235
5042
  /* The first two word digits is not the same, */
6236
5043
  /* then compare magnitude, and divide actually. */
@@ -6283,49 +5090,26 @@ sub_mult:
6283
5090
  }
6284
5091
 
6285
5092
  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
5093
  }
6294
5094
  /* End of operation, now final arrangement */
6295
5095
  out_side:
6296
5096
  c->Prec = word_c;
6297
5097
  c->exponent = a->exponent;
6298
- if (!AddExponent(c, 2)) return 0;
5098
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5099
+ if (!AddExponent(c, 1)) return 0;
6299
5100
  if (!AddExponent(c, -(b->exponent))) return 0;
6300
5101
 
6301
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6302
5102
  VpNmlz(c); /* normalize c */
6303
5103
  r->Prec = word_r;
6304
5104
  r->exponent = a->exponent;
6305
- if (!AddExponent(r, 1)) return 0;
6306
5105
  VpSetSign(r, VpGetSign(a));
6307
5106
  VpNmlz(r); /* normalize r(remainder) */
6308
5107
  goto Exit;
6309
5108
 
6310
5109
  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
5110
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6321
5111
 
6322
5112
  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
5113
  return c->Prec * BASE_FIG;
6330
5114
  }
6331
5115
 
@@ -6448,13 +5232,6 @@ Exit:
6448
5232
  if (val > 1) val = 1;
6449
5233
  else if (val < -1) val = -1;
6450
5234
 
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
5235
  return (int)val;
6459
5236
  }
6460
5237
 
@@ -6572,25 +5349,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6572
5349
  static void
6573
5350
  VpFormatSt(char *psz, size_t fFmt)
6574
5351
  {
6575
- size_t ie, i, nf = 0;
6576
- char ch;
5352
+ size_t iend, idig = 0, iexp = 0, nspaces;
5353
+ char *p;
6577
5354
 
6578
5355
  if (fFmt == 0) return;
6579
5356
 
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
- }
5357
+ iend = strlen(psz);
5358
+
5359
+ if ((p = strchr(psz, '.'))) {
5360
+ idig = (p - psz) + 1;
5361
+ }
5362
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
5363
+ iexp = p - psz;
5364
+ }
5365
+ if (idig == 0 || idig > iexp) return;
5366
+
5367
+ nspaces = (iexp - idig - 1) / fFmt;
5368
+ p = psz + iend + 1;
5369
+ for (size_t i = nspaces; i > 0; i--) {
5370
+ char *src = psz + idig + i * fFmt;
5371
+ char *dst = psz + idig + i * (fFmt + 1);
5372
+ memmove(dst, src, p - src);
5373
+ dst[-1] = ' ';
5374
+ p = src;
6594
5375
  }
6595
5376
  }
6596
5377
 
@@ -6872,7 +5653,7 @@ VP_EXPORT int
6872
5653
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6873
5654
  {
6874
5655
  size_t i, j, ind_a, ma, mi, me;
6875
- SIGNED_VALUE e, es, eb, ef;
5656
+ SIGNED_VALUE e;
6876
5657
  int sign, signe, exponent_overflow;
6877
5658
 
6878
5659
  /* get exponent part */
@@ -6895,23 +5676,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6895
5676
  ++me;
6896
5677
  }
6897
5678
  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:
5679
+ int dig = exp_chr[i] - '0';
5680
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5681
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6911
5682
  exponent_overflow = 1;
6912
- e = es; /* keep sign */
6913
5683
  break;
6914
5684
  }
5685
+ e = e * 10 + signe * dig;
6915
5686
  ++i;
6916
5687
  }
6917
5688
  }
@@ -6930,34 +5701,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6930
5701
  ++mi;
6931
5702
  }
6932
5703
  }
5704
+ /* skip leading zeros in integer part */
5705
+ while (i < mi && int_chr[i] == '0') {
5706
+ ++i;
5707
+ --ni;
5708
+ }
6933
5709
 
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;
5710
+ /* set actual exponent size. */
5711
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5712
+ exponent_overflow = 1;
5713
+ } else {
5714
+ e += ni;
5715
+ }
6939
5716
 
6940
5717
  /* 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
- }
5718
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5719
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5720
+ exponent_overflow = 1;
5721
+ } else {
5722
+ e += j;
6952
5723
  }
6953
5724
 
6954
- eb = e / (SIGNED_VALUE)BASE_FIG;
6955
-
6956
- if (exponent_overflow) {
5725
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6957
5726
  int zero = 1;
6958
5727
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6959
5728
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6960
- if (!zero && signe > 0) {
5729
+ if (!zero && e > 0) {
6961
5730
  VpSetInf(a, sign);
6962
5731
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6963
5732
  }
@@ -7007,7 +5776,7 @@ Final:
7007
5776
  ++j;
7008
5777
  }
7009
5778
  a->Prec = ind_a + 1;
7010
- a->exponent = eb;
5779
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
7011
5780
  VpSetSign(a, sign);
7012
5781
  VpNmlz(a);
7013
5782
  return 1;
@@ -7079,254 +5848,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7079
5848
  *d *= VpGetSign(m);
7080
5849
 
7081
5850
  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
5851
  return f;
7090
5852
  }
7091
5853
 
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
5854
  /*
7331
5855
  * Round relatively from the decimal point.
7332
5856
  * f: rounding mode
@@ -7503,7 +6027,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7503
6027
  DECDIG v;
7504
6028
  if (!VpHasVal(y)) return 0; /* Unable to round */
7505
6029
  v = y->frac[0];
7506
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6030
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7507
6031
  while ((v /= 10) != 0) nf--;
7508
6032
  nf += (ssize_t)BASE_FIG-1;
7509
6033
  return VpMidRound(y, f, nf);
@@ -7610,7 +6134,7 @@ VpFrac(Real *y, Real *x)
7610
6134
  size_t my, ind_y, ind_x;
7611
6135
 
7612
6136
  if (!VpHasVal(x)) {
7613
- VpAsgn(y, x, 1);
6137
+ VpAsgn(y, x, 10);
7614
6138
  goto Exit;
7615
6139
  }
7616
6140
 
@@ -7619,7 +6143,7 @@ VpFrac(Real *y, Real *x)
7619
6143
  goto Exit;
7620
6144
  }
7621
6145
  else if (x->exponent <= 0) {
7622
- VpAsgn(y, x, 1);
6146
+ VpAsgn(y, x, 10);
7623
6147
  goto Exit;
7624
6148
  }
7625
6149
 
@@ -7640,117 +6164,9 @@ VpFrac(Real *y, Real *x)
7640
6164
  VpNmlz(y);
7641
6165
 
7642
6166
  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
6167
  return;
7650
6168
  }
7651
6169
 
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
6170
  #ifdef BIGDECIMAL_DEBUG
7755
6171
  int
7756
6172
  VpVarCheck(Real * v)