bigdecimal 3.2.2 → 4.1.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.
@@ -29,18 +29,29 @@
29
29
  #endif
30
30
 
31
31
  #include "bits.h"
32
+ #include "ntt.h"
33
+ #include "div.h"
32
34
  #include "static_assert.h"
33
35
 
34
- #define BIGDECIMAL_VERSION "3.2.2"
35
-
36
- /* #define ENABLE_NUMERIC_STRING */
36
+ #define BIGDECIMAL_VERSION "4.1.1"
37
37
 
38
+ /* Make sure VPMULT_BATCH_SIZE*BASE*BASE does not overflow DECDIG_DBL */
39
+ #define VPMULT_BATCH_SIZE 16
40
+ #define NTT_MULTIPLICATION_THRESHOLD 450
41
+ #define NEWTON_RAPHSON_DIVISION_THRESHOLD 100
38
42
  #define SIGNED_VALUE_MAX INTPTR_MAX
39
43
  #define SIGNED_VALUE_MIN INTPTR_MIN
40
44
  #define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
45
+ #define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
46
+
47
+ /* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
48
+ #define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
49
+ /* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
50
+ #define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
51
+ #define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
52
+ #define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
41
53
 
42
54
  VALUE rb_cBigDecimal;
43
- VALUE rb_mBigMath;
44
55
 
45
56
  static ID id_BigDecimal_exception_mode;
46
57
  static ID id_BigDecimal_rounding_mode;
@@ -68,15 +79,18 @@ static struct {
68
79
  uint8_t mode;
69
80
  } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
70
81
 
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))
82
+ static inline BDVALUE
83
+ bdvalue_nonnullable(NULLABLE_BDVALUE v)
84
+ {
85
+ assert(v.real_or_null != NULL);
86
+ return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
87
+ }
88
+
89
+ static inline NULLABLE_BDVALUE
90
+ bdvalue_nullable(BDVALUE v)
91
+ {
92
+ return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
93
+ }
80
94
 
81
95
  #define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
82
96
  #define BASE BIGDECIMAL_BASE
@@ -84,31 +98,6 @@ static struct {
84
98
  #define HALF_BASE (BASE/2)
85
99
  #define BASE1 (BASE/10)
86
100
 
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
101
  #ifndef MAYBE_UNUSED
113
102
  # define MAYBE_UNUSED(x) x
114
103
  #endif
@@ -145,6 +134,17 @@ check_allocation_count_nonzero(void)
145
134
  # define check_allocation_count_nonzero() /* nothing */
146
135
  #endif /* BIGDECIMAL_DEBUG */
147
136
 
137
+ /* VpMult VpDivd helpers */
138
+ #define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
139
+ /* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
140
+ /* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
141
+ #define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
142
+ /* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
143
+ #define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
144
+
145
+ static NULLABLE_BDVALUE
146
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
147
+
148
148
  PUREFUNC(static inline size_t rbd_struct_size(size_t const));
149
149
 
150
150
  static inline size_t
@@ -154,118 +154,6 @@ rbd_struct_size(size_t const internal_digits)
154
154
  return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
155
155
  }
156
156
 
157
- static inline Real *
158
- rbd_allocate_struct(size_t const internal_digits)
159
- {
160
- size_t const size = rbd_struct_size(internal_digits);
161
- Real *real = ruby_xcalloc(1, size);
162
- atomic_allocation_count_inc();
163
- real->MaxPrec = internal_digits;
164
- return real;
165
- }
166
-
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
- 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)
195
- {
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;
205
- }
206
-
207
- static void
208
- rbd_free_struct(Real *real)
209
- {
210
- if (real != NULL) {
211
- check_allocation_count_nonzero();
212
- ruby_xfree(real);
213
- atomic_allocation_count_dec_nounderflow();
214
- }
215
- }
216
-
217
- #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
- 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)
245
- {
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);
250
- return real;
251
- }
252
-
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
157
  /*
270
158
  * ================== Ruby Interface part ==========================
271
159
  */
@@ -277,10 +165,9 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
277
165
  static unsigned short VpGetException(void);
278
166
  static void VpSetException(unsigned short f);
279
167
  static void VpCheckException(Real *p, bool always);
280
- static VALUE VpCheckGetValue(Real *p);
168
+ static VALUE CheckGetValue(BDVALUE v);
281
169
  static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
282
170
  static int VpLimitRound(Real *c, size_t ixDigit);
283
- static Real *VpCopy(Real *pv, Real const* const x);
284
171
  static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
285
172
 
286
173
  /*
@@ -292,85 +179,81 @@ static VALUE BigDecimal_positive_infinity(void);
292
179
  static VALUE BigDecimal_negative_infinity(void);
293
180
  static VALUE BigDecimal_positive_zero(void);
294
181
  static VALUE BigDecimal_negative_zero(void);
182
+ static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
183
+ static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
295
184
 
296
- static void
297
- BigDecimal_delete(void *pv)
298
- {
299
- rbd_free_struct(pv);
300
- }
185
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
186
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
187
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
188
+ #endif
189
+
190
+ #ifdef RUBY_TYPED_EMBEDDABLE
191
+ # define HAVE_RUBY_TYPED_EMBEDDABLE 1
192
+ #else
193
+ # ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
194
+ # define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
195
+ # define HAVE_RUBY_TYPED_EMBEDDABLE 1
196
+ # else
197
+ # define RUBY_TYPED_EMBEDDABLE 0
198
+ # endif
199
+ #endif
301
200
 
302
201
  static size_t
303
202
  BigDecimal_memsize(const void *ptr)
304
203
  {
204
+ #ifdef HAVE_RUBY_TYPED_EMBEDDABLE
205
+ return 0; // Entirely embedded
206
+ #else
305
207
  const Real *pv = ptr;
306
208
  return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
307
- }
308
-
309
- #ifndef HAVE_RB_EXT_RACTOR_SAFE
310
- # undef RUBY_TYPED_FROZEN_SHAREABLE
311
- # define RUBY_TYPED_FROZEN_SHAREABLE 0
312
209
  #endif
210
+ }
313
211
 
314
212
  static const rb_data_type_t BigDecimal_data_type = {
315
- "BigDecimal",
316
- { 0, BigDecimal_delete, BigDecimal_memsize, },
317
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
318
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED
319
- #endif
213
+ .wrap_struct_name = "BigDecimal",
214
+ .function = {
215
+ .dmark = 0,
216
+ .dfree = RUBY_DEFAULT_FREE,
217
+ .dsize = BigDecimal_memsize,
218
+ },
219
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
320
220
  };
321
221
 
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)
222
+ static VALUE
223
+ BigDecimal_allocate(size_t const internal_digits)
337
224
  {
338
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
225
+ const size_t size = rbd_struct_size(internal_digits);
226
+ VALUE bd = rb_data_typed_object_zalloc(rb_cBigDecimal, size, &BigDecimal_data_type);
227
+ Real *vp;
228
+ TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
229
+ vp->MaxPrec = internal_digits;
230
+ RB_OBJ_FREEZE(bd);
231
+ return bd;
339
232
  }
340
233
 
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)
234
+ static VALUE
235
+ BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
345
236
  {
346
- return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
237
+ return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
347
238
  }
348
239
 
349
240
  static Real *
350
- rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
351
- {
352
- Real *real = rbd_allocate_struct_one(sign, digits, limit_precision);
353
- if (real != NULL) {
354
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
355
- BigDecimal_wrap_struct(obj, real);
356
- }
357
- return real;
358
- }
359
-
360
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits));
361
- #define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap
362
- static inline Real *
363
- rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
241
+ VpPtr(VALUE obj)
364
242
  {
365
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
243
+ Real *vp;
244
+ TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
245
+ return vp;
366
246
  }
367
247
 
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)
248
+ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
249
+ #define NewZeroWrap rbd_allocate_struct_zero_wrap
250
+ static BDVALUE
251
+ rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
372
252
  {
373
- return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
253
+ VALUE obj = BigDecimal_allocate_decimal_digits(digits);
254
+ Real *real = VpPtr(obj);
255
+ VpSetZero(real, sign);
256
+ return (BDVALUE) { obj, real };
374
257
  }
375
258
 
376
259
  static inline int
@@ -398,24 +281,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
398
281
  }
399
282
 
400
283
  static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
401
- static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
284
+ static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
402
285
  static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
403
286
  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);
287
+ static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
405
288
  static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
406
289
 
407
- static Real*
408
- GetVpValueWithPrec(VALUE v, long prec, int must)
290
+ static NULLABLE_BDVALUE
291
+ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
409
292
  {
410
- const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
411
-
412
293
  switch(TYPE(v)) {
413
294
  case T_FLOAT:
414
- v = rb_float_convert_to_BigDecimal(v, digs, must);
295
+ v = rb_float_convert_to_BigDecimal(v, 0, true);
415
296
  break;
416
297
 
417
298
  case T_RATIONAL:
418
- v = rb_rational_convert_to_BigDecimal(v, digs, must);
299
+ v = rb_rational_convert_to_BigDecimal(v, prec, true);
419
300
  break;
420
301
 
421
302
  case T_DATA:
@@ -424,25 +305,9 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
424
305
  }
425
306
  break;
426
307
 
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);
431
- break;
432
- }
433
-
434
- #ifdef ENABLE_NUMERIC_STRING
435
- case T_STRING: {
436
- const char *c_str = StringValueCStr(v);
437
- v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
438
- break;
439
- }
440
- #endif /* ENABLE_NUMERIC_STRING */
441
-
308
+ case T_FIXNUM:
442
309
  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);
310
+ v = rb_inum_convert_to_BigDecimal(v);
446
311
  break;
447
312
  }
448
313
 
@@ -450,21 +315,40 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
450
315
  goto SomeOneMayDoIt;
451
316
  }
452
317
 
453
- Real *vp;
454
- TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
455
- return vp;
318
+ Real *vp = VpPtr(v);
319
+ return (NULLABLE_BDVALUE) { v, vp };
456
320
 
457
321
  SomeOneMayDoIt:
458
322
  if (must) {
459
323
  cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
460
324
  }
461
- return NULL; /* NULL means to coerce */
325
+ return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
326
+ }
327
+
328
+ static inline NULLABLE_BDVALUE
329
+ GetBDValueWithPrec(VALUE v, size_t prec)
330
+ {
331
+ return GetBDValueWithPrecInternal(v, prec, 0);
332
+ }
333
+
334
+
335
+ static inline BDVALUE
336
+ GetBDValueWithPrecMust(VALUE v, size_t prec)
337
+ {
338
+ return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
462
339
  }
463
340
 
341
+ // self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
464
342
  static inline Real*
465
- GetVpValue(VALUE v, int must)
343
+ GetSelfVpValue(VALUE self)
344
+ {
345
+ return GetBDValueWithPrecMust(self, 0).real;
346
+ }
347
+
348
+ static inline BDVALUE
349
+ GetBDValueMust(VALUE v)
466
350
  {
467
- return GetVpValueWithPrec(v, -1, must);
351
+ return GetBDValueWithPrecMust(v, 0);
468
352
  }
469
353
 
470
354
  /* call-seq:
@@ -479,37 +363,7 @@ GetVpValue(VALUE v, int must)
479
363
  static inline VALUE
480
364
  BigDecimal_double_fig(VALUE self)
481
365
  {
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;
366
+ return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
513
367
  }
514
368
 
515
369
  static void
@@ -623,10 +477,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
623
477
  static void
624
478
  BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
625
479
  {
626
- ENTER(1);
627
- Real *p;
628
- GUARD_OBJ(p, GetVpValue(self, 1));
629
- VpCountPrecisionAndScale(p, out_precision, out_scale);
480
+ BDVALUE v = GetBDValueMust(self);
481
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
482
+ RB_GC_GUARD(v.bigdecimal);
630
483
  }
631
484
 
632
485
  /*
@@ -664,8 +517,8 @@ BigDecimal_precision(VALUE self)
664
517
  * BigDecimal("1").scale # => 0
665
518
  * BigDecimal("1.1").scale # => 1
666
519
  * BigDecimal("3.1415").scale # => 4
667
- * BigDecimal("-1e20").precision # => 0
668
- * BigDecimal("1e-20").precision # => 20
520
+ * BigDecimal("-1e20").scale # => 0
521
+ * BigDecimal("1e-20").scale # => 20
669
522
  * BigDecimal("Infinity").scale # => 0
670
523
  * BigDecimal("-Infinity").scale # => 0
671
524
  * BigDecimal("NaN").scale # => 0
@@ -715,25 +568,23 @@ BigDecimal_precision_scale(VALUE self)
715
568
  static VALUE
716
569
  BigDecimal_n_significant_digits(VALUE self)
717
570
  {
718
- ENTER(1);
719
-
720
- Real *p;
721
- GUARD_OBJ(p, GetVpValue(self, 1));
722
- if (VpIsZero(p) || !VpIsDef(p)) {
571
+ BDVALUE v = GetBDValueMust(self);
572
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
723
573
  return INT2FIX(0);
724
574
  }
725
575
 
726
- ssize_t n = p->Prec; /* The length of frac without trailing zeros. */
727
- for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n);
576
+ ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
577
+ for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
728
578
  if (n == 0) return INT2FIX(0);
729
579
 
730
580
  DECDIG x;
731
581
  int nlz = BASE_FIG;
732
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
582
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
733
583
 
734
584
  int ntz = 0;
735
- for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
585
+ for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
736
586
 
587
+ RB_GC_GUARD(v.bigdecimal);
737
588
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
738
589
  return SSIZET2NUM(n_significant_digits);
739
590
  }
@@ -755,17 +606,14 @@ BigDecimal_n_significant_digits(VALUE self)
755
606
  static VALUE
756
607
  BigDecimal_hash(VALUE self)
757
608
  {
758
- ENTER(1);
759
- Real *p;
760
- st_index_t hash;
761
-
762
- GUARD_OBJ(p, GetVpValue(self, 1));
763
- hash = (st_index_t)p->sign;
609
+ BDVALUE v = GetBDValueMust(self);
610
+ st_index_t hash = (st_index_t)v.real->sign;
764
611
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
765
612
  if(hash == 2 || hash == (st_index_t)-2) {
766
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
767
- hash += p->exponent;
613
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
614
+ hash += v.real->exponent;
768
615
  }
616
+ RB_GC_GUARD(v.bigdecimal);
769
617
  return ST2FIX(hash);
770
618
  }
771
619
 
@@ -784,21 +632,22 @@ BigDecimal_hash(VALUE self)
784
632
  static VALUE
785
633
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
786
634
  {
787
- ENTER(5);
788
- Real *vp;
635
+ BDVALUE v;
789
636
  char *psz;
790
637
  VALUE dummy;
791
638
  volatile VALUE dump;
792
639
  size_t len;
793
640
 
794
641
  rb_scan_args(argc, argv, "01", &dummy);
795
- GUARD_OBJ(vp,GetVpValue(self, 1));
796
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
642
+ v = GetBDValueMust(self);
643
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
797
644
  psz = RSTRING_PTR(dump);
798
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
645
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
799
646
  len = strlen(psz);
800
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
647
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
801
648
  rb_str_resize(dump, strlen(psz));
649
+
650
+ RB_GC_GUARD(v.bigdecimal);
802
651
  return dump;
803
652
  }
804
653
 
@@ -808,27 +657,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
808
657
  static VALUE
809
658
  BigDecimal_load(VALUE self, VALUE str)
810
659
  {
811
- ENTER(2);
812
- Real *pv;
660
+ BDVALUE v;
813
661
  unsigned char *pch;
814
662
  unsigned char ch;
815
- unsigned long m=0;
816
663
 
817
664
  pch = (unsigned char *)StringValueCStr(str);
818
- /* First get max prec */
665
+ /* First skip max prec. Don't trust the value. */
819
666
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
820
667
  if(!ISDIGIT(ch)) {
821
668
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
822
669
  }
823
- m = m*10 + (unsigned long)(ch-'0');
824
- }
825
- if (m > VpBaseFig()) m -= VpBaseFig();
826
- GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
827
- m /= VpBaseFig();
828
- if (m && pv->MaxPrec > m) {
829
- pv->MaxPrec = m+1;
830
670
  }
831
- return VpCheckGetValue(pv);
671
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
672
+ return CheckGetValue(v);
832
673
  }
833
674
 
834
675
  static unsigned short
@@ -1121,22 +962,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1121
962
  static size_t
1122
963
  GetAddSubPrec(Real *a, Real *b)
1123
964
  {
1124
- size_t mxs;
1125
- size_t mx = a->Prec;
1126
- SIGNED_VALUE d;
1127
-
1128
- if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
1129
- if (mx < b->Prec) mx = b->Prec;
1130
- if (a->exponent != b->exponent) {
1131
- mxs = mx;
1132
- d = a->exponent - b->exponent;
1133
- if (d < 0) d = -d;
1134
- mx = mx + (size_t)d;
1135
- if (mx < mxs) {
1136
- return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
1137
- }
1138
- }
1139
- return mx;
965
+ if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
966
+ ssize_t min_a = a->exponent - a->Prec;
967
+ ssize_t min_b = b->exponent - b->Prec;
968
+ return Max(a->exponent, b->exponent) - Min(min_a, min_b);
1140
969
  }
1141
970
 
1142
971
  static inline SIGNED_VALUE
@@ -1156,62 +985,28 @@ check_int_precision(VALUE v)
1156
985
  return n;
1157
986
  }
1158
987
 
1159
- static VALUE
1160
- BigDecimal_wrap_struct(VALUE obj, Real *vp)
1161
- {
1162
- assert(is_kind_of_BigDecimal(obj));
1163
- assert(vp != NULL);
1164
-
1165
- if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
1166
- return obj;
1167
-
1168
- assert(RTYPEDDATA_DATA(obj) == NULL);
1169
- assert(vp->obj == 0);
1170
-
1171
- RTYPEDDATA_DATA(obj) = vp;
1172
- vp->obj = obj;
1173
- RB_OBJ_FREEZE(obj);
1174
- return obj;
1175
- }
1176
-
1177
- VP_EXPORT Real *
1178
- VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
1179
- {
1180
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
1181
- Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
1182
- if (!pv)
1183
- return NULL;
1184
- BigDecimal_wrap_struct(obj, pv);
1185
- return pv;
1186
- }
1187
-
1188
- VP_EXPORT Real *
1189
- VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
988
+ static NULLABLE_BDVALUE
989
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1190
990
  {
1191
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
991
+ return VpAlloc(str, strict_p, raise_exception);
1192
992
  }
1193
993
 
1194
- static Real *
1195
- VpCopy(Real *pv, Real const* const x)
994
+ void
995
+ VpMemCopy(Real *pv, Real const* const x)
1196
996
  {
1197
- assert(x != NULL);
1198
-
1199
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1200
997
  pv->MaxPrec = x->MaxPrec;
1201
998
  pv->Prec = x->Prec;
1202
999
  pv->exponent = x->exponent;
1203
1000
  pv->sign = x->sign;
1204
1001
  pv->flag = x->flag;
1205
1002
  MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
1206
-
1207
- return pv;
1208
1003
  }
1209
1004
 
1210
1005
  /* Returns True if the value is Not a Number. */
1211
1006
  static VALUE
1212
1007
  BigDecimal_IsNaN(VALUE self)
1213
1008
  {
1214
- Real *p = GetVpValue(self, 1);
1009
+ Real *p = GetSelfVpValue(self);
1215
1010
  if (VpIsNaN(p)) return Qtrue;
1216
1011
  return Qfalse;
1217
1012
  }
@@ -1222,7 +1017,7 @@ BigDecimal_IsNaN(VALUE self)
1222
1017
  static VALUE
1223
1018
  BigDecimal_IsInfinite(VALUE self)
