bigdecimal 3.1.8 → 4.1.2

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.1.8"
35
-
36
- /* #define ENABLE_NUMERIC_STRING */
36
+ #define BIGDECIMAL_VERSION "4.1.2"
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,49 +363,14 @@ 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
516
- BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
370
+ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
517
371
  {
518
- ENTER(1);
519
-
520
372
  if (out_precision == NULL && out_scale == NULL)
521
373
  return;
522
-
523
- Real *p;
524
- GUARD_OBJ(p, GetVpValue(self, 1));
525
374
  if (VpIsZero(p) || !VpIsDef(p)) {
526
375
  zero:
527
376
  if (out_precision) *out_precision = 0;
@@ -625,6 +474,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
625
474
  }
626
475
  }
627
476
 
477
+ static void
478
+ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
479
+ {
480
+ BDVALUE v = GetBDValueMust(self);
481
+ VpCountPrecisionAndScale(v.real, out_precision, out_scale);
482
+ RB_GC_GUARD(v.bigdecimal);
483
+ }
484
+
628
485
  /*
629
486
  * call-seq:
630
487
  * precision -> integer
@@ -660,8 +517,8 @@ BigDecimal_precision(VALUE self)
660
517
  * BigDecimal("1").scale # => 0
661
518
  * BigDecimal("1.1").scale # => 1
662
519
  * BigDecimal("3.1415").scale # => 4
663
- * BigDecimal("-1e20").precision # => 0
664
- * BigDecimal("1e-20").precision # => 20
520
+ * BigDecimal("-1e20").scale # => 0
521
+ * BigDecimal("1e-20").scale # => 20
665
522
  * BigDecimal("Infinity").scale # => 0
666
523
  * BigDecimal("-Infinity").scale # => 0
667
524
  * BigDecimal("NaN").scale # => 0
@@ -711,25 +568,23 @@ BigDecimal_precision_scale(VALUE self)
711
568
  static VALUE
712
569
  BigDecimal_n_significant_digits(VALUE self)
713
570
  {
714
- ENTER(1);
715
-
716
- Real *p;
717
- GUARD_OBJ(p, GetVpValue(self, 1));
718
- if (VpIsZero(p) || !VpIsDef(p)) {
571
+ BDVALUE v = GetBDValueMust(self);
572
+ if (VpIsZero(v.real) || !VpIsDef(v.real)) {
719
573
  return INT2FIX(0);
720
574
  }
721
575
 
722
- ssize_t n = p->Prec; /* The length of frac without trailing zeros. */
723
- for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n);
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);
724
578
  if (n == 0) return INT2FIX(0);
725
579
 
726
580
  DECDIG x;
727
581
  int nlz = BASE_FIG;
728
- for (x = p->frac[0]; x > 0; x /= 10) --nlz;
582
+ for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
729
583
 
730
584
  int ntz = 0;
731
- 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;
732
586
 
587
+ RB_GC_GUARD(v.bigdecimal);
733
588
  ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
734
589
  return SSIZET2NUM(n_significant_digits);
735
590
  }
@@ -751,17 +606,14 @@ BigDecimal_n_significant_digits(VALUE self)
751
606
  static VALUE
752
607
  BigDecimal_hash(VALUE self)
753
608
  {
754
- ENTER(1);
755
- Real *p;
756
- st_index_t hash;
757
-
758
- GUARD_OBJ(p, GetVpValue(self, 1));
759
- hash = (st_index_t)p->sign;
609
+ BDVALUE v = GetBDValueMust(self);
610
+ st_index_t hash = (st_index_t)v.real->sign;
760
611
  /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
761
612
  if(hash == 2 || hash == (st_index_t)-2) {
762
- hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
763
- hash += p->exponent;
613
+ hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
614
+ hash += v.real->exponent;
764
615
  }
616
+ RB_GC_GUARD(v.bigdecimal);
765
617
  return ST2FIX(hash);
766
618
  }
767
619
 
@@ -780,21 +632,22 @@ BigDecimal_hash(VALUE self)
780
632
  static VALUE
781
633
  BigDecimal_dump(int argc, VALUE *argv, VALUE self)
782
634
  {
783
- ENTER(5);
784
- Real *vp;
635
+ BDVALUE v;
785
636
  char *psz;
786
637
  VALUE dummy;
787
638
  volatile VALUE dump;
788
639
  size_t len;
789
640
 
790
641
  rb_scan_args(argc, argv, "01", &dummy);
791
- GUARD_OBJ(vp,GetVpValue(self, 1));
792
- dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
642
+ v = GetBDValueMust(self);
643
+ dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
793
644
  psz = RSTRING_PTR(dump);
794
- snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
645
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
795
646
  len = strlen(psz);
796
- VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
647
+ VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
797
648
  rb_str_resize(dump, strlen(psz));
649
+
650
+ RB_GC_GUARD(v.bigdecimal);
798
651
  return dump;
799
652
  }
800
653
 
@@ -804,27 +657,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
804
657
  static VALUE
805
658
  BigDecimal_load(VALUE self, VALUE str)
806
659
  {
807
- ENTER(2);
808
- Real *pv;
660
+ BDVALUE v;
809
661
  unsigned char *pch;
810
662
  unsigned char ch;
811
- unsigned long m=0;
812
663
 
813
664
  pch = (unsigned char *)StringValueCStr(str);
814
- /* First get max prec */
665
+ /* First skip max prec. Don't trust the value. */
815
666
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
816
667
  if(!ISDIGIT(ch)) {
817
668
  rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
818
669
  }
819
- m = m*10 + (unsigned long)(ch-'0');
820
- }
821
- if (m > VpBaseFig()) m -= VpBaseFig();
822
- GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
823
- m /= VpBaseFig();
824
- if (m && pv->MaxPrec > m) {
825
- pv->MaxPrec = m+1;
826
670
  }
827
- return VpCheckGetValue(pv);
671
+ v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
672
+ return CheckGetValue(v);
828
673
  }
829
674
 
830
675
  static unsigned short
@@ -1117,22 +962,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1117
962
  static size_t
1118
963
  GetAddSubPrec(Real *a, Real *b)
1119
964
  {
1120
- size_t mxs;
1121
- size_t mx = a->Prec;
1122
- SIGNED_VALUE d;
1123
-
1124
- if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
1125
- if (mx < b->Prec) mx = b->Prec;
1126
- if (a->exponent != b->exponent) {
1127
- mxs = mx;
1128
- d = a->exponent - b->exponent;
1129
- if (d < 0) d = -d;
1130
- mx = mx + (size_t)d;
1131
- if (mx < mxs) {
1132
- return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
1133
- }
1134
- }
1135
- return mx;
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);
1136
969
  }
1137
970
 
1138
971
  static inline SIGNED_VALUE
@@ -1152,62 +985,28 @@ check_int_precision(VALUE v)
1152
985
  return n;
1153
986
  }
1154
987
 
1155
- static VALUE
1156
- BigDecimal_wrap_struct(VALUE obj, Real *vp)
1157
- {
1158
- assert(is_kind_of_BigDecimal(obj));
1159
- assert(vp != NULL);
1160
-
1161
- if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
1162
- return obj;
1163
-
1164
- assert(RTYPEDDATA_DATA(obj) == NULL);
1165
- assert(vp->obj == 0);
1166
-
1167
- RTYPEDDATA_DATA(obj) = vp;
1168
- vp->obj = obj;
1169
- RB_OBJ_FREEZE(obj);
1170
- return obj;
1171
- }
1172
-
1173
- VP_EXPORT Real *
1174
- VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
1175
- {
1176
- VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
1177
- Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
1178
- if (!pv)
1179
- return NULL;
1180
- BigDecimal_wrap_struct(obj, pv);
1181
- return pv;
1182
- }
1183
-
1184
- VP_EXPORT Real *
1185
- VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
988
+ static NULLABLE_BDVALUE
989
+ CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1186
990
  {
1187
- return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
991
+ return VpAlloc(str, strict_p, raise_exception);
1188
992
  }
1189
993
 
1190
- static Real *
1191
- VpCopy(Real *pv, Real const* const x)
994
+ void
995
+ VpMemCopy(Real *pv, Real const* const x)
1192
996
  {
1193
- assert(x != NULL);
1194
-
1195
- pv = rbd_reallocate_struct(pv, x->MaxPrec);
1196
997
  pv->MaxPrec = x->MaxPrec;
1197
998
  pv->Prec = x->Prec;
1198
999
  pv->exponent = x->exponent;
1199
1000
  pv->sign = x->sign;
1200
1001
  pv->flag = x->flag;
1201
1002
  MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
1202
-
1203
- return pv;
1204
1003
  }
1205
1004
 
1206
1005
  /* Returns True if the value is Not a Number. */
1207
1006
  static VALUE
1208
1007
  BigDecimal_IsNaN(VALUE self)
1209
1008
  {
1210
- Real *p = GetVpValue(self, 1);
1009
+ Real *p = GetSelfVpValue(self);
1211
1010
  if (VpIsNaN(p)) return Qtrue;
1212
1011
  return Qfalse;
1213
1012
  }
@@ -1218,7 +1017,7 @@ BigDecimal_IsNaN(VALUE self)
1218
1017
  static VALUE
1219
1018
  BigDecimal_IsInfinite(VALUE self)
1220
1019
  {
1221
- Real *p = GetVpValue(self, 1);
1020
+ Real *p = GetSelfVpValue(self);
1222
1021
  if (VpIsPosInf(p)) return INT2FIX(1);
1223
1022
  if (VpIsNegInf(p)) return INT2FIX(-1);
1224
1023
  return Qnil;
@@ -1228,7 +1027,7 @@ BigDecimal_IsInfinite(VALUE self)
1228
1027
  static VALUE
1229
1028
  BigDecimal_IsFinite(VALUE self)
1230
1029
  {
1231
- Real *p = GetVpValue(self, 1);
1030
+ Real *p = GetSelfVpValue(self);
1232
1031
  if (VpIsNaN(p)) return Qfalse;
1233
1032
  if (VpIsInf(p)) return Qfalse;
1234
1033
  return Qtrue;
@@ -1240,8 +1039,6 @@ BigDecimal_check_num(Real *p)
1240
1039
  VpCheckException(p, true);
1241
1040
  }
1242
1041
 
1243
- static VALUE BigDecimal_split(VALUE self);
1244
-
1245
1042
  /* Returns the value as an Integer.
1246
1043
  *
1247
1044
  * If the BigDecimal is infinity or NaN, raises FloatDomainError.
@@ -1249,44 +1046,36 @@ static VALUE BigDecimal_split(VALUE self);
1249
1046
  static VALUE
1250
1047
  BigDecimal_to_i(VALUE self)
1251
1048
  {
1252
- ENTER(5);
1253
- ssize_t e, nf;
1254
- Real *p;
1049
+ BDVALUE v;
1050
+ VALUE ret;
1255
1051
 
1256
- GUARD_OBJ(p, GetVpValue(self, 1));
1257
- BigDecimal_check_num(p);
1052
+ v = GetBDValueMust(self);
1053
+ BigDecimal_check_num(v.real);
1258
1054
 
1259
- e = VpExponent10(p);
1260
- if (e <= 0) return INT2FIX(0);
1261
- nf = VpBaseFig();
1262
- if (e <= nf) {
1263
- return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
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]));
1264
1058
  }
1265
1059
  else {
1266
- VALUE a = BigDecimal_split(self);
1267
- VALUE digits = RARRAY_AREF(a, 1);
1268
- VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
1269
- VALUE ret;
1270
- ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
1271
-
1272
- if (BIGDECIMAL_NEGATIVE_P(p)) {
1273
- numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
1274
- }
1275
- if (dpower < 0) {
1276
- ret = rb_funcall(numerator, rb_intern("div"), 1,
1277
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1278
- INT2FIX(-dpower)));
1279
- }
1280
- else {
1281
- ret = rb_funcall(numerator, '*', 1,
1282
- rb_funcall(INT2FIX(10), rb_intern("**"), 1,
1283
- INT2FIX(dpower)));
1284
- }
1285
- if (RB_TYPE_P(ret, T_FLOAT)) {
1286
- rb_raise(rb_eFloatDomainError, "Infinity");
1287
- }
1288
- return ret;
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
+ }
1289
1075
  }
1076
+
1077
+ RB_GC_GUARD(v.bigdecimal);
1078
+ return ret;
1290
1079
  }
1291
1080
 
1292
1081
  /* Returns a new Float object having approximately the same value as the
@@ -1296,24 +1085,26 @@ BigDecimal_to_i(VALUE self)
1296
1085
  static VALUE
1297
1086
  BigDecimal_to_f(VALUE self)
1298
1087
  {
1299
- ENTER(1);
1300
- Real *p;
1301
1088
  double d;
1302
1089
  SIGNED_VALUE e;
1303
1090
  char *buf;
1304
1091
  volatile VALUE str;
1092
+ BDVALUE v = GetBDValueMust(self);
1093
+ bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
1305
1094
 
1306
- GUARD_OBJ(p, GetVpValue(self, 1));
1307
- if (VpVtoD(&d, &e, p) != 1)
1095
+ if (VpVtoD(&d, &e, v.real) != 1)
1308
1096
  return rb_float_new(d);
1309
1097
  if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
1310
1098
  goto overflow;
1311
- if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
1099
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
1312
1100
  goto underflow;
1313
1101
 
1314
- str = rb_str_new(0, VpNumOfChars(p, "E"));
1102
+ str = rb_str_new(0, VpNumOfChars(v.real, "E"));
1315
1103
  buf = RSTRING_PTR(str);
1316
- 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
+
1317
1108
  errno = 0;
1318
1109
  d = strtod(buf, 0);
1319
1110
  if (errno == ERANGE) {
@@ -1324,14 +1115,14 @@ BigDecimal_to_f(VALUE self)
1324
1115
 
1325
1116
  overflow:
1326
1117
  VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
1327
- if (BIGDECIMAL_NEGATIVE_P(p))
1118
+ if (negative)
1328
1119
  return rb_float_new(VpGetDoubleNegInf());
1329
1120
  else
1330
1121
  return rb_float_new(VpGetDoublePosInf());
1331
1122
 
1332
1123
  underflow:
1333
1124
  VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
1334
- if (BIGDECIMAL_NEGATIVE_P(p))
1125
+ if (negative)
1335
1126
  return rb_float_new(-0.0);
1336
1127
  else
1337
1128
  return rb_float_new(0.0);
@@ -1343,15 +1134,16 @@ underflow:
1343
1134
  static VALUE
1344
1135
  BigDecimal_to_r(VALUE self)
1345
1136
  {
1346
- Real *p;
1137
+ BDVALUE v;
1347
1138
  ssize_t sign, power, denomi_power;
1348
1139
  VALUE a, digits, numerator;
1349
1140
 
1350
- p = GetVpValue(self, 1);
1351
- 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);
1352
1146
 
1353
- sign = VpGetSign(p);
1354
- power = VpExponent10(p);
1355
1147
  a = BigDecimal_split(self);
1356
1148
  digits = RARRAY_AREF(a, 1);
1357
1149
  denomi_power = power - RSTRING_LEN(digits);
@@ -1372,6 +1164,14 @@ BigDecimal_to_r(VALUE self)
1372
1164
  }
1373
1165
  }
1374
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
+
1375
1175
  /* The coerce method provides support for Ruby type coercion. It is not
1376
1176
  * enabled by default.
1377
1177
  *
@@ -1389,26 +1189,9 @@ BigDecimal_to_r(VALUE self)
1389
1189
  static VALUE
1390
1190
  BigDecimal_coerce(VALUE self, VALUE other)
1391
1191
  {
1392
- ENTER(2);
1393
- VALUE obj;
1394
- Real *b;
1395
-
1396
- if (RB_TYPE_P(other, T_FLOAT)) {
1397
- GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
1398
- obj = rb_assoc_new(VpCheckGetValue(b), self);
1399
- }
1400
- else {
1401
- if (RB_TYPE_P(other, T_RATIONAL)) {
1402
- Real* pv = DATA_PTR(self);
1403
- GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
1404
- }
1405
- else {
1406
- GUARD_OBJ(b, GetVpValue(other, 1));
1407
- }
1408
- obj = rb_assoc_new(b->obj, self);
1409
- }
1410
-
1411
- return obj;
1192
+ Real* pv = VpPtr(self);
1193
+ BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1194
+ return rb_assoc_new(CheckGetValue(b), self);
1412
1195
  }
1413
1196
 
1414
1197
  /*
@@ -1428,6 +1211,15 @@ BigDecimal_uplus(VALUE self)
1428
1211
  return self;
1429
1212
  }
1430
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
+
1431
1223
  /*
1432
1224
  * call-seq:
1433
1225
  * self + value -> bigdecimal
@@ -1447,45 +1239,63 @@ BigDecimal_uplus(VALUE self)
1447
1239
  static VALUE
1448
1240
  BigDecimal_add(VALUE self, VALUE r)
1449
1241
  {
1450
- ENTER(5);
1451
- Real *c, *a, *b;
1452
- 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
+ }
1453
1245
 
1454
- GUARD_OBJ(a, GetVpValue(self, 1));
1455
- if (RB_TYPE_P(r, T_FLOAT)) {
1456
- b = GetVpValueWithPrec(r, 0, 1);
1457
- }
1458
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1459
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1460
- }
1461
- else {
1462
- b = GetVpValue(r, 0);
1463
- }
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;
1464
1251
 
1465
- if (!b) return DoSomeOne(self,r,'+');
1466
- SAVE(b);
1252
+ a = GetBDValueMust(self);
1253
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1467
1254
 
1468
- if (VpIsNaN(b)) return b->obj;
1469
- if (VpIsNaN(a)) return a->obj;
1255
+ if (VpIsNaN(a.real)) return CheckGetValue(a);
1256
+ if (VpIsNaN(b.real)) return CheckGetValue(b);
1470
1257
 
1471
- mx = GetAddSubPrec(a, b);
1472
- if (mx == (size_t)-1L) {
1473
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1474
- 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);
1475
1261
  }
1476
1262
  else {
1477
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1478
- if (!mx) {
1479
- VpSetInf(c, VpGetSign(a));
1480
- }
1481
- else {
1482
- VpAddSub(c, a, b, 1);
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
+ }
1483
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);
1484
1290
  }
1485
- return VpCheckGetValue(c);
1291
+
1292
+ RB_GC_GUARD(a.bigdecimal);
1293
+ RB_GC_GUARD(b.bigdecimal);
1294
+ return CheckGetValue(c);
1486
1295
  }
1487
1296
 
1488
- /* call-seq:
1297
+ /*
1298
+ * call-seq:
1489
1299
  * self - value -> bigdecimal
1490
1300
  *
1491
1301
  * Returns the \BigDecimal difference of +self+ and +value+:
@@ -1502,73 +1312,18 @@ BigDecimal_add(VALUE self, VALUE r)
1502
1312
  static VALUE
1503
1313
  BigDecimal_sub(VALUE self, VALUE r)
1504
1314
  {
1505
- ENTER(5);
1506
- Real *c, *a, *b;
1507
- size_t mx;
1508
-
1509
- GUARD_OBJ(a, GetVpValue(self,1));
1510
- if (RB_TYPE_P(r, T_FLOAT)) {
1511
- b = GetVpValueWithPrec(r, 0, 1);
1512
- }
1513
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1514
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1515
- }
1516
- else {
1517
- b = GetVpValue(r,0);
1518
- }
1519
-
1520
- if (!b) return DoSomeOne(self,r,'-');
1521
- SAVE(b);
1522
-
1523
- if (VpIsNaN(b)) return b->obj;
1524
- if (VpIsNaN(a)) return a->obj;
1525
-
1526
- mx = GetAddSubPrec(a,b);
1527
- if (mx == (size_t)-1L) {
1528
- GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1529
- VpAddSub(c, a, b, -1);
1530
- }
1531
- else {
1532
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
1533
- if (!mx) {
1534
- VpSetInf(c,VpGetSign(a));
1535
- }
1536
- else {
1537
- VpAddSub(c, a, b, -1);
1538
- }
1539
- }
1540
- return VpCheckGetValue(c);
1315
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
1316
+ return BigDecimal_addsub_with_coerce(self, r, 0, -1);
1541
1317
  }
1542
1318
 
1543
1319
  static VALUE
1544
1320
  BigDecimalCmp(VALUE self, VALUE r,char op)
1545
1321
  {
1546
- ENTER(5);
1547
1322
  SIGNED_VALUE e;
1548
- Real *a, *b=0;
1549
- GUARD_OBJ(a, GetVpValue(self, 1));
1550
- switch (TYPE(r)) {
1551
- case T_DATA:
1552
- if (!is_kind_of_BigDecimal(r)) break;
1553
- /* fall through */
1554
- case T_FIXNUM:
1555
- /* fall through */
1556
- case T_BIGNUM:
1557
- GUARD_OBJ(b, GetVpValue(r, 0));
1558
- break;
1559
-
1560
- case T_FLOAT:
1561
- GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
1562
- break;
1323
+ BDVALUE a = GetBDValueMust(self);
1324
+ NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1563
1325
 
1564
- case T_RATIONAL:
1565
- GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
1566
- break;
1567
-
1568
- default:
1569
- break;
1570
- }
1571
- if (b == NULL) {
1326
+ if (b.real_or_null == NULL) {
1572
1327
  ID f = 0;
1573
1328
 
1574
1329
  switch (op) {
@@ -1597,8 +1352,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1597
1352
  }
1598
1353
  return rb_num_coerce_relop(self, r, f);
1599
1354
  }
1600
- SAVE(b);
1601
- 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
+
1602
1360
  if (e == 999)
1603
1361
  return (op == '*') ? Qnil : Qfalse;
1604
1362
  switch (op) {
@@ -1638,7 +1396,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1638
1396
  static VALUE
1639
1397
  BigDecimal_zero(VALUE self)
1640
1398
  {
1641
- Real *a = GetVpValue(self, 1);
1399
+ Real *a = GetSelfVpValue(self);
1642
1400
  return VpIsZero(a) ? Qtrue : Qfalse;
1643
1401
  }
1644
1402
 
@@ -1646,7 +1404,7 @@ BigDecimal_zero(VALUE self)
1646
1404
  static VALUE
1647
1405
  BigDecimal_nonzero(VALUE self)
1648
1406
  {
1649
- Real *a = GetVpValue(self, 1);
1407
+ Real *a = GetSelfVpValue(self);
1650
1408
  return VpIsZero(a) ? Qnil : self;
1651
1409
  }
1652
1410
 
@@ -1772,12 +1530,11 @@ BigDecimal_ge(VALUE self, VALUE r)
1772
1530
  static VALUE
1773
1531
  BigDecimal_neg(VALUE self)
1774
1532
  {
1775
- ENTER(5);
1776
- Real *c, *a;
1777
- GUARD_OBJ(a, GetVpValue(self, 1));
1778
- GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
1779
- VpAsgn(c, a, -1);
1780
- return VpCheckGetValue(c);
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);
1781
1538
  }
1782
1539
 
1783
1540
  /*
@@ -1790,84 +1547,36 @@ BigDecimal_neg(VALUE self)
1790
1547
  *
1791
1548
  * See BigDecimal#mult.
1792
1549
  */
1793
-
1794
1550
  static VALUE
1795
1551
  BigDecimal_mult(VALUE self, VALUE r)
1796
1552
  {
1797
- ENTER(5);
1798
- Real *c, *a, *b;
1799
- size_t mx;
1800
-
1801
- GUARD_OBJ(a, GetVpValue(self, 1));
1802
- if (RB_TYPE_P(r, T_FLOAT)) {
1803
- b = GetVpValueWithPrec(r, 0, 1);
1804
- }
1805
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1806
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
1807
- }
1808
- else {
1809
- b = GetVpValue(r,0);
1810
- }
1811
-
1812
- if (!b) return DoSomeOne(self, r, '*');
1813
- SAVE(b);
1814
-
1815
- mx = a->Prec + b->Prec;
1816
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1817
- VpMult(c, a, b);
1818
- return VpCheckGetValue(c);
1553
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
1554
+ return BigDecimal_mult_with_coerce(self, r, 0);
1819
1555
  }
