bigdecimal 3.3.1 → 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,12 +29,16 @@
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.3.1"
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)
@@ -75,16 +79,6 @@ static struct {
75
79
  uint8_t mode;
76
80
  } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
77
81
 
78
- typedef struct {
79
- VALUE bigdecimal;
80
- Real *real;
81
- } BDVALUE;
82
-
83
- typedef struct {
84
- VALUE bigdecimal_or_nil;
85
- Real *real_or_null;
86
- } NULLABLE_BDVALUE;
87
-
88
82
  static inline BDVALUE
89
83
  bdvalue_nonnullable(NULLABLE_BDVALUE v)
90
84
  {
@@ -160,42 +154,6 @@ rbd_struct_size(size_t const internal_digits)
160
154
  return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
161
155
  }
162
156
 
163
- static inline Real *
164
- rbd_allocate_struct(size_t const internal_digits)
165
- {
166
- size_t const size = rbd_struct_size(internal_digits);
167
- Real *real = ruby_xcalloc(1, size);
168
- atomic_allocation_count_inc();
169
- real->MaxPrec = internal_digits;
170
- return real;
171
- }
172
-
173
- static inline Real *
174
- rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
175
- {
176
- return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
177
- }
178
-
179
- static void
180
- rbd_free_struct(Real *real)
181
- {
182
- if (real != NULL) {
183
- check_allocation_count_nonzero();
184
- ruby_xfree(real);
185
- atomic_allocation_count_dec_nounderflow();
186
- }
187
- }
188
-
189
- MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
190
- #define NewZero rbd_allocate_struct_zero
191
- static inline Real *
192
- rbd_allocate_struct_zero(int sign, size_t const digits)
193
- {
194
- Real *real = rbd_allocate_struct_decimal_digits(digits);
195
- VpSetZero(real, sign);
196
- return real;
197
- }
198
-
199
157
  /*
200
158
  * ================== Ruby Interface part ==========================
201
159
  */
@@ -207,11 +165,9 @@ rbd_allocate_struct_zero(int sign, size_t const digits)
207
165
  static unsigned short VpGetException(void);
208
166
  static void VpSetException(unsigned short f);
209
167
  static void VpCheckException(Real *p, bool always);
210
- static int AddExponent(Real *a, SIGNED_VALUE n);
211
168
  static VALUE CheckGetValue(BDVALUE v);
212
169
  static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
213
170
  static int VpLimitRound(Real *c, size_t ixDigit);
214
- static Real *VpCopy(Real *pv, Real const* const x);
215
171
  static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
216
172
 