1224
1019
  {
1225
- Real *p = GetVpValue(self, 1);
1020
+ Real *p = GetSelfVpValue(self);
1226
1021
  if (VpIsPosInf(p)) return INT2FIX(1);
1227
1022
  if (VpIsNegInf(p)) return INT2FIX(-1);
1228
1023
  return Qnil;
@@ -1232,7 +1027,7 @@ BigDecimal_IsInfinite(VALUE self)
1232
1027
  static VALUE
1233
1028
  BigDecimal_IsFinite(VALUE self)
1234
1029
  {
1235
- Real *p = GetVpValue(self, 1);
1030
+ Real *p = GetSelfVpValue(self);
1236
1031
  if (VpIsNaN(p)) return Qfalse;
1237
1032
  if (VpIsInf(p)) return Qfalse;
1238
1033
  return Qtrue;
@@ -1244,8 +1039,6 @@ BigDecimal_check_num(Real *p)
1244
1039
  VpCheckException(p, true);
1245
1040
  }
1246
1041
 
1247
- static VALUE BigDecimal_split(VALUE self);
1248
-
1249
1042
  /* Returns the value as an Integer.
1250
1043
  *
1251
1044
  * If the BigDecimal is infinity or NaN, raises FloatDomainError.
@@ -1253,44 +1046,36 @@ static VALUE BigDecimal_split(VALUE self);
1253
1046
  static VALUE
1254
1047
  BigDecimal_to_i(VALUE self)
1255
1048
  {
1256
- ENTER(5);
1257
- ssize_t e, nf;
1258
- Real *p;
1049
+ BDVALUE v;
1050
+ VALUE ret;
1259
1051
 
1260
- GUARD_OBJ(p, GetVpValue(self, 1));
1261
- BigDecimal_check_num(p);
1052
+ v = GetBDValueMust(self);
1053
+ BigDecimal_check_num(v.real);
1262
1054
 
1263
- e = VpExponent10(p);
1264
- if (e <= 0) return INT2FIX(0);
1265
- nf = VpBaseFig();
1266
- if (e <= nf) {
1267
- return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
1055
+ if (v.real->exponent <= 0) return INT2FIX(0);
1056
+ if (v.real->exponent == 1) {
1057
+ ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
1268
1058
  }
1269
1059
  else {
1270
- VALUE a = BigDecimal_split(self);
1271
- VALUE digits = RARRAY_AREF(a, 1);
1272
- VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
1273
- VALUE ret;
1274
- ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
1275
-
1276
- if (BIGDECIMAL_NEGATIVE_P(p)) {
1277
- numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
1278
- }
1279
- if (dpower < 0) {
1280
- ret = rb_funcall(numerator, rb_intern("div"), 1,
1281
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1282
- INT2FIX(-dpower)));
1283
- }
1284
- else {
1285
- ret = rb_funcall(numerator, '*', 1,
1286
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1287
- INT2FIX(dpower)));
1288
- }
1289
- if (RB_TYPE_P(ret, T_FLOAT)) {
1290
- rb_raise(rb_eFloatDomainError, "Infinity");
1291
- }
1292
- return ret;
1060
+ VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
1061
+ VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
1062
+ ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
1063
+ ret = rb_funcall(digits, rb_intern("to_i"), 0);
1064
+
1065
+ if (BIGDECIMAL_NEGATIVE_P(v.real)) {
1066
+ ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
1067
+ }
1068
+ if (dpower) {
1069
+ VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
1070
+ // In Ruby < 3.4, int**int may return Float::INFINITY
1071
+ if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
1072
+
1073
+ ret = rb_funcall(ret, '*', 1, pow10);
1074
+ }
1293
1075
  }
1076
+
1077
+ RB_GC_GUARD(v.bigdecimal);
1078
+ return ret;
1294
1079
  }
1295
1080
 
1296
1081
  /* Returns a new Float object having approximately the same value as the
@@ -1300,24 +1085,26 @@ BigDecimal_to_i(VALUE self)
1300
1085
  static VALUE
1301
1086
  BigDecimal_to_f(VALUE self)
1302
1087
  {
1303
- ENTER(1);
1304
- Real *p;
1305
1088
  double d;
1306
1089
  SIGNED_VALUE e;
1307
1090
  char *buf;
1308
1091
  volatile VALUE str;
1092
+ BDVALUE v = GetBDValueMust(self);
1093
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1309
1094
 
1310
- GUARD_OBJ(p, GetVpValue(self, 1));
1311
- if (VpVtoD(&d, &e, p) != 1)
1095
+ if (VpVtoD(&d, &e, v.real) != 1)
1312
1096
  return rb_float_new(d);
1313
1097
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1314
1098
  goto overflow;
1315
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1099
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1316
1100
  goto underflow;
1317
1101
 
1318
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1102
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1319
1103
  buf = RSTRING_PTR(str);
1320
- VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1104
+ VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
1105
+
1106
+ RB_GC_GUARD(v.bigdecimal);
1107
+
1321
1108
  errno = 0;
1322
1109
  d = strtod(buf, 0);
1323
1110
  if (errno == ERANGE) {
@@ -1328,14 +1115,14 @@ BigDecimal_to_f(VALUE self)
1328
1115
 
1329
1116
  overflow:
1330
1117
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1331
- if (BIGDECIMAL_NEGATIVE_P(p))
1118
+ if (negative)
1332
1119
  return rb_float_new(VpGetDoubleNegInf());
1333
1120
  else
1334
1121
  return rb_float_new(VpGetDoublePosInf());
1335
1122
 
1336
1123
  underflow:
1337
1124
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1338
- if (BIGDECIMAL_NEGATIVE_P(p))
1125
+ if (negative)
1339
1126
  return rb_float_new(-0.0);
1340
1127
  else
1341
1128
  return rb_float_new(0.0);
@@ -1347,15 +1134,16 @@ underflow:
1347
1134
  static VALUE
1348
1135
  BigDecimal_to_r(VALUE self)
1349
1136
  {
1350
- Real *p;
1137
+ BDVALUE v;
1351
1138
  ssize_t sign, power, denomi_power;
1352
1139
  VALUE a, digits, numerator;
1353
1140
 
1354
- p = GetVpValue(self, 1);
1355
- BigDecimal_check_num(p);
1141
+ v = GetBDValueMust(self);
1142
+ BigDecimal_check_num(v.real);
1143
+ sign = VpGetSign(v.real);
1144
+ power = VpExponent10(v.real);
1145
+ RB_GC_GUARD(v.bigdecimal);
1356
1146
 
1357
- sign = VpGetSign(p);
1358
- power = VpExponent10(p);
1359
1147
  a = BigDecimal_split(self);
1360
1148
  digits = RARRAY_AREF(a, 1);
1361
1149
  denomi_power = power - RSTRING_LEN(digits);
@@ -1376,6 +1164,14 @@ BigDecimal_to_r(VALUE self)
1376
1164
  }
1377
1165
  }
1378
1166
 
1167
+ static size_t
1168
+ GetCoercePrec(Real *a, size_t prec)
1169
+ {
1170
+ if (prec == 0) prec = a->Prec * BASE_FIG;
1171
+ if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1172
+ return prec;
1173
+ }
1174
+
1379
1175
  /* The coerce method provides support for Ruby type coercion. It is not
1380
1176
  * enabled by default.
1381
1177
  *
@@ -1393,26 +1189,9 @@ BigDecimal_to_r(VALUE self)
1393
1189
  static VALUE
1394
1190
  BigDecimal_coerce(VALUE self, VALUE other)
1395
1191
  {
1396
- ENTER(2);
1397
- VALUE obj;
1398
- Real *b;
1399
-
1400
- if (RB_TYPE_P(other, T_FLOAT)) {
1401
- GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
1402
- obj = rb_assoc_new(VpCheckGetValue(b), self);
1403
- }
1404
- else {
1405
- if (RB_TYPE_P(other, T_RATIONAL)) {
1406
- Real* pv = DATA_PTR(self);
1407
- GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
1408
- }
1409
- else {
1410
- GUARD_OBJ(b, GetVpValue(other, 1));
1411
- }
1412
- obj = rb_assoc_new(b->obj, self);
1413
- }
1414
-
1415
- return obj;
1192
+ Real* pv = VpPtr(self);
1193
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1194
+ return rb_assoc_new(CheckGetValue(b), self);
1416
1195
  }
1417
1196
 
1418
1197
  /*
@@ -1432,6 +1211,15 @@ BigDecimal_uplus(VALUE self)
1432
1211
  return self;
1433
1212
  }
1434
1213
 
1214
+ static bool
1215
+ is_coerceable_to_BigDecimal(VALUE r)
1216
+ {
1217
+ return is_kind_of_BigDecimal(r) ||
1218
+ RB_INTEGER_TYPE_P(r) ||
1219
+ RB_TYPE_P(r, T_FLOAT) ||
1220
+ RB_TYPE_P(r, T_RATIONAL);
1221
+ }
1222
+
1435
1223
  /*
1436
1224
  * call-seq:
1437
1225
  * self + value -> bigdecimal
@@ -1451,42 +1239,59 @@ BigDecimal_uplus(VALUE self)
1451
1239
  static VALUE
1452
1240
  BigDecimal_add(VALUE self, VALUE r)
1453
1241
  {
1454
- ENTER(5);
1455
- Real *c, *a, *b;
1456
- size_t mx;
1242
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
1243
+ return BigDecimal_addsub_with_coerce(self, r, 0, +1);
1244
+ }
1457
1245
 
1458
- GUARD_OBJ(a, GetVpValue(self, 1));
1459
- if (RB_TYPE_P(r, T_FLOAT)) {
1460
- b = GetVpValueWithPrec(r, 0, 1);
1461
- }
1462
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1463
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1464
- }
1465
- else {
1466
- b = GetVpValue(r, 0);
1467
- }
1246
+ static VALUE
1247
+ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1248
+ {
1249
+ BDVALUE a, b, c;
1250
+ size_t mx;
1468
1251
 
1469
- if (!b) return DoSomeOne(self,r,'+');
1470
- SAVE(b);
1252
+ a = GetBDValueMust(self);
1253
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1471
1254
 
1472
- if (VpIsNaN(b)) return b->obj;
1473
- if (VpIsNaN(a)) return a->obj;
1255
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1256
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1474
1257
 
1475
- mx = GetAddSubPrec(a, b);
1476
- if (mx == (size_t)-1L) {
1477
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1478
- VpAddSub(c, a, b, 1);
1258
+ if (VpIsInf(a.real) || VpIsInf(b.real)) {
1259
+ c = NewZeroWrap(1, BASE_FIG);
1260
+ VpAddSub(c.real, a.real, b.real, operation);
1479
1261
  }
1480
1262
  else {
1481
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1482
- if (!mx) {
1483
- VpSetInf(c, VpGetSign(a));
1484
- }
1485
- else {
1486
- VpAddSub(c, a, b, 1);
1263
+
1264
+ // Optimization when exponent difference is large
1265
+ // (1.234e+1000).add(5.678e-1000, 10) == (1.234e+1000).add(0.1e+990, 10) in every rounding mode
1266
+ if (prec && !VpIsZero(a.real) && !VpIsZero(b.real)) {
1267
+ size_t precRoom = roomof(prec, BASE_FIG);
1268
+ if (a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1 > b.real->exponent) {
1269
+ BDVALUE b2 = NewZeroWrap(1, BASE_FIG);
1270
+ VpSetOne(b2.real)
1271
+ VpSetSign(b2.real, b.real->sign);
1272
+ b2.real->exponent = a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1;
1273
+ b = b2;
1274
+ } else if (b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1 > a.real->exponent) {
1275
+ BDVALUE a2 = NewZeroWrap(1, BASE_FIG);
1276
+ VpSetOne(a2.real)
1277
+ VpSetSign(a2.real, a.real->sign);
1278
+ a2.real->exponent = b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1;
1279
+ a = a2;
1280
+ }
1487
1281
  }
1282
+
1283
+ mx = GetAddSubPrec(a.real, b.real);
1284
+ c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1285
+ size_t pl = VpGetPrecLimit();
1286
+ if (prec) VpSetPrecLimit(prec);
1287
+ // Let VpAddSub round the result
1288
+ VpAddSub(c.real, a.real, b.real, operation);
1289
+ if (prec) VpSetPrecLimit(pl);
1488
1290
  }
1489
- return VpCheckGetValue(c);
1291
+
1292
+ RB_GC_GUARD(a.bigdecimal);
1293
+ RB_GC_GUARD(b.bigdecimal);
1294
+ return CheckGetValue(c);
1490
1295
  }
1491
1296
 
1492
1297
  /*
@@ -1507,73 +1312,18 @@ BigDecimal_add(VALUE self, VALUE r)
1507
1312
  static VALUE
1508
1313
  BigDecimal_sub(VALUE self, VALUE r)
1509
1314
  {
1510
- ENTER(5);
1511
- Real *c, *a, *b;
1512
- size_t mx;
1513
-
1514
- GUARD_OBJ(a, GetVpValue(self,1));
1515
- if (RB_TYPE_P(r, T_FLOAT)) {
1516
- b = GetVpValueWithPrec(r, 0, 1);
1517
- }
1518
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1519
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1520
- }
1521
- else {
1522
- b = GetVpValue(r,0);
1523
- }
1524
-
1525
- if (!b) return DoSomeOne(self,r,'-');
1526
- SAVE(b);
1527
-
1528
- if (VpIsNaN(b)) return b->obj;
1529
- if (VpIsNaN(a)) return a->obj;
1530
-
1531
- mx = GetAddSubPrec(a,b);
1532
- if (mx == (size_t)-1L) {
1533
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1534
- VpAddSub(c, a, b, -1);
1535
- }
1536
- else {
1537
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
1538
- if (!mx) {
1539
- VpSetInf(c,VpGetSign(a));
1540
- }
1541
- else {
1542
- VpAddSub(c, a, b, -1);
1543
- }
1544
- }
1545
- return VpCheckGetValue(c);
1315
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1316
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1546
1317
  }
1547
1318
 
1548
1319
  static VALUE
1549
1320
  BigDecimalCmp(VALUE self, VALUE r,char op)
1550
1321
  {
1551
- ENTER(5);
1552
1322
  SIGNED_VALUE e;
1553
- Real *a, *b=0;
1554
- GUARD_OBJ(a, GetVpValue(self, 1));
1555
- switch (TYPE(r)) {
1556
- case T_DATA:
1557
- if (!is_kind_of_BigDecimal(r)) break;
1558
- /* fall through */
1559
- case T_FIXNUM:
1560
- /* fall through */
1561
- case T_BIGNUM:
1562
- GUARD_OBJ(b, GetVpValue(r, 0));
1563
- break;
1323
+ BDVALUE a = GetBDValueMust(self);
1324
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1564
1325
 
1565
- case T_FLOAT:
1566
- GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
1567
- break;
1568
-
1569
- case T_RATIONAL:
1570
- GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
1571
- break;
1572
-
1573
- default:
1574
- break;
1575
- }
1576
- if (b == NULL) {
1326
+ if (b.real_or_null == NULL) {
1577
1327
  ID f = 0;
1578
1328
 
1579
1329
  switch (op) {
@@ -1602,8 +1352,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1602
1352
  }
1603
1353
  return rb_num_coerce_relop(self, r, f);
1604
1354
  }
1605
- SAVE(b);
1606
- e = VpComp(a, b);
1355
+ e = VpComp(a.real, b.real_or_null);
1356
+
1357
+ RB_GC_GUARD(a.bigdecimal);
1358
+ RB_GC_GUARD(b.bigdecimal_or_nil);
1359
+
1607
1360
  if (e == 999)
1608
1361
  return (op == '*') ? Qnil : Qfalse;
1609
1362
  switch (op) {
@@ -1643,7 +1396,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1643
1396
  static VALUE
1644
1397
  BigDecimal_zero(VALUE self)
1645
1398
  {
1646
- Real *a = GetVpValue(self, 1);
1399
+ Real *a = GetSelfVpValue(self);
1647
1400
  return VpIsZero(a) ? Qtrue : Qfalse;
1648
1401
  }
1649
1402
 
@@ -1651,7 +1404,7 @@ BigDecimal_zero(VALUE self)
1651
1404
  static VALUE
1652
1405
  BigDecimal_nonzero(VALUE self)
1653
1406
  {
1654
- Real *a = GetVpValue(self, 1);
1407
+ Real *a = GetSelfVpValue(self);
1655
1408
  return VpIsZero(a) ? Qnil : self;
1656
1409
  }
1657
1410
 
@@ -1777,12 +1530,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1777
1530
  static VALUE
1778
1531
  BigDecimal_neg(VALUE self)
1779
1532
  {
1780
- ENTER(5);
1781
- Real *c, *a;
1782
- GUARD_OBJ(a, GetVpValue(self, 1));
1783
- GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
1784
- VpAsgn(c, a, -1);
1785
- return VpCheckGetValue(c);
1533
+ BDVALUE a = GetBDValueMust(self);
1534
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
1535
+ VpAsgn(c.real, a.real, -10);
1536
+ RB_GC_GUARD(a.bigdecimal);
1537
+ return CheckGetValue(c);
1786
1538
  }
1787
1539
 
1788
1540
  /*
@@ -1795,35 +1547,36 @@ BigDecimal_neg(VALUE self)
1795
1547
  *
1796
1548
  * See BigDecimal#mult.
1797
1549
  */
1798
-
1799
1550
  static VALUE
1800
1551
  BigDecimal_mult(VALUE self, VALUE r)
1801
1552
  {
1802
- ENTER(5);
1803
- Real *c, *a, *b;
1804
- size_t mx;
1553
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1554
+ return BigDecimal_mult_with_coerce(self, r, 0);
1555
+ }
1805
1556
 
1806
- GUARD_OBJ(a, GetVpValue(self, 1));
1807
- if (RB_TYPE_P(r, T_FLOAT)) {
1808
- b = GetVpValueWithPrec(r, 0, 1);
1809
- }
1810
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1811
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1557
+ static VALUE
1558
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1559
+ {
1560
+ BDVALUE a, b, c;
1561
+
1562
+ a = GetBDValueMust(self);
1563
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1564
+
1565
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
1566
+ VpMult(c.real, a.real, b.real);
1567
+ if (prec) {
1568
+ VpLeftRound(c.real, VpGetRoundMode(), prec);
1812
1569
  }
1813
1570
  else {
1814
- b = GetVpValue(r,0);
1571
+ VpLimitRound(c.real, 0);
1815
1572
  }
1816
1573
 
1817
- if (!b) return DoSomeOne(self, r, '*');
1818
- SAVE(b);
1819
-
1820
- mx = a->Prec + b->Prec;
1821
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1822
- VpMult(c, a, b);
1823
- return VpCheckGetValue(c);
1574
+ RB_GC_GUARD(a.bigdecimal);
1575
+ RB_GC_GUARD(b.bigdecimal);
1576
+ return CheckGetValue(c);
1824
1577
  }
1825
1578
 
1826
- static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1579
+ static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
1827
1580
 
1828
1581
  /* call-seq:
1829
1582
  * a / b -> bigdecimal
@@ -1840,14 +1593,7 @@ static VALUE
1840
1593
  BigDecimal_div(VALUE self, VALUE r)
1841
1594
  /* For c = self/r: with round operation */
1842
1595
  {
1843
- if (
1844
- !is_kind_of_BigDecimal(r) &&
1845
- !RB_INTEGER_TYPE_P(r) &&
1846
- !RB_TYPE_P(r, T_FLOAT) &&
1847
- !RB_TYPE_P(r, T_RATIONAL)
1848
- ) {
1849
- return DoSomeOne(self, r, '/');
1850
- }
1596
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1851
1597
  return BigDecimal_div2(self, r, INT2FIX(0));
1852
1598
  }
1853
1599
 
@@ -1893,114 +1639,110 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1893
1639
  /*
1894
1640
  * %: mod = a%b = a - (a.to_f/b).floor * b
1895
1641
  * div = (a.to_f/b).floor
1642
+ * In truncate mode, use truncate instead of floor.
1896
1643
  */
1897
- static VALUE
1898
- BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1644
+ static bool
1645
+ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
1899
1646
  {
1900
- ENTER(8);
1901
- Real *c=NULL, *d=NULL, *res=NULL;
1902
- Real *a, *b;
1903
- ssize_t a_prec, b_prec;
1904
- size_t mx;
1647
+ BDVALUE a, b, dv, md, res;
1648
+ NULLABLE_BDVALUE b2;
1649
+ ssize_t a_exponent, b_exponent;
1650
+ size_t mx, rx, pl;
1905
1651
 
1906
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1907
- SAVE(a);
1652
+ a = GetBDValueMust(self);
1908
1653
 
1909
- VALUE rr = r;
1910
- if (is_kind_of_BigDecimal(rr)) {
1911
- /* do nothing */
1912
- }
1913
- else if (RB_INTEGER_TYPE_P(r)) {
1914
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
1915
- }
1916
- else if (RB_TYPE_P(r, T_FLOAT)) {
1917
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1918
- }
1919
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1920
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1921
- }
1654
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1655
+ if (!b2.real_or_null) return false;
1656
+ b = bdvalue_nonnullable(b2);
1922
1657
 
1923
- if (!is_kind_of_BigDecimal(rr)) {
1924
- return Qfalse;
1658
+ if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1659
+ VALUE nan = BigDecimal_nan();
1660
+ *div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
1661
+ goto Done;
1925
1662
  }
1926
-
1927
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1928
- SAVE(b);
1929
-
1930
- if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
1931
- if (VpIsInf(a) && VpIsInf(b)) goto NaN;
1932
- if (VpIsZero(b)) {
1663
+ if (VpIsZero(b.real)) {
1933
1664
  rb_raise(rb_eZeroDivError, "divided by 0");
1934
1665
  }
1935
- if (VpIsInf(a)) {
1936
- if (VpGetSign(a) == VpGetSign(b)) {
1666
+ if (VpIsInf(a.real)) {
1667
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1937
1668
  VALUE inf = BigDecimal_positive_infinity();
1938
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1669
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1939
1670
  }
1940
1671
  else {
1941
1672
  VALUE inf = BigDecimal_negative_infinity();
1942
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1673
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1943
1674
  }
1944
1675
  VALUE nan = BigDecimal_nan();
1945
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
1946
- return Qtrue;
1676
+ *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
1677
+ goto Done;
1947
1678
  }
1948
- if (VpIsInf(b)) {
1679
+ if (VpIsZero(a.real)) {
1949
1680
  VALUE zero = BigDecimal_positive_zero();
1950
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
1951
- *mod = a;
1952
- return Qtrue;
1953
- }
1954
- if (VpIsZero(a)) {
1955
- VALUE zero = BigDecimal_positive_zero();
1956
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
1957
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
1958
- return Qtrue;
1959
- }
1960
-
1961
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
1962
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
1963
-
1964
- mx = (a_prec > b_prec) ? a_prec : b_prec;
1965
- mx *= 2;
1966
-
1967
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1968
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1969
-
1970
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
1971
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
1972
- VpDivd(c, res, a, b);
1973
-
1974
- mx = c->Prec * BASE_FIG;
1975
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
1976
- VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1977
-
1978
- VpMult(res, d, b);
1979
- VpAddSub(c, a, res, -1);
1681
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
1682
+ *mod = bdvalue_nullable(a);
1683
+ goto Done;
1684
+ }
1685
+ if (VpIsInf(b.real)) {
1686
+ if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
1687
+ BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
1688
+ VpSetOne(minus_one.real);
1689
+ VpSetSign(minus_one.real, -1);
1690
+ RB_GC_GUARD(minus_one.bigdecimal);
1691
+ *div = bdvalue_nullable(minus_one);
1692
+ *mod = bdvalue_nullable(b);
1693
+ } else {
1694
+ VALUE zero = BigDecimal_positive_zero();
1695
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
1696
+ *mod = bdvalue_nullable(a);
1697
+ }
1698
+ goto Done;
1699
+ }
1700
+
1701
+ a_exponent = VpExponent10(a.real);
1702
+ b_exponent = VpExponent10(b.real);
1703
+ mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
1704
+ dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
1705
+
1706
+ /* res is reused for VpDivd remainder and VpMult result */
1707
+ rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
1708
+ mx = VPMULT_RESULT_PREC(dv.real, b.real);
1709
+ res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
1710
+ /* AddSub needs one more prec */
1711
+ md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
1712
+
1713
+ VpDivd(dv.real, res.real, a.real, b.real);
1714
+ VpMidRound(dv.real, VP_ROUND_DOWN, 0);
1715
+ VpMult(res.real, dv.real, b.real);
1716
+ pl = VpGetPrecLimit();
1717
+ VpSetPrecLimit(0);
1718
+ VpAddSub(md.real, a.real, res.real, -1);
1719
+ VpSetPrecLimit(pl);
1980
1720
 
1981
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1721
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
1982
1722
  /* result adjustment for negative case */
1983
- res = rbd_reallocate_struct(res, d->MaxPrec);
1984
- res->MaxPrec = d->MaxPrec;
1985
- VpAddSub(res, d, VpOne(), -1);
1986
- GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
1987
- VpAddSub(d, c, b, 1);
1988
- *div = res;
1989
- *mod = d;
1723
+ BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
1724
+ BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
1725
+ VpSetPrecLimit(0);
1726
+ VpAddSub(dv2.real, dv.real, VpOne(), -1);
1727
+ VpAddSub(md2.real, md.real, b.real, 1);
1728
+ VpSetPrecLimit(pl);
1729
+ *div = bdvalue_nullable(dv2);
1730
+ *mod = bdvalue_nullable(md2);
1731
+ RB_GC_GUARD(dv2.bigdecimal);
1732
+ RB_GC_GUARD(md2.bigdecimal);
1990
1733
  }
1991
1734
  else {
1992
- *div = d;
1993
- *mod = c;
1735
+ *div = bdvalue_nullable(dv);
1736
+ *mod = bdvalue_nullable(md);
1994
1737
  }
1995
- return Qtrue;
1996
1738
 
1997
- NaN:
1998
- {
1999
- VALUE nan = BigDecimal_nan();
2000
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
2001
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
2002
- }
2003
- return Qtrue;
1739
+ Done:
1740
+ RB_GC_GUARD(a.bigdecimal);
1741
+ RB_GC_GUARD(b.bigdecimal);
1742
+ RB_GC_GUARD(dv.bigdecimal);
1743
+ RB_GC_GUARD(md.bigdecimal);
1744
+ RB_GC_GUARD(res.bigdecimal);
1745
+ return true;
2004
1746
  }
2005
1747
 
2006
1748
  /* call-seq:
@@ -2014,69 +1756,14 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2014
1756
  static VALUE
2015
1757
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2016
1758
  {
2017
- ENTER(3);
2018
- Real *div = NULL, *mod = NULL;
1759
+ NULLABLE_BDVALUE div, mod;
2019
1760
 
2020
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2021
- SAVE(div); SAVE(mod);
2022
- return VpCheckGetValue(mod);
1761
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1762
+ return CheckGetValue(bdvalue_nonnullable(mod));
2023
1763
  }
2024
1764
  return DoSomeOne(self, r, '%');
2025
1765
  }
2026
1766
 
2027
- static VALUE
2028
- BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2029
- {
2030
- ENTER(10);
2031
- size_t mx;
2032
- Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
2033
- Real *f = NULL;
2034
-
2035
- GUARD_OBJ(a, GetVpValue(self, 1));
2036
- if (RB_TYPE_P(r, T_FLOAT)) {
2037
- b = GetVpValueWithPrec(r, 0, 1);
2038
- }
2039
- else if (RB_TYPE_P(r, T_RATIONAL)) {
2040
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
2041
- }
2042
- else {
2043
- b = GetVpValue(r, 0);
2044
- }
2045
-
2046
- if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
2047
- SAVE(b);
2048
-
2049
- if (VpIsPosInf(b) || VpIsNegInf(b)) {
2050
- GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2051
- VpSetZero(*dv, 1);
2052
- *rv = a;
2053
- return Qnil;
2054
- }
2055
-
2056
- mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
2057
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2058
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2059
- GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2060
- GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2061
-
2062
- VpDivd(c, res, a, b);
2063
-
2064
- mx = c->Prec *(VpBaseFig() + 1);
2065
-
2066
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2067
- GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
2068
-
2069
- VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
2070
-
2071
- VpFrac(f, c);
2072
- VpMult(rr, f, b);
2073
- VpAddSub(ff, res, rr, 1);
2074
-
2075
- *dv = d;
2076
- *rv = ff;
2077
- return Qnil;
2078
- }
2079
-
2080
1767
  /* call-seq:
2081
1768
  * remainder(value)
2082
1769
  *
@@ -2087,11 +1774,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2087
1774
  static VALUE
2088
1775
  BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2089
1776
  {
2090
- VALUE f;
2091
- Real *d, *rv = 0;
2092
- f = BigDecimal_divremain(self, r, &d, &rv);
2093
- if (!NIL_P(f)) return f;
2094
- return VpCheckGetValue(rv);
1777
+ NULLABLE_BDVALUE div, mod = { Qnil, NULL };
1778
+
1779
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
1780
+ return CheckGetValue(bdvalue_nonnullable(mod));
1781
+ }
1782
+ return DoSomeOne(self, r, rb_intern("remainder"));
2095
1783
  }
2096
1784
 
2097
1785
  /* call-seq:
@@ -2119,12 +1807,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2119
1807
  static VALUE
2120
1808
  BigDecimal_divmod(VALUE self, VALUE r)
2121
1809
  {
2122
- ENTER(5);
2123
- Real *div = NULL, *mod = NULL;
1810
+ NULLABLE_BDVALUE div, mod;
2124
1811
 
2125
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2126
- SAVE(div); SAVE(mod);
2127
- return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
1812
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1813
+ return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
2128
1814
  }
2129
1815
  return DoSomeOne(self,r,rb_intern("divmod"));
2130
1816
  }
@@ -2136,17 +1822,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
2136
1822
  static inline VALUE
2137
1823
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2138
1824
  {
2139
- ENTER(5);
2140
1825
  SIGNED_VALUE ix;
2141
- Real *res = NULL;
2142
- Real *av = NULL, *bv = NULL, *cv = NULL;
2143
- size_t mx, pl;
1826
+ BDVALUE av, bv, cv, res;
2144
1827
 
2145
1828
  if (NIL_P(n)) { /* div in Float sense */
2146
- Real *div = NULL;
2147
- Real *mod;
2148
- if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
2149
- return BigDecimal_to_i(VpCheckGetValue(div));
1829
+ NULLABLE_BDVALUE div;
1830
+ NULLABLE_BDVALUE mod;
1831
+ if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
1832
+ return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
2150
1833
  }