1820
1556
 
1821
1557
  static VALUE
1822
- BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1823
- /* For c = self.div(r): with round operation */
1558
+ BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
1824
1559
  {
1825
- ENTER(5);
1826
- Real *a, *b;
1827
- ssize_t a_prec, b_prec;
1828
- size_t mx;
1560
+ BDVALUE a, b, c;
1829
1561
 
1830
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1831
- SAVE(a);
1562
+ a = GetBDValueMust(self);
1563
+ b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
1832
1564
 
1833
- VALUE rr = r;
1834
- if (is_kind_of_BigDecimal(rr)) {
1835
- /* do nothing */
1836
- }
1837
- else if (RB_INTEGER_TYPE_P(r)) {
1838
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
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);
1839
1569
  }
1840
- else if (RB_TYPE_P(r, T_FLOAT)) {
1841
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1842
- }
1843
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1844
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1570
+ else {
1571
+ VpLimitRound(c.real, 0);
1845
1572
  }
1846
1573
 
1847
- if (!is_kind_of_BigDecimal(rr)) {
1848
- return DoSomeOne(self, r, '/');
1849
- }
1850
-
1851
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1852
- SAVE(b);
1853
- *div = b;
1854
-
1855
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
1856
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
1857
- mx = (a_prec > b_prec) ? a_prec : b_prec;
1858
- mx *= 2;
1859
-
1860
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1861
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1862
-
1863
- GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
1864
- GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
1865
- VpDivd(*c, *res, a, b);
1866
-
1867
- return Qnil;
1574
+ RB_GC_GUARD(a.bigdecimal);
1575
+ RB_GC_GUARD(b.bigdecimal);
1576
+ return CheckGetValue(c);
1868
1577
  }
1869
1578
 
1870
- 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);
1871
1580
 
1872
1581
  /* call-seq:
1873
1582
  * a / b -> bigdecimal
@@ -1884,20 +1593,8 @@ static VALUE
1884
1593
  BigDecimal_div(VALUE self, VALUE r)
1885
1594
  /* For c = self/r: with round operation */
1886
1595
  {
1887
- ENTER(5);
1888
- Real *c=NULL, *res=NULL, *div = NULL;
1889
- r = BigDecimal_divide(self, r, &c, &res, &div);
1890
- if (!NIL_P(r)) return r; /* coerced by other */
1891
- SAVE(c); SAVE(res); SAVE(div);
1892
- /* a/b = c + r/b */
1893
- /* c xxxxx
1894
- r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
1895
- */
1896
- /* Round */
1897
- if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
1898
- VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
1899
- }
1900
- return VpCheckGetValue(c);
1596
+ if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
1597
+ return BigDecimal_div2(self, r, INT2FIX(0));
1901
1598
  }
1902
1599
 
1903
1600
  static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
@@ -1942,119 +1639,115 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1942
1639
  /*
1943
1640
  * %: mod = a%b = a - (a.to_f/b).floor * b
1944
1641
  * div = (a.to_f/b).floor
1642
+ * In truncate mode, use truncate instead of floor.
1945
1643
  */
1946
- static VALUE
1947
- 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)
1948
1646
  {
1949
- ENTER(8);
1950
- Real *c=NULL, *d=NULL, *res=NULL;
1951
- Real *a, *b;
1952
- ssize_t a_prec, b_prec;
1953
- size_t mx;
1647
+ BDVALUE a, b, dv, md, res;
1648
+ NULLABLE_BDVALUE b2;
1649
+ ssize_t a_exponent, b_exponent;
1650
+ size_t mx, rx, pl;
1954
1651
 
1955
- TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
1956
- SAVE(a);
1652
+ a = GetBDValueMust(self);
1957
1653
 
1958
- VALUE rr = r;
1959
- if (is_kind_of_BigDecimal(rr)) {
1960
- /* do nothing */
1961
- }
1962
- else if (RB_INTEGER_TYPE_P(r)) {
1963
- rr = rb_inum_convert_to_BigDecimal(r, 0, true);
1964
- }
1965
- else if (RB_TYPE_P(r, T_FLOAT)) {
1966
- rr = rb_float_convert_to_BigDecimal(r, 0, true);
1967
- }
1968
- else if (RB_TYPE_P(r, T_RATIONAL)) {
1969
- rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
1970
- }
1654
+ b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
1655
+ if (!b2.real_or_null) return false;
1656
+ b = bdvalue_nonnullable(b2);
1971
1657
 
1972
- if (!is_kind_of_BigDecimal(rr)) {
1973
- 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;
1974
1662
  }
1975
-
1976
- TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1977
- SAVE(b);
1978
-
1979
- if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
1980
- if (VpIsInf(a) && VpIsInf(b)) goto NaN;
1981
- if (VpIsZero(b)) {
1663
+ if (VpIsZero(b.real)) {
1982
1664
  rb_raise(rb_eZeroDivError, "divided by 0");
1983
1665
  }
1984
- if (VpIsInf(a)) {
1985
- if (VpGetSign(a) == VpGetSign(b)) {
1666
+ if (VpIsInf(a.real)) {
1667
+ if (VpGetSign(a.real) == VpGetSign(b.real)) {
1986
1668
  VALUE inf = BigDecimal_positive_infinity();
1987
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1669
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1988
1670
  }
1989
1671
  else {
1990
1672
  VALUE inf = BigDecimal_negative_infinity();
1991
- TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
1673
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1992
1674
  }
1993
1675
  VALUE nan = BigDecimal_nan();
1994
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
1995
- return Qtrue;
1996
- }
1997
- if (VpIsInf(b)) {
1998
- VALUE zero = BigDecimal_positive_zero();
1999
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
2000
- *mod = a;
2001
- return Qtrue;
1676
+ *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
1677
+ goto Done;
2002
1678
  }
2003
- if (VpIsZero(a)) {
1679
+ if (VpIsZero(a.real)) {
2004
1680
  VALUE zero = BigDecimal_positive_zero();
2005
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
2006
- TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
2007
- return Qtrue;
2008
- }
2009
-
2010
- BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
2011
- BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
2012
-
2013
- mx = (a_prec > b_prec) ? a_prec : b_prec;
2014
- mx *= 2;
2015
-
2016
- if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
2017
- mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
2018
-
2019
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
2020
- GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
2021
- VpDivd(c, res, a, b);
2022
-
2023
- mx = c->Prec * BASE_FIG;
2024
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2025
- VpActiveRound(d, c, VP_ROUND_DOWN, 0);
2026
-
2027
- VpMult(res, d, b);
2028
- VpAddSub(c, a, res, -1);
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);
2029
1720
 
2030
- if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1721
+ if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
2031
1722
  /* result adjustment for negative case */
2032
- res = rbd_reallocate_struct(res, d->MaxPrec);
2033
- res->MaxPrec = d->MaxPrec;
2034
- VpAddSub(res, d, VpOne(), -1);
2035
- GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
2036
- VpAddSub(d, c, b, 1);
2037
- *div = res;
2038
- *mod = d;
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);
2039
1733
  }
2040
1734
  else {
2041
- *div = d;
2042
- *mod = c;
1735
+ *div = bdvalue_nullable(dv);
1736
+ *mod = bdvalue_nullable(md);
2043
1737
  }
2044
- return Qtrue;
2045
1738
 
2046
- NaN:
2047
- {
2048
- VALUE nan = BigDecimal_nan();
2049
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
2050
- TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
2051
- }
2052
- return Qtrue;
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;
2053
1746
  }
2054
1747
 
2055
1748
  /* call-seq:
2056
- * a % b
2057
- * a.modulo(b)
1749
+ * a % b
1750
+ * a.modulo(b)
2058
1751
  *
2059
1752
  * Returns the modulus from dividing by b.
2060
1753
  *
@@ -2063,71 +1756,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
2063
1756
  static VALUE
2064
1757
  BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
2065
1758
  {
2066
- ENTER(3);
2067
- Real *div = NULL, *mod = NULL;
1759
+ NULLABLE_BDVALUE div, mod;
2068
1760
 
2069
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2070
- SAVE(div); SAVE(mod);
2071
- return VpCheckGetValue(mod);
1761
+ if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1762
+ return CheckGetValue(bdvalue_nonnullable(mod));
2072
1763
  }
2073
1764
  return DoSomeOne(self, r, '%');
2074
1765
  }
2075
1766
 
2076
- static VALUE
2077
- BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2078
- {
2079
- ENTER(10);
2080
- size_t mx;
2081
- Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
2082
- Real *f = NULL;
2083
-
2084
- GUARD_OBJ(a, GetVpValue(self, 1));
2085
- if (RB_TYPE_P(r, T_FLOAT)) {
2086
- b = GetVpValueWithPrec(r, 0, 1);
2087
- }
2088
- else if (RB_TYPE_P(r, T_RATIONAL)) {
2089
- b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
2090
- }
2091
- else {
2092
- b = GetVpValue(r, 0);
2093
- }
2094
-
2095
- if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
2096
- SAVE(b);
2097
-
2098
- if (VpIsPosInf(b) || VpIsNegInf(b)) {
2099
- GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2100
- VpSetZero(*dv, 1);
2101
- *rv = a;
2102
- return Qnil;
2103
- }
2104
-
2105
- mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
2106
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2107
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2108
- GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2109
- GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2110
-
2111
- VpDivd(c, res, a, b);
2112
-
2113
- mx = c->Prec *(VpBaseFig() + 1);
2114
-
2115
- GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2116
- GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
2117
-
2118
- VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
2119
-
2120
- VpFrac(f, c);
2121
- VpMult(rr, f, b);
2122
- VpAddSub(ff, res, rr, 1);
2123
-
2124
- *dv = d;
2125
- *rv = ff;
2126
- return Qnil;
2127
- }
2128
-
2129
1767
  /* call-seq:
2130
- * remainder(value)
1768
+ * remainder(value)
2131
1769
  *
2132
1770
  * Returns the remainder from dividing by the value.
2133
1771
  *
@@ -2136,15 +1774,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
2136
1774
  static VALUE
2137
1775
  BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2138
1776
  {
2139
- VALUE f;
2140
- Real *d, *rv = 0;
2141
- f = BigDecimal_divremain(self, r, &d, &rv);
2142
- if (!NIL_P(f)) return f;
2143
- return VpCheckGetValue(rv);
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"));
2144
1783
  }
2145
1784
 
2146
1785
  /* call-seq:
2147
- * divmod(value)
1786
+ * divmod(value)
2148
1787
  *
2149
1788
  * Divides by the specified value, and returns the quotient and modulus
2150
1789
  * as BigDecimal numbers. The quotient is rounded towards negative infinity.
@@ -2168,12 +1807,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
2168
1807
  static VALUE
2169
1808
  BigDecimal_divmod(VALUE self, VALUE r)
2170
1809
  {
2171
- ENTER(5);
2172
- Real *div = NULL, *mod = NULL;
1810
+ NULLABLE_BDVALUE div, mod;
2173
1811
 
2174
- if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
2175
- SAVE(div); SAVE(mod);
2176
- 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)));
2177
1814
  }
2178
1815
  return DoSomeOne(self,r,rb_intern("divmod"));
2179
1816
  }
@@ -2185,47 +1822,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
2185
1822
  static inline VALUE
2186
1823
  BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2187
1824
  {
2188
- ENTER(5);
2189
1825
  SIGNED_VALUE ix;
1826
+ BDVALUE av, bv, cv, res;
2190
1827
 
2191
1828
  if (NIL_P(n)) { /* div in Float sense */
2192
- Real *div = NULL;
2193
- Real *mod;
2194
- if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
2195
- return BigDecimal_to_i(VpCheckGetValue(div));
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)));
2196
1833
  }