217
173
  /*
@@ -226,49 +182,67 @@ static VALUE BigDecimal_negative_zero(void);
226
182
  static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
227
183
  static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
228
184
 
229
- static void
230
- BigDecimal_delete(void *pv)
231
- {
232
- rbd_free_struct(pv);
233
- }
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
234
200
 
235
201
  static size_t
236
202
  BigDecimal_memsize(const void *ptr)
237
203
  {
204
+ #ifdef HAVE_RUBY_TYPED_EMBEDDABLE
205
+ return 0; // Entirely embedded
206
+ #else
238
207
  const Real *pv = ptr;
239
208
  return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
240
- }
241
-
242
- #ifndef HAVE_RB_EXT_RACTOR_SAFE
243
- # undef RUBY_TYPED_FROZEN_SHAREABLE
244
- # define RUBY_TYPED_FROZEN_SHAREABLE 0
245
209
  #endif
210
+ }
246
211
 
247
212
  static const rb_data_type_t BigDecimal_data_type = {
248
- "BigDecimal",
249
- { 0, BigDecimal_delete, BigDecimal_memsize, },
250
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
251
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED
252
- #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,
253
220
  };
254
221
 
255
- // TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
256
- // We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
257
- typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
258
- static NULL_WRAPPED_VALUE
259
- BigDecimal_alloc_empty_struct(VALUE klass)
222
+ static VALUE
223
+ BigDecimal_allocate(size_t const internal_digits)
260
224
  {
261
- return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
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;
262
232
  }
263
233
 
264
234
  static VALUE
265
- BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
235
+ BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
266
236
  {
267
- VALUE obj = v._obj;
268
- assert(RTYPEDDATA_DATA(obj) == NULL);
269
- RTYPEDDATA_DATA(obj) = real;
270
- RB_OBJ_FREEZE(obj);
271
- return obj;
237
+ return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
238
+ }
239
+
240
+ static Real *
241
+ VpPtr(VALUE obj)
242
+ {
243
+ Real *vp;
244
+ TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
245
+ return vp;
272
246
  }
273
247
 
274
248
  MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
@@ -276,9 +250,10 @@ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_
276
250
  static BDVALUE
277
251
  rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
278
252
  {
279
- NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
280
- Real *real = rbd_allocate_struct_zero(sign, digits);
281
- return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
253
+ VALUE obj = BigDecimal_allocate_decimal_digits(digits);
254
+ Real *real = VpPtr(obj);
255
+ VpSetZero(real, sign);
256
+ return (BDVALUE) { obj, real };
282
257
  }
283
258
 
284
259
  static inline int
@@ -336,20 +311,11 @@ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
336
311
  break;
337
312
  }
338
313
 
339
- #ifdef ENABLE_NUMERIC_STRING
340
- case T_STRING: {
341
- const char *c_str = StringValueCStr(v);
342
- v = rb_cstr_convert_to_BigDecimal(c_str, must);
343
- break;
344
- }
345
- #endif /* ENABLE_NUMERIC_STRING */
346
-
347
314
  default:
348
315
  goto SomeOneMayDoIt;
349
316
  }
350
317
 
351
- Real *vp;
352
- TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
318
+ Real *vp = VpPtr(v);
353
319
  return (NULLABLE_BDVALUE) { v, vp };
354
320
 
355
321
  SomeOneMayDoIt:
@@ -400,37 +366,6 @@ BigDecimal_double_fig(VALUE self)
400
366
  return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
401
367
  }
402
368
 
403
- /* call-seq:
404
- * precs -> array
405
- *
406
- * Returns an Array of two Integer values that represent platform-dependent
407
- * internal storage properties.
408
- *
409
- * This method is deprecated and will be removed in the future.
410
- * Instead, use BigDecimal#n_significant_digits for obtaining the number of
411
- * significant digits in scientific notation, and BigDecimal#precision for
412
- * obtaining the number of digits in decimal notation.
413
- *
414
- */
415
-
416
- static VALUE
417
- BigDecimal_prec(VALUE self)
418
- {
419
- BDVALUE v;
420
- VALUE obj;
421
-
422
- rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
423
- "BigDecimal#precs is deprecated and will be removed in the future; "
424
- "use BigDecimal#precision instead.");
425
-
426
- v = GetBDValueMust(self);
427
- obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
428
- SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
429
-
430
- RB_GC_GUARD(v.bigdecimal);
431
- return obj;
432
- }
433
-
434
369
  static void
435
370
  VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