2151
1834
  return DoSomeOne(self, b, rb_intern("div"));
2152
1835
  }
@@ -2154,48 +1837,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2154
1837
  /* div in BigDecimal sense */
2155
1838
  ix = check_int_precision(n);
2156
1839
 
2157
- pl = VpSetPrecLimit(0);
2158
- if (ix == 0) ix = pl;
2159
-
2160
- GUARD_OBJ(av, GetVpValue(self, 1));
2161
- if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) {
2162
- /* TODO: I want to refactor this precision control for a float value later
2163
- * by introducing an implicit conversion function instead of
2164
- * GetVpValueWithPrec. */
2165
- GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1));
2166
- }
2167
- else {
2168
- GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1));
2169
- }
1840
+ av = GetBDValueMust(self);
1841
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
2170
1842
 
2171
1843
  if (ix == 0) {
2172
- ssize_t a_prec, b_prec;
2173
- VpCountPrecisionAndScale(av, &a_prec, NULL);
2174
- VpCountPrecisionAndScale(bv, &b_prec, NULL);
1844
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1845
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1846
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
2175
1847
  ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
2176
1848
  if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
2177
1849
  ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1850
+ if (limit && limit < ix) ix = limit;
2178
1851
  }
2179
1852
 
2180
- // VpDivd needs 2 extra DECDIGs. One more is needed for rounding.
2181
- GUARD_OBJ(cv, NewZeroWrapLimited(1, ix + 3 * VpBaseFig()));
1853
+ // Needs to calculate 1 extra digit for rounding.
1854
+ cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
1855
+ res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
1856
+ VpDivd(cv.real, res.real, av.real, bv.real);
2182
1857
 
2183
- mx = bv->Prec + cv->MaxPrec - 1;
2184
- if (mx <= av->Prec) mx = av->Prec + 1;
2185
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig()));
2186
- VpDivd(cv, res, av, bv);
2187
- VpSetPrecLimit(pl);
2188
- if (!VpIsZero(res)) {
1858
+ if (!VpIsZero(res.real)) {
2189
1859
  // Remainder value affects rounding result.
2190
- // ROUND_UP cv = 0.1e0 with ix=10 will be:
1860
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
2191
1861
  // 0.1e0 if remainder == 0
2192
1862
  // 0.1000000001e0 if remainder != 0
2193
1863
  size_t idx = roomof(ix, BASE_FIG);
2194
- while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0;
2195
- if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++;
1864
+ while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
1865
+ if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
2196
1866
  }
2197
- VpLeftRound(cv, VpGetRoundMode(), ix);
2198
- return VpCheckGetValue(cv);
1867
+ VpLeftRound(cv.real, VpGetRoundMode(), ix);
1868
+
1869
+ RB_GC_GUARD(av.bigdecimal);
1870
+ RB_GC_GUARD(bv.bigdecimal);
1871
+ RB_GC_GUARD(res.bigdecimal);
1872
+ return CheckGetValue(cv);
2199
1873
  }
2200
1874
 
2201
1875
  /*
@@ -2271,18 +1945,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2271
1945
  static VALUE
2272
1946
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2273
1947
  {
2274
- ENTER(2);
2275
- Real *cv;
2276
- SIGNED_VALUE mx = check_int_precision(n);
2277
- if (mx == 0) return BigDecimal_add(self, b);
2278
- else {
2279
- size_t pl = VpSetPrecLimit(0);
2280
- VALUE c = BigDecimal_add(self, b);
2281
- VpSetPrecLimit(pl);
2282
- GUARD_OBJ(cv, GetVpValue(c, 1));
2283
- VpLeftRound(cv, VpGetRoundMode(), mx);
2284
- return VpCheckGetValue(cv);
2285
- }
1948
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2286
1949
  }
2287
1950
 
2288
1951
  /* call-seq:
@@ -2301,18 +1964,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2301
1964
  static VALUE
2302
1965
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2303
1966
  {
2304
- ENTER(2);
2305
- Real *cv;
2306
- SIGNED_VALUE mx = check_int_precision(n);
2307
- if (mx == 0) return BigDecimal_sub(self, b);
2308
- else {
2309
- size_t pl = VpSetPrecLimit(0);
2310
- VALUE c = BigDecimal_sub(self, b);
2311
- VpSetPrecLimit(pl);
2312
- GUARD_OBJ(cv, GetVpValue(c, 1));
2313
- VpLeftRound(cv, VpGetRoundMode(), mx);
2314
- return VpCheckGetValue(cv);
2315
- }
1967
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2316
1968
  }
2317
1969
 
2318
1970
  /*
@@ -2344,18 +1996,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2344
1996
  static VALUE
2345
1997
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2346
1998
  {
2347
- ENTER(2);
2348
- Real *cv;
2349
- SIGNED_VALUE mx = check_int_precision(n);
2350
- if (mx == 0) return BigDecimal_mult(self, b);
2351
- else {
2352
- size_t pl = VpSetPrecLimit(0);
2353
- VALUE c = BigDecimal_mult(self, b);
2354
- VpSetPrecLimit(pl);
2355
- GUARD_OBJ(cv, GetVpValue(c, 1));
2356
- VpLeftRound(cv, VpGetRoundMode(), mx);
2357
- return VpCheckGetValue(cv);
2358
- }
1999
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2359
2000
  }
2360
2001
 
2361
2002
  /*
@@ -2372,41 +2013,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2372
2013
  static VALUE
2373
2014
  BigDecimal_abs(VALUE self)
2374
2015
  {
2375
- ENTER(5);
2376
- Real *c, *a;
2377
- size_t mx;
2378
-
2379
- GUARD_OBJ(a, GetVpValue(self, 1));
2380
- mx = a->Prec *(VpBaseFig() + 1);
2381
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2382
- VpAsgn(c, a, 1);
2383
- VpChangeSign(c, 1);
2384
- return VpCheckGetValue(c);
2385
- }
2386
-
2387
- /* call-seq:
2388
- * sqrt(n)
2389
- *
2390
- * Returns the square root of the value.
2391
- *
2392
- * Result has at least n significant digits.
2393
- */
2394
- static VALUE
2395
- BigDecimal_sqrt(VALUE self, VALUE nFig)
2396
- {
2397
- ENTER(5);
2398
- Real *c, *a;
2399
- size_t mx, n;
2400
-
2401
- GUARD_OBJ(a, GetVpValue(self, 1));
2402
- mx = a->Prec * (VpBaseFig() + 1);
2403
-
2404
- n = check_int_precision(nFig);
2405
- n += VpDblFig() + VpBaseFig();
2406
- if (mx <= n) mx = n;
2407
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2408
- VpSqrt(c, a);
2409
- return VpCheckGetValue(c);
2016
+ BDVALUE a = GetBDValueMust(self);
2017
+ BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
2018
+ VpAsgn(c.real, a.real, 10);
2019
+ VpChangeSign(c.real, 1);
2020
+ RB_GC_GUARD(a.bigdecimal);
2021
+ return CheckGetValue(c);
2410
2022
  }
2411
2023
 