2197
1834
  return DoSomeOne(self, b, rb_intern("div"));
2198
1835
  }
2199
1836
 
2200
1837
  /* div in BigDecimal sense */
2201
1838
  ix = check_int_precision(n);
1839
+
1840
+ av = GetBDValueMust(self);
1841
+ bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
1842
+
2202
1843
  if (ix == 0) {
2203
- return BigDecimal_div(self, b);
1844
+ ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
1845
+ VpCountPrecisionAndScale(av.real, &a_prec, NULL);
1846
+ VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
1847
+ ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
1848
+ if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
1849
+ ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
1850
+ if (limit && limit < ix) ix = limit;
2204
1851
  }
2205
- else {
2206
- Real *res = NULL;
2207
- Real *av = NULL, *bv = NULL, *cv = NULL;
2208
- size_t mx = ix + VpBaseFig()*2;
2209
- size_t b_prec = ix;
2210
- size_t pl = VpSetPrecLimit(0);
2211
-
2212
- GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig()));
2213
- GUARD_OBJ(av, GetVpValue(self, 1));
2214
- /* TODO: I want to refactor this precision control for a float value later
2215
- * by introducing an implicit conversion function instead of
2216
- * GetVpValueWithPrec. */
2217
- if (RB_FLOAT_TYPE_P(b) && b_prec > BIGDECIMAL_DOUBLE_FIGURES) {
2218
- b_prec = BIGDECIMAL_DOUBLE_FIGURES;
2219
- }
2220
- GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
2221
- mx = av->Prec + bv->Prec + 2;
2222
- if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
2223
- GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
2224
- VpDivd(cv, res, av, bv);
2225
- VpSetPrecLimit(pl);
2226
- VpLeftRound(cv, VpGetRoundMode(), ix);
2227
- return VpCheckGetValue(cv);
1852
+
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);
1857
+
1858
+ if (!VpIsZero(res.real)) {
1859
+ // Remainder value affects rounding result.
1860
+ // ROUND_UP cv = 0.1e0 with idx=10 will be:
1861
+ // 0.1e0 if remainder == 0
1862
+ // 0.1000000001e0 if remainder != 0
1863
+ size_t idx = roomof(ix, BASE_FIG);
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]++;
2228
1866
  }
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);
2229
1873
  }
2230
1874
 
2231
1875
  /*
@@ -2301,22 +1945,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
2301
1945
  static VALUE
2302
1946
  BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2303
1947
  {
2304
- ENTER(2);
2305
- Real *cv;
2306
- SIGNED_VALUE mx = check_int_precision(n);
2307
- if (mx == 0) return BigDecimal_add(self, b);
2308
- else {
2309
- size_t pl = VpSetPrecLimit(0);
2310
- VALUE c = BigDecimal_add(self, b);
2311
- VpSetPrecLimit(pl);
2312
- GUARD_OBJ(cv, GetVpValue(c, 1));
2313
- VpLeftRound(cv, VpGetRoundMode(), mx);
2314
- return VpCheckGetValue(cv);
2315
- }
1948
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
2316
1949
  }
2317
1950
 
2318
1951
  /* call-seq:
2319
- * sub(value, digits) -> bigdecimal
1952
+ * sub(value, digits) -> bigdecimal
2320
1953
  *
2321
1954
  * Subtract the specified value.
2322
1955
  *
@@ -2331,18 +1964,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2331
1964
  static VALUE
2332
1965
  BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2333
1966
  {
2334
- ENTER(2);
2335
- Real *cv;
2336
- SIGNED_VALUE mx = check_int_precision(n);
2337
- if (mx == 0) return BigDecimal_sub(self, b);
2338
- else {
2339
- size_t pl = VpSetPrecLimit(0);
2340
- VALUE c = BigDecimal_sub(self, b);
2341
- VpSetPrecLimit(pl);
2342
- GUARD_OBJ(cv, GetVpValue(c, 1));
2343
- VpLeftRound(cv, VpGetRoundMode(), mx);
2344
- return VpCheckGetValue(cv);
2345
- }
1967
+ return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
2346
1968
  }
2347
1969
 
2348
1970
  /*
@@ -2374,18 +1996,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2374
1996
  static VALUE
2375
1997
  BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2376
1998
  {
2377
- ENTER(2);
2378
- Real *cv;
2379
- SIGNED_VALUE mx = check_int_precision(n);
2380
- if (mx == 0) return BigDecimal_mult(self, b);
2381
- else {
2382
- size_t pl = VpSetPrecLimit(0);
2383
- VALUE c = BigDecimal_mult(self, b);
2384
- VpSetPrecLimit(pl);
2385
- GUARD_OBJ(cv, GetVpValue(c, 1));
2386
- VpLeftRound(cv, VpGetRoundMode(), mx);
2387
- return VpCheckGetValue(cv);
2388
- }
1999
+ return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
2389
2000
  }
2390
2001
 
2391
2002
  /*
@@ -2402,41 +2013,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2402
2013
  static VALUE
2403
2014
  BigDecimal_abs(VALUE self)
2404
2015
  {
2405
- ENTER(5);
2406
- Real *c, *a;
2407
- size_t mx;
2408
-
2409
- GUARD_OBJ(a, GetVpValue(self, 1));
2410
- mx = a->Prec *(VpBaseFig() + 1);
2411
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2412
- VpAsgn(c, a, 1);
2413
- VpChangeSign(c, 1);
2414
- return VpCheckGetValue(c);
2415
- }
2416
-
2417
- /* call-seq:
2418
- * sqrt(n)
2419
- *
2420
- * Returns the square root of the value.
2421
- *
2422
- * Result has at least n significant digits.
2423
- */
2424
- static VALUE
2425
- BigDecimal_sqrt(VALUE self, VALUE nFig)
2426
- {
2427
- ENTER(5);
2428
- Real *c, *a;
2429
- size_t mx, n;
2430
-
2431
- GUARD_OBJ(a, GetVpValue(self, 1));
2432
- mx = a->Prec * (VpBaseFig() + 1);
2433
-
2434
- n = check_int_precision(nFig);
2435
- n += VpDblFig() + VpBaseFig();
2436
- if (mx <= n) mx = n;
2437
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2438
- VpSqrt(c, a);
2439
- return VpCheckGetValue(c);
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);
2440
2022
  }
2441
2023
 
2442
2024
  /* Return the integer part of the number, as a BigDecimal.
@@ -2444,22 +2026,18 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2444
2026
  static VALUE
2445
2027
  BigDecimal_fix(VALUE self)
2446
2028
  {
2447
- ENTER(5);
2448
- Real *c, *a;
2449
- size_t mx;
2450
-
2451
- GUARD_OBJ(a, GetVpValue(self, 1));
2452
- mx = a->Prec *(VpBaseFig() + 1);
2453
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2454
- VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2455
- return VpCheckGetValue(c);
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);
2456
2034
  }
2457
2035
 
2458
2036
  /* call-seq:
2459
- * round(n, mode)
2037
+ * round(n, mode)
2460
2038
  *
2461
2039
  * Round to the nearest integer (by default), returning the result as a
2462
- * BigDecimal if n is specified, or as an Integer if it isn't.
2040
+ * BigDecimal if n is specified and positive, or as an Integer if it isn't.
2463
2041
  *
2464
2042
  * BigDecimal('3.14159').round #=> 3
2465
2043
  * BigDecimal('8.7').round #=> 9
@@ -2467,6 +2045,7 @@ BigDecimal_fix(VALUE self)
2467
2045
  *
2468
2046
  * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
2469
2047
  * BigDecimal('3.14159').round.class.name #=> "Integer"
2048
+ * BigDecimal('3.14159').round(0).class.name #=> "Integer"
2470
2049
  *
2471
2050
  * If n is specified and positive, the fractional part of the result has no
2472
2051
  * more than that many digits.
@@ -2483,13 +2062,12 @@ BigDecimal_fix(VALUE self)
2483
2062
  static VALUE
2484
2063
  BigDecimal_round(int argc, VALUE *argv, VALUE self)
2485
2064
  {
2486
- ENTER(5);
2487
- Real *c, *a;
2065
+ BDVALUE c, a;
2488
2066
  int iLoc = 0;
2489
2067
  VALUE vLoc;
2490
2068
  VALUE vRound;
2491
2069
  int round_to_int = 0;
2492
- size_t mx, pl;
2070
+ size_t mx;
2493
2071
 
2494
2072
  unsigned short sw = VpGetRoundMode();
2495
2073
 
@@ -2520,20 +2098,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2520
2098
  break;
2521
2099
  }
2522
2100
 
2523
- pl = VpSetPrecLimit(0);
2524
- GUARD_OBJ(a, GetVpValue(self, 1));
2525
- mx = a->Prec * (VpBaseFig() + 1);
2526
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2527
- VpSetPrecLimit(pl);
2528
- 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
+
2529
2109
  if (round_to_int) {
2530
- return BigDecimal_to_i(VpCheckGetValue(c));
2110
+ return BigDecimal_to_i(CheckGetValue(c));
2531
2111
  }
2532
- return VpCheckGetValue(c);
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));
2139
+ }
2140
+ return CheckGetValue(c);
2533
2141
  }
2534
2142
 
2535
2143
  /* call-seq:
2536
- * truncate(n)
2144
+ * truncate(n)
2537
2145
  *
2538
2146
  * Truncate to the nearest integer (by default), returning the result as a
2539
2147
  * BigDecimal.
@@ -2554,28 +2162,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2554
2162
  static VALUE
2555
2163
  BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2556
2164
  {
2557
- ENTER(5);
2558
- Real *c, *a;
2559
- int iLoc;
2560
- VALUE vLoc;
2561
- size_t mx, pl = VpSetPrecLimit(0);
2562
-
2563
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2564
- iLoc = 0;
2565
- }
2566
- else {
2567
- iLoc = NUM2INT(vLoc);
2568
- }
2569
-
2570
- GUARD_OBJ(a, GetVpValue(self, 1));
2571
- mx = a->Prec * (VpBaseFig() + 1);
2572
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2573
- VpSetPrecLimit(pl);
2574
- VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2575
- if (argc == 0) {
2576
- return BigDecimal_to_i(VpCheckGetValue(c));
2577
- }
2578
- return VpCheckGetValue(c);
2165
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
2579
2166
  }
2580
2167
 
2581
2168
  /* Return the fractional part of the number, as a BigDecimal.
@@ -2583,19 +2170,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2583
2170
  static VALUE
2584
2171
  BigDecimal_frac(VALUE self)
2585
2172
  {
2586
- ENTER(5);
2587
- Real *c, *a;
2588
- size_t mx;
2589
-
2590
- GUARD_OBJ(a, GetVpValue(self, 1));
2591
- mx = a->Prec * (VpBaseFig() + 1);
2592
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2593
- VpFrac(c, a);
2594
- 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);
2595
2178
  }
2596
2179
 
2597
2180
  /* call-seq:
2598
- * floor(n)
2181
+ * floor(n)
2599
2182
  *
2600
2183
  * Return the largest integer less than or equal to the value, as a BigDecimal.
2601
2184
  *
@@ -2614,35 +2197,11 @@ BigDecimal_frac(VALUE self)
2614
2197
  static VALUE
2615
2198
  BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2616
2199
  {
2617
- ENTER(5);
2618
- Real *c, *a;
2619
- int iLoc;
2620
- VALUE vLoc;
2621
- size_t mx, pl = VpSetPrecLimit(0);
2622
-
2623
- if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
2624
- iLoc = 0;
2625
- }
2626
- else {
2627
- iLoc = NUM2INT(vLoc);
2628
- }
2629
-
2630
- GUARD_OBJ(a, GetVpValue(self, 1));
2631
- mx = a->Prec * (VpBaseFig() + 1);
2632
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2633
- VpSetPrecLimit(pl);
2634
- VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2635
- #ifdef BIGDECIMAL_DEBUG
2636
- VPrint(stderr, "floor: c=%\n", c);
2637
- #endif
2638
- if (argc == 0) {
2639
- return BigDecimal_to_i(VpCheckGetValue(c));
2640
- }
2641
- return VpCheckGetValue(c);
2200
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
2642
2201
  }
2643
2202
 
2644
2203
  /* call-seq:
2645
- * ceil(n)
2204
+ * ceil(n)
2646
2205
  *
2647
2206
  * Return the smallest integer greater than or equal to the value, as a BigDecimal.
2648
2207
  *
@@ -2661,31 +2220,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2661
2220
  static VALUE
2662
2221
  BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2663
2222
  {
2664
- ENTER(5);
2665
- Real *c, *a;
2666
- int iLoc;
2667
- VALUE vLoc;
2668
- size_t mx, pl = VpSetPrecLimit(0);
2669
-
2670
- if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
2671
- iLoc = 0;
2672
- } else {
2673
- iLoc = NUM2INT(vLoc);
2674
- }
2675
-
2676
- GUARD_OBJ(a, GetVpValue(self, 1));
2677
- mx = a->Prec * (VpBaseFig() + 1);
2678
- GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2679
- VpSetPrecLimit(pl);
2680
- VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2681
- if (argc == 0) {
2682
- return BigDecimal_to_i(VpCheckGetValue(c));
2683
- }
2684
- return VpCheckGetValue(c);
2223
+ return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
2685
2224
  }
2686
2225
 
2687
2226
  /* call-seq:
2688
- * to_s(s)
2227
+ * to_s(s)
2689
2228
  *
2690
2229
  * Converts the value to a string.
2691
2230
  *
@@ -2702,7 +2241,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2702
2241
  * If s contains a number, a space is inserted after each group of that many
2703
2242
  * digits, starting from '.' and counting outwards.
2704
2243
  *
2705
- * 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.
2706
2245
  *
2707
2246
  * If s ends with an 'F', conventional floating point notation is used.
2708
2247
  *
@@ -2720,10 +2259,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2720
2259
  static VALUE
2721
2260
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2722
2261
  {
2723
- ENTER(5);
2724
2262
  int fmt = 0; /* 0: E format, 1: F format */
2725
2263
  int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
2726
- Real *vp;
2264
+ BDVALUE v;
2727
2265
  volatile VALUE str;
2728
2266
  char *psz;
2729
2267
  char ch;
@@ -2731,7 +2269,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2731
2269
  SIGNED_VALUE m;
2732
2270
  VALUE f;
2733
2271
 
2734
- GUARD_OBJ(vp, GetVpValue(self, 1));
2272
+ v = GetBDValueMust(self);
2735
2273
 
2736
2274
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2737
2275
  if (RB_TYPE_P(f, T_STRING)) {
@@ -2766,10 +2304,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2766
2304
  }
2767
2305
  }
2768
2306
  if (fmt) {
2769
- nc = VpNumOfChars(vp, "F");
2307
+ nc = VpNumOfChars(v.real, "F");
2770
2308
  }
2771
2309
  else {
2772
- nc = VpNumOfChars(vp, "E");
2310
+ nc = VpNumOfChars(v.real, "E");
2773
2311
  }
2774
2312
  if (mc > 0) {
2775
2313
  nc += (nc + mc - 1) / mc + 1;
@@ -2779,12 +2317,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2779
2317
  psz = RSTRING_PTR(str);
2780
2318
 
2781
2319
  if (fmt) {
2782
- VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2320
+ VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
2783
2321
  }
2784
2322
  else {
2785
- VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2323
+ VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
2786
2324
  }
2787
2325
  rb_str_resize(str, strlen(psz));
2326
+
2327
+ RB_GC_GUARD(v.bigdecimal);
2788
2328
  return str;
2789
2329
  }
2790
2330
 
@@ -2801,471 +2341,163 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2801
2341
  *
2802
2342
  * The fourth value is an Integer exponent.
2803
2343
  *