436
371
  {
@@ -1027,7 +962,7 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
1027
962
  static size_t
1028
963
  GetAddSubPrec(Real *a, Real *b)
1029
964
  {
1030
- if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
965
+ if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
1031
966
  ssize_t min_a = a->exponent - a->Prec;
1032
967
  ssize_t min_b = b->exponent - b->Prec;
1033
968
  return Max(a->exponent, b->exponent) - Min(min_a, min_b);
@@ -1053,26 +988,18 @@ check_int_precision(VALUE v)
1053
988
  static NULLABLE_BDVALUE
1054
989
  CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
1055
990
  {
1056
- NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
1057
- Real *pv = VpAlloc(str, strict_p, raise_exception);
1058
- if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
1059
- return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
991
+ return VpAlloc(str, strict_p, raise_exception);
1060
992
  }
1061
993
 
1062
- static Real *
1063
- VpCopy(Real *pv, Real const* const x)
994
+ void
995
+ VpMemCopy(Real *pv, Real const* const x)
1064
996
  {
1065
- assert(x != NULL);
1066
-
1067
- pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
1068
997
  pv->MaxPrec = x->MaxPrec;
1069
998
  pv->Prec = x->Prec;
1070
999
  pv->exponent = x->exponent;
1071
1000
  pv->sign = x->sign;
1072
1001
  pv->flag = x->flag;
1073
1002
  MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
1074
-
1075
- return pv;
1076
1003
  }
1077
1004
 
1078
1005
  /* Returns True if the value is Not a Number. */
@@ -1112,9 +1039,6 @@ BigDecimal_check_num(Real *p)
1112
1039
  VpCheckException(p, true);
1113
1040
  }
1114
1041
 
1115
- static VALUE BigDecimal_fix(VALUE self);
1116
- static VALUE BigDecimal_split(VALUE self);
1117
-
1118
1042
  /* Returns the value as an Integer.
1119
1043
  *
1120
1044
  * If the BigDecimal is infinity or NaN, raises FloatDomainError.
@@ -1265,7 +1189,7 @@ GetCoercePrec(Real *a, size_t prec)
1265
1189
  static VALUE
1266
1190
  BigDecimal_coerce(VALUE self, VALUE other)
1267
1191
  {
1268
- Real* pv = DATA_PTR(self);
1192
+ Real* pv = VpPtr(self);
1269
1193
  BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
1270
1194
  return rb_assoc_new(CheckGetValue(b), self);
1271
1195
  }
@@ -1331,13 +1255,32 @@ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
1331
1255
  if (VpIsNaN(a.real)) return CheckGetValue(a);
1332
1256
  if (VpIsNaN(b.real)) return CheckGetValue(b);
1333
1257
 
1334
- mx = GetAddSubPrec(a.real, b.real);
1335
- if (mx == (size_t)-1L) {
1336
- /* a or b is inf */
1258
+ if (VpIsInf(a.real) || VpIsInf(b.real)) {
1337
1259
  c = NewZeroWrap(1, BASE_FIG);
1338
1260
  VpAddSub(c.real, a.real, b.real, operation);
1339
1261
  }
1340
1262
  else {
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
+ }
1281
+ }
1282
+
1283
+ mx = GetAddSubPrec(a.real, b.real);
1341
1284
  c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
1342
1285
  size_t pl = VpGetPrecLimit();
1343
1286
  if (prec) VpSetPrecLimit(prec);
@@ -1714,7 +1657,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
1714
1657
 
1715
1658
  if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
1716
1659
  VALUE nan = BigDecimal_nan();
1717
- *div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1660
+ *div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
1718
1661
  goto Done;
1719
1662
  }
1720
1663
  if (VpIsZero(b.real)) {
@@ -1723,19 +1666,19 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
1723
1666
  if (VpIsInf(a.real)) {
1724
1667
  if (VpGetSign(a.real) == VpGetSign(b.real)) {
1725
1668
  VALUE inf = BigDecimal_positive_infinity();
1726
- *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1669
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1727
1670
  }
1728
1671
  else {
1729
1672
  VALUE inf = BigDecimal_negative_infinity();
1730
- *div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
1673
+ *div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
1731
1674
  }
1732
1675
  VALUE nan = BigDecimal_nan();
1733
- *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
1676
+ *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
1734
1677
  goto Done;
1735
1678
  }
1736
1679
  if (VpIsZero(a.real)) {
1737
1680
  VALUE zero = BigDecimal_positive_zero();
1738
- *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1681
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
1739
1682
  *mod = bdvalue_nullable(a);
1740
1683
  goto Done;
1741
1684
  }
@@ -1749,7 +1692,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
1749
1692
  *mod = bdvalue_nullable(b);
1750
1693
  } else {
1751
1694
  VALUE zero = BigDecimal_positive_zero();
1752
- *div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
1695
+ *div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
1753
1696
  *mod = bdvalue_nullable(a);
1754
1697
  }
1755
1698
  goto Done;