2412
2024
  /* Return the integer part of the number, as a BigDecimal.
@@ -2414,15 +2026,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2414
2026
  static VALUE
2415
2027
  BigDecimal_fix(VALUE self)
2416
2028
  {
2417
- ENTER(5);
2418
- Real *c, *a;
2419
- size_t mx;
2420
-
2421
- GUARD_OBJ(a, GetVpValue(self, 1));
2422
- mx = a->Prec *(VpBaseFig() + 1);
2423
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2424
- VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2425
- return VpCheckGetValue(c);
2029
+ BDVALUE a = GetBDValueMust(self);
2030
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2031
+ VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
2032
+ RB_GC_GUARD(a.bigdecimal);
2033
+ return CheckGetValue(c);
2426
2034
  }
2427
2035
 
2428
2036
  /* call-seq:
@@ -2454,13 +2062,12 @@ BigDecimal_fix(VALUE self)
2454
2062
  static VALUE
2455
2063
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2456
2064
  {
2457
- ENTER(5);
2458
- Real *c, *a;
2065
+ BDVALUE c, a;
2459
2066
  int iLoc = 0;
2460
2067
  VALUE vLoc;
2461
2068
  VALUE vRound;
2462
2069
  int round_to_int = 0;
2463
- size_t mx, pl;
2070
+ size_t mx;
2464
2071
 
2465
2072
  unsigned short sw = VpGetRoundMode();
2466
2073
 
@@ -2491,16 +2098,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2491
2098
  break;
2492
2099
  }
2493
2100
 
2494
- pl = VpSetPrecLimit(0);
2495
- GUARD_OBJ(a, GetVpValue(self, 1));
2496
- mx = a->Prec * (VpBaseFig() + 1);
2497
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2498
- VpSetPrecLimit(pl);
2499
- VpActiveRound(c, a, sw, iLoc);
2101
+ a = GetBDValueMust(self);
2102
+ mx = (a.real->Prec + 1) * BASE_FIG;
2103
+ c = NewZeroWrap(1, mx);
2104
+
2105
+ VpActiveRound(c.real, a.real, sw, iLoc);
2106
+
2107
+ RB_GC_GUARD(a.bigdecimal);
2108
+
2500
2109
  if (round_to_int) {
2501
- return BigDecimal_to_i(VpCheckGetValue(c));
2110
+ return BigDecimal_to_i(CheckGetValue(c));
2111
+ }
2112
+ return CheckGetValue(c);
2113
+ }
2114
+
2115
+ static VALUE
2116
+ BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
2117
+ {
2118
+ BDVALUE c, a;
2119
+ int iLoc;
2120
+ VALUE vLoc;
2121
+ size_t mx;
2122
+
2123
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2124
+ iLoc = 0;
2125
+ }
2126
+ else {
2127
+ iLoc = NUM2INT(vLoc);
2128
+ }
2129
+
2130
+ a = GetBDValueMust(self);
2131
+ mx = (a.real->Prec + 1) * BASE_FIG;
2132
+ c = NewZeroWrap(1, mx);
2133
+ VpActiveRound(c.real, a.real, rounding_mode, iLoc);
2134
+
2135
+ RB_GC_GUARD(a.bigdecimal);
2136
+
2137
+ if (argc == 0) {
2138
+ return BigDecimal_to_i(CheckGetValue(c));
2502
2139
  }
2503
- return VpCheckGetValue(c);
2140
+ return CheckGetValue(c);
2504
2141
  }
2505
2142
 
2506
2143
  /* call-seq:
@@ -2525,28 +2162,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2525
2162
  static VALUE
2526
2163
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2527
2164
  {
2528
- ENTER(5);
2529
- Real *c, *a;
2530
- int iLoc;
2531
- VALUE vLoc;
2532
- size_t mx, pl = VpSetPrecLimit(0);
2533
-
2534
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2535
- iLoc = 0;
2536
- }
2537
- else {
2538
- iLoc = NUM2INT(vLoc);
2539
- }
2540
-
2541
- GUARD_OBJ(a, GetVpValue(self, 1));
2542
- mx = a->Prec * (VpBaseFig() + 1);
2543
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2544
- VpSetPrecLimit(pl);
2545
- VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2546
- if (argc == 0) {
2547
- return BigDecimal_to_i(VpCheckGetValue(c));
2548
- }
2549
- return VpCheckGetValue(c);
2165
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2550
2166
  }
2551
2167
 
2552
2168
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2554,15 +2170,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2554
2170
  static VALUE
2555
2171
  BigDecimal_frac(VALUE self)
2556
2172
  {
2557
- ENTER(5);
2558
- Real *c, *a;
2559
- size_t mx;
2560
-
2561
- GUARD_OBJ(a, GetVpValue(self, 1));
2562
- mx = a->Prec * (VpBaseFig() + 1);
2563
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2564
- VpFrac(c, a);
2565
- return VpCheckGetValue(c);
2173
+ BDVALUE a = GetBDValueMust(self);
2174
+ BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
2175
+ VpFrac(c.real, a.real);
2176
+ RB_GC_GUARD(a.bigdecimal);
2177
+ return CheckGetValue(c);
2566
2178
  }
2567
2179
 
2568
2180
  /* call-seq:
@@ -2585,31 +2197,7 @@ BigDecimal_frac(VALUE self)
2585
2197
  static VALUE
2586
2198
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2587
2199
  {
2588
- ENTER(5);
2589
- Real *c, *a;
2590
- int iLoc;
2591
- VALUE vLoc;
2592
- size_t mx, pl = VpSetPrecLimit(0);
2593
-
2594
- if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
2595
- iLoc = 0;
2596
- }
2597
- else {
2598
- iLoc = NUM2INT(vLoc);
2599
- }
2600
-
2601
- GUARD_OBJ(a, GetVpValue(self, 1));
2602
- mx = a->Prec * (VpBaseFig() + 1);
2603
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2604
- VpSetPrecLimit(pl);
2605
- VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2606
- #ifdef BIGDECIMAL_DEBUG
2607
- VPrint(stderr, "floor: c=%\n", c);
2608
- #endif
2609
- if (argc == 0) {
2610
- return BigDecimal_to_i(VpCheckGetValue(c));
2611
- }
2612
- return VpCheckGetValue(c);
2200
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2613
2201
  }
2614
2202
 
2615
2203
  /* call-seq:
@@ -2632,27 +2220,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2632
2220
  static VALUE
2633
2221
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2634
2222
  {
2635
- ENTER(5);
2636
- Real *c, *a;
2637
- int iLoc;
2638
- VALUE vLoc;
2639
- size_t mx, pl = VpSetPrecLimit(0);
2640
-
2641
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2642
- iLoc = 0;
2643
- } else {
2644
- iLoc = NUM2INT(vLoc);
2645
- }
2646
-
2647
- GUARD_OBJ(a, GetVpValue(self, 1));
2648
- mx = a->Prec * (VpBaseFig() + 1);
2649
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2650
- VpSetPrecLimit(pl);
2651
- VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2652
- if (argc == 0) {
2653
- return BigDecimal_to_i(VpCheckGetValue(c));
2654
- }
2655
- return VpCheckGetValue(c);
2223
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2656
2224
  }
2657
2225
 
2658
2226
  /* call-seq:
@@ -2673,7 +2241,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2673
2241
  * If s contains a number, a space is inserted after each group of that many
2674
2242
  * digits, starting from '.' and counting outwards.
2675
2243
  *
2676
- * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2244
+ * If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
2677
2245
  *
2678
2246
  * If s ends with an 'F', conventional floating point notation is used.
2679
2247
  *
@@ -2691,10 +2259,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2691
2259
  static VALUE
2692
2260
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2693
2261
  {
2694
- ENTER(5);
2695
2262
  int fmt = 0; /* 0: E format, 1: F format */
2696
2263
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2697
- Real *vp;
2264
+ BDVALUE v;
2698
2265
  volatile VALUE str;
2699
2266
  char *psz;
2700
2267
  char ch;
@@ -2702,7 +2269,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2702
2269
  SIGNED_VALUE m;
2703
2270
  VALUE f;
2704
2271
 
2705
- GUARD_OBJ(vp, GetVpValue(self, 1));
2272
+ v = GetBDValueMust(self);
2706
2273
 
2707
2274
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2708
2275
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2737,10 +2304,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2737
2304
  }
2738
2305
  }
2739
2306
  if (fmt) {
2740
- nc = VpNumOfChars(vp, "F");
2307
+ nc = VpNumOfChars(v.real, "F");
2741
2308
  }
2742
2309
  else {
2743
- nc = VpNumOfChars(vp, "E");
2310
+ nc = VpNumOfChars(v.real, "E");
2744
2311
  }
2745
2312
  if (mc > 0) {
2746
2313
  nc += (nc + mc - 1) / mc + 1;
@@ -2749,494 +2316,188 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2749
2316
  str = rb_usascii_str_new(0, nc);
2750
2317
  psz = RSTRING_PTR(str);
2751
2318
 
2752
- if (fmt) {
2753
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2754
- }
2755
- else {
2756
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2757
- }
2758
- rb_str_resize(str, strlen(psz));
2759
- return str;
2760
- }
2761
-
2762
- /* Splits a BigDecimal number into four parts, returned as an array of values.
2763
- *
2764
- * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
2765
- * if the BigDecimal is Not a Number.
2766
- *
2767
- * The second value is a string representing the significant digits of the
2768
- * BigDecimal, with no leading zeros.
2769
- *
2770
- * The third value is the base used for arithmetic (currently always 10) as an
2771
- * Integer.
2772
- *
2773
- * The fourth value is an Integer exponent.
2774
- *
2775
- * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
2776
- * string of significant digits with no leading zeros, and n is the exponent.
2777
- *
2778
- * From these values, you can translate a BigDecimal to a float as follows:
2779
- *
2780
- * sign, significant_digits, base, exponent = a.split
2781
- * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
2782
- *
2783
- * (Note that the to_f method is provided as a more convenient way to translate
2784
- * a BigDecimal to a Float.)
2785
- */
2786
- static VALUE
2787
- BigDecimal_split(VALUE self)
2788
- {
2789
- ENTER(5);
2790
- Real *vp;
2791
- VALUE obj,str;
2792
- ssize_t e, s;
2793
- char *psz1;
2794
-
2795
- GUARD_OBJ(vp, GetVpValue(self, 1));
2796
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2797
- psz1 = RSTRING_PTR(str);
2798
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2799
- s = 1;
2800
- if(psz1[0] == '-') {
2801
- size_t len = strlen(psz1 + 1);
2802
-
2803
- memmove(psz1, psz1 + 1, len);
2804
- psz1[len] = '\0';
2805
- s = -1;
2806
- }
2807
- if (psz1[0] == 'N') s = 0; /* NaN */
2808
- e = VpExponent10(vp);
2809
- obj = rb_ary_new2(4);
2810
- rb_ary_push(obj, INT2FIX(s));
2811
- rb_ary_push(obj, str);
2812
- rb_str_resize(str, strlen(psz1));
2813
- rb_ary_push(obj, INT2FIX(10));
2814
- rb_ary_push(obj, SSIZET2NUM(e));
2815
- return obj;
2816
- }
2817
-
2818
- /* Returns the exponent of the BigDecimal number, as an Integer.
2819
- *
2820
- * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
2821
- * of digits with no leading zeros, then n is the exponent.
2822
- */
2823
- static VALUE
2824
- BigDecimal_exponent(VALUE self)
2825
- {
2826
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2827
- return SSIZET2NUM(e);
2828
- }
2829
-
2830
- /* Returns a string representation of self.
2831
- *
2832
- * BigDecimal("1234.5678").inspect
2833
- * #=> "0.12345678e4"
2834
- */
2835
- static VALUE
2836
- BigDecimal_inspect(VALUE self)
2837
- {
2838
- ENTER(5);
2839
- Real *vp;
2840
- volatile VALUE str;
2841
- size_t nc;
2842
-
2843
- GUARD_OBJ(vp, GetVpValue(self, 1));
2844
- nc = VpNumOfChars(vp, "E");
2845
-
2846
- str = rb_str_new(0, nc);
2847
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2848
- rb_str_resize(str, strlen(RSTRING_PTR(str)));
2849
- return str;
2850
- }
2851
-
2852
- static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
2853
- static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
2854
-
2855
- #define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
2856
- #define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
2857
-
2858
- inline static int
2859
- is_integer(VALUE x)
2860
- {
2861
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2862
- }
2863
-
2864
- inline static int
2865
- is_negative(VALUE x)
2866
- {
2867
- if (FIXNUM_P(x)) {
2868
- return FIX2LONG(x) < 0;
2869
- }
2870
- else if (RB_TYPE_P(x, T_BIGNUM)) {
2871
- return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
2872
- }
2873
- else if (RB_TYPE_P(x, T_FLOAT)) {
2874
- return RFLOAT_VALUE(x) < 0.0;
2875
- }
2876
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2877
- }
2878
-
2879
- #define is_positive(x) (!is_negative(x))
2880
-
2881
- inline static int
2882
- is_zero(VALUE x)
2883
- {
2884
- VALUE num;
2885
-
2886
- switch (TYPE(x)) {
2887
- case T_FIXNUM:
2888
- return FIX2LONG(x) == 0;
2889
-
2890
- case T_BIGNUM:
2891
- return Qfalse;
2892
-
2893
- case T_RATIONAL:
2894
- num = rb_rational_num(x);
2895
- return FIXNUM_P(num) && FIX2LONG(num) == 0;
2896
-
2897
- default:
2898
- break;
2899
- }
2900
-
2901
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2902
- }
2903
-
2904
- inline static int
2905
- is_one(VALUE x)
2906
- {
2907
- VALUE num, den;
2908
-
2909
- switch (TYPE(x)) {
2910
- case T_FIXNUM:
2911
- return FIX2LONG(x) == 1;
2912
-
2913
- case T_BIGNUM:
2914
- return Qfalse;
2915
-
2916
- case T_RATIONAL:
2917
- num = rb_rational_num(x);
2918
- den = rb_rational_den(x);
2919
- return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
2920
- FIXNUM_P(num) && FIX2LONG(num) == 1;
2921
-
2922
- default:
2923
- break;
2924
- }
2925
-
2926
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
2927
- }
2928
-
2929
- inline static int
2930
- is_even(VALUE x)
2931
- {
2932
- switch (TYPE(x)) {
2933
- case T_FIXNUM:
2934
- return (FIX2LONG(x) % 2) == 0;
2935
-
2936
- case T_BIGNUM:
2937
- {
2938
- unsigned long l;
2939
- rb_big_pack(x, &l, 1);
2940
- return l % 2 == 0;
2941
- }
2942
-
2943
- default:
2944
- break;
2945
- }
2946
-
2947
- return 0;
2948
- }
2949
-
2950
- static VALUE
2951
- bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2952
- {
2953
- VALUE log_x, multiplied, y;
2954
- volatile VALUE obj = exp->obj;
2955
-
2956
- if (VpIsZero(exp)) {
2957
- return VpCheckGetValue(NewOneWrapLimited(1, n));
2958
- }
2959
-
2960
- log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
2961
- multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
2962
- y = BigMath_exp(multiplied, SSIZET2NUM(n));
2963
- RB_GC_GUARD(obj);
2964
-
2965
- return y;
2966
- }
2967
-
2968
- /* call-seq:
2969
- * power(n)
2970
- * power(n, prec)
2971
- *
2972
- * Returns the value raised to the power of n.
2973
- *
2974
- * Note that n must be an Integer.
2975
- *
2976
- * Also available as the operator **.
2977
- */
2978
- static VALUE
2979
- BigDecimal_power(int argc, VALUE*argv, VALUE self)
2980
- {
2981
- ENTER(5);
2982
- VALUE vexp, prec;
2983
- Real* exp = NULL;
2984
- Real *x, *y;
2985
- ssize_t mp, ma, n;
2986
- SIGNED_VALUE int_exp;
2987
- double d;
2988
-
2989
- rb_scan_args(argc, argv, "11", &vexp, &prec);
2990
-
2991
- GUARD_OBJ(x, GetVpValue(self, 1));
2992
- n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2993
-
2994
- if (VpIsNaN(x)) {
2995
- y = NewZeroWrapLimited(1, n);
2996
- VpSetNaN(y);
2997
- RB_GC_GUARD(y->obj);
2998
- return VpCheckGetValue(y);
2999
- }
3000
-
3001
- retry:
3002
- switch (TYPE(vexp)) {
3003
- case T_FIXNUM:
3004
- break;
3005
-
3006
- case T_BIGNUM:
3007
- break;
3008
-
3009
- case T_FLOAT:
3010
- d = RFLOAT_VALUE(vexp);
3011
- if (d == round(d)) {
3012
- if (FIXABLE(d)) {
3013
- vexp = LONG2FIX((long)d);
3014
- }
3015
- else {
3016
- vexp = rb_dbl2big(d);
3017
- }
3018
- goto retry;
3019
- }
3020
- if (NIL_P(prec)) {
3021
- n += BIGDECIMAL_DOUBLE_FIGURES;
3022
- }
3023
- exp = GetVpValueWithPrec(vexp, 0, 1);
3024
- break;
3025
-
3026
- case T_RATIONAL:
3027
- if (is_zero(rb_rational_num(vexp))) {
3028
- if (is_positive(vexp)) {
3029
- vexp = INT2FIX(0);
3030
- goto retry;
3031
- }
3032
- }
3033
- else if (is_one(rb_rational_den(vexp))) {
3034
- vexp = rb_rational_num(vexp);
3035
- goto retry;
3036
- }
3037
- exp = GetVpValueWithPrec(vexp, n, 1);
3038
- if (NIL_P(prec)) {
3039
- n += n;
3040
- }
3041
- break;
3042
-
3043
- case T_DATA:
3044
- if (is_kind_of_BigDecimal(vexp)) {
3045
- VALUE zero = INT2FIX(0);
3046
- VALUE rounded = BigDecimal_round(1, &zero, vexp);
3047
- if (RTEST(BigDecimal_eq(vexp, rounded))) {
3048
- vexp = BigDecimal_to_i(vexp);
3049
- goto retry;
3050
- }
3051
- if (NIL_P(prec)) {
3052
- GUARD_OBJ(y, GetVpValue(vexp, 1));
3053
- n += y->Prec*VpBaseFig();
3054
- }
3055
- exp = DATA_PTR(vexp);
3056
- break;
3057
- }
3058
- /* fall through */
3059
- default:
3060
- rb_raise(rb_eTypeError,
3061
- "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
3062
- RB_OBJ_CLASSNAME(vexp));
3063
- }
3064
-
3065
- if (VpIsZero(x)) {
3066
- if (is_negative(vexp)) {
3067
- y = NewZeroWrapNolimit(1, n);
3068
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3069
- if (is_integer(vexp)) {
3070
- if (is_even(vexp)) {
3071
- /* (-0) ** (-even_integer) -> Infinity */
3072
- VpSetPosInf(y);
3073
- }
3074
- else {
3075
- /* (-0) ** (-odd_integer) -> -Infinity */
3076
- VpSetNegInf(y);
3077
- }
3078
- }
3079
- else {
3080
- /* (-0) ** (-non_integer) -> Infinity */
3081
- VpSetPosInf(y);
3082
- }
3083
- }
3084
- else {
3085
- /* (+0) ** (-num) -> Infinity */
3086
- VpSetPosInf(y);
3087
- }
3088
- RB_GC_GUARD(y->obj);
3089
- return VpCheckGetValue(y);
3090
- }
3091
- else if (is_zero(vexp)) {
3092
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3093
- }
3094
- else {
3095
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3096
- }
3097
- }
3098
-
3099
- if (is_zero(vexp)) {
3100
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3101
- }
3102
- else if (is_one(vexp)) {
3103
- return self;
3104
- }
3105
-
3106
- if (VpIsInf(x)) {
3107
- if (is_negative(vexp)) {
3108
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3109
- if (is_integer(vexp)) {
3110
- if (is_even(vexp)) {
3111
- /* (-Infinity) ** (-even_integer) -> +0 */
3112
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3113
- }
3114
- else {
3115
- /* (-Infinity) ** (-odd_integer) -> -0 */
3116
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3117
- }
3118
- }
3119
- else {
3120
- /* (-Infinity) ** (-non_integer) -> -0 */
3121
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3122
- }
3123
- }
3124
- else {
3125
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3126
- }
3127
- }
3128
- else {
3129
- y = NewZeroWrapLimited(1, n);
3130
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3131
- if (is_integer(vexp)) {
3132
- if (is_even(vexp)) {
3133
- VpSetPosInf(y);
3134
- }
3135
- else {
3136
- VpSetNegInf(y);
3137
- }
3138
- }
3139
- else {
3140
- /* TODO: support complex */
3141
- rb_raise(rb_eMathDomainError,
3142
- "a non-integral exponent for a negative base");
3143
- }
3144
- }
3145
- else {
3146
- VpSetPosInf(y);
3147
- }
3148
- return VpCheckGetValue(y);
3149
- }
3150
- }
3151
-
3152
- if (exp != NULL) {
3153
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3154
- }
3155
- else if (RB_TYPE_P(vexp, T_BIGNUM)) {
3156
- VALUE abs_value = BigDecimal_abs(self);
3157
- if (is_one(abs_value)) {
3158
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3159
- }
3160
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
3161
- if (is_negative(vexp)) {
3162
- y = NewZeroWrapLimited(1, n);
3163
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3164
- return VpCheckGetValue(y);
3165
- }
3166
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3167
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3168
- }
3169
- else {
3170
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3171
- }
3172
- }
3173
- else {
3174
- if (is_positive(vexp)) {
3175
- y = NewZeroWrapLimited(1, n);
3176
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3177
- return VpCheckGetValue(y);
3178
- }
3179
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3180
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3181
- }
3182
- else {
3183
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3184
- }
3185
- }
3186
- }
3187
-
3188
- int_exp = FIX2LONG(vexp);
3189
- ma = int_exp;
3190
- if (ma < 0) ma = -ma;
3191
- if (ma == 0) ma = 1;
3192
-
3193
- if (VpIsDef(x)) {
3194
- mp = x->Prec * (VpBaseFig() + 1);
3195
- GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
2319
+ if (fmt) {
2320
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
3196
2321
  }
3197
2322
  else {
3198
- GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3199
- }
3200
- VpPowerByInt(y, x, int_exp);
3201
- if (!NIL_P(prec) && VpIsDef(y)) {
3202
- VpMidRound(y, VpGetRoundMode(), n);
2323
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
3203
2324
  }
3204
- return VpCheckGetValue(y);
2325
+ rb_str_resize(str, strlen(psz));
2326
+
2327
+ RB_GC_GUARD(v.bigdecimal);
2328
+ return str;
3205
2329
  }
3206
2330
 