2804
- * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
2805
- * string of significant digits with no leading zeros, and n is the exponent.
2806
- *
2807
- * From these values, you can translate a BigDecimal to a float as follows:
2808
- *
2809
- * sign, significant_digits, base, exponent = a.split
2810
- * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
2811
- *
2812
- * (Note that the to_f method is provided as a more convenient way to translate
2813
- * a BigDecimal to a Float.)
2814
- */
2815
- static VALUE
2816
- BigDecimal_split(VALUE self)
2817
- {
2818
- ENTER(5);
2819
- Real *vp;
2820
- VALUE obj,str;
2821
- ssize_t e, s;
2822
- char *psz1;
2823
-
2824
- GUARD_OBJ(vp, GetVpValue(self, 1));
2825
- str = rb_str_new(0, VpNumOfChars(vp, "E"));
2826
- psz1 = RSTRING_PTR(str);
2827
- VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2828
- s = 1;
2829
- if(psz1[0] == '-') {
2830
- size_t len = strlen(psz1 + 1);
2831
-
2832
- memmove(psz1, psz1 + 1, len);
2833
- psz1[len] = '\0';
2834
- s = -1;
2835
- }
2836
- if (psz1[0] == 'N') s = 0; /* NaN */
2837
- e = VpExponent10(vp);
2838
- obj = rb_ary_new2(4);
2839
- rb_ary_push(obj, INT2FIX(s));
2840
- rb_ary_push(obj, str);
2841
- rb_str_resize(str, strlen(psz1));
2842
- rb_ary_push(obj, INT2FIX(10));
2843
- rb_ary_push(obj, SSIZET2NUM(e));
2844
- return obj;
2845
- }
2846
-
2847
- /* Returns the exponent of the BigDecimal number, as an Integer.
2848
- *
2849
- * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
2850
- * of digits with no leading zeros, then n is the exponent.
2851
- */
2852
- static VALUE
2853
- BigDecimal_exponent(VALUE self)
2854
- {
2855
- ssize_t e = VpExponent10(GetVpValue(self, 1));
2856
- return SSIZET2NUM(e);
2857
- }
2858
-
2859
- /* Returns a string representation of self.
2860
- *
2861
- * BigDecimal("1234.5678").inspect
2862
- * #=> "0.12345678e4"
2863
- */
2864
- static VALUE
2865
- BigDecimal_inspect(VALUE self)
2866
- {
2867
- ENTER(5);
2868
- Real *vp;
2869
- volatile VALUE str;
2870
- size_t nc;
2871
-
2872
- GUARD_OBJ(vp, GetVpValue(self, 1));
2873
- nc = VpNumOfChars(vp, "E");
2874
-
2875
- str = rb_str_new(0, nc);
2876
- VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2877
- rb_str_resize(str, strlen(RSTRING_PTR(str)));
2878
- return str;
2879
- }
2880
-
2881
- static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
2882
- static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
2883
-
2884
- #define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
2885
- #define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
2886
-
2887
- inline static int
2888
- is_integer(VALUE x)
2889
- {
2890
- return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
2891
- }
2892
-
2893
- inline static int
2894
- is_negative(VALUE x)
2895
- {
2896
- if (FIXNUM_P(x)) {
2897
- return FIX2LONG(x) < 0;
2898
- }
2899
- else if (RB_TYPE_P(x, T_BIGNUM)) {
2900
- return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
2901
- }
2902
- else if (RB_TYPE_P(x, T_FLOAT)) {
2903
- return RFLOAT_VALUE(x) < 0.0;
2904
- }
2905
- return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
2906
- }
2907
-
2908
- #define is_positive(x) (!is_negative(x))
2909
-
2910
- inline static int
2911
- is_zero(VALUE x)
2912
- {
2913
- VALUE num;
2914
-
2915
- switch (TYPE(x)) {
2916
- case T_FIXNUM:
2917
- return FIX2LONG(x) == 0;
2918
-
2919
- case T_BIGNUM:
2920
- return Qfalse;
2921
-
2922
- case T_RATIONAL:
2923
- num = rb_rational_num(x);
2924
- return FIXNUM_P(num) && FIX2LONG(num) == 0;
2925
-
2926
- default:
2927
- break;
2928
- }
2929
-
2930
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
2931
- }
2932
-
2933
- inline static int
2934
- is_one(VALUE x)
2935
- {
2936
- VALUE num, den;
2937
-
2938
- switch (TYPE(x)) {
2939
- case T_FIXNUM:
2940
- return FIX2LONG(x) == 1;
2941
-
2942
- case T_BIGNUM:
2943
- return Qfalse;
2944
-
2945
- case T_RATIONAL:
2946
- num = rb_rational_num(x);
2947
- den = rb_rational_den(x);
2948
- return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
2949
- FIXNUM_P(num) && FIX2LONG(num) == 1;
2950
-
2951
- default:
2952
- break;
2953
- }
2954
-
2955
- return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
2956
- }
2957
-
2958
- inline static int
2959
- is_even(VALUE x)
2960
- {
2961
- switch (TYPE(x)) {
2962
- case T_FIXNUM:
2963
- return (FIX2LONG(x) % 2) == 0;
2964
-
2965
- case T_BIGNUM:
2966
- {
2967
- unsigned long l;
2968
- rb_big_pack(x, &l, 1);
2969
- return l % 2 == 0;
2970
- }
2971
-
2972
- default:
2973
- break;
2974
- }
2975
-
2976
- return 0;
2977
- }
2978
-
2979
- static VALUE
2980
- bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2981
- {
2982
- VALUE log_x, multiplied, y;
2983
- volatile VALUE obj = exp->obj;
2984
-
2985
- if (VpIsZero(exp)) {
2986
- return VpCheckGetValue(NewOneWrapLimited(1, n));
2987
- }
2988
-
2989
- log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
2990
- multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
2991
- y = BigMath_exp(multiplied, SSIZET2NUM(n));
2992
- RB_GC_GUARD(obj);
2993
-
2994
- return y;
2995
- }
2996
-
2997
- /* call-seq:
2998
- * power(n)
2999
- * power(n, prec)
3000
- *
3001
- * Returns the value raised to the power of n.
3002
- *
3003
- * Note that n must be an Integer.
3004
- *
3005
- * Also available as the operator **.
3006
- */
3007
- static VALUE
3008
- BigDecimal_power(int argc, VALUE*argv, VALUE self)
3009
- {
3010
- ENTER(5);
3011
- VALUE vexp, prec;
3012
- Real* exp = NULL;
3013
- Real *x, *y;
3014
- ssize_t mp, ma, n;
3015
- SIGNED_VALUE int_exp;
3016
- double d;
3017
-
3018
- rb_scan_args(argc, argv, "11", &vexp, &prec);
3019
-
3020
- GUARD_OBJ(x, GetVpValue(self, 1));
3021
- n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
3022
-
3023
- if (VpIsNaN(x)) {
3024
- y = NewZeroWrapLimited(1, n);
3025
- VpSetNaN(y);
3026
- RB_GC_GUARD(y->obj);
3027
- return VpCheckGetValue(y);
3028
- }
3029
-
3030
- retry:
3031
- switch (TYPE(vexp)) {
3032
- case T_FIXNUM:
3033
- break;
3034
-
3035
- case T_BIGNUM:
3036
- break;
3037
-
3038
- case T_FLOAT:
3039
- d = RFLOAT_VALUE(vexp);
3040
- if (d == round(d)) {
3041
- if (FIXABLE(d)) {
3042
- vexp = LONG2FIX((long)d);
3043
- }
3044
- else {
3045
- vexp = rb_dbl2big(d);
3046
- }
3047
- goto retry;
3048
- }
3049
- if (NIL_P(prec)) {
3050
- n += BIGDECIMAL_DOUBLE_FIGURES;
3051
- }
3052
- exp = GetVpValueWithPrec(vexp, 0, 1);
3053
- break;
3054
-
3055
- case T_RATIONAL:
3056
- if (is_zero(rb_rational_num(vexp))) {
3057
- if (is_positive(vexp)) {
3058
- vexp = INT2FIX(0);
3059
- goto retry;
3060
- }
3061
- }
3062
- else if (is_one(rb_rational_den(vexp))) {
3063
- vexp = rb_rational_num(vexp);
3064
- goto retry;
3065
- }
3066
- exp = GetVpValueWithPrec(vexp, n, 1);
3067
- if (NIL_P(prec)) {
3068
- n += n;
3069
- }
3070
- break;
3071
-
3072
- case T_DATA:
3073
- if (is_kind_of_BigDecimal(vexp)) {
3074
- VALUE zero = INT2FIX(0);
3075
- VALUE rounded = BigDecimal_round(1, &zero, vexp);
3076
- if (RTEST(BigDecimal_eq(vexp, rounded))) {
3077
- vexp = BigDecimal_to_i(vexp);
3078
- goto retry;
3079
- }
3080
- if (NIL_P(prec)) {
3081
- GUARD_OBJ(y, GetVpValue(vexp, 1));
3082
- n += y->Prec*VpBaseFig();
3083
- }
3084
- exp = DATA_PTR(vexp);
3085
- break;
3086
- }
3087
- /* fall through */
3088
- default:
3089
- rb_raise(rb_eTypeError,
3090
- "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
3091
- RB_OBJ_CLASSNAME(vexp));
3092
- }
3093
-
3094
- if (VpIsZero(x)) {
3095
- if (is_negative(vexp)) {
3096
- y = NewZeroWrapNolimit(1, n);
3097
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3098
- if (is_integer(vexp)) {
3099
- if (is_even(vexp)) {
3100
- /* (-0) ** (-even_integer) -> Infinity */
3101
- VpSetPosInf(y);
3102
- }
3103
- else {
3104
- /* (-0) ** (-odd_integer) -> -Infinity */
3105
- VpSetNegInf(y);
3106
- }
3107
- }
3108
- else {
3109
- /* (-0) ** (-non_integer) -> Infinity */
3110
- VpSetPosInf(y);
3111
- }
3112
- }
3113
- else {
3114
- /* (+0) ** (-num) -> Infinity */
3115
- VpSetPosInf(y);
3116
- }
3117
- RB_GC_GUARD(y->obj);
3118
- return VpCheckGetValue(y);
3119
- }
3120
- else if (is_zero(vexp)) {
3121
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3122
- }
3123
- else {
3124
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3125
- }
3126
- }
3127
-
3128
- if (is_zero(vexp)) {
3129
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3130
- }
3131
- else if (is_one(vexp)) {
3132
- return self;
3133
- }
3134
-
3135
- if (VpIsInf(x)) {
3136
- if (is_negative(vexp)) {
3137
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3138
- if (is_integer(vexp)) {
3139
- if (is_even(vexp)) {
3140
- /* (-Infinity) ** (-even_integer) -> +0 */
3141
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3142
- }
3143
- else {
3144
- /* (-Infinity) ** (-odd_integer) -> -0 */
3145
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3146
- }
3147
- }
3148
- else {
3149
- /* (-Infinity) ** (-non_integer) -> -0 */
3150
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3151
- }
3152
- }
3153
- else {
3154
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3155
- }
3156
- }
3157
- else {
3158
- y = NewZeroWrapLimited(1, n);
3159
- if (BIGDECIMAL_NEGATIVE_P(x)) {
3160
- if (is_integer(vexp)) {
3161
- if (is_even(vexp)) {
3162
- VpSetPosInf(y);
3163
- }
3164
- else {
3165
- VpSetNegInf(y);
3166
- }
3167
- }
3168
- else {
3169
- /* TODO: support complex */
3170
- rb_raise(rb_eMathDomainError,
3171
- "a non-integral exponent for a negative base");
3172
- }
3173
- }
3174
- else {
3175
- VpSetPosInf(y);
3176
- }
3177
- return VpCheckGetValue(y);
3178
- }
3179
- }
3180
-
3181
- if (exp != NULL) {
3182
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3183
- }
3184
- else if (RB_TYPE_P(vexp, T_BIGNUM)) {
3185
- VALUE abs_value = BigDecimal_abs(self);
3186
- if (is_one(abs_value)) {
3187
- return VpCheckGetValue(NewOneWrapLimited(1, n));
3188
- }
3189
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
3190
- if (is_negative(vexp)) {
3191
- y = NewZeroWrapLimited(1, n);
3192
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3193
- return VpCheckGetValue(y);
3194
- }
3195
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3196
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3197
- }
3198
- else {
3199
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3200
- }
3201
- }
3202
- else {
3203
- if (is_positive(vexp)) {
3204
- y = NewZeroWrapLimited(1, n);
3205
- VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
3206
- return VpCheckGetValue(y);
3207
- }
3208
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3209
- return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3210
- }
3211
- else {
3212
- return VpCheckGetValue(NewZeroWrapLimited(1, n));
3213
- }
3214
- }
3215
- }
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)
2351
+ *
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;
3216
2362
 
3217
- int_exp = FIX2LONG(vexp);
3218
- ma = int_exp;
3219
- if (ma < 0) ma = -ma;
3220
- if (ma == 0) ma = 1;
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);
3221
2370
 
3222
- if (VpIsDef(x)) {
3223
- mp = x->Prec * (VpBaseFig() + 1);
3224
- GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
3225
- }
3226
- else {
3227
- GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3228
- }
3229
- VpPowerByInt(y, x, int_exp);
3230
- if (!NIL_P(prec) && VpIsDef(y)) {
3231
- VpMidRound(y, VpGetRoundMode(), n);
2371
+ memmove(psz1, psz1 + 1, len);
2372
+ psz1[len] = '\0';
2373
+ s = -1;
3232
2374
  }
3233
- return VpCheckGetValue(y);
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;
3234
2386
  }
3235
2387
 
3236
- /* call-seq:
3237
- * self ** other -> bigdecimal
3238
- *
3239
- * Returns the \BigDecimal value of +self+ raised to power +other+:
3240
- *
3241
- * b = BigDecimal('3.14')
3242
- * b ** 2 # => 0.98596e1
3243
- * b ** 2.0 # => 0.98596e1
3244
- * b ** Rational(2, 1) # => 0.98596e1
2388
+ /* Returns the exponent of the BigDecimal number, as an Integer.
3245
2389
  *
3246
- * 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.
3247
2401
  *
2402
+ * BigDecimal("1234.5678").inspect
2403
+ * #=> "0.12345678e4"
3248
2404
  */
3249
2405
  static VALUE
3250
- BigDecimal_power_op(VALUE self, VALUE exp)
2406
+ BigDecimal_inspect(VALUE self)
3251
2407
  {
3252
- 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;
3253
2421
  }
3254
2422
 
3255
- /* :nodoc:
2423
+ /* Returns self * 10**v without changing the precision.
2424
+ * This method is currently for internal use.
3256
2425
  *
3257
- * 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"
3258
2428
  */
3259
2429
  static VALUE
3260
- 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)
3261
2482
  {
3262
- Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
3263
- 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;
3264
2495
 
3265
- if (self != other) {
3266
- DATA_PTR(self) = VpCopy(pv, x);
2496
+ default:
2497
+ break;
3267
2498
  }
3268
- return self;
2499
+
2500
+ return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
3269
2501
  }
3270
2502
 
3271
2503
  /* :nodoc: */
@@ -3304,30 +2536,27 @@ check_exception(VALUE bd)
3304
2536
  {
3305
2537
  assert(is_kind_of_BigDecimal(bd));
3306
2538
 
3307
- Real *vp;
3308
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
3309
- VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
2539
+ VpCheckException(VpPtr(bd), false);
3310
2540
 
3311
2541
  return bd;
3312
2542
  }
3313
2543
 
3314
2544
  static VALUE
3315
- 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)
3316
2546
  {
3317
- VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3318
-
2547
+ VALUE bd;
3319
2548
  Real *vp;
3320
2549
  if (uval == 0) {
3321
- vp = rbd_allocate_struct(1);
3322
- vp->MaxPrec = 1;
2550
+ bd = BigDecimal_allocate(1);
2551
+ vp = VpPtr(bd);
3323
2552
  vp->Prec = 1;
3324
2553
  vp->exponent = 1;
3325
2554
  VpSetZero(vp, 1);
3326
2555
  vp->frac[0] = 0;
3327
2556
  }
3328
2557
  else if (uval < BASE) {
3329
- vp = rbd_allocate_struct(1);
3330
- vp->MaxPrec = 1;
2558
+ bd = BigDecimal_allocate(1);
2559
+ vp = VpPtr(bd);
3331
2560
  vp->Prec = 1;
3332
2561
  vp->exponent = 1;
3333
2562
  VpSetSign(vp, 1);
@@ -3352,32 +2581,31 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3352
2581
  }
3353
2582
 
3354
2583
  const size_t exp = len + ntz;
3355
- vp = rbd_allocate_struct(len);
3356
- vp->MaxPrec = len;
2584
+ bd = BigDecimal_allocate(len);
2585
+ vp = VpPtr(bd);
3357
2586
  vp->Prec = len;
3358
2587
  vp->exponent = exp;
3359
2588
  VpSetSign(vp, 1);
3360
2589
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
3361
2590
  }
3362
2591
 
3363
- return BigDecimal_wrap_struct(obj, vp);
2592
+ return bd;
3364
2593
  }
3365
2594
 
3366
2595
  static VALUE
3367
- rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
2596
+ rb_int64_convert_to_BigDecimal(int64_t ival)
3368
2597
  {
3369
2598
  const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
3370
- VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception);
2599
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
3371
2600
  if (ival < 0) {
3372
- Real *vp;
3373
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2601
+ Real *vp = VpPtr(bd);
3374
2602
  VpSetSign(vp, -1);
3375
2603
  }
3376
2604
  return bd;
3377
2605
  }
3378
2606
 
3379
2607
  static VALUE
3380
- rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2608
+ rb_big_convert_to_BigDecimal(VALUE val)
3381
2609
  {
3382
2610
  assert(RB_TYPE_P(val, T_BIGNUM));
3383
2611
 
@@ -3389,40 +2617,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
3389
2617
  }
3390
2618
  if (size <= sizeof(long)) {
3391
2619
  if (sign < 0) {
3392
- return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
2620
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
3393
2621
  }
3394
2622
  else {
3395
- return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
2623
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
3396
2624
  }
3397
2625
  }
3398
2626
  #if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
3399
2627
  else if (size <= sizeof(LONG_LONG)) {
3400
2628
  if (sign < 0) {
3401
- return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
2629
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val));
3402
2630
  }
3403
2631
  else {
3404
- return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
2632
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
3405
2633
  }
3406
2634
  }
3407
2635
  #endif