@@ -1867,7 +1810,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
1867
1810
  NULLABLE_BDVALUE div, mod;
1868
1811
 
1869
1812
  if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
1870
- return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
1813
+ return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
1871
1814
  }
1872
1815
  return DoSomeOne(self,r,rb_intern("divmod"));
1873
1816
  }
@@ -2507,7 +2450,7 @@ BigDecimal_decimal_shift(VALUE self, VALUE v)
2507
2450
  prec = a.real->Prec + shiftDown;
2508
2451
  c = NewZeroWrap(1, prec * BASE_FIG);
2509
2452
  if (shift == 0) {
2510
- VpAsgn(c.real, a.real, 1);
2453
+ VpAsgn(c.real, a.real, 10);
2511
2454
  } else if (shiftDown) {
2512
2455
  DECDIG carry = 0;
2513
2456
  exponentShift++;
@@ -2593,9 +2536,7 @@ check_exception(VALUE bd)
2593
2536
  {
2594
2537
  assert(is_kind_of_BigDecimal(bd));
2595
2538
 
2596
- Real *vp;
2597
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2598
- VpCheckException(vp, false);
2539
+ VpCheckException(VpPtr(bd), false);
2599
2540
 
2600
2541
  return bd;
2601
2542
  }
@@ -2603,17 +2544,19 @@ check_exception(VALUE bd)
2603
2544
  static VALUE
2604
2545
  rb_uint64_convert_to_BigDecimal(uint64_t uval)
2605
2546
  {
2606
- NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
2547
+ VALUE bd;
2607
2548
  Real *vp;
2608
2549
  if (uval == 0) {
2609
- vp = rbd_allocate_struct(1);
2550
+ bd = BigDecimal_allocate(1);
2551
+ vp = VpPtr(bd);
2610
2552
  vp->Prec = 1;
2611
2553
  vp->exponent = 1;
2612
2554
  VpSetZero(vp, 1);
2613
2555
  vp->frac[0] = 0;
2614
2556
  }
2615
2557
  else if (uval < BASE) {
2616
- vp = rbd_allocate_struct(1);
2558
+ bd = BigDecimal_allocate(1);
2559
+ vp = VpPtr(bd);
2617
2560
  vp->Prec = 1;
2618
2561
  vp->exponent = 1;
2619
2562
  VpSetSign(vp, 1);
@@ -2638,14 +2581,15 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval)
2638
2581
  }
2639
2582
 
2640
2583
  const size_t exp = len + ntz;
2641
- vp = rbd_allocate_struct(len);
2584
+ bd = BigDecimal_allocate(len);
2585
+ vp = VpPtr(bd);
2642
2586
  vp->Prec = len;
2643
2587
  vp->exponent = exp;
2644
2588
  VpSetSign(vp, 1);
2645
2589
  MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
2646
2590
  }
2647
2591
 
2648
- return BigDecimal_wrap_struct(null_wrapped, vp);
2592
+ return bd;
2649
2593
  }
2650
2594
 
2651
2595
  static VALUE
@@ -2654,8 +2598,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival)
2654
2598
  const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
2655
2599
  VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
2656
2600
  if (ival < 0) {
2657
- Real *vp;
2658
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2601
+ Real *vp = VpPtr(bd);
2659
2602
  VpSetSign(vp, -1);
2660
2603
  }
2661
2604
  return bd;
@@ -2766,7 +2709,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2766
2709
  len10 = BIGDECIMAL_DOUBLE_FIGURES;
2767
2710
  }
2768
2711
  memcpy(buf, p, len10);
2769
- xfree(p);
2712
+ free(p);
2770
2713
 
2771
2714
  VALUE inum;
2772
2715
  size_t RB_UNUSED_VAR(prec) = 0;
@@ -2862,8 +2805,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2862
2805
  }
2863
2806
 
2864
2807
  VALUE bd = rb_inum_convert_to_BigDecimal(inum);