3207
- /* call-seq:
3208
- * self ** other -> bigdecimal
2331
+ /* Splits a BigDecimal number into four parts, returned as an array of values.
2332
+ *
2333
+ * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
2334
+ * if the BigDecimal is Not a Number.
2335
+ *
2336
+ * The second value is a string representing the significant digits of the
2337
+ * BigDecimal, with no leading zeros.
2338
+ *
2339
+ * The third value is the base used for arithmetic (currently always 10) as an
2340
+ * Integer.
3209
2341
  *
3210
- * Returns the \BigDecimal value of +self+ raised to power +other+:
2342
+ * The fourth value is an Integer exponent.
2343
+ *
2344
+ * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
2345
+ * string of significant digits with no leading zeros, and n is the exponent.
2346
+ *
2347
+ * From these values, you can translate a BigDecimal to a float as follows:
2348
+ *
2349
+ * sign, significant_digits, base, exponent = a.split
2350
+ * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
3211
2351
  *
3212
- * b = BigDecimal('3.14')
3213
- * b ** 2 # => 0.98596e1
3214
- * b ** 2.0 # => 0.98596e1
3215
- * b ** Rational(2, 1) # => 0.98596e1
2352
+ * (Note that the to_f method is provided as a more convenient way to translate
2353
+ * a BigDecimal to a Float.)
2354
+ */
2355
+ static VALUE
2356
+ BigDecimal_split(VALUE self)
2357
+ {
2358
+ BDVALUE v;
2359
+ VALUE obj,str;
2360
+ ssize_t e, s;
2361
+ char *psz1;
2362
+
2363
+ v = GetBDValueMust(self);
2364
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
2365
+ psz1 = RSTRING_PTR(str);
2366
+ VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
2367
+ s = 1;
2368
+ if(psz1[0] == '-') {
2369
+ size_t len = strlen(psz1 + 1);
2370
+
2371
+ memmove(psz1, psz1 + 1, len);
2372
+ psz1[len] = '\0';
2373
+ s = -1;
2374
+ }
2375
+ if (psz1[0] == 'N') s = 0; /* NaN */
2376
+ e = VpExponent10(v.real);
2377
+ obj = rb_ary_new2(4);
2378
+ rb_ary_push(obj, INT2FIX(s));
2379
+ rb_ary_push(obj, str);
2380
+ rb_str_resize(str, strlen(psz1));
2381
+ rb_ary_push(obj, INT2FIX(10));
2382
+ rb_ary_push(obj, SSIZET2NUM(e));
2383
+
2384
+ RB_GC_GUARD(v.bigdecimal);
2385
+ return obj;
2386
+ }
2387
+
2388
+ /* Returns the exponent of the BigDecimal number, as an Integer.
3216
2389
  *
3217
- * Related: BigDecimal#power.
2390
+ * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
2391
+ * of digits with no leading zeros, then n is the exponent.
2392
+ */
2393
+ static VALUE
2394
+ BigDecimal_exponent(VALUE self)
2395
+ {
2396
+ ssize_t e = VpExponent10(GetSelfVpValue(self));
2397
+ return SSIZET2NUM(e);
2398
+ }
2399
+
2400
+ /* Returns a string representation of self.
3218
2401
  *
2402
+ * BigDecimal("1234.5678").inspect
2403
+ * #=> "0.12345678e4"
3219
2404
  */
3220
2405
  static VALUE
3221
- BigDecimal_power_op(VALUE self, VALUE exp)
2406
+ BigDecimal_inspect(VALUE self)
3222
2407
  {
3223
- return BigDecimal_power(1, &exp, self);
2408
+ BDVALUE v;
2409
+ volatile VALUE str;
2410
+ size_t nc;
2411
+
2412
+ v = GetBDValueMust(self);
2413
+ nc = VpNumOfChars(v.real, "E");
2414
+
2415
+ str = rb_str_new(0, nc);
2416
+ VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2417
+ rb_str_resize(str, strlen(RSTRING_PTR(str)));
2418
+
2419
+ RB_GC_GUARD(v.bigdecimal);
2420
+ return str;
3224
2421
  }
3225
2422
 
3226
- /* :nodoc:
2423
+ /* Returns self * 10**v without changing the precision.
2424
+ * This method is currently for internal use.
3227
2425
  *
3228
- * private method for dup and clone the provided BigDecimal +other+
2426
+ * BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
2427
+ * BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
3229
2428
  */
3230
2429
  static VALUE
3231
- BigDecimal_initialize_copy(VALUE self, VALUE other)
2430
+ BigDecimal_decimal_shift(VALUE self, VALUE v)
2431
+ {
2432
+ BDVALUE a, c;
2433
+ ssize_t shift, exponentShift;
2434
+ bool shiftDown;
2435
+ size_t prec;
2436
+ DECDIG ex, iex;
2437
+
2438
+ a = GetBDValueMust(self);
2439
+ shift = NUM2SSIZET(rb_to_int(v));
2440
+
2441
+ if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
2442
+
2443
+ exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
2444
+ shift -= exponentShift * BASE_FIG;
2445
+ ex = 1;
2446
+ for (int i = 0; i < shift; i++) ex *= 10;
2447
+ shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
2448
+ iex = BASE / ex;
2449
+
2450
+ prec = a.real->Prec + shiftDown;
2451
+ c = NewZeroWrap(1, prec * BASE_FIG);
2452
+ if (shift == 0) {
2453
+ VpAsgn(c.real, a.real, 10);
2454
+ } else if (shiftDown) {
2455
+ DECDIG carry = 0;
2456
+ exponentShift++;
2457
+ for (size_t i = 0; i < a.real->Prec; i++) {
2458
+ DECDIG v = a.real->frac[i];
2459
+ c.real->frac[i] = carry * ex + v / iex;
2460
+ carry = v % iex;
2461
+ }
2462
+ c.real->frac[a.real->Prec] = carry * ex;
2463
+ } else {
2464
+ DECDIG carry = 0;
2465
+ for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
2466
+ DECDIG v = a.real->frac[i];
2467
+ c.real->frac[i] = v % iex * ex + carry;
2468
+ carry = v / iex;
2469
+ }
2470
+ }
2471
+ while (c.real->frac[prec - 1] == 0) prec--;
2472
+ c.real->Prec = prec;
2473
+ c.real->sign = a.real->sign;
2474
+ c.real->exponent = a.real->exponent;
2475
+ AddExponent(c.real, exponentShift);
2476
+ RB_GC_GUARD(a.bigdecimal);
2477
+ return CheckGetValue(c);
2478
+ }
2479
+
2480
+ inline static int
2481
+ is_zero(VALUE x)
3232
2482
  {
3233
- Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
3234
- Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
2483
+ VALUE num;
2484
+
2485
+ switch (TYPE(x)) {
2486
+ case T_FIXNUM:
2487
+ return FIX2LONG(x) == 0;
2488
+
2489
+ case T_BIGNUM:
2490
+ return Qfalse;
2491
+
2492
+ case T_RATIONAL:
2493
+ num = rb_rational_num(x);
2494
+ return FIXNUM_P(num) && FIX2LONG(num) == 0;
3235
2495
 
3236
- if (self != other) {
3237
- DATA_PTR(self) = VpCopy(pv, x);
2496
+ default:
2497
+ break;
3238
2498
  }
3239
- return self;
2499
+
2500
+ return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
3240
2501
  }
3241
2502
 
3242
2503
  /* :nodoc: */
@@ -3275,30 +2536,27 @@ check_exception(VALUE bd)
3275
2536
  {
3276
2537
  assert(is_kind_of_BigDecimal(bd));
3277
2538
 
3278
- Real *vp;
3279
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3280
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2539
+ VpCheckException(VpPtr(bd), false);
3281
2540
 
3282
2541
  return bd;
3283
2542
  }
3284
2543
 
3285
2544
  static VALUE
3286
- rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
2545
+ rb_uint64_convert_to_BigDecimal(uint64_t uval)
3287
2546
  {
3288
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3289
-
2547
+ VALUE bd;
3290
2548
  Real *vp;
3291
2549
  if (uval == 0) {
3292
- vp = rbd_allocate_struct(1);
3293
- vp->MaxPrec = 1;
2550
+ bd = BigDecimal_allocate(1);
2551
+ vp = VpPtr(bd);
3294
2552
  vp->Prec = 1;
3295
2553
  vp->exponent = 1;
3296
2554
  VpSetZero(vp, 1);
3297
2555
  vp->frac[0] = 0;
3298
2556
  }
3299
2557
  else if (uval < BASE) {
3300
- vp = rbd_allocate_struct(1);
3301
- vp->MaxPrec = 1;
2558
+ bd = BigDecimal_allocate(1);
2559
+ vp = VpPtr(bd);
3302
2560
  vp->Prec = 1;
3303
2561
  vp->exponent = 1;
3304
2562
  VpSetSign(vp, 1);
@@ -3323,32 +2581,31 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3323
2581
  }
3324
2582
 
3325
2583
  const size_t exp = len + ntz;
3326
- vp = rbd_allocate_struct(len);
3327
- vp->MaxPrec = len;
2584
+ bd = BigDecimal_allocate(len);
2585
+ vp = VpPtr(bd);
3328
2586
  vp->Prec = len;
3329
2587
  vp->exponent = exp;
3330
2588
  VpSetSign(vp, 1);
3331
2589
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3332
2590
  }
3333
2591
 
3334
- return BigDecimal_wrap_struct(obj, vp);
2592
+ return bd;
3335
2593
  }
3336
2594
 
3337
2595
  static VALUE
3338
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2596
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3339
2597
  {
3340
2598
  const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
3341
- VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception);
2599
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3342
2600
  if (ival < 0) {
3343
- Real *vp;
3344
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2601
+ Real *vp = VpPtr(bd);
3345
2602
  VpSetSign(vp, -1);
3346
2603
  }
3347
2604
  return bd;
3348
2605
  }
3349
2606
 
3350
2607
  static VALUE
3351
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2608
+ rb_big_convert_to_BigDecimal(VALUE val)
3352
2609
  {
3353
2610
  assert(RB_TYPE_P(val, T_BIGNUM));
3354
2611
 
@@ -3360,40 +2617,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3360
2617
  }
3361
2618
  if (size <= sizeof(long)) {
3362
2619
  if (sign < 0) {
3363
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2620
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3364
2621
  }
3365
2622
  else {
3366
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2623
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3367
2624
  }
3368
2625
  }
3369
2626
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3370
2627
  else if (size <= sizeof(LONG_LONG)) {
3371
2628
  if (sign < 0) {
3372
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2629
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3373
2630
  }
3374
2631
  else {
3375
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2632
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3376
2633
  }
3377
2634
  }
3378
2635
  #endif
3379
2636
  else {
3380
2637
  VALUE str = rb_big2str(val, 10);
3381
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3382
- RSTRING_PTR(str), true);
2638
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2639
+ RSTRING_PTR(str),
2640
+ rb_cBigDecimal,
2641
+ true,
2642
+ true
2643
+ ));
3383
2644
  RB_GC_GUARD(str);
3384
- return check_exception(vp->obj);
2645
+ return CheckGetValue(v);
3385
2646
  }
3386
2647
  }
3387
2648
 
3388
2649
  static VALUE
3389
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2650
+ rb_inum_convert_to_BigDecimal(VALUE val)
3390
2651
  {
3391
2652
  assert(RB_INTEGER_TYPE_P(val));
3392
2653
  if (FIXNUM_P(val)) {
3393
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2654
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3394
2655
  }
3395
2656
  else {
3396
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2657
+ return rb_big_convert_to_BigDecimal(val);
3397
2658
  }
3398
2659
  }
3399
2660
 
@@ -3428,11 +2689,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3428
2689
  }
3429
2690
 
3430
2691
  if (digs == SIZE_MAX) {
3431
- if (!raise_exception)
3432
- return Qnil;
3433
- rb_raise(rb_eArgError,
3434
- "can't omit precision for a %"PRIsVALUE".",
3435
- CLASS_OF(val));
2692
+ digs = 0;
3436
2693
  }
3437
2694
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3438
2695
  if (!raise_exception)
@@ -3547,9 +2804,8 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3547
2804
  exp = -exp;
3548
2805
  }
3549
2806
 
3550
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
3551
- Real *vp;
3552
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2807
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
2808
+ Real *vp = VpPtr(bd);
3553
2809
  assert(vp->Prec == prec);
3554
2810
  vp->exponent = exp;
3555
2811
 
@@ -3570,28 +2826,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3570
2826
  CLASS_OF(val));
3571
2827
  }
3572
2828
 
3573
- VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
2829
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
3574
2830
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3575
2831
  return d;
3576
2832
  }
3577
2833
 
3578
2834
  static VALUE
3579
- rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
2835
+ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
3580
2836
  {
3581
- if (digs == SIZE_MAX)
3582
- digs = 0;
3583
-
3584
- Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
3585
- if (!vp)
3586
- return Qnil;
3587
- return VpCheckGetValue(vp);
2837
+ NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
2838
+ if (v.bigdecimal_or_nil == Qnil) return Qnil;
2839
+ return CheckGetValue(bdvalue_nonnullable(v));
3588
2840
  }
3589
2841
 
3590
2842
  static inline VALUE
3591
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2843
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3592
2844
  {
3593
2845
  const char *c_str = StringValueCStr(val);
3594
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2846
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3595
2847
  }
3596
2848
 
3597
2849
  static VALUE
@@ -3619,17 +2871,20 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3619
2871
  if (digs == SIZE_MAX)
3620
2872
  return check_exception(val);
3621
2873
 
3622
- Real *vp;
3623
- TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
2874
+ Real *vp = VpPtr(val);
2875
+
2876
+ VALUE copy = BigDecimal_allocate(vp->MaxPrec);
2877
+ Real *vp_copy = VpPtr(copy);
2878
+
2879
+ VpMemCopy(vp_copy, vp);
2880
+
2881
+ RB_GC_GUARD(val);
3624
2882
 
3625
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3626
- vp = VpCopy(NULL, vp);
3627
2883
  /* TODO: rounding */
3628
- BigDecimal_wrap_struct(copy, vp);
3629
- return VpCheckGetValue(vp);
2884
+ return check_exception(copy);
3630
2885
  }
3631
2886
  else if (RB_INTEGER_TYPE_P(val)) {
3632
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2887
+ return rb_inum_convert_to_BigDecimal(val);
3633
2888
  }
3634
2889
  else if (RB_FLOAT_TYPE_P(val)) {
3635
2890
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3647,7 +2902,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3647
2902
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3648
2903
  }
3649
2904
  else if (RB_TYPE_P(val, T_STRING)) {
3650
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2905
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3651
2906
  }
3652
2907
 
3653
2908
  /* TODO: chheck to_d */
@@ -3661,7 +2916,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3661
2916
  }
3662
2917
  return Qnil;
3663
2918
  }
3664
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2919
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3665
2920
  }
3666
2921
 
3667
2922
  /* call-seq:
@@ -3682,12 +2937,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3682
2937
  *
3683
2938
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3684
2939
  *
3685
- * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
2940
+ * # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
3686
2941
  * BigDecimal(2) # => 0.2e1
3687
2942
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3688
2943
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3689
- * # Float or Rational value requires ndigits.
3690
- * BigDecimal(2.0, 0) # => 0.2e1
2944
+ * BigDecimal(2.0) # => 0.2e1
2945
+ * # Rational value requires ndigits.
3691
2946
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3692
2947
  *
3693
2948
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3751,11 +3006,11 @@ static VALUE
3751
3006
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3752
3007
  {
3753
3008
  char const *c_str = StringValueCStr(str);
3754
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3755
- if (!vp)
3009
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3010
+ if (v.bigdecimal_or_nil == Qnil)
3756
3011
  return Qnil;
3757
3012
  else
3758
- return VpCheckGetValue(vp);
3013
+ return CheckGetValue(bdvalue_nonnullable(v));
3759
3014
  }
3760
3015
 
3761
3016
  /*
@@ -3810,7 +3065,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3810
3065
  static VALUE
3811
3066
  BigDecimal_sign(VALUE self)
3812
3067
  { /* sign */
3813
- int s = GetVpValue(self, 1)->sign;
3068
+ int s = GetSelfVpValue(self)->sign;
3814
3069
  return INT2FIX(s);
3815
3070
  }
3816
3071
 
@@ -3893,301 +3148,6 @@ BigDecimal_save_limit(VALUE self)
3893
3148
  return ret;
3894
3149
  }
3895
3150
 
3896
- /* call-seq:
3897
- * BigMath.exp(decimal, numeric) -> BigDecimal
3898
- *
3899
- * Computes the value of e (the base of natural logarithms) raised to the
3900
- * power of +decimal+, to the specified number of digits of precision.
3901
- *
3902
- * If +decimal+ is infinity, returns Infinity.
3903
- *
3904
- * If +decimal+ is NaN, returns NaN.
3905
- */
3906
- static VALUE
3907
- BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3908
- {
3909
- ssize_t prec, n, i;
3910
- Real* vx = NULL;
3911
- VALUE one, d, y;
3912
- int negative = 0;
3913
- int infinite = 0;
3914
- int nan = 0;
3915
- double flo;
3916
-
3917
- prec = NUM2SSIZET(vprec);
3918
- if (prec <= 0) {
3919
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
3920
- }
3921
-
3922
- /* TODO: the following switch statement is almost same as one in the
3923
- * BigDecimalCmp function. */
3924
- switch (TYPE(x)) {
3925
- case T_DATA:
3926
- if (!is_kind_of_BigDecimal(x)) break;
3927
- vx = DATA_PTR(x);
3928
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3929
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3930
- nan = VpIsNaN(vx);
3931
- break;
3932
-
3933
- case T_FIXNUM:
3934
- /* fall through */
3935
- case T_BIGNUM:
3936
- vx = GetVpValue(x, 0);
3937
- break;
3938
-
3939
- case T_FLOAT:
3940
- flo = RFLOAT_VALUE(x);
3941
- negative = flo < 0;
3942
- infinite = isinf(flo);
3943
- nan = isnan(flo);
3944
- if (!infinite && !nan) {
3945
- vx = GetVpValueWithPrec(x, 0, 0);
3946
- }
3947
- break;
3948
-
3949
- case T_RATIONAL:
3950
- vx = GetVpValueWithPrec(x, prec, 0);
3951
- break;
3952
-
3953
- default:
3954
- break;
3955
- }
3956
- if (infinite) {
3957
- if (negative) {
3958
- return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3959
- }
3960
- else {
3961
- Real* vy = NewZeroWrapNolimit(1, prec);
3962
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3963
- RB_GC_GUARD(vy->obj);
3964
- return VpCheckGetValue(vy);
3965
- }
3966
- }
3967
- else if (nan) {
3968
- Real* vy = NewZeroWrapNolimit(1, prec);
3969
- VpSetNaN(vy);
3970
- RB_GC_GUARD(vy->obj);
3971
- return VpCheckGetValue(vy);
3972
- }
3973
- else if (vx == NULL) {
3974
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
3975
- }
3976
- x = vx->obj;
3977
-
3978
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
3979
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3980
- if (negative) {
3981
- VALUE x_zero = INT2NUM(1);
3982
- VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
3983
- x = BigDecimal_initialize_copy(x_copy, x);
3984
- vx = DATA_PTR(x);
3985
- VpSetSign(vx, 1);
3986
- }
3987
-
3988
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
3989
- y = one;
3990
- d = y;
3991
- i = 1;
3992
-
3993
- while (!VpIsZero((Real*)DATA_PTR(d))) {
3994
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
3995
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
3996
- ssize_t m = n - vabs(ey - ed);
3997
-
3998
- rb_thread_check_ints();
3999
-
4000
- if (m <= 0) {
4001
- break;
4002
- }
4003
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4004
- m = BIGDECIMAL_DOUBLE_FIGURES;
4005
- }
4006
-
4007
- d = BigDecimal_mult(d, x); /* d <- d * x */
4008
- d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
4009
- y = BigDecimal_add(y, d); /* y <- y + d */
4010
- ++i; /* i <- i + 1 */
4011
- }
4012
-
4013
- if (negative) {
4014
- return BigDecimal_div2(one, y, vprec);
4015
- }
4016
- else {
4017
- vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
4018
- return BigDecimal_round(1, &vprec, y);
4019
- }
4020
-
4021
- RB_GC_GUARD(one);
4022
- RB_GC_GUARD(x);
4023
- RB_GC_GUARD(y);
4024
- RB_GC_GUARD(d);
4025
- }
4026
-
4027
- /* call-seq:
4028
- * BigMath.log(decimal, numeric) -> BigDecimal
4029
- *
4030
- * Computes the natural logarithm of +decimal+ to the specified number of
4031
- * digits of precision, +numeric+.
4032
- *
4033
- * If +decimal+ is zero or negative, raises Math::DomainError.
4034
- *
4035
- * If +decimal+ is positive infinity, returns Infinity.
4036
- *
4037
- * If +decimal+ is NaN, returns NaN.
4038
- */
4039
- static VALUE
4040
- BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
4041
- {
4042
- ssize_t prec, n, i;
4043
- SIGNED_VALUE expo;
4044
- Real* vx = NULL;
4045
- VALUE vn, one, two, w, x2, y, d;
4046
- int zero = 0;
4047
- int negative = 0;
4048
- int infinite = 0;
4049
- int nan = 0;
4050
- double flo;
4051
- long fix;
4052
-
4053
- if (!is_integer(vprec)) {
4054
- rb_raise(rb_eArgError, "precision must be an Integer");
4055
- }
4056
-
4057
- prec = NUM2SSIZET(vprec);
4058
- if (prec <= 0) {
4059
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
4060
- }
4061
-
4062
- /* TODO: the following switch statement is almost same as one in the
4063
- * BigDecimalCmp function. */
4064
- switch (TYPE(x)) {
4065
- case T_DATA:
4066
- if (!is_kind_of_BigDecimal(x)) break;
4067
- vx = DATA_PTR(x);
4068
- zero = VpIsZero(vx);
4069
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4070
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
4071
- nan = VpIsNaN(vx);
4072
- break;
4073
-
4074
- case T_FIXNUM:
4075
- fix = FIX2LONG(x);
4076
- zero = fix == 0;
4077
- negative = fix < 0;
4078
- goto get_vp_value;
4079
-
4080
- case T_BIGNUM:
4081
- i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
4082
- zero = i == 0;
4083
- negative = i < 0;
4084
- get_vp_value:
4085
- if (zero || negative) break;
4086
- vx = GetVpValue(x, 0);
4087
- break;
4088
-
4089
- case T_FLOAT:
4090
- flo = RFLOAT_VALUE(x);
4091
- zero = flo == 0;
4092
- negative = flo < 0;
4093
- infinite = isinf(flo);
4094
- nan = isnan(flo);
4095
- if (!zero && !negative && !infinite && !nan) {
4096
- vx = GetVpValueWithPrec(x, 0, 1);
4097
- }
4098
- break;
4099
-
4100
- case T_RATIONAL:
4101
- zero = RRATIONAL_ZERO_P(x);
4102
- negative = RRATIONAL_NEGATIVE_P(x);
4103
- if (zero || negative) break;
4104
- vx = GetVpValueWithPrec(x, prec, 1);
4105
- break;
4106
-
4107
- case T_COMPLEX:
4108
- rb_raise(rb_eMathDomainError,
4109
- "Complex argument for BigMath.log");
4110
-
4111
- default:
4112
- break;
4113
- }
4114
- if (infinite && !negative) {
4115
- Real *vy = NewZeroWrapNolimit(1, prec);
4116
- RB_GC_GUARD(vy->obj);
4117
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
4118
- return VpCheckGetValue(vy);
4119
- }
4120
- else if (nan) {
4121
- Real* vy = NewZeroWrapNolimit(1, prec);
4122
- RB_GC_GUARD(vy->obj);
4123
- VpSetNaN(vy);
4124
- return VpCheckGetValue(vy);
4125
- }
4126
- else if (zero || negative) {
4127
- rb_raise(rb_eMathDomainError,
4128
- "Zero or negative argument for log");
4129
- }
4130
- else if (vx == NULL) {
4131
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4132
- }
4133
- x = VpCheckGetValue(vx);
4134
-
4135
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4136
- two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4137
-
4138
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4139
- vn = SSIZET2NUM(n);
4140
- expo = VpExponent10(vx);
4141
- if (expo < 0 || expo >= 3) {
4142
- char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
4143
- snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
4144
- x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
4145
- }
4146
- else {
4147
- expo = 0;
4148
- }
4149
- w = BigDecimal_sub(x, one);
4150
- x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
4151
- x2 = BigDecimal_mult2(x, x, vn);
4152
- y = x;
4153
- d = y;
4154
- i = 1;
4155
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4156
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4157
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4158
- ssize_t m = n - vabs(ey - ed);
4159
- if (m <= 0) {
4160
- break;
4161
- }
4162
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4163
- m = BIGDECIMAL_DOUBLE_FIGURES;
4164
- }
4165
-
4166
- x = BigDecimal_mult2(x2, x, vn);
4167
- i += 2;
4168
- d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
4169
- y = BigDecimal_add(y, d);
4170
- }
4171
-
4172
- y = BigDecimal_mult(y, two);
4173
- if (expo != 0) {
4174
- VALUE log10, vexpo, dy;
4175
- log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
4176
- vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
4177
- dy = BigDecimal_mult(log10, vexpo);
4178
- y = BigDecimal_add(y, dy);
4179
- }
4180
-
4181
- RB_GC_GUARD(one);
4182
- RB_GC_GUARD(two);
4183
- RB_GC_GUARD(vn);
4184
- RB_GC_GUARD(x2);
4185
- RB_GC_GUARD(y);
4186
- RB_GC_GUARD(d);
4187
-
4188
- return y;
4189
- }
4190
-
4191
3151
  static VALUE BIGDECIMAL_NAN = Qnil;