3408
2636
  else {
3409
2637
  VALUE str = rb_big2str(val, 10);
3410
- Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
3411
- RSTRING_PTR(str), true);
2638
+ BDVALUE v = bdvalue_nonnullable(CreateFromString(
2639
+ RSTRING_PTR(str),
2640
+ rb_cBigDecimal,
2641
+ true,
2642
+ true
2643
+ ));
3412
2644
  RB_GC_GUARD(str);
3413
- return check_exception(vp->obj);
2645
+ return CheckGetValue(v);
3414
2646
  }
3415
2647
  }
3416
2648
 
3417
2649
  static VALUE
3418
- rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
2650
+ rb_inum_convert_to_BigDecimal(VALUE val)
3419
2651
  {
3420
2652
  assert(RB_INTEGER_TYPE_P(val));
3421
2653
  if (FIXNUM_P(val)) {
3422
- return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
2654
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
3423
2655
  }
3424
2656
  else {
3425
- return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
2657
+ return rb_big_convert_to_BigDecimal(val);
3426
2658
  }
3427
2659
  }
3428
2660
 
@@ -3457,11 +2689,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3457
2689
  }
3458
2690
 
3459
2691
  if (digs == SIZE_MAX) {
3460
- if (!raise_exception)
3461
- return Qnil;
3462
- rb_raise(rb_eArgError,
3463
- "can't omit precision for a %"PRIsVALUE".",
3464
- CLASS_OF(val));
2692
+ digs = 0;
3465
2693
  }
3466
2694
  else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
3467
2695
  if (!raise_exception)
@@ -3481,7 +2709,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3481
2709
  len10 = BIGDECIMAL_DOUBLE_FIGURES;
3482
2710
  }
3483
2711
  memcpy(buf, p, len10);
3484
- xfree(p);
2712
+ free(p);
3485
2713
 
3486
2714
  VALUE inum;
3487
2715
  size_t RB_UNUSED_VAR(prec) = 0;
@@ -3576,9 +2804,8 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3576
2804
  exp = -exp;
3577
2805
  }
3578
2806
 
3579
- VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
3580
- Real *vp;
3581
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2807
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum);
2808
+ Real *vp = VpPtr(bd);
3582
2809
  assert(vp->Prec == prec);
3583
2810
  vp->exponent = exp;
3584
2811
 
@@ -3599,28 +2826,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3599
2826
  CLASS_OF(val));
3600
2827
  }
3601
2828
 
3602
- 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));
3603
2830
  VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
3604
2831
  return d;
3605
2832
  }
3606
2833
 
3607
2834
  static VALUE
3608
- 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)
3609
2836
  {
3610
- if (digs == SIZE_MAX)
3611
- digs = 0;
3612
-
3613
- Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
3614
- if (!vp)
3615
- return Qnil;
3616
- 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));
3617
2840
  }
3618
2841
 
3619
2842
  static inline VALUE
3620
- rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2843
+ rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
3621
2844
  {
3622
2845
  const char *c_str = StringValueCStr(val);
3623
- return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
2846
+ return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
3624
2847
  }
3625
2848
 
3626
2849
  static VALUE
@@ -3648,17 +2871,20 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3648
2871
  if (digs == SIZE_MAX)
3649
2872
  return check_exception(val);
3650
2873
 
3651
- Real *vp;
3652
- 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);
3653
2882
 
3654
- VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
3655
- vp = VpCopy(NULL, vp);
3656
2883
  /* TODO: rounding */
3657
- BigDecimal_wrap_struct(copy, vp);
3658
- return VpCheckGetValue(vp);
2884
+ return check_exception(copy);
3659
2885
  }
3660
2886
  else if (RB_INTEGER_TYPE_P(val)) {
3661
- return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
2887
+ return rb_inum_convert_to_BigDecimal(val);
3662
2888
  }
3663
2889
  else if (RB_FLOAT_TYPE_P(val)) {
3664
2890
  return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
@@ -3676,7 +2902,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3676
2902
  return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
3677
2903
  }
3678
2904
  else if (RB_TYPE_P(val, T_STRING)) {
3679
- return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
2905
+ return rb_str_convert_to_BigDecimal(val, raise_exception);
3680
2906
  }
3681
2907
 
3682
2908
  /* TODO: chheck to_d */
@@ -3690,7 +2916,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3690
2916
  }
3691
2917
  return Qnil;
3692
2918
  }
3693
- return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
2919
+ return rb_str_convert_to_BigDecimal(str, raise_exception);
3694
2920
  }
3695
2921
 
3696
2922
  /* call-seq:
@@ -3711,12 +2937,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3711
2937
  *
3712
2938
  * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
3713
2939
  *
3714
- * # 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.
3715
2941
  * BigDecimal(2) # => 0.2e1
3716
2942
  * BigDecimal(Complex(2, 0)) # => 0.2e1
3717
2943
  * BigDecimal(BigDecimal(2)) # => 0.2e1
3718
- * # Float or Rational value requires ndigits.
3719
- * BigDecimal(2.0, 0) # => 0.2e1
2944
+ * BigDecimal(2.0) # => 0.2e1
2945
+ * # Rational value requires ndigits.
3720
2946
  * BigDecimal(Rational(2, 1), 0) # => 0.2e1
3721
2947
  *
3722
2948
  * - String: converted by parsing if it contains an integer or floating-point literal;
@@ -3780,15 +3006,16 @@ static VALUE
3780
3006
  BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
3781
3007
  {
3782
3008
  char const *c_str = StringValueCStr(str);
3783
- Real *vp = VpNewRbClass(0, c_str, klass, false, true);
3784
- if (!vp)
3009
+ NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
3010
+ if (v.bigdecimal_or_nil == Qnil)
3785
3011
  return Qnil;
3786
3012
  else
3787
- return VpCheckGetValue(vp);
3013
+ return CheckGetValue(bdvalue_nonnullable(v));
3788
3014
  }
3789
3015
 
3790
- /* call-seq:
3791
- * BigDecimal.limit(digits)
3016
+ /*
3017
+ * call-seq:
3018
+ * BigDecimal.limit(digits)
3792
3019
  *
3793
3020
  * Limit the number of significant digits in newly created BigDecimal
3794
3021
  * numbers to the specified value. Rounding is performed as necessary,
@@ -3838,7 +3065,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3838
3065
  static VALUE
3839
3066
  BigDecimal_sign(VALUE self)
3840
3067
  { /* sign */
3841
- int s = GetVpValue(self, 1)->sign;
3068
+ int s = GetSelfVpValue(self)->sign;
3842
3069
  return INT2FIX(s);
3843
3070
  }
3844
3071
 
@@ -3921,301 +3148,6 @@ BigDecimal_save_limit(VALUE self)
3921
3148
  return ret;
3922
3149
  }
3923
3150
 
3924
- /* call-seq:
3925
- * BigMath.exp(decimal, numeric) -> BigDecimal
3926
- *
3927
- * Computes the value of e (the base of natural logarithms) raised to the
3928
- * power of +decimal+, to the specified number of digits of precision.
3929
- *
3930
- * If +decimal+ is infinity, returns Infinity.
3931
- *
3932
- * If +decimal+ is NaN, returns NaN.
3933
- */
3934
- static VALUE
3935
- BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3936
- {
3937
- ssize_t prec, n, i;
3938
- Real* vx = NULL;
3939
- VALUE one, d, y;
3940
- int negative = 0;
3941
- int infinite = 0;
3942
- int nan = 0;
3943
- double flo;
3944
-
3945
- prec = NUM2SSIZET(vprec);
3946
- if (prec <= 0) {
3947
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
3948
- }
3949
-
3950
- /* TODO: the following switch statement is almost same as one in the
3951
- * BigDecimalCmp function. */
3952
- switch (TYPE(x)) {
3953
- case T_DATA:
3954
- if (!is_kind_of_BigDecimal(x)) break;
3955
- vx = DATA_PTR(x);
3956
- negative = BIGDECIMAL_NEGATIVE_P(vx);
3957
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
3958
- nan = VpIsNaN(vx);
3959
- break;
3960
-
3961
- case T_FIXNUM:
3962
- /* fall through */
3963
- case T_BIGNUM:
3964
- vx = GetVpValue(x, 0);
3965
- break;
3966
-
3967
- case T_FLOAT:
3968
- flo = RFLOAT_VALUE(x);
3969
- negative = flo < 0;
3970
- infinite = isinf(flo);
3971
- nan = isnan(flo);
3972
- if (!infinite && !nan) {
3973
- vx = GetVpValueWithPrec(x, 0, 0);
3974
- }
3975
- break;
3976
-
3977
- case T_RATIONAL:
3978
- vx = GetVpValueWithPrec(x, prec, 0);
3979
- break;
3980
-
3981
- default:
3982
- break;
3983
- }
3984
- if (infinite) {
3985
- if (negative) {
3986
- return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3987
- }
3988
- else {
3989
- Real* vy = NewZeroWrapNolimit(1, prec);
3990
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3991
- RB_GC_GUARD(vy->obj);
3992
- return VpCheckGetValue(vy);
3993
- }
3994
- }
3995
- else if (nan) {
3996
- Real* vy = NewZeroWrapNolimit(1, prec);
3997
- VpSetNaN(vy);
3998
- RB_GC_GUARD(vy->obj);
3999
- return VpCheckGetValue(vy);
4000
- }
4001
- else if (vx == NULL) {
4002
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4003
- }
4004
- x = vx->obj;
4005
-
4006
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4007
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4008
- if (negative) {
4009
- VALUE x_zero = INT2NUM(1);
4010
- VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
4011
- x = BigDecimal_initialize_copy(x_copy, x);
4012
- vx = DATA_PTR(x);
4013
- VpSetSign(vx, 1);
4014
- }
4015
-
4016
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4017
- y = one;
4018
- d = y;
4019
- i = 1;
4020
-
4021
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4022
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4023
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4024
- ssize_t m = n - vabs(ey - ed);
4025
-
4026
- rb_thread_check_ints();
4027
-
4028
- if (m <= 0) {
4029
- break;
4030
- }
4031
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4032
- m = BIGDECIMAL_DOUBLE_FIGURES;
4033
- }
4034
-
4035
- d = BigDecimal_mult(d, x); /* d <- d * x */
4036
- d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
4037
- y = BigDecimal_add(y, d); /* y <- y + d */
4038
- ++i; /* i <- i + 1 */
4039
- }
4040
-
4041
- if (negative) {
4042
- return BigDecimal_div2(one, y, vprec);
4043
- }
4044
- else {
4045
- vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
4046
- return BigDecimal_round(1, &vprec, y);
4047
- }
4048
-
4049
- RB_GC_GUARD(one);
4050
- RB_GC_GUARD(x);
4051
- RB_GC_GUARD(y);
4052
- RB_GC_GUARD(d);
4053
- }
4054
-
4055
- /* call-seq:
4056
- * BigMath.log(decimal, numeric) -> BigDecimal
4057
- *
4058
- * Computes the natural logarithm of +decimal+ to the specified number of
4059
- * digits of precision, +numeric+.
4060
- *
4061
- * If +decimal+ is zero or negative, raises Math::DomainError.
4062
- *
4063
- * If +decimal+ is positive infinity, returns Infinity.
4064
- *
4065
- * If +decimal+ is NaN, returns NaN.
4066
- */
4067
- static VALUE
4068
- BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
4069
- {
4070
- ssize_t prec, n, i;
4071
- SIGNED_VALUE expo;
4072
- Real* vx = NULL;
4073
- VALUE vn, one, two, w, x2, y, d;
4074
- int zero = 0;
4075
- int negative = 0;
4076
- int infinite = 0;
4077
- int nan = 0;
4078
- double flo;
4079
- long fix;
4080
-
4081
- if (!is_integer(vprec)) {
4082
- rb_raise(rb_eArgError, "precision must be an Integer");
4083
- }
4084
-
4085
- prec = NUM2SSIZET(vprec);
4086
- if (prec <= 0) {
4087
- rb_raise(rb_eArgError, "Zero or negative precision for exp");
4088
- }
4089
-
4090
- /* TODO: the following switch statement is almost same as one in the
4091
- * BigDecimalCmp function. */
4092
- switch (TYPE(x)) {
4093
- case T_DATA:
4094
- if (!is_kind_of_BigDecimal(x)) break;
4095
- vx = DATA_PTR(x);
4096
- zero = VpIsZero(vx);
4097
- negative = BIGDECIMAL_NEGATIVE_P(vx);
4098
- infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
4099
- nan = VpIsNaN(vx);
4100
- break;
4101
-
4102
- case T_FIXNUM:
4103
- fix = FIX2LONG(x);
4104
- zero = fix == 0;
4105
- negative = fix < 0;
4106
- goto get_vp_value;
4107
-
4108
- case T_BIGNUM:
4109
- i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
4110
- zero = i == 0;
4111
- negative = i < 0;
4112
- get_vp_value:
4113
- if (zero || negative) break;
4114
- vx = GetVpValue(x, 0);
4115
- break;
4116
-
4117
- case T_FLOAT:
4118
- flo = RFLOAT_VALUE(x);
4119
- zero = flo == 0;
4120
- negative = flo < 0;
4121
- infinite = isinf(flo);
4122
- nan = isnan(flo);
4123
- if (!zero && !negative && !infinite && !nan) {
4124
- vx = GetVpValueWithPrec(x, 0, 1);
4125
- }
4126
- break;
4127
-
4128
- case T_RATIONAL:
4129
- zero = RRATIONAL_ZERO_P(x);
4130
- negative = RRATIONAL_NEGATIVE_P(x);
4131
- if (zero || negative) break;
4132
- vx = GetVpValueWithPrec(x, prec, 1);
4133
- break;
4134
-
4135
- case T_COMPLEX:
4136
- rb_raise(rb_eMathDomainError,
4137
- "Complex argument for BigMath.log");
4138
-
4139
- default:
4140
- break;
4141
- }
4142
- if (infinite && !negative) {
4143
- Real *vy = NewZeroWrapNolimit(1, prec);
4144
- RB_GC_GUARD(vy->obj);
4145
- VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
4146
- return VpCheckGetValue(vy);
4147
- }
4148
- else if (nan) {
4149
- Real* vy = NewZeroWrapNolimit(1, prec);
4150
- RB_GC_GUARD(vy->obj);
4151
- VpSetNaN(vy);
4152
- return VpCheckGetValue(vy);
4153
- }
4154
- else if (zero || negative) {
4155
- rb_raise(rb_eMathDomainError,
4156
- "Zero or negative argument for log");
4157
- }
4158
- else if (vx == NULL) {
4159
- cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
4160
- }
4161
- x = VpCheckGetValue(vx);
4162
-
4163
- one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4164
- two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4165
-
4166
- n = prec + BIGDECIMAL_DOUBLE_FIGURES;
4167
- vn = SSIZET2NUM(n);
4168
- expo = VpExponent10(vx);
4169
- if (expo < 0 || expo >= 3) {
4170
- char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
4171
- snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
4172
- x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
4173
- }
4174
- else {
4175
- expo = 0;
4176
- }
4177
- w = BigDecimal_sub(x, one);
4178
- x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
4179
- x2 = BigDecimal_mult2(x, x, vn);
4180
- y = x;
4181
- d = y;
4182
- i = 1;
4183
- while (!VpIsZero((Real*)DATA_PTR(d))) {
4184
- SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
4185
- SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
4186
- ssize_t m = n - vabs(ey - ed);
4187
- if (m <= 0) {
4188
- break;
4189
- }
4190
- else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
4191
- m = BIGDECIMAL_DOUBLE_FIGURES;
4192
- }
4193
-
4194
- x = BigDecimal_mult2(x2, x, vn);
4195
- i += 2;
4196
- d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
4197
- y = BigDecimal_add(y, d);
4198
- }
4199
-
4200
- y = BigDecimal_mult(y, two);
4201
- if (expo != 0) {
4202
- VALUE log10, vexpo, dy;
4203
- log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
4204
- vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
4205
- dy = BigDecimal_mult(log10, vexpo);
4206
- y = BigDecimal_add(y, dy);
4207
- }
4208
-
4209
- RB_GC_GUARD(one);
4210
- RB_GC_GUARD(two);
4211
- RB_GC_GUARD(vn);
4212
- RB_GC_GUARD(x2);
4213
- RB_GC_GUARD(y);
4214
- RB_GC_GUARD(d);
4215
-
4216
- return y;
4217
- }
4218
-
4219
3151
  static VALUE BIGDECIMAL_NAN = Qnil;
4220
3152
 
4221
3153
  static VALUE
@@ -4267,6 +3199,71 @@ BigDecimal_literal(const char *str)
4267
3199
 
4268
3200
  #define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
4269
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
+
4270
3267
  /* Document-class: BigDecimal
4271
3268
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
4272
3269
  *
@@ -4383,14 +3380,16 @@ BigDecimal_literal(const char *str)
4383
3380
  *
4384
3381
  * When you require +bigdecimal/util+, the #to_d method will be
4385
3382
  * available on BigDecimal and the native Integer, Float, Rational,
4386
- * and String classes:
3383
+ * String, Complex, and NilClass classes:
4387
3384
  *
4388
3385
  * require 'bigdecimal/util'
4389
3386
  *
4390
- * 42.to_d # => 0.42e2
4391
- * 0.5.to_d # => 0.5e0
4392
- * (2/3r).to_d(3) # => 0.667e0
4393
- * "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
4394
3393
  *
4395
3394
  * == Methods for Working with \JSON
4396
3395
  *
@@ -4464,7 +3463,7 @@ Init_bigdecimal(void)
4464
3463
  * guarantee that two groups could always be multiplied together without
4465
3464
  * overflow.)
4466
3465
  */