2865
- Real *vp;
2866
- TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
2808
+ Real *vp = VpPtr(bd);
2867
2809
  assert(vp->Prec == prec);
2868
2810
  vp->exponent = exp;
2869
2811
 
@@ -2929,13 +2871,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
2929
2871
  if (digs == SIZE_MAX)
2930
2872
  return check_exception(val);
2931
2873
 
2932
- NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
2933
- Real *vp;
2934
- TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
2935
- vp = VpCopy(NULL, 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
+
2936
2881
  RB_GC_GUARD(val);
2937
2882
 
2938
- VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
2939
2883
  /* TODO: rounding */
2940
2884
  return check_exception(copy);
2941
2885
  }
@@ -3257,19 +3201,39 @@ BigDecimal_literal(const char *str)
3257
3201
 
3258
3202
  #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3259
3203
  VALUE
3260
- BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
3261
- BDVALUE a,b,c,d;
3204
+ BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
3205
+ BDVALUE a, b, c, d;
3262
3206
  size_t cn = NUM2INT(cprec);
3263
3207
  a = GetBDValueMust(self);
3264
3208
  b = GetBDValueMust(r);
3265
3209
  c = NewZeroWrap(1, cn * BASE_FIG);
3266
3210
  d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
3267
- VpDivd(c.real, d.real, a.real, b.real);
3211
+ vpdivd_func(c.real, d.real, a.real, b.real);
3268
3212
  RB_GC_GUARD(a.bigdecimal);
3269
3213
  RB_GC_GUARD(b.bigdecimal);
3270
3214
  return rb_assoc_new(c.bigdecimal, d.bigdecimal);
3271
3215
  }
3272
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
+
3273
3237
  VALUE