4192
3152
 
4193
3153
  static VALUE
@@ -4239,6 +3199,71 @@ BigDecimal_literal(const char *str)
4239
3199
 
4240
3200
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4241
3201
 
3202
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3203
+ VALUE
3204
+ BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
3205
+ BDVALUE a, b, c, d;
3206
+ size_t cn = NUM2INT(cprec);
3207
+ a = GetBDValueMust(self);
3208
+ b = GetBDValueMust(r);
3209
+ c = NewZeroWrap(1, cn * BASE_FIG);
3210
+ d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3211
+ vpdivd_func(c.real, d.real, a.real, b.real);
3212
+ RB_GC_GUARD(a.bigdecimal);
3213
+ RB_GC_GUARD(b.bigdecimal);
3214
+ return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3215
+ }
3216
+
3217
+ void
3218
+ VpDivdNormal(Real *c, Real *r, Real *a, Real *b) {
3219
+ VpDivd(c, r, a, b);
3220
+ }
3221
+
3222
+ VALUE
3223
+ BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3224
+ return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNormal);
3225
+ }
3226
+
3227
+ VALUE
3228
+ BigDecimal_vpdivd_newton(VALUE self, VALUE r, VALUE cprec) {
3229
+ return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNewton);
3230
+ }
3231
+
3232
+ VALUE
3233
+ BigDecimal_newton_raphson_inverse(VALUE self, VALUE prec) {
3234
+ return newton_raphson_inverse(self, NUM2SIZET(prec));
3235
+ }
3236
+
3237
+ VALUE
3238
+ BigDecimal_vpmult(VALUE self, VALUE v) {
3239
+ BDVALUE a,b,c;
3240
+ a = GetBDValueMust(self);
3241
+ b = GetBDValueMust(v);
3242
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3243
+ VpMult(c.real, a.real, b.real);
3244
+ RB_GC_GUARD(a.bigdecimal);
3245
+ RB_GC_GUARD(b.bigdecimal);
3246
+ return c.bigdecimal;
3247
+ }
3248
+
3249
+ VALUE
3250
+ BigDecimal_nttmult(VALUE self, VALUE v) {
3251
+ BDVALUE a,b,c;
3252
+ a = GetBDValueMust(self);
3253
+ b = GetBDValueMust(v);
3254
+ c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
3255
+ ntt_multiply(a.real->Prec, b.real->Prec, a.real->frac, b.real->frac, c.real->frac);
3256
+ VpSetSign(c.real, a.real->sign * b.real->sign);
3257
+ c.real->exponent = a.real->exponent + b.real->exponent;
3258
+ c.real->Prec = a.real->Prec + b.real->Prec;
3259
+ VpNmlz(c.real);
3260
+ RB_GC_GUARD(a.bigdecimal);
3261
+ RB_GC_GUARD(b.bigdecimal);
3262
+ return c.bigdecimal;
3263
+ }
3264
+
3265
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3266
+
4242
3267
  /* Document-class: BigDecimal
4243
3268
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4244
3269
  *
@@ -4355,14 +3380,16 @@ BigDecimal_literal(const char *str)
4355
3380
  *
4356
3381
  * When you require +bigdecimal/util+, the #to_d method will be
4357
3382
  * available on BigDecimal and the native Integer, Float, Rational,
4358
- * and String classes:
3383
+ * String, Complex, and NilClass classes:
4359
3384
  *
4360
3385
  * require 'bigdecimal/util'
4361
3386
  *
4362
- * 42.to_d # => 0.42e2
4363
- * 0.5.to_d # => 0.5e0
4364
- * (2/3r).to_d(3) # => 0.667e0
4365
- * "0.5".to_d # => 0.5e0
3387
+ * 42.to_d # => 0.42e2
3388
+ * 0.5.to_d # => 0.5e0
3389
+ * (2/3r).to_d(3) # => 0.667e0
3390
+ * "0.5".to_d # => 0.5e0
3391
+ * Complex(0.1234567, 0).to_d(4) # => 0.1235e0
3392
+ * nil.to_d # => 0.0
4366
3393
  *
4367
3394
  * == Methods for Working with \JSON
4368
3395
  *
@@ -4436,7 +3463,7 @@ Init_bigdecimal(void)
4436
3463
  * guarantee that two groups could always be multiplied together without
4437
3464
  * overflow.)
4438
3465
  */
4439
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3466
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4440
3467
 
4441
3468
  /* Exceptions */
4442
3469
 
@@ -4547,7 +3574,6 @@ Init_bigdecimal(void)
4547
3574
  rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
4548
3575
 
4549
3576
  /* instance methods */
4550
- rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
4551
3577
  rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
4552
3578
  rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
4553
3579
  rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
@@ -4578,14 +3604,11 @@ Init_bigdecimal(void)
4578
3604
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4579
3605
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4580
3606
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4581
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4582
3607
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4583
3608
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4584
3609
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4585
3610
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4586
3611
  rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
4587
- rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
4588
- rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
4589
3612
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4590
3613
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4591
3614
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4604,11 +3627,16 @@ Init_bigdecimal(void)
4604
3627
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4605
3628
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4606
3629
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3630
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4607
3631
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4608
3632
 
4609
- rb_mBigMath = rb_define_module("BigMath");
4610
- rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4611
- rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
3633
+ #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3634
+ rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
3635
+ rb_define_method(rb_cBigDecimal, "vpdivd_newton", BigDecimal_vpdivd_newton, 2);
3636
+ rb_define_method(rb_cBigDecimal, "newton_raphson_inverse", BigDecimal_newton_raphson_inverse, 1);
3637
+ rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3638
+ rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
3639
+ #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
4612
3640
 
4613
3641
  #define ROUNDING_MODE(i, name, value) \
4614
3642
  id_##name = rb_intern_const(#name); \
@@ -4648,19 +3676,9 @@ Init_bigdecimal(void)
4648
3676
  */
4649
3677
  #ifdef BIGDECIMAL_DEBUG
4650
3678
  static int gfDebug = 1; /* Debug switch */
4651
- #if 0
4652
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4653
- #endif
4654
3679
  #endif /* BIGDECIMAL_DEBUG */
4655
3680
 
4656
- static Real *VpConstOne; /* constant 1.0 */
4657
- static Real *VpConstPt5; /* constant 0.5 */
4658
- #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4659
- /* used in VpSqrt() */
4660
-
4661
- /* ETC */
4662
- #define MemCmp(x,y,z) memcmp(x,y,z)
4663
- #define StrCmp(x,y) strcmp(x,y)
3681
+ static VALUE VpConstOne; /* constant 1.0 */
4664
3682
 
4665
3683
  enum op_sw {
4666
3684
  OP_SW_ADD = 1, /* + */
@@ -4670,11 +3688,9 @@ enum op_sw {
4670
3688
  };
4671
3689
 
4672
3690
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4673
- static int AddExponent(Real *a, SIGNED_VALUE n);
4674
3691
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4675
3692
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4676
3693
  static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
4677
- static int VpNmlz(Real *a);
4678
3694
  static void VpFormatSt(char *psz, size_t fFmt);
4679
3695
  static int VpRdup(Real *m, size_t ind_m);
4680
3696
 
@@ -4733,10 +3749,10 @@ VpCheckException(Real *p, bool always)
4733
3749
  }
4734
3750
 
4735
3751
  static VALUE
4736
- VpCheckGetValue(Real *p)
3752
+ CheckGetValue(BDVALUE v)
4737
3753
  {
4738
- VpCheckException(p, false);
4739
- return p->obj;
3754
+ VpCheckException(v.real, false);
3755
+ return v.bigdecimal;
4740
3756
  }
4741
3757
 
4742
3758
  /*
@@ -4768,12 +3784,10 @@ VpGetPrecLimit(void)
4768
3784
  return NUM2SIZET(vlimit);
4769
3785
  }
4770
3786
 
4771
- VP_EXPORT size_t
3787
+ VP_EXPORT void
4772
3788
  VpSetPrecLimit(size_t n)
4773
3789
  {
4774
- size_t const s = VpGetPrecLimit();
4775
3790
  bigdecimal_set_thread_local_precision_limit(n);
4776
- return s;
4777
3791
  }
4778
3792
 
4779
3793
  /*
@@ -4888,15 +3902,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4888
3902
  return nzero;
4889
3903
  }
4890
3904
 
4891
- #if 0 /* unused */
4892
- VP_EXPORT int
4893
- VpIsNegDoubleZero(double v)
4894
- {
4895
- double z = VpGetDoubleNegZero();
4896
- return MemCmp(&v,&z,sizeof(v))==0;
4897
- }
4898
- #endif
4899
-
4900
3905
  VP_EXPORT int
4901
3906
  VpException(unsigned short f, const char *str,int always)
4902
3907
  {
@@ -5048,7 +4053,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5048
4053
  case 'E':
5049
4054
  /* fall through */
5050
4055
  default:
5051
- nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
4056
+ nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
5052
4057
  }
5053
4058
  return nc;
5054
4059
  }
@@ -5074,35 +4079,21 @@ VpInit(DECDIG BaseVal)
5074
4079
  VpGetDoubleNegZero();
5075
4080
 
5076
4081
  /* Const 1.0 */
5077
- VpConstOne = NewOneNolimit(1, 1);
5078
-
5079
- /* Const 0.5 */
5080
- VpConstPt5 = NewOneNolimit(1, 1);
5081
- VpConstPt5->exponent = 0;
5082
- VpConstPt5->frac[0] = 5*BASE1;
4082
+ rb_global_variable(&VpConstOne);
4083
+ VpConstOne = NewZeroWrap(1, 1).bigdecimal;
4084
+ VpSetOne(VpPtr(VpConstOne));
5083
4085
 
5084
4086
  #ifdef BIGDECIMAL_DEBUG
5085
4087
  gnAlloc = 0;
5086
4088
  #endif /* BIGDECIMAL_DEBUG */
5087
4089
 
5088
- #ifdef BIGDECIMAL_DEBUG
5089
- if (gfDebug) {
5090
- printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
5091
- printf("\tBASE = %"PRIuDECDIG"\n", BASE);
5092
- printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
5093
- printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
5094
- printf("\tBASE_FIG = %u\n", BASE_FIG);
5095
- printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
5096
- }
5097
- #endif /* BIGDECIMAL_DEBUG */
5098
-
5099
4090
  return BIGDECIMAL_DOUBLE_FIGURES;
5100
4091
  }
5101
4092
 
5102
4093
  VP_EXPORT Real *
5103
4094
  VpOne(void)
5104
4095
  {
5105
- return VpConstOne;
4096
+ return VpPtr(VpConstOne);
5106
4097
  }
5107
4098
 
5108
4099
  /* If exponent overflows,then raise exception or returns 0 */
@@ -5111,24 +4102,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5111
4102
  {
5112
4103
  SIGNED_VALUE e = a->exponent;
5113
4104
  SIGNED_VALUE m = e+n;
5114
- SIGNED_VALUE eb, mb;
5115
- if (e > 0) {
5116
- if (n > 0) {
5117
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5118
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5119
- goto overflow;
5120
- mb = m*(SIGNED_VALUE)BASE_FIG;
5121
- eb = e*(SIGNED_VALUE)BASE_FIG;
5122
- if (eb - mb > 0) goto overflow;
5123
- }
5124
- }
5125
- else if (n < 0) {
5126
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5127
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5128
- goto underflow;
5129
- mb = m*(SIGNED_VALUE)BASE_FIG;
5130
- eb = e*(SIGNED_VALUE)BASE_FIG;
5131
- if (mb - eb > 0) goto underflow;
4105
+ if (e > 0 && n > 0) {
4106
+ if (n > VP_EXPONENT_MAX - e) goto overflow;
4107
+ } else if (e < 0 && n < 0) {
4108
+ if (n < VP_EXPONENT_MIN - e) goto underflow;
4109
+ } else if (m > VP_EXPONENT_MAX) {
4110
+ goto overflow;
4111
+ } else if (m < VP_EXPONENT_MIN) {
4112
+ goto underflow;
5132
4113
  }
5133
4114
  a->exponent = m;
5134
4115
  return 1;
@@ -5143,7 +4124,7 @@ overflow:
5143
4124
  return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
5144
4125
  }
5145
4126
 
5146
- Real *
4127
+ NULLABLE_BDVALUE
5147
4128
  bigdecimal_parse_special_string(const char *str)
5148
4129
  {
5149
4130
  static const struct {
@@ -5168,120 +4149,61 @@ bigdecimal_parse_special_string(const char *str)
5168
4149
  p = str + table[i].len;
5169
4150
  while (*p && ISSPACE(*p)) ++p;
5170
4151
  if (*p == '\0') {
5171
- Real *vp = rbd_allocate_struct(1);
5172
- vp->MaxPrec = 1;
4152
+ VALUE obj = BigDecimal_allocate(1);
4153
+ Real *vp = VpPtr(obj);
5173
4154
  switch (table[i].sign) {
5174
4155
  default:
5175
- UNREACHABLE; break;
4156
+ UNREACHABLE;
4157
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5176
4158
  case VP_SIGN_POSITIVE_INFINITE:
5177
4159
  VpSetPosInf(vp);
5178
- return vp;
4160
+ break;
5179
4161
  case VP_SIGN_NEGATIVE_INFINITE:
5180
4162
  VpSetNegInf(vp);
5181
- return vp;
4163
+ break;
5182
4164
  case VP_SIGN_NaN:
5183
4165
  VpSetNaN(vp);
5184
- return vp;
4166
+ break;
5185
4167
  }
4168
+ return (NULLABLE_BDVALUE) { obj, vp };
5186
4169
  }
5187
4170
  }
5188
4171
 
5189
- return NULL;
5190
- }
5191
-
5192
- struct VpCtoV_args {
5193
- Real *a;
5194
- const char *int_chr;
5195
- size_t ni;
5196
- const char *frac;
5197
- size_t nf;
5198
- const char *exp_chr;
5199
- size_t ne;
5200
- };
5201
-
5202
- static VALUE
5203
- call_VpCtoV(VALUE arg)
5204
- {
5205
- struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
5206
- return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
5207
- }
5208
-
5209
- static int
5210
- protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne, int free_on_error)
5211
- {
5212
- struct VpCtoV_args args;
5213
- int state = 0;
5214
-
5215
- args.a = a;
5216
- args.int_chr = int_chr;
5217
- args.ni = ni;
5218
- args.frac = frac;
5219
- args.nf = nf;
5220
- args.exp_chr = exp_chr;
5221
- args.ne = ne;
5222
-
5223
- VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
5224
- if (state) {
5225
- if (free_on_error) {
5226
- rbd_free_struct(a);
5227
- }
5228
- rb_jump_tag(state);
5229
- }
5230
-
5231
- return (int)result;
4172
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5232
4173
  }
5233
4174
 
5234
4175
  /*
5235
4176
  * Allocates variable.
5236
4177
  * [Input]
5237
- * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5238
- * The mx will be the number of significant digits can to be stored.
5239
- * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5240
- * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5241
- * so that the full precision specified by szVal is allocated.
4178
+ * szVal ... The value assigned(char).
5242
4179
  *
5243
4180
  * [Returns]
5244
- * Pointer to the newly allocated variable, or
5245
- * NULL be returned if memory allocation is failed,or any error.
4181
+ * NULLABLE_BDVALUE to the newly allocated variable.
4182
+ * Null is returned if memory allocation failed, or any error occured.
5246
4183
  */