4467
- rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
3466
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
4468
3467
 
4469
3468
  /* Exceptions */
4470
3469
 
@@ -4575,7 +3574,6 @@ Init_bigdecimal(void)
4575
3574
  rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
4576
3575
 
4577
3576
  /* instance methods */
4578
- rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
4579
3577
  rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
4580
3578
  rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
4581
3579
  rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
@@ -4606,14 +3604,11 @@ Init_bigdecimal(void)
4606
3604
  rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
4607
3605
  rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
4608
3606
  rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
4609
- rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
4610
3607
  rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
4611
3608
  rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
4612
3609
  rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
4613
3610
  rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
4614
3611
  rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
4615
- rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
4616
- rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
4617
3612
  rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
4618
3613
  rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
4619
3614
  rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
@@ -4632,11 +3627,16 @@ Init_bigdecimal(void)
4632
3627
  rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
4633
3628
  rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
4634
3629
  rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
3630
+ rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
4635
3631
  rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
4636
3632
 
4637
- rb_mBigMath = rb_define_module("BigMath");
4638
- rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4639
- 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 */
4640
3640
 
4641
3641
  #define ROUNDING_MODE(i, name, value) \
4642
3642
  id_##name = rb_intern_const(#name); \
@@ -4676,19 +3676,9 @@ Init_bigdecimal(void)
4676
3676
  */
4677
3677
  #ifdef BIGDECIMAL_DEBUG
4678
3678
  static int gfDebug = 1; /* Debug switch */
4679
- #if 0
4680
- static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4681
- #endif
4682
3679
  #endif /* BIGDECIMAL_DEBUG */
4683
3680
 
4684
- static Real *VpConstOne; /* constant 1.0 */
4685
- static Real *VpConstPt5; /* constant 0.5 */
4686
- #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4687
- /* used in VpSqrt() */
4688
-
4689
- /* ETC */
4690
- #define MemCmp(x,y,z) memcmp(x,y,z)
4691
- #define StrCmp(x,y) strcmp(x,y)
3681
+ static VALUE VpConstOne; /* constant 1.0 */
4692
3682
 
4693
3683
  enum op_sw {
4694
3684
  OP_SW_ADD = 1, /* + */
@@ -4698,11 +3688,9 @@ enum op_sw {
4698
3688
  };
4699
3689
 
4700
3690
  static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
4701
- static int AddExponent(Real *a, SIGNED_VALUE n);
4702
3691
  static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
4703
3692
  static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
4704
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);
4705
- static int VpNmlz(Real *a);
4706
3694
  static void VpFormatSt(char *psz, size_t fFmt);
4707
3695
  static int VpRdup(Real *m, size_t ind_m);
4708
3696
 
@@ -4761,10 +3749,10 @@ VpCheckException(Real *p, bool always)
4761
3749
  }
4762
3750
 
4763
3751
  static VALUE
4764
- VpCheckGetValue(Real *p)
3752
+ CheckGetValue(BDVALUE v)
4765
3753
  {
4766
- VpCheckException(p, false);
4767
- return p->obj;
3754
+ VpCheckException(v.real, false);
3755
+ return v.bigdecimal;
4768
3756
  }
4769
3757
 
4770
3758
  /*
@@ -4796,12 +3784,10 @@ VpGetPrecLimit(void)
4796
3784
  return NUM2SIZET(vlimit);
4797
3785
  }
4798
3786
 
4799
- VP_EXPORT size_t
3787
+ VP_EXPORT void
4800
3788
  VpSetPrecLimit(size_t n)
4801
3789
  {
4802
- size_t const s = VpGetPrecLimit();
4803
3790
  bigdecimal_set_thread_local_precision_limit(n);
4804
- return s;
4805
3791
  }
4806
3792
 
4807
3793
  /*
@@ -4916,15 +3902,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
4916
3902
  return nzero;
4917
3903
  }
4918
3904
 
4919
- #if 0 /* unused */
4920
- VP_EXPORT int
4921
- VpIsNegDoubleZero(double v)
4922
- {
4923
- double z = VpGetDoubleNegZero();
4924
- return MemCmp(&v,&z,sizeof(v))==0;
4925
- }
4926
- #endif
4927
-
4928
3905
  VP_EXPORT int
4929
3906
  VpException(unsigned short f, const char *str,int always)
4930
3907
  {
@@ -5076,7 +4053,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
5076
4053
  case 'E':
5077
4054
  /* fall through */
5078
4055
  default:
5079
- 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) */
5080
4057
  }
5081
4058
  return nc;
5082
4059
  }
@@ -5102,35 +4079,21 @@ VpInit(DECDIG BaseVal)
5102
4079
  VpGetDoubleNegZero();
5103
4080
 
5104
4081
  /* Const 1.0 */
5105
- VpConstOne = NewOneNolimit(1, 1);
5106
-
5107
- /* Const 0.5 */
5108
- VpConstPt5 = NewOneNolimit(1, 1);
5109
- VpConstPt5->exponent = 0;
5110
- VpConstPt5->frac[0] = 5*BASE1;
4082
+ rb_global_variable(&VpConstOne);
4083
+ VpConstOne = NewZeroWrap(1, 1).bigdecimal;
4084
+ VpSetOne(VpPtr(VpConstOne));
5111
4085
 
5112
4086
  #ifdef BIGDECIMAL_DEBUG
5113
4087
  gnAlloc = 0;
5114
4088
  #endif /* BIGDECIMAL_DEBUG */
5115
4089
 
5116
- #ifdef BIGDECIMAL_DEBUG
5117
- if (gfDebug) {
5118
- printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
5119
- printf("\tBASE = %"PRIuDECDIG"\n", BASE);
5120
- printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
5121
- printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
5122
- printf("\tBASE_FIG = %u\n", BASE_FIG);
5123
- printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
5124
- }
5125
- #endif /* BIGDECIMAL_DEBUG */
5126
-
5127
4090
  return BIGDECIMAL_DOUBLE_FIGURES;
5128
4091
  }
5129
4092
 
5130
4093
  VP_EXPORT Real *
5131
4094
  VpOne(void)
5132
4095
  {
5133
- return VpConstOne;
4096
+ return VpPtr(VpConstOne);
5134
4097
  }
5135
4098
 
5136
4099
  /* If exponent overflows,then raise exception or returns 0 */
@@ -5139,24 +4102,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
5139
4102
  {
5140
4103
  SIGNED_VALUE e = a->exponent;
5141
4104
  SIGNED_VALUE m = e+n;
5142
- SIGNED_VALUE eb, mb;
5143
- if (e > 0) {
5144
- if (n > 0) {
5145
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5146
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5147
- goto overflow;
5148
- mb = m*(SIGNED_VALUE)BASE_FIG;
5149
- eb = e*(SIGNED_VALUE)BASE_FIG;
5150
- if (eb - mb > 0) goto overflow;
5151
- }
5152
- }
5153
- else if (n < 0) {
5154
- if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
5155
- MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
5156
- goto underflow;
5157
- mb = m*(SIGNED_VALUE)BASE_FIG;
5158
- eb = e*(SIGNED_VALUE)BASE_FIG;
5159
- 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;
5160
4113
  }
5161
4114
  a->exponent = m;
5162
4115
  return 1;
@@ -5171,7 +4124,7 @@ overflow:
5171
4124
  return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
5172
4125
  }
5173
4126
 
5174
- Real *
4127
+ NULLABLE_BDVALUE
5175
4128
  bigdecimal_parse_special_string(const char *str)
5176
4129
  {
5177
4130
  static const struct {
@@ -5196,120 +4149,61 @@ bigdecimal_parse_special_string(const char *str)
5196
4149
  p = str + table[i].len;
5197
4150
  while (*p && ISSPACE(*p)) ++p;
5198
4151
  if (*p == '\0') {
5199
- Real *vp = rbd_allocate_struct(1);
5200
- vp->MaxPrec = 1;
4152
+ VALUE obj = BigDecimal_allocate(1);
4153
+ Real *vp = VpPtr(obj);
5201
4154
  switch (table[i].sign) {
5202
4155
  default:
5203
- UNREACHABLE; break;
4156
+ UNREACHABLE;
4157
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5204
4158
  case VP_SIGN_POSITIVE_INFINITE:
5205
4159
  VpSetPosInf(vp);
5206
- return vp;
4160
+ break;
5207
4161
  case VP_SIGN_NEGATIVE_INFINITE:
5208
4162
  VpSetNegInf(vp);
5209
- return vp;
4163
+ break;
5210
4164
  case VP_SIGN_NaN:
5211
4165
  VpSetNaN(vp);
5212
- return vp;
4166
+ break;
5213
4167
  }
4168
+ return (NULLABLE_BDVALUE) { obj, vp };
5214
4169
  }
5215
4170
  }
5216
4171
 
5217
- return NULL;
5218
- }
5219
-
5220
- struct VpCtoV_args {
5221
- Real *a;
5222
- const char *int_chr;
5223
- size_t ni;
5224
- const char *frac;
5225
- size_t nf;
5226
- const char *exp_chr;
5227
- size_t ne;
5228
- };
5229
-
5230
- static VALUE
5231
- call_VpCtoV(VALUE arg)
5232
- {
5233
- struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
5234
- return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
5235
- }
5236
-
5237
- static int
5238
- 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)
5239
- {
5240
- struct VpCtoV_args args;
5241
- int state = 0;
5242
-
5243
- args.a = a;
5244
- args.int_chr = int_chr;
5245
- args.ni = ni;
5246
- args.frac = frac;
5247
- args.nf = nf;
5248
- args.exp_chr = exp_chr;
5249
- args.ne = ne;
5250
-
5251
- VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
5252
- if (state) {
5253
- if (free_on_error) {
5254
- rbd_free_struct(a);
5255
- }
5256
- rb_jump_tag(state);
5257
- }
5258
-
5259
- return (int)result;
4172
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5260
4173
  }
5261
4174
 
5262
4175
  /*
5263
4176
  * Allocates variable.
5264
4177
  * [Input]
5265
- * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5266
- * The mx will be the number of significant digits can to be stored.
5267
- * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5268
- * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5269
- * so that the full precision specified by szVal is allocated.
4178
+ * szVal ... The value assigned(char).
5270
4179
  *
5271
4180
  * [Returns]
5272
- * Pointer to the newly allocated variable, or
5273
- * 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.
5274
4183
  */
5275
- VP_EXPORT Real *
5276
- 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)
5277
4186
  {
5278
4187
  const char *orig_szVal = szVal;
5279
- size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
5280
- size_t len;
4188
+ size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
5281
4189
  char v, *psz;
5282
4190
  int sign=1;
5283
- Real *vp = NULL;
5284
4191
  VALUE buf;
5285
4192
 
5286
- if (szVal == NULL) {
5287
- return_zero:
5288
- /* necessary to be able to store */
5289
- /* at least mx digits. */
5290
- /* szVal==NULL ==> allocate zero value. */
5291
- vp = rbd_allocate_struct(mx);
5292
- vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5293
- VpSetZero(vp, 1); /* initialize vp to zero. */
5294
- return vp;
5295
- }
5296
-
5297
4193
  /* Skipping leading spaces */
5298
4194
  while (ISSPACE(*szVal)) szVal++;
5299
4195
 
5300
4196
  /* Check on Inf & NaN */
5301
- if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
5302
- return vp;
4197
+ NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
4198
+ if (special_bd.real_or_null != NULL) {
4199
+ return special_bd;
5303
4200
  }
5304
4201
 
5305
- /* Processing the leading one `#` */
5306
- if (*szVal != '#') {
5307
- len = rbd_calculate_internal_digits(mx, true);
5308
- }
5309
- else {
5310
- len = rbd_calculate_internal_digits(mx, false);
5311
- ++szVal;
5312
- }
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;
5313
4207
 
5314
4208
  /* Scanning digits */
5315
4209
 
@@ -5362,13 +4256,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5362
4256
  ne = 0; /* number of digits in the exponential part */
5363
4257
  ipf = 0; /* index of the beginning of the fractional part */
5364
4258
  ipe = 0; /* index of the beginning of the exponential part */
5365
- dot_seen = 0;
5366
4259
  exp_seen = 0;
5367
4260
 
5368
4261
  if (v != '\0') {
5369
4262
  /* Scanning fractional part */
5370
4263
  if ((psz[i] = szVal[j]) == '.') {
5371
- dot_seen = 1;
5372
4264
  ++i;
5373
4265
  ++j;
5374
4266
  ipf = i;
@@ -5384,9 +4276,6 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5384
4276
  }
5385
4277
  if (!strict_p) {
5386
4278
  v = psz[i] = '\0';
5387
- if (nf == 0) {
5388
- dot_seen = 0;
5389
- }
5390
4279
  break;
5391
4280
  }
5392
4281
  goto invalid_value;
@@ -5457,14 +4346,15 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5457
4346
 
5458
4347
  psz[i] = '\0';
5459
4348
 
5460
- if (strict_p && (((ni == 0 || dot_seen) && nf == 0) || (exp_seen && ne == 0))) {
4349
+ if (strict_p && ((ni == 0 && nf == 0) || (exp_seen && ne == 0))) {
5461
4350
  VALUE str;
5462
4351
  invalid_value:
5463
4352
  if (!strict_p) {
5464
- goto return_zero;
4353
+ BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
4354
+ return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
5465
4355
  }
5466
4356
  if (!exc) {
5467
- return NULL;
4357
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
5468
4358
  }
5469
4359
  str = rb_str_new2(orig_szVal);
5470
4360
  rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
@@ -5472,15 +4362,12 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5472
4362
 
5473
4363
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5474
4364
  /* units for szVal[] */
5475
- if (len == 0) len = 1;
5476
- nalloc = Max(nalloc, len);
5477
- len = nalloc;
5478
- vp = rbd_allocate_struct(len);
5479
- vp->MaxPrec = len; /* set max precision */
4365
+ VALUE obj = BigDecimal_allocate(nalloc);
4366
+ Real *vp = VpPtr(obj);
5480
4367
  VpSetZero(vp, sign);
5481
- protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
4368
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
5482
4369
  rb_str_resize(buf, 0);
5483
- return vp;
4370
+ return (NULLABLE_BDVALUE) { obj, vp };
5484
4371
  }
5485
4372
 
5486
4373
  /*
@@ -5516,7 +4403,7 @@ VpAsgn(Real *c, Real *a, int isw)
5516
4403
  c->Prec = n;
5517
4404
  memcpy(c->frac, a->frac, n * sizeof(DECDIG));
5518
4405
  /* Needs round ? */
5519
- if (isw != 10) {
4406
+ if (isw != 10 && isw != -10) {
5520
4407
  /* Not in ActiveRound */
5521
4408
  if(c->Prec < a->Prec) {
5522
4409
  VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
@@ -5542,19 +4429,11 @@ VpAsgn(Real *c, Real *a, int isw)
5542
4429
  VP_EXPORT size_t
5543
4430
  VpAddSub(Real *c, Real *a, Real *b, int operation)
5544
4431
  {
5545
- short sw, isw;
4432
+ short sw, isw, sign;
5546
4433
  Real *a_ptr, *b_ptr;
5547
4434
  size_t n, na, nb, i;
5548
4435
  DECDIG mrv;
5549
4436
 
5550
- #ifdef BIGDECIMAL_DEBUG
5551
- if (gfDebug) {
5552
- VPrint(stdout, "VpAddSub(enter) a=% \n", a);
5553
- VPrint(stdout, " b=% \n", b);
5554
- printf(" operation=%d\n", operation);
5555
- }
5556
- #endif /* BIGDECIMAL_DEBUG */
5557
-
5558
4437
  if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
5559
4438
 
5560
4439
  /* check if a or b is zero */
@@ -5643,28 +4522,21 @@ end_if:
5643
4522
  if (isw) { /* addition */
5644
4523
  VpSetSign(c, 1);
5645
4524
  mrv = VpAddAbs(a_ptr, b_ptr, c);
5646
- VpSetSign(c, isw / 2);
4525
+ sign = isw / 2;
5647
4526
  }
5648
4527
  else { /* subtraction */
5649
4528
  VpSetSign(c, 1);
5650
4529
  mrv = VpSubAbs(a_ptr, b_ptr, c);
5651
- if (a_ptr == a) {
5652
- VpSetSign(c,VpGetSign(a));
5653
- }
5654
- else {
5655
- VpSetSign(c, VpGetSign(a_ptr) * sw);
5656
- }
4530
+ sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
5657
4531
  }
5658
- VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
5659
-
5660
- #ifdef BIGDECIMAL_DEBUG
5661
- if (gfDebug) {
5662
- VPrint(stdout, "VpAddSub(result) c=% \n", c);
5663
- VPrint(stdout, " a=% \n", a);
5664
- VPrint(stdout, " b=% \n", b);
5665
- printf(" operation=%d\n", operation);
4532
+ if (VpIsInf(c)) {
4533
+ VpSetInf(c, sign);
5666
4534
  }
5667
- #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
+
5668
4540
  return c->Prec * BASE_FIG;
5669
4541
  }
5670
4542
 
@@ -5685,13 +4557,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
5685
4557
  size_t c_pos;
5686
4558
  DECDIG av, bv, carry, mrv;
5687
4559
 
5688
- #ifdef BIGDECIMAL_DEBUG
5689
- if (gfDebug) {
5690
- VPrint(stdout, "VpAddAbs called: a = %\n", a);
5691
- VPrint(stdout, " b = %\n", b);
5692
- }
5693
- #endif /* BIGDECIMAL_DEBUG */
5694
-
5695
4560
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5696
4561
  a_pos = ap;
5697
4562
  b_pos = bp;
@@ -5757,11 +4622,6 @@ Assign_a:
5757
4622
 
5758
4623
  Exit:
5759
4624
 
5760
- #ifdef BIGDECIMAL_DEBUG
5761
- if (gfDebug) {
5762
- VPrint(stdout, "VpAddAbs exit: c=% \n", c);
5763
- }
5764
- #endif /* BIGDECIMAL_DEBUG */
5765
4625
  return mrv;
5766
4626
  }
5767
4627
 
@@ -5780,13 +4640,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
5780
4640
  size_t c_pos;
5781
4641
  DECDIG av, bv, borrow, mrv;
5782
4642
 
5783
- #ifdef BIGDECIMAL_DEBUG
5784
- if (gfDebug) {
5785
- VPrint(stdout, "VpSubAbs called: a = %\n", a);
5786
- VPrint(stdout, " b = %\n", b);
5787
- }
5788
- #endif /* BIGDECIMAL_DEBUG */
5789
-
5790
4643
  word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
5791
4644
  a_pos = ap;
5792
4645
  b_pos = bp;
@@ -5862,11 +4715,6 @@ Assign_a:
5862
4715
  mrv = 0;
5863
4716
 
5864
4717
  Exit:
5865
- #ifdef BIGDECIMAL_DEBUG
5866
- if (gfDebug) {
5867
- VPrint(stdout, "VpSubAbs exit: c=% \n", c);
5868
- }
5869
- #endif /* BIGDECIMAL_DEBUG */
5870
4718
  return mrv;
5871
4719
  }
5872
4720
 
@@ -5991,25 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
5991
4839
  * a0 a1 .... an * b0
5992
4840
  * +_____________________________
5993
4841
  * c0 c1 c2 ...... cl
5994
- * nc <---|
5995
- * MaxAB |--------------------|
5996
4842
  */
5997
4843
  VP_EXPORT size_t
5998
4844
  VpMult(Real *c, Real *a, Real *b)
5999
4845
  {
6000
- size_t MxIndA, MxIndB, MxIndAB, MxIndC;
6001
- size_t ind_c, i, ii, nc;
6002
- size_t ind_as, ind_ae, ind_bs;
6003
- DECDIG carry;
6004
- DECDIG_DBL s;
6005
- Real *w;
6006
-
6007
- #ifdef BIGDECIMAL_DEBUG
6008
- if (gfDebug) {
6009
- VPrint(stdout, "VpMult(Enter): a=% \n", a);
6010
- VPrint(stdout, " b=% \n", b);
6011
- }
6012
- #endif /* BIGDECIMAL_DEBUG */
4846
+ ssize_t a_batch_max, b_batch_max;
4847
+ DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
6013
4848
 
6014
4849
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
6015
4850
 
@@ -6020,108 +4855,82 @@ VpMult(Real *c, Real *a, Real *b)
6020
4855
  }
6021
4856
 
6022
4857
  if (VpIsOne(a)) {
6023
- VpAsgn(c, b, VpGetSign(a));
4858
+ VpAsgn(c, b, 10 * VpGetSign(a));
6024
4859
  goto Exit;
6025
4860
  }
6026
4861
  if (VpIsOne(b)) {
6027
- VpAsgn(c, a, VpGetSign(b));
4862
+ VpAsgn(c, a, 10 * VpGetSign(b));
6028
4863
  goto Exit;
6029
4864
  }
6030
4865
  if (b->Prec > a->Prec) {
6031
4866
  /* Adjust so that digits(a)>digits(b) */
6032
- w = a;
4867
+ Real *w = a;
6033
4868
  a = b;
6034
4869
  b = w;
6035
4870
  }
6036
- w = NULL;
6037
- MxIndA = a->Prec - 1;
6038
- MxIndB = b->Prec - 1;
6039
- MxIndC = c->MaxPrec - 1;
6040
- MxIndAB = a->Prec + b->Prec - 1;
6041
-
6042
- if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
6043
- w = c;
6044
- c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
6045
- MxIndC = MxIndAB;
6046
- }
6047
4871
 
6048
4872
  /* set LHSV c info */
6049
4873
 
6050
4874
  c->exponent = a->exponent; /* set exponent */
6051
- if (!AddExponent(c, b->exponent)) {
6052
- if (w) rbd_free_struct(c);
6053
- return 0;
6054
- }
6055
4875
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
6056
- carry = 0;
6057
- nc = ind_c = MxIndAB;
6058
- memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
6059
- c->Prec = nc + 1; /* set precision */
6060
- for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
6061
- if (nc < MxIndB) { /* The left triangle of the Fig. */
6062
- ind_as = MxIndA - nc;
6063
- ind_ae = MxIndA;
6064
- ind_bs = MxIndB;
6065
- }
6066
- else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
6067
- ind_as = MxIndA - nc;
6068
- ind_ae = MxIndA - (nc - MxIndB);
6069
- ind_bs = MxIndB;
6070
- }
6071
- else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
6072
- ind_as = 0;
6073
- ind_ae = MxIndAB - nc - 1;
6074
- ind_bs = MxIndB - (nc - MxIndA);
6075
- }
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
+ }
6076
4904
 
6077
- for (i = ind_as; i <= ind_ae; ++i) {
6078
- s = (DECDIG_DBL)a->frac[i] * b->frac[ind_bs--];
6079
- carry = (DECDIG)(s / BASE);
6080
- s -= (DECDIG_DBL)carry * BASE;
6081
- c->frac[ind_c] += (DECDIG)s;
6082
- if (c->frac[ind_c] >= BASE) {
6083
- s = c->frac[ind_c] / BASE;
6084
- carry += (DECDIG)s;
6085
- 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);
6086
4912
  }
6087
- if (carry) {
6088
- ii = ind_c;
6089
- while (ii-- > 0) {
6090
- c->frac[ii] += carry;
6091
- if (c->frac[ii] >= BASE) {
6092
- carry = c->frac[ii] / BASE;
6093
- c->frac[ii] -= (carry * BASE);
6094
- }
6095
- else {
6096
- break;
6097
- }
6098
- }
6099
- }
6100
- }
6101
- }
6102
- if (w != NULL) { /* free work variable */
6103
- VpNmlz(c);
6104
- VpAsgn(w, c, 1);
6105
- rbd_free_struct(c);
6106
- c = w;
6107
- }
6108
- else {
6109
- 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
+ }
6110
4919
  }