3274
3238
  BigDecimal_vpmult(VALUE self, VALUE v) {
3275
3239
  BDVALUE a,b,c;
@@ -3281,6 +3245,23 @@ BigDecimal_vpmult(VALUE self, VALUE v) {
3281
3245
  RB_GC_GUARD(b.bigdecimal);
3282
3246
  return c.bigdecimal;
3283
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
+
3284
3265
  #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3285
3266
 
3286
3267
  /* Document-class: BigDecimal
@@ -3593,7 +3574,6 @@ Init_bigdecimal(void)
3593
3574
  rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
3594
3575
 
3595
3576
  /* instance methods */
3596
- rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
3597
3577
  rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
3598
3578
  rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
3599
3579
  rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
@@ -3652,7 +3632,10 @@ Init_bigdecimal(void)
3652
3632
 
3653
3633
  #ifdef BIGDECIMAL_USE_VP_TEST_METHODS
3654
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);
3655
3637
  rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
3638
+ rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
3656
3639
  #endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
3657
3640
 
3658
3641
  #define ROUNDING_MODE(i, name, value) \
@@ -3695,7 +3678,7 @@ Init_bigdecimal(void)
3695
3678
  static int gfDebug = 1; /* Debug switch */
3696
3679
  #endif /* BIGDECIMAL_DEBUG */
3697
3680
 
3698
- static Real *VpConstOne; /* constant 1.0 */
3681
+ static VALUE VpConstOne; /* constant 1.0 */
3699
3682
 
3700
3683
  enum op_sw {
3701
3684
  OP_SW_ADD = 1, /* + */
@@ -4096,8 +4079,9 @@ VpInit(DECDIG BaseVal)
4096
4079
  VpGetDoubleNegZero();
4097
4080
 
4098
4081
  /* Const 1.0 */
4099
- VpConstOne = NewZero(1, 1);
4100
- VpSetOne(VpConstOne);
4082
+ rb_global_variable(&VpConstOne);
4083
+ VpConstOne = NewZeroWrap(1, 1).bigdecimal;
4084
+ VpSetOne(VpPtr(VpConstOne));
4101
4085
 
4102
4086
  #ifdef BIGDECIMAL_DEBUG
4103
4087
  gnAlloc = 0;
@@ -4109,7 +4093,7 @@ VpInit(DECDIG BaseVal)
4109
4093
  VP_EXPORT Real *
4110
4094
  VpOne(void)
4111
4095
  {
4112
- return VpConstOne;
4096
+ return VpPtr(VpConstOne);
4113
4097
  }
4114
4098
 
4115
4099
  /* If exponent overflows,then raise exception or returns 0 */
@@ -4140,7 +4124,7 @@ overflow:
4140
4124
  return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
4141
4125
  }
4142
4126
 
4143
- Real *
4127
+ NULLABLE_BDVALUE
4144
4128
  bigdecimal_parse_special_string(const char *str)
4145
4129
  {
4146
4130
  static const struct {
@@ -4165,66 +4149,27 @@ bigdecimal_parse_special_string(const char *str)
4165
4149
  p = str + table[i].len;
4166
4150
  while (*p && ISSPACE(*p)) ++p;
4167
4151
  if (*p == '\0') {
4168
- Real *vp = rbd_allocate_struct(1);
4152
+ VALUE obj = BigDecimal_allocate(1);
4153
+ Real *vp = VpPtr(obj);
4169
4154
  switch (table[i].sign) {
4170
4155
  default:
4171
- UNREACHABLE; break;
4156
+ UNREACHABLE;
4157
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
4172
4158
  case VP_SIGN_POSITIVE_INFINITE:
4173
4159
  VpSetPosInf(vp);
4174
- return vp;
4160
+ break;
4175
4161
  case VP_SIGN_NEGATIVE_INFINITE:
4176
4162
  VpSetNegInf(vp);
4177
- return vp;
4163
+ break;
4178
4164
  case VP_SIGN_NaN:
4179
4165
  VpSetNaN(vp);
4180
- return vp;
4166
+ break;
4181
4167
  }
4168
+ return (NULLABLE_BDVALUE) { obj, vp };
4182
4169
  }
4183
4170
  }
4184
4171
 
4185
- return NULL;
4186
- }
4187
-
4188
- struct VpCtoV_args {
4189
- Real *a;
4190
- const char *int_chr;
4191
- size_t ni;
4192
- const char *frac;
4193
- size_t nf;
4194
- const char *exp_chr;
4195
- size_t ne;
4196
- };
4197
-
4198
- static VALUE
4199
- call_VpCtoV(VALUE arg)
4200
- {
4201
- struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
4202
- return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
4203
- }
4204
-
4205
- static int
4206
- 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)
4207
- {
4208
- struct VpCtoV_args args;
4209
- int state = 0;
4210
-
4211
- args.a = a;
4212
- args.int_chr = int_chr;
4213
- args.ni = ni;
4214
- args.frac = frac;
4215
- args.nf = nf;
4216
- args.exp_chr = exp_chr;
4217
- args.ne = ne;
4218
-
4219
- VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
4220
- if (state) {
4221
- if (free_on_error) {
4222
- rbd_free_struct(a);
4223
- }
4224
- rb_jump_tag(state);
4225
- }
4226
-
4227
- return (int)result;
4172
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
4228
4173
  }
4229
4174
 
4230
4175
  /*
@@ -4233,25 +4178,25 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
4233
4178
  * szVal ... The value assigned(char).
4234
4179
  *
4235
4180
  * [Returns]
4236
- * Pointer to the newly allocated variable, or
4237
- * 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.
4238
4183
  */
4239
- VP_EXPORT Real *
4184
+ VP_EXPORT NULLABLE_BDVALUE
4240
4185
  VpAlloc(const char *szVal, int strict_p, int exc)