5247
- VP_EXPORT Real *
5248
- VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4184
+ VP_EXPORT NULLABLE_BDVALUE
4185
+ VpAlloc(const char *szVal, int strict_p, int exc)
5249
4186
  {
5250
4187
  const char *orig_szVal = szVal;
5251
4188
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5252
- size_t len;
5253
4189
  char v, *psz;
5254
4190
  int sign=1;
5255
- Real *vp = NULL;
5256
4191
  VALUE buf;
5257
4192
 
5258
- if (szVal == NULL) {
5259
- return_zero:
5260
- /* necessary to be able to store */
5261
- /* at least mx digits. */
5262
- /* szVal==NULL ==> allocate zero value. */
5263
- vp = rbd_allocate_struct(mx);
5264
- vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5265
- VpSetZero(vp, 1); /* initialize vp to zero. */
5266
- return vp;
5267
- }
5268
-
5269
4193
  /* Skipping leading spaces */
5270
4194
  while (ISSPACE(*szVal)) szVal++;
5271
4195
 
5272
4196
  /* Check on Inf & NaN */
5273
- if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
5274
- return vp;
4197
+ NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
4198
+ if (special_bd.real_or_null != NULL) {
4199
+ return special_bd;
5275
4200
  }
5276
4201
 
5277
- /* Processing the leading one `#` */
5278
- if (*szVal != '#') {
5279
- len = rbd_calculate_internal_digits(mx, true);
5280
- }
5281
- else {
5282
- len = rbd_calculate_internal_digits(mx, false);
5283
- ++szVal;
5284
- }
4202
+ /* Skip leading `#`.
4203
+ * It used to be a mark to indicate that an extra MaxPrec should be allocated,
4204
+ * but now it has no effect.
4205
+ */
4206
+ if (*szVal == '#') ++szVal;
5285
4207
 
5286
4208
  /* Scanning digits */
5287
4209
 
@@ -5428,10 +4350,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5428
4350
  VALUE str;
5429
4351
  invalid_value:
5430
4352
  if (!strict_p) {
5431
- goto return_zero;
4353
+ BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
4354
+ return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
5432
4355
  }
5433
4356
  if (!exc) {
5434
- return NULL;
4357
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5435
4358
  }
5436
4359
  str = rb_str_new2(orig_szVal);
5437
4360
  rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
@@ -5439,15 +4362,12 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5439
4362
 
5440
4363
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5441
4364
  /* units for szVal[] */
5442
- if (len == 0) len = 1;
5443
- nalloc = Max(nalloc, len);
5444
- len = nalloc;
5445
- vp = rbd_allocate_struct(len);
5446
- vp->MaxPrec = len; /* set max precision */
4365
+ VALUE obj = BigDecimal_allocate(nalloc);
4366
+ Real *vp = VpPtr(obj);
5447
4367
  VpSetZero(vp, sign);
5448
- protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
4368
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
5449
4369
  rb_str_resize(buf, 0);
5450
- return vp;
4370
+ return (NULLABLE_BDVALUE) { obj, vp };
5451
4371
  }
5452
4372
 
5453
4373
  /*
@@ -5483,7 +4403,7 @@ VpAsgn(Real *c, Real *a, int isw)
5483
4403
  c->Prec = n;
5484
4404
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5485
4405
  /* Needs round ? */
5486
- if (isw != 10) {
4406
+ if (isw != 10 && isw != -10) {
5487
4407
  /* Not in ActiveRound */
5488
4408
  if(c->Prec < a->Prec) {
5489
4409
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5509,19 +4429,11 @@ VpAsgn(Real *c, Real *a, int isw)
5509
4429
  VP_EXPORT size_t
5510
4430
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5511
4431
  {
5512
- short sw, isw;
4432
+ short sw, isw, sign;
5513
4433
  Real *a_ptr, *b_ptr;
5514
4434
  size_t n, na, nb, i;
5515
4435
  DECDIG mrv;
5516
4436
 
5517
- #ifdef BIGDECIMAL_DEBUG
5518
- if (gfDebug) {
5519
- VPrint(stdout, "VpAddSub(enter) a=% \n", a);
5520
- VPrint(stdout, " b=% \n", b);
5521
- printf(" operation=%d\n", operation);
5522
- }
5523
- #endif /* BIGDECIMAL_DEBUG */
5524
-
5525
4437
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5526
4438
 
5527
4439
  /* check if a or b is zero */
@@ -5610,28 +4522,21 @@ end_if:
5610
4522
  if (isw) { /* addition */
5611
4523
  VpSetSign(c, 1);
5612
4524
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5613
- VpSetSign(c, isw / 2);
4525
+ sign = isw / 2;
5614
4526
  }
5615
4527
  else { /* subtraction */
5616
4528
  VpSetSign(c, 1);
5617
4529
  mrv = VpSubAbs(a_ptr, b_ptr, c);
5618
- if (a_ptr == a) {
5619
- VpSetSign(c,VpGetSign(a));
5620
- }
5621
- else {
5622
- VpSetSign(c, VpGetSign(a_ptr) * sw);
5623
- }
4530
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5624
4531
  }
5625
- VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
5626
-
5627
- #ifdef BIGDECIMAL_DEBUG
5628
- if (gfDebug) {
5629
- VPrint(stdout, "VpAddSub(result) c=% \n", c);
5630
- VPrint(stdout, " a=% \n", a);
5631
- VPrint(stdout, " b=% \n", b);
5632
- printf(" operation=%d\n", operation);
4532
+ if (VpIsInf(c)) {
4533
+ VpSetInf(c, sign);
5633
4534
  }
5634
- #endif /* BIGDECIMAL_DEBUG */
4535
+ else {
4536
+ VpSetSign(c, sign);
4537
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
4538
+ }
4539
+
5635
4540
  return c->Prec * BASE_FIG;
5636
4541
  }
5637
4542
 
@@ -5652,13 +4557,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5652
4557
  size_t c_pos;
5653
4558
  DECDIG av, bv, carry, mrv;
5654
4559
 
5655
- #ifdef BIGDECIMAL_DEBUG
5656
- if (gfDebug) {
5657
- VPrint(stdout, "VpAddAbs called: a = %\n", a);
5658
- VPrint(stdout, " b = %\n", b);
5659
- }
5660
- #endif /* BIGDECIMAL_DEBUG */
5661
-
5662
4560
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5663
4561
  a_pos = ap;
5664
4562
  b_pos = bp;
@@ -5724,11 +4622,6 @@ Assign_a:
5724
4622
 
5725
4623
  Exit:
5726
4624
 
5727
- #ifdef BIGDECIMAL_DEBUG
5728
- if (gfDebug) {
5729
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5730
- }
5731
- #endif /* BIGDECIMAL_DEBUG */
5732
4625
  return mrv;
5733
4626
  }
5734
4627
 
@@ -5747,13 +4640,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5747
4640
  size_t c_pos;
5748
4641
  DECDIG av, bv, borrow, mrv;
5749
4642
 
5750
- #ifdef BIGDECIMAL_DEBUG
5751
- if (gfDebug) {
5752
- VPrint(stdout, "VpSubAbs called: a = %\n", a);
5753
- VPrint(stdout, " b = %\n", b);
5754
- }
5755
- #endif /* BIGDECIMAL_DEBUG */
5756
-
5757
4643
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5758
4644
  a_pos = ap;
5759
4645
  b_pos = bp;
@@ -5829,11 +4715,6 @@ Assign_a:
5829
4715
  mrv = 0;
5830
4716
 
5831
4717
  Exit:
5832
- #ifdef BIGDECIMAL_DEBUG
5833
- if (gfDebug) {
5834
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5835
- }
5836
- #endif /* BIGDECIMAL_DEBUG */
5837
4718
  return mrv;
5838
4719
  }
5839
4720
 
@@ -5958,25 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5958
4839
  * a0 a1 .... an * b0
5959
4840
  * +_____________________________
5960
4841
  * c0 c1 c2 ...... cl
5961
- * nc <---|
5962
- * MaxAB |--------------------|
5963
4842
  */
5964
4843
  VP_EXPORT size_t
5965
4844
  VpMult(Real *c, Real *a, Real *b)
5966
4845
  {
5967
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
5968
- size_t ind_c, i, ii, nc;
5969
- size_t ind_as, ind_ae, ind_bs;
5970
- DECDIG carry;
5971
- DECDIG_DBL s;
5972
- Real *w;
5973
-
5974
- #ifdef BIGDECIMAL_DEBUG
5975
- if (gfDebug) {
5976
- VPrint(stdout, "VpMult(Enter): a=% \n", a);
5977
- VPrint(stdout, " b=% \n", b);
5978
- }
5979
- #endif /* BIGDECIMAL_DEBUG */
4846
+ ssize_t a_batch_max, b_batch_max;
4847
+ DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
5980
4848
 
5981
4849
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
5982
4850
 
@@ -5987,108 +4855,82 @@ VpMult(Real *c, Real *a, Real *b)
5987
4855
  }
5988
4856
 
5989
4857
  if (VpIsOne(a)) {
5990
- VpAsgn(c, b, VpGetSign(a));
4858
+ VpAsgn(c, b, 10 * VpGetSign(a));
5991
4859
  goto Exit;
5992
4860
  }
5993
4861
  if (VpIsOne(b)) {
5994
- VpAsgn(c, a, VpGetSign(b));
4862
+ VpAsgn(c, a, 10 * VpGetSign(b));
5995
4863
  goto Exit;
5996
4864
  }
5997
4865
  if (b->Prec > a->Prec) {
5998
4866
  /* Adjust so that digits(a)>digits(b) */
5999
- w = a;
4867
+ Real *w = a;
6000
4868
  a = b;
6001
4869
  b = w;
6002
4870
  }
6003
- w = NULL;
6004
- MxIndA = a->Prec - 1;
6005
- MxIndB = b->Prec - 1;
6006
- MxIndC = c->MaxPrec - 1;
6007
- MxIndAB = a->Prec + b->Prec - 1;
6008
-
6009
- if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
6010
- w = c;
6011
- c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
6012
- MxIndC = MxIndAB;
6013
- }
6014
4871
 
6015
4872
  /* set LHSV c info */
6016
4873
 
6017
4874
  c->exponent = a->exponent; /* set exponent */
6018
- if (!AddExponent(c, b->exponent)) {
6019
- if (w) rbd_free_struct(c);
6020
- return 0;
6021
- }
6022
4875
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
6023
- carry = 0;
6024
- nc = ind_c = MxIndAB;
6025
- memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
6026
- c->Prec = nc + 1; /* set precision */
6027
- for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
6028
- if (nc < MxIndB) { /* The left triangle of the Fig. */
6029
- ind_as = MxIndA - nc;
6030
- ind_ae = MxIndA;
6031
- ind_bs = MxIndB;
6032
- }
6033
- else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
6034
- ind_as = MxIndA - nc;
6035
- ind_ae = MxIndA - (nc - MxIndB);
6036
- ind_bs = MxIndB;
6037
- }
6038
- else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
6039
- ind_as = 0;
6040
- ind_ae = MxIndAB - nc - 1;
6041
- ind_bs = MxIndB - (nc - MxIndA);
6042
- }
4876
+ if (!AddExponent(c, b->exponent)) return 0;
4877
+
4878
+ if (b->Prec >= NTT_MULTIPLICATION_THRESHOLD) {
4879
+ ntt_multiply(a->Prec, b->Prec, a->frac, b->frac, c->frac);
4880
+ c->Prec = a->Prec + b->Prec;
4881
+ goto Cleanup;
4882
+ }
4883
+
4884
+ c->Prec = a->Prec + b->Prec; /* set precision */
4885
+ memset(c->frac, 0, c->Prec * sizeof(DECDIG)); /* Initialize c */
4886
+
4887
+ // Process VPMULT_BATCH_SIZE decdigits at a time to reduce the number of carry operations.
4888
+ a_batch_max = (a->Prec - 1) / VPMULT_BATCH_SIZE;
4889
+ b_batch_max = (b->Prec - 1) / VPMULT_BATCH_SIZE;
4890
+ for (ssize_t ibatch = a_batch_max; ibatch >= 0; ibatch--) {
4891
+ int isize = ibatch == a_batch_max ? (a->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
4892
+ for (ssize_t jbatch = b_batch_max; jbatch >= 0; jbatch--) {
4893
+ int jsize = jbatch == b_batch_max ? (b->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
4894
+ memset(batch, 0, (isize + jsize - 1) * sizeof(DECDIG_DBL));
4895
+
4896
+ // Perform multiplication without carry calculation.
4897
+ // BASE * BASE * VPMULT_BATCH_SIZE < 2**64 should be satisfied so that
4898
+ // DECDIG_DBL can hold the intermediate sum without overflow.
4899
+ for (int i = 0; i < isize; i++) {
4900
+ for (int j = 0; j < jsize; j++) {
4901
+ batch[i + j] += (DECDIG_DBL)a->frac[ibatch * VPMULT_BATCH_SIZE + i] * b->frac[jbatch * VPMULT_BATCH_SIZE + j];
4902
+ }
4903
+ }
6043
4904
 
6044
- for (i = ind_as; i <= ind_ae; ++i) {
6045
- s = (DECDIG_DBL)a->frac[i] * b->frac[ind_bs--];
6046
- carry = (DECDIG)(s / BASE);
6047
- s -= (DECDIG_DBL)carry * BASE;
6048
- c->frac[ind_c] += (DECDIG)s;
6049
- if (c->frac[ind_c] >= BASE) {
6050
- s = c->frac[ind_c] / BASE;
6051
- carry += (DECDIG)s;
6052
- c->frac[ind_c] -= (DECDIG)(s * BASE);
4905
+ // Add the batch result to c with carry calculation.
4906
+ DECDIG_DBL carry = 0;
4907
+ for (int k = isize + jsize - 2; k >= 0; k--) {
4908
+ size_t l = (ibatch + jbatch) * VPMULT_BATCH_SIZE + k + 1;
4909
+ DECDIG_DBL s = c->frac[l] + batch[k] + carry;
4910
+ c->frac[l] = (DECDIG)(s % BASE);
4911
+ carry = (DECDIG_DBL)(s / BASE);
6053
4912
  }
6054
- if (carry) {
6055
- ii = ind_c;
6056
- while (ii-- > 0) {
6057
- c->frac[ii] += carry;
6058
- if (c->frac[ii] >= BASE) {
6059
- carry = c->frac[ii] / BASE;
6060
- c->frac[ii] -= (carry * BASE);
6061
- }
6062
- else {
6063
- break;
6064
- }
6065
- }
6066
- }
6067
- }
6068
- }
6069
- if (w != NULL) { /* free work variable */
6070
- VpNmlz(c);
6071
- VpAsgn(w, c, 1);
6072
- rbd_free_struct(c);
6073
- c = w;
6074
- }
6075
- else {
6076
- VpLimitRound(c,0);
4913
+
4914
+ // Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
4915
+ // Exceeded value will be resolved in the carry operation of next (ibatch + jbatch - 1) batch.
4916
+ // WARNING: This safety strongly relies on the current nested loop execution order.
4917
+ c->frac[(ibatch + jbatch) * VPMULT_BATCH_SIZE] += (DECDIG)carry;
4918
+ }
6077
4919
  }
6078
4920
 
4921
+ Cleanup:
4922
+ VpNmlz(c);
4923
+
6079
4924
  Exit:
6080
- #ifdef BIGDECIMAL_DEBUG
6081
- if (gfDebug) {
6082
- VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
6083
- VPrint(stdout, " a=% \n", a);
6084
- VPrint(stdout, " b=% \n", b);
6085
- }
6086
- #endif /*BIGDECIMAL_DEBUG */
6087
4925
  return c->Prec*BASE_FIG;
6088
4926
  }
6089
4927
 
6090
4928
  /*
6091
4929
  * c = a / b, remainder = r
4930
+ * XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
4931
+ * XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
4932
+ * 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
4933
+ * 0001_0000_0000 / 9999 = 0000_0001_0001
6092
4934
  */
6093
4935
  VP_EXPORT size_t
6094
4936
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6097,16 +4939,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6097
4939
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6098
4940
  size_t nLoop;
6099
4941
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6100
- DECDIG borrow, borrow1, borrow2;
4942
+ DECDIG borrow1, borrow2;
6101
4943
  DECDIG_DBL qb;
6102
4944
 
6103
- #ifdef BIGDECIMAL_DEBUG
6104
- if (gfDebug) {
6105
- VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
6106
- VPrint(stdout, " b=% \n", b);
6107
- }
6108
- #endif /*BIGDECIMAL_DEBUG */
6109
-
6110
4945
  VpSetNaN(r);
6111
4946
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6112
4947
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6123,30 +4958,22 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6123
4958
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6124
4959
  goto Exit;
6125
4960
  }
6126
- if (VpIsOne(b)) {
6127
- /* divide by one */
6128
- VpAsgn(c, a, VpGetSign(b));
6129
- VpSetZero(r, VpGetSign(a));
6130
- goto Exit;
6131
- }
6132
4961
 
6133
4962
  word_a = a->Prec;
6134
4963
  word_b = b->Prec;
6135
4964
  word_c = c->MaxPrec;
6136
4965
  word_r = r->MaxPrec;
6137
4966
 
6138
- if (word_a >= word_r || word_b + word_c - 2 >= word_r) goto space_error;
4967
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6139
4968
 
6140
- ind_r = 1;
6141
- r->frac[0] = 0;
6142
- while (ind_r <= word_a) {
6143
- r->frac[ind_r] = a->frac[ind_r - 1];
6144
- ++ind_r;
4969
+ if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
4970
+ VpDivdNewton(c, r, a, b);
4971
+ goto Exit;
6145
4972
  }
6146
- while (ind_r < word_r) r->frac[ind_r++] = 0;
6147
4973
 
6148
- ind_c = 0;
6149
- while (ind_c < word_c) c->frac[ind_c++] = 0;
4974
+ for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
4975
+ for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
4976
+ for (i = 0; i < word_c; ++i) c->frac[i] = 0;
6150
4977
 
6151
4978
  /* initial procedure */
6152
4979
  b1 = b1p1 = b->frac[0];
@@ -6161,15 +4988,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6161
4988
 
6162
4989
  /* */
6163
4990
  /* loop start */
6164
- ind_c = word_r - 1;
6165
- nLoop = Min(word_c,ind_c);
6166
- ind_c = 1;
4991
+ nLoop = Min(word_c, word_r);
4992
+ ind_c = 0;
6167
4993
  while (ind_c < nLoop) {
6168
4994
  if (r->frac[ind_c] == 0) {
6169
4995
  ++ind_c;
6170
4996
  continue;
6171
4997
  }
6172
- r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
4998
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
6173
4999
  if (r1r2 == b1b2) {
6174
5000
  /* The first two word digits is the same */
6175
5001
  ind_b = 2;
@@ -6182,26 +5008,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6182
5008
  }
6183
5009
  /* The first few word digits of r and b is the same and */
6184
5010
  /* the first different word digit of w is greater than that */
6185
- /* of b, so quotient is 1 and just subtract b from r. */
6186
- borrow = 0; /* quotient=1, then just r-b */
6187
- ind_b = b->Prec - 1;
6188
- ind_r = ind_c + ind_b;
6189
- if (ind_r >= word_r) goto space_error;
6190
- n = ind_b;
6191
- for (i = 0; i <= n; ++i) {
6192
- if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
6193
- r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
6194
- borrow = 1;
6195
- }
6196
- else {
6197
- r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
6198
- borrow = 0;
6199
- }
6200
- --ind_r;
6201
- --ind_b;
6202
- }
5011
+ /* of b, so quotient is 1. */
5012
+ q = 1;
6203
5013
  ++c->frac[ind_c];
6204
- goto carry;
5014
+ ind_r = b->Prec + ind_c - 1;
5015
+ goto sub_mult;
6205
5016
  }
6206
5017
  /* The first two word digits is not the same, */
6207
5018
  /* then compare magnitude, and divide actually. */
@@ -6254,49 +5065,26 @@ sub_mult:
6254
5065
  }
6255
5066
 
6256
5067
  r->frac[ind_r] -= borrow2;
6257
- carry:
6258
- ind_r = ind_c;
6259
- while (c->frac[ind_r] >= BASE) {
6260
- c->frac[ind_r] -= BASE;
6261
- --ind_r;
6262
- ++c->frac[ind_r];
6263
- }
6264
5068
  }
6265
5069
  /* End of operation, now final arrangement */
6266
5070
  out_side:
6267
5071
  c->Prec = word_c;
6268
5072
  c->exponent = a->exponent;
6269
- if (!AddExponent(c, 2)) return 0;
5073
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5074
+ if (!AddExponent(c, 1)) return 0;
6270
5075
  if (!AddExponent(c, -(b->exponent))) return 0;
6271
5076
 