6111
4920
 
4921
+ Cleanup:
4922
+ VpNmlz(c);
4923
+
6112
4924
  Exit:
6113
- #ifdef BIGDECIMAL_DEBUG
6114
- if (gfDebug) {
6115
- VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
6116
- VPrint(stdout, " a=% \n", a);
6117
- VPrint(stdout, " b=% \n", b);
6118
- }
6119
- #endif /*BIGDECIMAL_DEBUG */
6120
4925
  return c->Prec*BASE_FIG;
6121
4926
  }
6122
4927
 
6123
4928
  /*
6124
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
6125
4934
  */
6126
4935
  VP_EXPORT size_t
6127
4936
  VpDivd(Real *c, Real *r, Real *a, Real *b)
@@ -6130,16 +4939,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6130
4939
  size_t i, n, ind_a, ind_b, ind_c, ind_r;
6131
4940
  size_t nLoop;
6132
4941
  DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
6133
- DECDIG borrow, borrow1, borrow2;
4942
+ DECDIG borrow1, borrow2;
6134
4943
  DECDIG_DBL qb;
6135
4944
 
6136
- #ifdef BIGDECIMAL_DEBUG
6137
- if (gfDebug) {
6138
- VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
6139
- VPrint(stdout, " b=% \n", b);
6140
- }
6141
- #endif /*BIGDECIMAL_DEBUG */
6142
-
6143
4945
  VpSetNaN(r);
6144
4946
  if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
6145
4947
  if (VpIsZero(a) && VpIsZero(b)) {
@@ -6156,30 +4958,22 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6156
4958
  VpSetZero(r, VpGetSign(a) * VpGetSign(b));
6157
4959
  goto Exit;
6158
4960
  }
6159
- if (VpIsOne(b)) {
6160
- /* divide by one */
6161
- VpAsgn(c, a, VpGetSign(b));
6162
- VpSetZero(r, VpGetSign(a));
6163
- goto Exit;
6164
- }
6165
4961
 
6166
4962
  word_a = a->Prec;
6167
4963
  word_b = b->Prec;
6168
4964
  word_c = c->MaxPrec;
6169
4965
  word_r = r->MaxPrec;
6170
4966
 
6171
- if (word_a >= word_r) goto space_error;
4967
+ if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
6172
4968
 
6173
- ind_r = 1;
6174
- r->frac[0] = 0;
6175
- while (ind_r <= word_a) {
6176
- r->frac[ind_r] = a->frac[ind_r - 1];
6177
- ++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;
6178
4972
  }
6179
- while (ind_r < word_r) r->frac[ind_r++] = 0;
6180
4973
 
6181
- ind_c = 0;
6182
- 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;
6183
4977
 
6184
4978
  /* initial procedure */
6185
4979
  b1 = b1p1 = b->frac[0];
@@ -6194,15 +4988,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6194
4988
 
6195
4989
  /* */
6196
4990
  /* loop start */
6197
- ind_c = word_r - 1;
6198
- nLoop = Min(word_c,ind_c);
6199
- ind_c = 1;
4991
+ nLoop = Min(word_c, word_r);
4992
+ ind_c = 0;
6200
4993
  while (ind_c < nLoop) {
6201
4994
  if (r->frac[ind_c] == 0) {
6202
4995
  ++ind_c;
6203
4996
  continue;
6204
4997
  }
6205
- 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);
6206
4999
  if (r1r2 == b1b2) {
6207
5000
  /* The first two word digits is the same */
6208
5001
  ind_b = 2;
@@ -6215,26 +5008,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
6215
5008
  }
6216
5009
  /* The first few word digits of r and b is the same and */
6217
5010
  /* the first different word digit of w is greater than that */
6218
- /* of b, so quotient is 1 and just subtract b from r. */
6219
- borrow = 0; /* quotient=1, then just r-b */
6220
- ind_b = b->Prec - 1;
6221
- ind_r = ind_c + ind_b;
6222
- if (ind_r >= word_r) goto space_error;
6223
- n = ind_b;
6224
- for (i = 0; i <= n; ++i) {
6225
- if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
6226
- r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
6227
- borrow = 1;
6228
- }
6229
- else {
6230
- r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
6231
- borrow = 0;
6232
- }
6233
- --ind_r;
6234
- --ind_b;
6235
- }
5011
+ /* of b, so quotient is 1. */
5012
+ q = 1;
6236
5013
  ++c->frac[ind_c];
6237
- goto carry;
5014
+ ind_r = b->Prec + ind_c - 1;
5015
+ goto sub_mult;
6238
5016
  }
6239
5017
  /* The first two word digits is not the same, */
6240
5018
  /* then compare magnitude, and divide actually. */
@@ -6287,49 +5065,26 @@ sub_mult:
6287
5065
  }
6288
5066
 
6289
5067
  r->frac[ind_r] -= borrow2;
6290
- carry:
6291
- ind_r = ind_c;
6292
- while (c->frac[ind_r] >= BASE) {
6293
- c->frac[ind_r] -= BASE;
6294
- --ind_r;
6295
- ++c->frac[ind_r];
6296
- }
6297
5068
  }
6298
5069
  /* End of operation, now final arrangement */
6299
5070
  out_side:
6300
5071
  c->Prec = word_c;
6301
5072
  c->exponent = a->exponent;
6302
- if (!AddExponent(c, 2)) return 0;
5073
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
5074
+ if (!AddExponent(c, 1)) return 0;
6303
5075
  if (!AddExponent(c, -(b->exponent))) return 0;
6304
5076
 
6305
- VpSetSign(c, VpGetSign(a) * VpGetSign(b));
6306
5077
  VpNmlz(c); /* normalize c */
6307
5078
  r->Prec = word_r;
6308
5079
  r->exponent = a->exponent;
6309
- if (!AddExponent(r, 1)) return 0;
6310
5080
  VpSetSign(r, VpGetSign(a));
6311
5081
  VpNmlz(r); /* normalize r(remainder) */
6312
5082
  goto Exit;
6313
5083
 
6314
5084
  space_error:
6315
- #ifdef BIGDECIMAL_DEBUG
6316
- if (gfDebug) {
6317
- printf(" word_a=%"PRIuSIZE"\n", word_a);
6318
- printf(" word_b=%"PRIuSIZE"\n", word_b);
6319
- printf(" word_c=%"PRIuSIZE"\n", word_c);
6320
- printf(" word_r=%"PRIuSIZE"\n", word_r);
6321
- printf(" ind_r =%"PRIuSIZE"\n", ind_r);
6322
- }
6323
- #endif /* BIGDECIMAL_DEBUG */
6324
5085
  rb_bug("ERROR(VpDivd): space for remainder too small.");
6325
5086
 
6326
5087
  Exit:
6327
- #ifdef BIGDECIMAL_DEBUG
6328
- if (gfDebug) {
6329
- VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
6330
- VPrint(stdout, " r=% \n", r);
6331
- }
6332
- #endif /* BIGDECIMAL_DEBUG */
6333
5088
  return c->Prec * BASE_FIG;
6334
5089
  }
6335
5090
 
@@ -6452,13 +5207,6 @@ Exit:
6452
5207
  if (val > 1) val = 1;
6453
5208
  else if (val < -1) val = -1;
6454
5209
 
6455
- #ifdef BIGDECIMAL_DEBUG
6456
- if (gfDebug) {
6457
- VPrint(stdout, " VpComp a=%\n", a);
6458
- VPrint(stdout, " b=%\n", b);
6459
- printf(" ans=%d\n", val);
6460
- }
6461
- #endif /* BIGDECIMAL_DEBUG */
6462
5210
  return (int)val;
6463
5211
  }
6464
5212
 
@@ -6576,25 +5324,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6576
5324
  static void
6577
5325
  VpFormatSt(char *psz, size_t fFmt)
6578
5326
  {
6579
- size_t ie, i, nf = 0;
6580
- char ch;
5327
+ size_t iend, idig = 0, iexp = 0, nspaces;
5328
+ char *p;
6581
5329
 
6582
5330
  if (fFmt == 0) return;
6583
5331
 
6584
- ie = strlen(psz);
6585
- for (i = 0; i < ie; ++i) {
6586
- ch = psz[i];
6587
- if (!ch) break;
6588
- if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
6589
- if (ch == '.') { nf = 0; continue; }
6590
- if (ch == 'E' || ch == 'e') break;
6591
-
6592
- if (++nf > fFmt) {
6593
- memmove(psz + i + 1, psz + i, ie - i + 1);
6594
- ++ie;
6595
- nf = 0;
6596
- psz[i] = ' ';
6597
- }
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;
6598
5350
  }
6599
5351
  }
6600
5352
 
@@ -6644,8 +5396,8 @@ VpSzMantissa(Real *a, char *buf, size_t buflen)
6644
5396
  while (m) {
6645
5397
  nn = e / m;
6646
5398
  if (!ZeroSup || nn) {
6647
- snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */
6648
- buf += strlen(buf);
5399
+ *buf = (char)('0' + nn);
5400
+ buf++;
6649
5401
  /* as 0.00xx will be ignored. */
6650
5402
  ZeroSup = 0; /* Set to print succeeding zeros */
6651
5403
  }
@@ -6697,10 +5449,22 @@ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
6697
5449
  return 0;
6698
5450
  }
6699
5451
 
5452
+ #define ULLTOA_BUFFER_SIZE 20
5453
+ static size_t Vp_ulltoa(unsigned long long number, char *buf)
5454
+ {
5455
+ static const char digits[] = "0123456789";
5456
+ char* tmp = buf;
5457
+
5458
+ do *tmp-- = digits[number % 10]; while (number /= 10);
5459
+ return buf - tmp;
5460
+ }
5461
+
6700
5462
  VP_EXPORT void
6701
5463
  VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6702
5464
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6703
5465
  {
5466
+ char ulltoa_buf[ULLTOA_BUFFER_SIZE];
5467
+ char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
6704
5468
  size_t i, n, ZeroSup;
6705
5469
  DECDIG shift, m, e, nn;
6706
5470
  char *p = buf;
@@ -6740,10 +5504,9 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6740
5504
  while (m) {
6741
5505
  nn = e / m;
6742
5506
  if (!ZeroSup || nn) {
6743
- /* The reading zero(s) */
6744
- size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn);
6745
- if (n > plen) goto overflow;
6746
- ADVANCE(n);
5507
+ *p = (char)('0' + nn);
5508
+ ADVANCE(1);
5509
+
6747
5510
  /* as 0.00xx will be ignored. */
6748
5511
  ZeroSup = 0; /* Set to print succeeding zeros */
6749
5512
  }
@@ -6762,7 +5525,22 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6762
5525
  *(--p) = '\0';
6763
5526
  ++plen;
6764
5527
  }