4241
4186
  {
4242
4187
  const char *orig_szVal = szVal;
4243
4188
  size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
4244
4189
  char v, *psz;
4245
4190
  int sign=1;
4246
- Real *vp = NULL;
4247
4191
  VALUE buf;
4248
4192
 
4249
4193
  /* Skipping leading spaces */
4250
4194
  while (ISSPACE(*szVal)) szVal++;
4251
4195
 
4252
4196
  /* Check on Inf & NaN */
4253
- if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
4254
- return vp;
4197
+ NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
4198
+ if (special_bd.real_or_null != NULL) {
4199
+ return special_bd;
4255
4200
  }
4256
4201
 
4257
4202
  /* Skip leading `#`.
@@ -4405,10 +4350,11 @@ VpAlloc(const char *szVal, int strict_p, int exc)
4405
4350
  VALUE str;
4406
4351
  invalid_value:
4407
4352
  if (!strict_p) {
4408
- return NewZero(1, 1);
4353
+ BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
4354
+ return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
4409
4355
  }
4410
4356
  if (!exc) {
4411
- return NULL;
4357
+ return (NULLABLE_BDVALUE) { Qnil, NULL };
4412
4358
  }
4413
4359
  str = rb_str_new2(orig_szVal);
4414
4360
  rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
@@ -4416,11 +4362,12 @@ VpAlloc(const char *szVal, int strict_p, int exc)
4416
4362
 
4417
4363
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
4418
4364
  /* units for szVal[] */
4419
- vp = rbd_allocate_struct(nalloc);
4365
+ VALUE obj = BigDecimal_allocate(nalloc);
4366
+ Real *vp = VpPtr(obj);
4420
4367
  VpSetZero(vp, sign);
4421
- protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
4368
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
4422
4369
  rb_str_resize(buf, 0);
4423
- return vp;
4370
+ return (NULLABLE_BDVALUE) { obj, vp };
4424
4371
  }
4425
4372
 
4426
4373
  /*
@@ -4892,17 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
4892
4839
  * a0 a1 .... an * b0
4893
4840
  * +_____________________________
4894
4841
  * c0 c1 c2 ...... cl
4895
- * nc <---|
4896
- * MaxAB |--------------------|
4897
4842
  */
4898
4843
  VP_EXPORT size_t
4899
4844
  VpMult(Real *c, Real *a, Real *b)
4900
4845
  {
4901
- size_t MxIndA, MxIndB, MxIndAB;
4902
- size_t ind_c, i, ii, nc;
4903
- size_t ind_as, ind_ae, ind_bs;
4904
- DECDIG carry;
4905
- DECDIG_DBL s;
4846
+ ssize_t a_batch_max, b_batch_max;
4847
+ DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
4906
4848
 
4907
4849
  if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
4908
4850
 
@@ -4926,61 +4868,57 @@ VpMult(Real *c, Real *a, Real *b)
4926
4868
  a = b;
4927
4869
  b = w;
4928
4870
  }
4929
- MxIndA = a->Prec - 1;
4930
- MxIndB = b->Prec - 1;
4931
- MxIndAB = a->Prec + b->Prec - 1;
4932
4871
 
4933
4872
  /* set LHSV c info */
4934
4873
 
4935
4874
  c->exponent = a->exponent; /* set exponent */
4936
4875
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
4937
4876
  if (!AddExponent(c, b->exponent)) return 0;
4938
- carry = 0;
4939
- nc = ind_c = MxIndAB;
4940
- memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
4941
- c->Prec = nc + 1; /* set precision */
4942
- for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
4943
- if (nc < MxIndB) { /* The left triangle of the Fig. */
4944
- ind_as = MxIndA - nc;
4945
- ind_ae = MxIndA;
4946
- ind_bs = MxIndB;
4947
- }
4948
- else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
4949
- ind_as = MxIndA - nc;
4950
- ind_ae = MxIndA - (nc - MxIndB);
4951
- ind_bs = MxIndB;
4952
- }
4953
- else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
4954
- ind_as = 0;
4955
- ind_ae = MxIndAB - nc - 1;
4956
- ind_bs = MxIndB - (nc - MxIndA);
4957
- }
4958
4877
 