6272
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6273
5077
  VpNmlz(c); /* normalize c */
6274
5078
  r->Prec = word_r;
6275
5079
  r->exponent = a->exponent;
6276
- if (!AddExponent(r, 1)) return 0;
6277
5080
  VpSetSign(r, VpGetSign(a));
6278
5081
  VpNmlz(r); /* normalize r(remainder) */
6279
5082
  goto Exit;
6280
5083
 
6281
5084
  space_error:
6282
- #ifdef BIGDECIMAL_DEBUG
6283
- if (gfDebug) {
6284
- printf(" word_a=%"PRIuSIZE"\n", word_a);
6285
- printf(" word_b=%"PRIuSIZE"\n", word_b);
6286
- printf(" word_c=%"PRIuSIZE"\n", word_c);
6287
- printf(" word_r=%"PRIuSIZE"\n", word_r);
6288
- printf(" ind_r =%"PRIuSIZE"\n", ind_r);
6289
- }
6290
- #endif /* BIGDECIMAL_DEBUG */
6291
5085
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6292
5086
 
6293
5087
  Exit:
6294
- #ifdef BIGDECIMAL_DEBUG
6295
- if (gfDebug) {
6296
- VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
6297
- VPrint(stdout, " r=% \n", r);
6298
- }
6299
- #endif /* BIGDECIMAL_DEBUG */
6300
5088
  return c->Prec * BASE_FIG;
6301
5089
  }
6302
5090
 
@@ -6419,13 +5207,6 @@ Exit:
6419
5207
  if (val > 1) val = 1;
6420
5208
  else if (val < -1) val = -1;
6421
5209
 
6422
- #ifdef BIGDECIMAL_DEBUG
6423
- if (gfDebug) {
6424
- VPrint(stdout, " VpComp a=%\n", a);
6425
- VPrint(stdout, " b=%\n", b);
6426
- printf(" ans=%d\n", val);
6427
- }
6428
- #endif /* BIGDECIMAL_DEBUG */
6429
5210
  return (int)val;
6430
5211
  }
6431
5212
 
@@ -6543,25 +5324,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6543
5324
  static void
6544
5325
  VpFormatSt(char *psz, size_t fFmt)
6545
5326
  {
6546
- size_t ie, i, nf = 0;
6547
- char ch;
5327
+ size_t iend, idig = 0, iexp = 0, nspaces;
5328
+ char *p;
6548
5329
 
6549
5330
  if (fFmt == 0) return;
6550
5331
 
6551
- ie = strlen(psz);
6552
- for (i = 0; i < ie; ++i) {
6553
- ch = psz[i];
6554
- if (!ch) break;
6555
- if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
6556
- if (ch == '.') { nf = 0; continue; }
6557
- if (ch == 'E' || ch == 'e') break;
6558
-
6559
- if (++nf > fFmt) {
6560
- memmove(psz + i + 1, psz + i, ie - i + 1);
6561
- ++ie;
6562
- nf = 0;
6563
- psz[i] = ' ';
6564
- }
5332
+ iend = strlen(psz);
5333
+
5334
+ if ((p = strchr(psz, '.'))) {
5335
+ idig = (p - psz) + 1;
5336
+ }
5337
+ if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
5338
+ iexp = p - psz;
5339
+ }
5340
+ if (idig == 0 || idig > iexp) return;
5341
+
5342
+ nspaces = (iexp - idig - 1) / fFmt;
5343
+ p = psz + iend + 1;
5344
+ for (size_t i = nspaces; i > 0; i--) {
5345
+ char *src = psz + idig + i * fFmt;
5346
+ char *dst = psz + idig + i * (fFmt + 1);
5347
+ memmove(dst, src, p - src);
5348
+ dst[-1] = ' ';
5349
+ p = src;
6565
5350
  }
6566
5351
  }
6567
5352
 
@@ -6843,7 +5628,7 @@ VP_EXPORT int
6843
5628
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6844
5629
  {
6845
5630
  size_t i, j, ind_a, ma, mi, me;
6846
- SIGNED_VALUE e, es, eb, ef;
5631
+ SIGNED_VALUE e;
6847
5632
  int sign, signe, exponent_overflow;
6848
5633
 
6849
5634
  /* get exponent part */
@@ -6866,23 +5651,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6866
5651
  ++me;
6867
5652
  }
6868
5653
  while (i < me) {
6869
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
6870
- es = e;
6871
- goto exp_overflow;
6872
- }
6873
- es = e * (SIGNED_VALUE)BASE_FIG;
6874
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
6875
- SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
6876
- goto exp_overflow;
6877
- e = e * 10 + exp_chr[i] - '0';
6878
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
6879
- goto exp_overflow;
6880
- if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
6881
- exp_overflow:
5654
+ int dig = exp_chr[i] - '0';
5655
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5656
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6882
5657
  exponent_overflow = 1;
6883
- e = es; /* keep sign */
6884
5658
  break;
6885
5659
  }
5660
+ e = e * 10 + signe * dig;
6886
5661
  ++i;
6887
5662
  }
6888
5663
  }
@@ -6901,34 +5676,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6901
5676
  ++mi;
6902
5677
  }
6903
5678
  }
5679
+ /* skip leading zeros in integer part */
5680
+ while (i < mi && int_chr[i] == '0') {
5681
+ ++i;
5682
+ --ni;
5683
+ }
6904
5684
 
6905
- e = signe * e; /* e: The value of exponent part. */
6906
- e = e + ni; /* set actual exponent size. */
6907
-
6908
- if (e > 0) signe = 1;
6909
- else signe = -1;
5685
+ /* set actual exponent size. */
5686
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5687
+ exponent_overflow = 1;
5688
+ } else {
5689
+ e += ni;
5690
+ }
6910
5691
 
6911
5692
  /* Adjust the exponent so that it is the multiple of BASE_FIG. */
6912
- j = 0;
6913
- ef = 1;
6914
- while (ef) {
6915
- if (e >= 0) eb = e;
6916
- else eb = -e;
6917
- ef = eb / (SIGNED_VALUE)BASE_FIG;
6918
- ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
6919
- if (ef) {
6920
- ++j; /* Means to add one more preceding zero */
6921
- ++e;
6922
- }
5693
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5694
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5695
+ exponent_overflow = 1;
5696
+ } else {
5697
+ e += j;
6923
5698
  }
6924
5699
 
6925
- eb = e / (SIGNED_VALUE)BASE_FIG;
6926
-
6927
- if (exponent_overflow) {
5700
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6928
5701
  int zero = 1;
6929
5702
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6930
5703
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6931
- if (!zero && signe > 0) {
5704
+ if (!zero && e > 0) {
6932
5705
  VpSetInf(a, sign);
6933
5706
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6934
5707
  }
@@ -6978,7 +5751,7 @@ Final:
6978
5751
  ++j;
6979
5752
  }
6980
5753
  a->Prec = ind_a + 1;
6981
- a->exponent = eb;
5754
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
6982
5755
  VpSetSign(a, sign);
6983
5756
  VpNmlz(a);
6984
5757
  return 1;
@@ -7050,254 +5823,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7050
5823
  *d *= VpGetSign(m);
7051
5824
 
7052
5825
  Exit:
7053
- #ifdef BIGDECIMAL_DEBUG
7054
- if (gfDebug) {
7055
- VPrint(stdout, " VpVtoD: m=%\n", m);
7056
- printf(" d=%e * 10 **%ld\n", *d, *e);
7057
- printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
7058
- }
7059
- #endif /*BIGDECIMAL_DEBUG */
7060
5826
  return f;
7061
5827
  }
7062
5828
 
7063
- /*
7064
- * m <- d
7065
- */
7066
- VP_EXPORT void
7067
- VpDtoV(Real *m, double d)
7068
- {
7069
- size_t ind_m, mm;
7070
- SIGNED_VALUE ne;
7071
- DECDIG i;
7072
- double val, val2;
7073
-
7074
- if (isnan(d)) {
7075
- VpSetNaN(m);
7076
- goto Exit;
7077
- }
7078
- if (isinf(d)) {
7079
- if (d > 0.0) VpSetPosInf(m);
7080
- else VpSetNegInf(m);
7081
- goto Exit;
7082
- }
7083
-
7084
- if (d == 0.0) {
7085
- VpSetZero(m, 1);
7086
- goto Exit;
7087
- }
7088
- val = (d > 0.) ? d : -d;
7089
- ne = 0;
7090
- if (val >= 1.0) {
7091
- while (val >= 1.0) {
7092
- val /= (double)BASE;
7093
- ++ne;
7094
- }
7095
- }
7096
- else {
7097
- val2 = 1.0 / (double)BASE;
7098
- while (val < val2) {
7099
- val *= (double)BASE;
7100
- --ne;
7101
- }
7102
- }
7103
- /* Now val = 0.xxxxx*BASE**ne */
7104
-
7105
- mm = m->MaxPrec;
7106
- memset(m->frac, 0, mm * sizeof(DECDIG));
7107
- for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
7108
- val *= (double)BASE;
7109
- i = (DECDIG)val;
7110
- val -= (double)i;
7111
- m->frac[ind_m] = i;
7112
- }
7113
- if (ind_m >= mm) ind_m = mm - 1;
7114
- VpSetSign(m, (d > 0.0) ? 1 : -1);
7115
- m->Prec = ind_m + 1;
7116
- m->exponent = ne;
7117
-
7118
- VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
7119
- (DECDIG)(val*(double)BASE));
7120
-
7121
- Exit:
7122
- #ifdef BIGDECIMAL_DEBUG
7123
- if (gfDebug) {
7124
- printf("VpDtoV d=%30.30e\n", d);
7125
- VPrint(stdout, " m=%\n", m);
7126
- }
7127
- #endif /* BIGDECIMAL_DEBUG */
7128
- return;
7129
- }
7130
-
7131
- /*
7132
- * m <- ival
7133
- */
7134
- #if 0 /* unused */
7135
- VP_EXPORT void
7136
- VpItoV(Real *m, SIGNED_VALUE ival)
7137
- {
7138
- size_t mm, ind_m;
7139
- size_t val, v1, v2, v;
7140
- int isign;
7141
- SIGNED_VALUE ne;
7142
-
7143
- if (ival == 0) {
7144
- VpSetZero(m, 1);
7145
- goto Exit;
7146
- }
7147
- isign = 1;
7148
- val = ival;
7149
- if (ival < 0) {
7150
- isign = -1;
7151
- val =(size_t)(-ival);
7152
- }
7153
- ne = 0;
7154
- ind_m = 0;
7155
- mm = m->MaxPrec;
7156
- while (ind_m < mm) {
7157
- m->frac[ind_m] = 0;
7158
- ++ind_m;
7159
- }
7160
- ind_m = 0;
7161
- while (val > 0) {
7162
- if (val) {
7163
- v1 = val;
7164
- v2 = 1;
7165
- while (v1 >= BASE) {
7166
- v1 /= BASE;
7167
- v2 *= BASE;
7168
- }
7169
- val = val - v2 * v1;
7170
- v = v1;
7171
- }
7172
- else {
7173
- v = 0;
7174
- }
7175
- m->frac[ind_m] = v;
7176
- ++ind_m;
7177
- ++ne;
7178
- }
7179
- m->Prec = ind_m - 1;
7180
- m->exponent = ne;
7181
- VpSetSign(m, isign);
7182
- VpNmlz(m);
7183
-
7184
- Exit:
7185
- #ifdef BIGDECIMAL_DEBUG
7186
- if (gfDebug) {
7187
- printf(" VpItoV i=%d\n", ival);
7188
- VPrint(stdout, " m=%\n", m);
7189
- }
7190
- #endif /* BIGDECIMAL_DEBUG */
7191
- return;
7192
- }
7193
- #endif
7194
-
7195
- /*
7196
- * y = SQRT(x), y*y - x =>0
7197
- */
7198
- VP_EXPORT int
7199
- VpSqrt(Real *y, Real *x)
7200
- {
7201
- Real *f = NULL;
7202
- Real *r = NULL;
7203
- size_t y_prec;
7204
- SIGNED_VALUE n, e;
7205
- ssize_t nr;
7206
- double val;
7207
-
7208
- /* Zero or +Infinity ? */
7209
- if (VpIsZero(x) || VpIsPosInf(x)) {
7210
- VpAsgn(y,x,1);
7211
- goto Exit;
7212
- }
7213
-
7214
- /* Negative ? */
7215
- if (BIGDECIMAL_NEGATIVE_P(x)) {
7216
- VpSetNaN(y);
7217
- return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
7218
- }
7219
-
7220
- /* NaN ? */
7221
- if (VpIsNaN(x)) {
7222
- VpSetNaN(y);
7223
- return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
7224
- }
7225
-
7226
- /* One ? */
7227
- if (VpIsOne(x)) {
7228
- VpSetOne(y);
7229
- goto Exit;
7230
- }
7231
-
7232
- n = (SIGNED_VALUE)y->MaxPrec;
7233
- if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
7234
-
7235
- /* allocate temporally variables */
7236
- /* TODO: reconsider MaxPrec of f and r */
7237
- f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7238
- r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
7239
-
7240
- nr = 0;
7241
- y_prec = y->MaxPrec;
7242
-
7243
- VpVtoD(&val, &e, x); /* val <- x */
7244
- e /= (SIGNED_VALUE)BASE_FIG;
7245
- n = e / 2;
7246
- if (e - n * 2 != 0) {
7247
- val /= BASE;
7248
- n = (e + 1) / 2;
7249
- }
7250
- VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
7251
- y->exponent += n;
7252
- n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
7253
- y->MaxPrec = Min((size_t)n , y_prec);
7254
- f->MaxPrec = y->MaxPrec + 1;
7255
- n = (SIGNED_VALUE)(y_prec * BASE_FIG);
7256
- if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7257
-
7258
- /*
7259
- * Perform: y_{n+1} = (y_n - x/y_n) / 2
7260
- */
7261
- do {
7262
- y->MaxPrec *= 2;
7263
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7264
- f->MaxPrec = y->MaxPrec;
7265
- VpDivd(f, r, x, y); /* f = x/y */
7266
- VpAddSub(r, f, y, -1); /* r = f - y */
7267
- VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7268
- if (VpIsZero(f))
7269
- goto converge;
7270
- VpAddSub(r, f, y, 1); /* r = y + f */
7271
- VpAsgn(y, r, 1); /* y = r */
7272
- } while (++nr < n);
7273
-
7274
- #ifdef BIGDECIMAL_DEBUG
7275
- if (gfDebug) {
7276
- printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
7277
- }
7278
- #endif /* BIGDECIMAL_DEBUG */
7279
- y->MaxPrec = y_prec;
7280
-
7281
- converge:
7282
- VpChangeSign(y, 1);
7283
- #ifdef BIGDECIMAL_DEBUG
7284
- if (gfDebug) {
7285
- VpMult(r, y, y);
7286
- VpAddSub(f, x, r, -1);
7287
- printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
7288
- VPrint(stdout, " y =% \n", y);
7289
- VPrint(stdout, " x =% \n", x);
7290
- VPrint(stdout, " x-y*y = % \n", f);
7291
- }
7292
- #endif /* BIGDECIMAL_DEBUG */
7293
- y->MaxPrec = y_prec;
7294
-
7295
- Exit:
7296
- rbd_free_struct(f);
7297
- rbd_free_struct(r);
7298
- return 1;
7299
- }
7300
-
7301
5829
  /*
7302
5830
  * Round relatively from the decimal point.
7303
5831
  * f: rounding mode
@@ -7474,7 +6002,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7474
6002
  DECDIG v;
7475
6003
  if (!VpHasVal(y)) return 0; /* Unable to round */
7476
6004
  v = y->frac[0];
7477
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6005
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7478
6006
  while ((v /= 10) != 0) nf--;
7479
6007
  nf += (ssize_t)BASE_FIG-1;
7480
6008
  return VpMidRound(y, f, nf);
@@ -7581,7 +6109,7 @@ VpFrac(Real *y, Real *x)
7581
6109
  size_t my, ind_y, ind_x;
7582
6110
 
7583
6111
  if (!VpHasVal(x)) {
7584
- VpAsgn(y, x, 1);
6112
+ VpAsgn(y, x, 10);
7585
6113
  goto Exit;
7586
6114
  }
7587
6115
 
@@ -7590,7 +6118,7 @@ VpFrac(Real *y, Real *x)
7590
6118
  goto Exit;
7591
6119
  }
7592
6120
  else if (x->exponent <= 0) {
7593
- VpAsgn(y, x, 1);
6121
+ VpAsgn(y, x, 10);
7594
6122
  goto Exit;
7595
6123
  }
7596
6124
 
@@ -7611,117 +6139,9 @@ VpFrac(Real *y, Real *x)
7611
6139
  VpNmlz(y);
7612
6140
 
7613
6141
  Exit:
7614
- #ifdef BIGDECIMAL_DEBUG
7615
- if (gfDebug) {
7616
- VPrint(stdout, "VpFrac y=%\n", y);
7617
- VPrint(stdout, " x=%\n", x);
7618
- }
7619
- #endif /* BIGDECIMAL_DEBUG */
7620
6142
  return;
7621
6143
  }
7622
6144
 
7623
- /*
7624
- * y = x ** n
7625
- */
7626
- VP_EXPORT int
7627
- VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7628
- {
7629
- size_t s, ss;
7630
- ssize_t sign;
7631
- Real *w1 = NULL;
7632
- Real *w2 = NULL;
7633
-
7634
- if (VpIsZero(x)) {
7635
- if (n == 0) {
7636
- VpSetOne(y);
7637
- goto Exit;
7638
- }
7639
- sign = VpGetSign(x);
7640
- if (n < 0) {
7641
- n = -n;
7642
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7643
- VpSetInf(y, sign);
7644
- }
7645
- else {
7646
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7647
- VpSetZero(y,sign);
7648
- }
7649
- goto Exit;
7650
- }
7651
- if (VpIsNaN(x)) {
7652
- VpSetNaN(y);
7653
- goto Exit;
7654
- }
7655
- if (VpIsInf(x)) {
7656
- if (n == 0) {
7657
- VpSetOne(y);
7658
- goto Exit;
7659
- }
7660
- if (n > 0) {
7661
- VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7662
- goto Exit;
7663
- }
7664
- VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7665
- goto Exit;
7666
- }
7667
-
7668
- if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
7669
- /* abs(x) = 1 */
7670
- VpSetOne(y);
7671
- if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
7672
- if ((n % 2) == 0) goto Exit;
7673
- VpSetSign(y, -1);
7674
- goto Exit;
7675
- }
7676
-
7677
- if (n > 0) sign = 1;
7678
- else if (n < 0) {
7679
- sign = -1;
7680
- n = -n;
7681
- }
7682
- else {
7683
- VpSetOne(y);
7684
- goto Exit;
7685
- }
7686
-
7687
- /* Allocate working variables */
7688
- /* TODO: reconsider MaxPrec of w1 and w2 */
7689
- w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7690
- w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7691
-
7692
- /* calculation start */
7693
-
7694
- VpAsgn(y, x, 1);
7695
- --n;
7696
- while (n > 0) {
7697
- VpAsgn(w1, x, 1);
7698
- s = 1;
7699
- while (ss = s, (s += s) <= (size_t)n) {
7700
- VpMult(w2, w1, w1);
7701
- VpAsgn(w1, w2, 1);
7702
- }
7703
- n -= (SIGNED_VALUE)ss;
7704
- VpMult(w2, y, w1);
7705
- VpAsgn(y, w2, 1);
7706
- }
7707
- if (sign < 0) {
7708
- VpDivd(w1, w2, VpConstOne, y);
7709
- VpAsgn(y, w1, 1);
7710
- }
7711
-
7712
- Exit:
7713
- #ifdef BIGDECIMAL_DEBUG
7714
- if (gfDebug) {
7715
- VPrint(stdout, "VpPowerByInt y=%\n", y);
7716
- VPrint(stdout, "VpPowerByInt x=%\n", x);
7717
- printf(" n=%"PRIdVALUE"\n", n);
7718
- }
7719
- #endif /* BIGDECIMAL_DEBUG */
7720
- rbd_free_struct(w2);
7721
- rbd_free_struct(w1);
7722
- return 1;
7723
- }
7724
-
7725
6145
  #ifdef BIGDECIMAL_DEBUG
7726
6146
  int
7727
6147
  VpVarCheck(Real * v)