6765
- snprintf(p, plen, "e%"PRIdSIZE, ex);
5528
+ *p = 'e';
5529
+ ADVANCE(1);
5530
+
5531
+ if (ex < 0) {
5532
+ *p = '-';
5533
+ ADVANCE(1);
5534
+ ex = -ex;
5535
+ }
5536
+
5537
+ size_t ex_n = Vp_ulltoa(ex, ulltoa_buf_end - 1);
5538
+ if (ex_n > plen) goto overflow;
5539
+ MEMCPY(p, ulltoa_buf_end - ex_n, char, ex_n);
5540
+ ADVANCE(ex_n);
5541
+ *p = '\0';
5542
+ ADVANCE(1);
5543
+
6766
5544
  if (fFmt) VpFormatSt(buf, fFmt);
6767
5545
 
6768
5546
  overflow:
@@ -6876,7 +5654,7 @@ VP_EXPORT int
6876
5654
  VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
6877
5655
  {
6878
5656
  size_t i, j, ind_a, ma, mi, me;
6879
- SIGNED_VALUE e, es, eb, ef;
5657
+ SIGNED_VALUE e;
6880
5658
  int sign, signe, exponent_overflow;
6881
5659
 
6882
5660
  /* get exponent part */
@@ -6899,23 +5677,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6899
5677
  ++me;
6900
5678
  }
6901
5679
  while (i < me) {
6902
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
6903
- es = e;
6904
- goto exp_overflow;
6905
- }
6906
- es = e * (SIGNED_VALUE)BASE_FIG;
6907
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
6908
- SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
6909
- goto exp_overflow;
6910
- e = e * 10 + exp_chr[i] - '0';
6911
- if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
6912
- goto exp_overflow;
6913
- if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
6914
- exp_overflow:
5680
+ int dig = exp_chr[i] - '0';
5681
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
5682
+ ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
6915
5683
  exponent_overflow = 1;
6916
- e = es; /* keep sign */
6917
5684
  break;
6918
5685
  }
5686
+ e = e * 10 + signe * dig;
6919
5687
  ++i;
6920
5688
  }
6921
5689
  }
@@ -6934,34 +5702,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
6934
5702
  ++mi;
6935
5703
  }
6936
5704
  }
5705
+ /* skip leading zeros in integer part */
5706
+ while (i < mi && int_chr[i] == '0') {
5707
+ ++i;
5708
+ --ni;
5709
+ }
6937
5710
 
6938
- e = signe * e; /* e: The value of exponent part. */
6939
- e = e + ni; /* set actual exponent size. */
6940
-
6941
- if (e > 0) signe = 1;
6942
- else signe = -1;
5711
+ /* set actual exponent size. */
5712
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
5713
+ exponent_overflow = 1;
5714
+ } else {
5715
+ e += ni;
5716
+ }
6943
5717
 
6944
5718
  /* Adjust the exponent so that it is the multiple of BASE_FIG. */
6945
- j = 0;
6946
- ef = 1;
6947
- while (ef) {
6948
- if (e >= 0) eb = e;
6949
- else eb = -e;
6950
- ef = eb / (SIGNED_VALUE)BASE_FIG;
6951
- ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
6952
- if (ef) {
6953
- ++j; /* Means to add one more preceding zero */
6954
- ++e;
6955
- }
5719
+ j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
5720
+ if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
5721
+ exponent_overflow = 1;
5722
+ } else {
5723
+ e += j;
6956
5724
  }
6957
5725
 
6958
- eb = e / (SIGNED_VALUE)BASE_FIG;
6959
-
6960
- if (exponent_overflow) {
5726
+ if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
6961
5727
  int zero = 1;
6962
5728
  for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
6963
5729
  for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
6964
- if (!zero && signe > 0) {
5730
+ if (!zero && e > 0) {
6965
5731
  VpSetInf(a, sign);
6966
5732
  VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
6967
5733
  }
@@ -7011,7 +5777,7 @@ Final:
7011
5777
  ++j;
7012
5778
  }
7013
5779
  a->Prec = ind_a + 1;
7014
- a->exponent = eb;
5780
+ a->exponent = e / (SIGNED_VALUE)BASE_FIG;
7015
5781
  VpSetSign(a, sign);
7016
5782
  VpNmlz(a);
7017
5783
  return 1;
@@ -7083,254 +5849,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
7083
5849
  *d *= VpGetSign(m);
7084
5850
 
7085
5851
  Exit:
7086
- #ifdef BIGDECIMAL_DEBUG
7087
- if (gfDebug) {
7088
- VPrint(stdout, " VpVtoD: m=%\n", m);
7089
- printf(" d=%e * 10 **%ld\n", *d, *e);
7090
- printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
7091
- }
7092
- #endif /*BIGDECIMAL_DEBUG */
7093
5852
  return f;
7094
5853
  }
7095
5854
 
7096
- /*
7097
- * m <- d
7098
- */
7099
- VP_EXPORT void
7100
- VpDtoV(Real *m, double d)
7101
- {
7102
- size_t ind_m, mm;
7103
- SIGNED_VALUE ne;
7104
- DECDIG i;
7105
- double val, val2;
7106
-
7107
- if (isnan(d)) {
7108
- VpSetNaN(m);
7109
- goto Exit;
7110
- }
7111
- if (isinf(d)) {
7112
- if (d > 0.0) VpSetPosInf(m);
7113
- else VpSetNegInf(m);
7114
- goto Exit;
7115
- }
7116
-
7117
- if (d == 0.0) {
7118
- VpSetZero(m, 1);
7119
- goto Exit;
7120
- }
7121
- val = (d > 0.) ? d : -d;
7122
- ne = 0;
7123
- if (val >= 1.0) {
7124
- while (val >= 1.0) {
7125
- val /= (double)BASE;
7126
- ++ne;
7127
- }
7128
- }
7129
- else {
7130
- val2 = 1.0 / (double)BASE;
7131
- while (val < val2) {
7132
- val *= (double)BASE;
7133
- --ne;
7134
- }
7135
- }
7136
- /* Now val = 0.xxxxx*BASE**ne */
7137
-
7138
- mm = m->MaxPrec;
7139
- memset(m->frac, 0, mm * sizeof(DECDIG));
7140
- for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
7141
- val *= (double)BASE;
7142
- i = (DECDIG)val;
7143
- val -= (double)i;
7144
- m->frac[ind_m] = i;
7145
- }
7146
- if (ind_m >= mm) ind_m = mm - 1;
7147
- VpSetSign(m, (d > 0.0) ? 1 : -1);
7148
- m->Prec = ind_m + 1;
7149
- m->exponent = ne;
7150
-
7151
- VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
7152
- (DECDIG)(val*(double)BASE));
7153
-
7154
- Exit:
7155
- #ifdef BIGDECIMAL_DEBUG
7156
- if (gfDebug) {
7157
- printf("VpDtoV d=%30.30e\n", d);
7158
- VPrint(stdout, " m=%\n", m);
7159
- }
7160
- #endif /* BIGDECIMAL_DEBUG */
7161
- return;
7162
- }
7163
-
7164
- /*
7165
- * m <- ival
7166
- */
7167
- #if 0 /* unused */
7168
- VP_EXPORT void
7169
- VpItoV(Real *m, SIGNED_VALUE ival)
7170
- {
7171
- size_t mm, ind_m;
7172
- size_t val, v1, v2, v;
7173
- int isign;
7174
- SIGNED_VALUE ne;
7175
-
7176
- if (ival == 0) {
7177
- VpSetZero(m, 1);
7178
- goto Exit;
7179
- }
7180
- isign = 1;
7181
- val = ival;
7182
- if (ival < 0) {
7183
- isign = -1;
7184
- val =(size_t)(-ival);
7185
- }
7186
- ne = 0;
7187
- ind_m = 0;
7188
- mm = m->MaxPrec;
7189
- while (ind_m < mm) {
7190
- m->frac[ind_m] = 0;
7191
- ++ind_m;
7192
- }
7193
- ind_m = 0;
7194
- while (val > 0) {
7195
- if (val) {
7196
- v1 = val;
7197
- v2 = 1;
7198
- while (v1 >= BASE) {
7199
- v1 /= BASE;
7200
- v2 *= BASE;
7201
- }
7202
- val = val - v2 * v1;
7203
- v = v1;
7204
- }
7205
- else {
7206
- v = 0;
7207
- }
7208
- m->frac[ind_m] = v;
7209
- ++ind_m;
7210
- ++ne;
7211
- }
7212
- m->Prec = ind_m - 1;
7213
- m->exponent = ne;
7214
- VpSetSign(m, isign);
7215
- VpNmlz(m);
7216
-
7217
- Exit:
7218
- #ifdef BIGDECIMAL_DEBUG
7219
- if (gfDebug) {
7220
- printf(" VpItoV i=%d\n", ival);
7221
- VPrint(stdout, " m=%\n", m);
7222
- }
7223
- #endif /* BIGDECIMAL_DEBUG */
7224
- return;
7225
- }
7226
- #endif
7227
-
7228
- /*
7229
- * y = SQRT(x), y*y - x =>0
7230
- */
7231
- VP_EXPORT int
7232
- VpSqrt(Real *y, Real *x)
7233
- {
7234
- Real *f = NULL;
7235
- Real *r = NULL;
7236
- size_t y_prec;
7237
- SIGNED_VALUE n, e;
7238
- ssize_t nr;
7239
- double val;
7240
-
7241
- /* Zero or +Infinity ? */
7242
- if (VpIsZero(x) || VpIsPosInf(x)) {
7243
- VpAsgn(y,x,1);
7244
- goto Exit;
7245
- }
7246
-
7247
- /* Negative ? */
7248
- if (BIGDECIMAL_NEGATIVE_P(x)) {
7249
- VpSetNaN(y);
7250
- return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
7251
- }
7252
-
7253
- /* NaN ? */
7254
- if (VpIsNaN(x)) {
7255
- VpSetNaN(y);
7256
- return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
7257
- }
7258
-
7259
- /* One ? */
7260
- if (VpIsOne(x)) {
7261
- VpSetOne(y);
7262
- goto Exit;
7263
- }
7264
-
7265
- n = (SIGNED_VALUE)y->MaxPrec;
7266
- if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
7267
-
7268
- /* allocate temporally variables */
7269
- /* TODO: reconsider MaxPrec of f and r */
7270
- f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7271
- r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
7272
-
7273
- nr = 0;
7274
- y_prec = y->MaxPrec;
7275
-
7276
- VpVtoD(&val, &e, x); /* val <- x */
7277
- e /= (SIGNED_VALUE)BASE_FIG;
7278
- n = e / 2;
7279
- if (e - n * 2 != 0) {
7280
- val /= BASE;
7281
- n = (e + 1) / 2;
7282
- }
7283
- VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
7284
- y->exponent += n;
7285
- n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
7286
- y->MaxPrec = Min((size_t)n , y_prec);
7287
- f->MaxPrec = y->MaxPrec + 1;
7288
- n = (SIGNED_VALUE)(y_prec * BASE_FIG);
7289
- if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7290
-
7291
- /*
7292
- * Perform: y_{n+1} = (y_n - x/y_n) / 2
7293
- */
7294
- do {
7295
- y->MaxPrec *= 2;
7296
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7297
- f->MaxPrec = y->MaxPrec;
7298
- VpDivd(f, r, x, y); /* f = x/y */
7299
- VpAddSub(r, f, y, -1); /* r = f - y */
7300
- VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7301
- if (VpIsZero(f))
7302
- goto converge;
7303
- VpAddSub(r, f, y, 1); /* r = y + f */
7304
- VpAsgn(y, r, 1); /* y = r */
7305
- } while (++nr < n);
7306
-
7307
- #ifdef BIGDECIMAL_DEBUG
7308
- if (gfDebug) {
7309
- printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
7310
- }
7311
- #endif /* BIGDECIMAL_DEBUG */
7312
- y->MaxPrec = y_prec;
7313
-
7314
- converge:
7315
- VpChangeSign(y, 1);
7316
- #ifdef BIGDECIMAL_DEBUG
7317
- if (gfDebug) {
7318
- VpMult(r, y, y);
7319
- VpAddSub(f, x, r, -1);
7320
- printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
7321
- VPrint(stdout, " y =% \n", y);
7322
- VPrint(stdout, " x =% \n", x);
7323
- VPrint(stdout, " x-y*y = % \n", f);
7324
- }
7325
- #endif /* BIGDECIMAL_DEBUG */
7326
- y->MaxPrec = y_prec;
7327
-
7328
- Exit:
7329
- rbd_free_struct(f);
7330
- rbd_free_struct(r);
7331
- return 1;
7332
- }
7333
-
7334
5855
  /*
7335
5856
  * Round relatively from the decimal point.
7336
5857
  * f: rounding mode
@@ -7507,7 +6028,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
7507
6028
  DECDIG v;
7508
6029
  if (!VpHasVal(y)) return 0; /* Unable to round */
7509
6030
  v = y->frac[0];
7510
- nf -= VpExponent(y) * (ssize_t)BASE_FIG;
6031
+ nf -= y->exponent * (ssize_t)BASE_FIG;
7511
6032
  while ((v /= 10) != 0) nf--;
7512
6033
  nf += (ssize_t)BASE_FIG-1;
7513
6034
  return VpMidRound(y, f, nf);
@@ -7614,7 +6135,7 @@ VpFrac(Real *y, Real *x)
7614
6135
  size_t my, ind_y, ind_x;
7615
6136
 
7616
6137
  if (!VpHasVal(x)) {
7617
- VpAsgn(y, x, 1);
6138
+ VpAsgn(y, x, 10);
7618
6139
  goto Exit;
7619
6140
  }
7620
6141
 
@@ -7623,7 +6144,7 @@ VpFrac(Real *y, Real *x)
7623
6144
  goto Exit;
7624
6145
  }
7625
6146
  else if (x->exponent <= 0) {
7626
- VpAsgn(y, x, 1);
6147
+ VpAsgn(y, x, 10);
7627
6148
  goto Exit;
7628
6149
  }
7629
6150
 
@@ -7644,117 +6165,9 @@ VpFrac(Real *y, Real *x)
7644
6165
  VpNmlz(y);
7645
6166
 
7646
6167
  Exit:
7647
- #ifdef BIGDECIMAL_DEBUG
7648
- if (gfDebug) {
7649
- VPrint(stdout, "VpFrac y=%\n", y);
7650
- VPrint(stdout, " x=%\n", x);
7651
- }
7652
- #endif /* BIGDECIMAL_DEBUG */
7653
6168
  return;
7654
6169
  }
7655
6170
 
7656
- /*
7657
- * y = x ** n
7658
- */
7659
- VP_EXPORT int
7660
- VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7661
- {
7662
- size_t s, ss;
7663
- ssize_t sign;
7664
- Real *w1 = NULL;
7665
- Real *w2 = NULL;
7666
-
7667
- if (VpIsZero(x)) {
7668
- if (n == 0) {
7669
- VpSetOne(y);
7670
- goto Exit;
7671
- }
7672
- sign = VpGetSign(x);
7673
- if (n < 0) {
7674
- n = -n;
7675
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7676
- VpSetInf(y, sign);
7677
- }
7678
- else {
7679
- if (sign < 0) sign = (n % 2) ? -1 : 1;
7680
- VpSetZero(y,sign);
7681
- }
7682
- goto Exit;
7683
- }
7684
- if (VpIsNaN(x)) {
7685
- VpSetNaN(y);
7686
- goto Exit;
7687
- }
7688
- if (VpIsInf(x)) {
7689
- if (n == 0) {
7690
- VpSetOne(y);
7691
- goto Exit;
7692
- }
7693
- if (n > 0) {
7694
- VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7695
- goto Exit;
7696
- }
7697
- VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
7698
- goto Exit;
7699
- }
7700
-
7701
- if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
7702
- /* abs(x) = 1 */
7703
- VpSetOne(y);
7704
- if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
7705
- if ((n % 2) == 0) goto Exit;
7706
- VpSetSign(y, -1);
7707
- goto Exit;
7708
- }
7709
-
7710
- if (n > 0) sign = 1;
7711
- else if (n < 0) {
7712
- sign = -1;
7713
- n = -n;
7714
- }
7715
- else {
7716
- VpSetOne(y);
7717
- goto Exit;
7718
- }
7719
-
7720
- /* Allocate working variables */
7721
- /* TODO: reconsider MaxPrec of w1 and w2 */
7722
- w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7723
- w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7724
-
7725
- /* calculation start */
7726
-
7727
- VpAsgn(y, x, 1);
7728
- --n;
7729
- while (n > 0) {
7730
- VpAsgn(w1, x, 1);
7731
- s = 1;
7732
- while (ss = s, (s += s) <= (size_t)n) {
7733
- VpMult(w2, w1, w1);
7734
- VpAsgn(w1, w2, 1);
7735
- }
7736
- n -= (SIGNED_VALUE)ss;
7737
- VpMult(w2, y, w1);
7738
- VpAsgn(y, w2, 1);
7739
- }
7740
- if (sign < 0) {
7741
- VpDivd(w1, w2, VpConstOne, y);
7742
- VpAsgn(y, w1, 1);
7743
- }
7744
-
7745
- Exit:
7746
- #ifdef BIGDECIMAL_DEBUG
7747
- if (gfDebug) {
7748
- VPrint(stdout, "VpPowerByInt y=%\n", y);
7749
- VPrint(stdout, "VpPowerByInt x=%\n", x);
7750
- printf(" n=%"PRIdVALUE"\n", n);
7751
- }
7752
- #endif /* BIGDECIMAL_DEBUG */
7753
- rbd_free_struct(w2);
7754
- rbd_free_struct(w1);
7755
- return 1;
7756
- }
7757
-
7758
6171
  #ifdef BIGDECIMAL_DEBUG
7759
6172
  int
7760
6173
  VpVarCheck(Real * v)