4959
- for (i = ind_as; i <= ind_ae; ++i) {
4960
- s = (DECDIG_DBL)a->frac[i] * b->frac[ind_bs--];
4961
- carry = (DECDIG)(s / BASE);
4962
- s -= (DECDIG_DBL)carry * BASE;
4963
- c->frac[ind_c] += (DECDIG)s;
4964
- if (c->frac[ind_c] >= BASE) {
4965
- s = c->frac[ind_c] / BASE;
4966
- carry += (DECDIG)s;
4967
- c->frac[ind_c] -= (DECDIG)(s * BASE);
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
+ }
4968
4903
  }
4969
- if (carry) {
4970
- ii = ind_c;
4971
- while (ii-- > 0) {
4972
- c->frac[ii] += carry;
4973
- if (c->frac[ii] >= BASE) {
4974
- carry = c->frac[ii] / BASE;
4975
- c->frac[ii] -= (carry * BASE);
4976
- }
4977
- else {
4978
- break;
4979
- }
4980
- }
4981
- }
4982
- }
4904
+
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);
4912
+ }
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
+ }
4983
4919
  }
4920
+
4921
+ Cleanup:
4984
4922
  VpNmlz(c);
4985
4923
 
4986
4924
  Exit:
@@ -5028,6 +4966,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
5028
4966
 
5029
4967
  if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
5030
4968
 
4969
+ if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
4970
+ VpDivdNewton(c, r, a, b);
4971
+ goto Exit;
4972
+ }
4973
+
5031
4974
  for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
5032
4975
  for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
5033
4976
  for (i = 0; i < word_c; ++i) c->frac[i] = 0;
@@ -5453,8 +5396,8 @@ VpSzMantissa(Real *a, char *buf, size_t buflen)
5453
5396
  while (m) {
5454
5397
  nn = e / m;
5455
5398
  if (!ZeroSup || nn) {
5456
- snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */
5457
- buf += strlen(buf);
5399
+ *buf = (char)('0' + nn);
5400
+ buf++;
5458
5401
  /* as 0.00xx will be ignored. */
5459
5402
  ZeroSup = 0; /* Set to print succeeding zeros */
5460
5403
  }
@@ -5506,10 +5449,22 @@ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
5506
5449
  return 0;
5507
5450
  }
5508
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
+
5509
5462
  VP_EXPORT void
5510
5463
  VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
5511
5464
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
5512
5465
  {
5466
+ char ulltoa_buf[ULLTOA_BUFFER_SIZE];
5467
+ char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
5513
5468
  size_t i, n, ZeroSup;
5514
5469
  DECDIG shift, m, e, nn;
5515
5470
  char *p = buf;
@@ -5549,10 +5504,9 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
5549
5504
  while (m) {
5550
5505
  nn = e / m;
5551
5506
  if (!ZeroSup || nn) {
5552
- /* The reading zero(s) */
5553
- size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn);
5554
- if (n > plen) goto overflow;
5555
- ADVANCE(n);
5507
+ *p = (char)('0' + nn);
5508
+ ADVANCE(1);
5509
+
5556
5510
  /* as 0.00xx will be ignored. */
5557
5511
  ZeroSup = 0; /* Set to print succeeding zeros */
5558
5512
  }
@@ -5571,7 +5525,22 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
5571
5525
  *(--p) = '\0';
5572
5526
  ++plen;
5573
5527
  }
5574
- 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
+
5575
5544
  if (fFmt) VpFormatSt(buf, fFmt);
5576
5545
 
5577
5546
  overflow:
@@ -6166,7 +6135,7 @@ VpFrac(Real *y, Real *x)
6166
6135
  size_t my, ind_y, ind_x;
6167
6136
 
6168
6137
  if (!VpHasVal(x)) {
6169
- VpAsgn(y, x, 1);
6138
+ VpAsgn(y, x, 10);
6170
6139
  goto Exit;
6171
6140
  }
6172
6141
 
@@ -6175,7 +6144,7 @@ VpFrac(Real *y, Real *x)
6175
6144
  goto Exit;
6176
6145
  }
6177
6146
  else if (x->exponent <= 0) {
6178
- VpAsgn(y, x, 1);
6147
+ VpAsgn(y, x, 10);
6179
6148
  goto Exit;
6180
6149
  }
6181
6150