bigdecimal 3.1.0 → 3.1.6

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.
@@ -7,9 +7,7 @@
7
7
  */
8
8
 
9
9
  /* #define BIGDECIMAL_DEBUG 1 */
10
- #ifdef BIGDECIMAL_DEBUG
11
- # define BIGDECIMAL_ENABLE_VPRINT 1
12
- #endif
10
+
13
11
  #include "bigdecimal.h"
14
12
  #include "ruby/util.h"
15
13
 
@@ -33,6 +31,8 @@
33
31
  #include "bits.h"
34
32
  #include "static_assert.h"
35
33
 
34
+ #define BIGDECIMAL_VERSION "3.1.6"
35
+
36
36
  /* #define ENABLE_NUMERIC_STRING */
37
37
 
38
38
  #define SIGNED_VALUE_MAX INTPTR_MAX
@@ -61,6 +61,13 @@ static ID id_to_r;
61
61
  static ID id_eq;
62
62
  static ID id_half;
63
63
 
64
+ #define RBD_NUM_ROUNDING_MODES 11
65
+
66
+ static struct {
67
+ ID id;
68
+ uint8_t mode;
69
+ } rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
70
+
64
71
  /* MACRO's to guard objects from GC by keeping them in stack */
65
72
  #ifdef RBIMPL_ATTR_MAYBE_UNUSED
66
73
  #define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0
@@ -102,9 +109,163 @@ static ID id_half;
102
109
  # define RB_OBJ_STRING(obj) StringValueCStr(obj)
103
110
  #endif
104
111
 
112
+ #ifndef MAYBE_UNUSED
113
+ # define MAYBE_UNUSED(x) x
114
+ #endif
115
+
105
116
  #define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0)
106
117
  #define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0)
107
118
 
119
+ /*
120
+ * ================== Memory allocation ============================
121
+ */
122
+
123
+ #ifdef BIGDECIMAL_DEBUG
124
+ static size_t rbd_allocation_count = 0; /* Memory allocation counter */
125
+ static inline void
126
+ atomic_allocation_count_inc(void)
127
+ {
128
+ RUBY_ATOMIC_SIZE_INC(rbd_allocation_count);
129
+ }
130
+ static inline void
131
+ atomic_allocation_count_dec_nounderflow(void)
132
+ {
133
+ if (rbd_allocation_count == 0) return;
134
+ RUBY_ATOMIC_SIZE_DEC(rbd_allocation_count);
135
+ }
136
+ static void
137
+ check_allocation_count_nonzero(void)
138
+ {
139
+ if (rbd_allocation_count != 0) return;
140
+ rb_bug("[bigdecimal][rbd_free_struct] Too many memory free calls");
141
+ }
142
+ #else
143
+ # define atomic_allocation_count_inc() /* nothing */
144
+ # define atomic_allocation_count_dec_nounderflow() /* nothing */
145
+ # define check_allocation_count_nonzero() /* nothing */
146
+ #endif /* BIGDECIMAL_DEBUG */
147
+
148
+ PUREFUNC(static inline size_t rbd_struct_size(size_t const));
149
+
150
+ static inline size_t
151
+ rbd_struct_size(size_t const internal_digits)
152
+ {
153
+ size_t const frac_len = (internal_digits == 0) ? 1 : internal_digits;
154
+ return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
155
+ }
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
+
108
269
  /*
109
270
  * ================== Ruby Interface part ==========================
110
271
  */
@@ -120,10 +281,7 @@ static VALUE VpCheckGetValue(Real *p);
120
281
  static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
121
282
  static int VpLimitRound(Real *c, size_t ixDigit);
122
283
  static Real *VpCopy(Real *pv, Real const* const x);
123
-
124
- #ifdef BIGDECIMAL_ENABLE_VPRINT
125
284
  static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
126
- #endif
127
285
 
128
286
  /*
129
287
  * **** BigDecimal part ****
@@ -138,7 +296,7 @@ static VALUE BigDecimal_negative_zero(void);
138
296
  static void
139
297
  BigDecimal_delete(void *pv)
140
298
  {
141
- VpFree(pv);
299
+ rbd_free_struct(pv);
142
300
  }
143
301
 
144
302
  static size_t
@@ -157,10 +315,64 @@ static const rb_data_type_t BigDecimal_data_type = {
157
315
  "BigDecimal",
158
316
  { 0, BigDecimal_delete, BigDecimal_memsize, },
159
317
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
160
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
318
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED
161
319
  #endif
162
320
  };
163
321
 
322
+ static Real *
323
+ rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
324
+ {
325
+ Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision);
326
+ if (real != NULL) {
327
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
328
+ BigDecimal_wrap_struct(obj, real);
329
+ }
330
+ return real;
331
+ }
332
+
333
+ MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
334
+ #define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
335
+ static inline Real *
336
+ rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
337
+ {
338
+ return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
339
+ }
340
+
341
+ MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
342
+ #define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
343
+ static inline Real *
344
+ rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
345
+ {
346
+ return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
347
+ }
348
+
349
+ static Real *
350
+ rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
351
+ {
352
+ Real *real = rbd_allocate_struct_one(sign, digits, limit_precision);
353
+ if (real != NULL) {
354
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
355
+ BigDecimal_wrap_struct(obj, real);
356
+ }
357
+ return real;
358
+ }
359
+
360
+ MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits));
361
+ #define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap
362
+ static inline Real *
363
+ rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
364
+ {
365
+ return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
366
+ }
367
+
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)
372
+ {
373
+ return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
374
+ }
375
+
164
376
  static inline int
165
377
  is_kind_of_BigDecimal(VALUE const v)
166
378
  {
@@ -214,7 +426,7 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
214
426
 
215
427
  case T_FIXNUM: {
216
428
  char szD[128];
217
- sprintf(szD, "%ld", FIX2LONG(v));
429
+ snprintf(szD, 128, "%ld", FIX2LONG(v));
218
430
  v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
219
431
  break;
220
432
  }
@@ -249,7 +461,7 @@ SomeOneMayDoIt:
249
461
  return NULL; /* NULL means to coerce */
250
462
  }
251
463
 
252
- static Real*
464
+ static inline Real*
253
465
  GetVpValue(VALUE v, int must)
254
466
  {
255
467
  return GetVpValueWithPrec(v, -1, must);
@@ -264,7 +476,7 @@ GetVpValue(VALUE v, int must)
264
476
  * BigDecimal.double_fig # => 16
265
477
  *
266
478
  */
267
- static VALUE
479
+ static inline VALUE
268
480
  BigDecimal_double_fig(VALUE self)
269
481
  {
270
482
  return INT2FIX(VpDblFig());
@@ -445,7 +657,7 @@ BigDecimal_precision(VALUE self)
445
657
  * Returns the number of decimal digits following the decimal digits in +self+.
446
658
  *
447
659
  * BigDecimal("0").scale # => 0
448
- * BigDecimal("1").scale # => 1
660
+ * BigDecimal("1").scale # => 0
449
661
  * BigDecimal("1.1").scale # => 1
450
662
  * BigDecimal("3.1415").scale # => 4
451
663
  * BigDecimal("-1e20").precision # => 0
@@ -486,15 +698,15 @@ BigDecimal_precision_scale(VALUE self)
486
698
  *
487
699
  * Returns the number of decimal significant digits in +self+.
488
700
  *
489
- * BigDecimal("0").scale # => 0
490
- * BigDecimal("1").scale # => 1
491
- * BigDecimal("1.1").scale # => 2
492
- * BigDecimal("3.1415").scale # => 5
493
- * BigDecimal("-1e20").precision # => 1
494
- * BigDecimal("1e-20").precision # => 1
495
- * BigDecimal("Infinity").scale # => 0
496
- * BigDecimal("-Infinity").scale # => 0
497
- * BigDecimal("NaN").scale # => 0
701
+ * BigDecimal("0").n_significant_digits # => 0
702
+ * BigDecimal("1").n_significant_digits # => 1
703
+ * BigDecimal("1.1").n_significant_digits # => 2
704
+ * BigDecimal("3.1415").n_significant_digits # => 5
705
+ * BigDecimal("-1e20").n_significant_digits # => 1
706
+ * BigDecimal("1e-20").n_significant_digits # => 1
707
+ * BigDecimal("Infinity").n_significant_digits # => 0
708
+ * BigDecimal("-Infinity").n_significant_digits # => 0
709
+ * BigDecimal("NaN").n_significant_digits # => 0
498
710
  */
499
711
  static VALUE
500
712
  BigDecimal_n_significant_digits(VALUE self)
@@ -573,13 +785,15 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
573
785
  char *psz;
574
786
  VALUE dummy;
575
787
  volatile VALUE dump;
788
+ size_t len;
576
789
 
577
790
  rb_scan_args(argc, argv, "01", &dummy);
578
791
  GUARD_OBJ(vp,GetVpValue(self, 1));
579
792
  dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
580
793
  psz = RSTRING_PTR(dump);
581
- sprintf(psz, "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
582
- VpToString(vp, psz+strlen(psz), 0, 0);
794
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
795
+ len = strlen(psz);
796
+ VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
583
797
  rb_str_resize(dump, strlen(psz));
584
798
  return dump;
585
799
  }
@@ -623,18 +837,19 @@ check_rounding_mode_option(VALUE const opts)
623
837
  assert(RB_TYPE_P(opts, T_HASH));
624
838
 
625
839
  if (NIL_P(opts))
626
- goto noopt;
840
+ goto no_opt;
627
841
 
628
842
  mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef);
629
843
  if (mode == Qundef || NIL_P(mode))
630
- goto noopt;
844
+ goto no_opt;
631
845
 
632
846
  if (SYMBOL_P(mode))
633
847
  mode = rb_sym2str(mode);
634
848
  else if (!RB_TYPE_P(mode, T_STRING)) {
635
- VALUE str_mode = rb_check_string_type(mode);
636
- if (NIL_P(str_mode)) goto invalid;
637
- mode = str_mode;
849
+ VALUE str_mode = rb_check_string_type(mode);
850
+ if (NIL_P(str_mode))
851
+ goto invalid;
852
+ mode = str_mode;
638
853
  }
639
854
  s = RSTRING_PTR(mode);
640
855
  l = RSTRING_LEN(mode);
@@ -652,13 +867,11 @@ check_rounding_mode_option(VALUE const opts)
652
867
  default:
653
868
  break;
654
869
  }
870
+
655
871
  invalid:
656
- if (NIL_P(mode))
657
- rb_raise(rb_eArgError, "invalid rounding mode: nil");
658
- else
659
- rb_raise(rb_eArgError, "invalid rounding mode: %"PRIsVALUE, mode);
872
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", mode);
660
873
 
661
- noopt:
874
+ no_opt:
662
875
  return VpGetRoundMode();
663
876
  }
664
877
 
@@ -667,34 +880,23 @@ check_rounding_mode(VALUE const v)
667
880
  {
668
881
  unsigned short sw;
669
882
  ID id;
670
- switch (TYPE(v)) {
671
- case T_SYMBOL:
672
- id = SYM2ID(v);
673
- if (id == id_up)
674
- return VP_ROUND_UP;
675
- if (id == id_down || id == id_truncate)
676
- return VP_ROUND_DOWN;
677
- if (id == id_half_up || id == id_default)
678
- return VP_ROUND_HALF_UP;
679
- if (id == id_half_down)
680
- return VP_ROUND_HALF_DOWN;
681
- if (id == id_half_even || id == id_banker)
682
- return VP_ROUND_HALF_EVEN;
683
- if (id == id_ceiling || id == id_ceil)
684
- return VP_ROUND_CEIL;
685
- if (id == id_floor)
686
- return VP_ROUND_FLOOR;
687
- rb_raise(rb_eArgError, "invalid rounding mode");
688
-
689
- default:
690
- break;
883
+ if (RB_TYPE_P(v, T_SYMBOL)) {
884
+ int i;
885
+ id = SYM2ID(v);
886
+ for (i = 0; i < RBD_NUM_ROUNDING_MODES; ++i) {
887
+ if (rbd_rounding_modes[i].id == id) {
888
+ return rbd_rounding_modes[i].mode;
889
+ }
890
+ }
891
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
691
892
  }
692
-
693
- sw = NUM2USHORT(v);
694
- if (!VpIsRoundMode(sw)) {
695
- rb_raise(rb_eArgError, "invalid rounding mode");
893
+ else {
894
+ sw = NUM2USHORT(v);
895
+ if (!VpIsRoundMode(sw)) {
896
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
897
+ }
898
+ return sw;
696
899
  }
697
- return sw;
698
900
  }
699
901
 
700
902
  /* call-seq:
@@ -933,11 +1135,17 @@ GetAddSubPrec(Real *a, Real *b)
933
1135
  return mx;
934
1136
  }
935
1137
 
936
- static SIGNED_VALUE
937
- GetPrecisionInt(VALUE v)
1138
+ static inline SIGNED_VALUE
1139
+ check_int_precision(VALUE v)
938
1140
  {
939
1141
  SIGNED_VALUE n;
940
- n = NUM2INT(v);
1142
+ #if SIZEOF_VALUE <= SIZEOF_LONG
1143
+ n = (SIGNED_VALUE)NUM2LONG(v);
1144
+ #elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
1145
+ n = (SIGNED_VALUE)NUM2LL(v);
1146
+ #else
1147
+ # error SIZEOF_VALUE is too large
1148
+ #endif
941
1149
  if (n < 0) {
942
1150
  rb_raise(rb_eArgError, "negative precision");
943
1151
  }
@@ -979,26 +1187,12 @@ VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
979
1187
  return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
980
1188
  }
981
1189
 
982
- #define VpAllocReal(prec) (Real *)VpMemAlloc(offsetof(Real, frac) + (prec) * sizeof(DECDIG))
983
-
984
- static Real *
985
- VpReallocReal(Real *pv, size_t prec)
986
- {
987
- VALUE obj = pv ? pv->obj : 0;
988
- Real *new_pv = (Real *)VpMemRealloc(pv, offsetof(Real, frac) + prec * sizeof(DECDIG));
989
- if (obj) {
990
- new_pv->obj = 0;
991
- BigDecimal_wrap_struct(obj, new_pv);
992
- }
993
- return new_pv;
994
- }
995
-
996
1190
  static Real *
997
1191
  VpCopy(Real *pv, Real const* const x)
998
1192
  {
999
1193
  assert(x != NULL);
1000
1194
 
1001
- pv = VpReallocReal(pv, x->MaxPrec);
1195
+ pv = rbd_reallocate_struct(pv, x->MaxPrec);
1002
1196
  pv->MaxPrec = x->MaxPrec;
1003
1197
  pv->Prec = x->Prec;
1004
1198
  pv->exponent = x->exponent;
@@ -1119,7 +1313,7 @@ BigDecimal_to_f(VALUE self)
1119
1313
 
1120
1314
  str = rb_str_new(0, VpNumOfChars(p, "E"));
1121
1315
  buf = RSTRING_PTR(str);
1122
- VpToString(p, buf, 0, 0);
1316
+ VpToString(p, buf, RSTRING_LEN(str), 0, 0);
1123
1317
  errno = 0;
1124
1318
  d = strtod(buf, 0);
1125
1319
  if (errno == ERANGE) {
@@ -1276,17 +1470,17 @@ BigDecimal_add(VALUE self, VALUE r)
1276
1470
 
1277
1471
  mx = GetAddSubPrec(a, b);
1278
1472
  if (mx == (size_t)-1L) {
1279
- GUARD_OBJ(c, VpCreateRbObject(VpBaseFig() + 1, "0", true));
1280
- VpAddSub(c, a, b, 1);
1473
+ GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1474
+ VpAddSub(c, a, b, 1);
1281
1475
  }
1282
1476
  else {
1283
- GUARD_OBJ(c, VpCreateRbObject(mx * (VpBaseFig() + 1), "0", true));
1284
- if(!mx) {
1285
- VpSetInf(c, VpGetSign(a));
1286
- }
1287
- else {
1288
- VpAddSub(c, a, b, 1);
1289
- }
1477
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1478
+ if (!mx) {
1479
+ VpSetInf(c, VpGetSign(a));
1480
+ }
1481
+ else {
1482
+ VpAddSub(c, a, b, 1);
1483
+ }
1290
1484
  }
1291
1485
  return VpCheckGetValue(c);
1292
1486
  }
@@ -1331,17 +1525,17 @@ BigDecimal_sub(VALUE self, VALUE r)
1331
1525
 
1332
1526
  mx = GetAddSubPrec(a,b);
1333
1527
  if (mx == (size_t)-1L) {
1334
- GUARD_OBJ(c, VpCreateRbObject(VpBaseFig() + 1, "0", true));
1335
- VpAddSub(c, a, b, -1);
1528
+ GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
1529
+ VpAddSub(c, a, b, -1);
1336
1530
  }
1337
1531
  else {
1338
- GUARD_OBJ(c,VpCreateRbObject(mx *(VpBaseFig() + 1), "0", true));
1339
- if (!mx) {
1340
- VpSetInf(c,VpGetSign(a));
1341
- }
1342
- else {
1343
- VpAddSub(c, a, b, -1);
1344
- }
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
+ }
1345
1539
  }
1346
1540
  return VpCheckGetValue(c);
1347
1541
  }
@@ -1581,7 +1775,7 @@ BigDecimal_neg(VALUE self)
1581
1775
  ENTER(5);
1582
1776
  Real *c, *a;
1583
1777
  GUARD_OBJ(a, GetVpValue(self, 1));
1584
- GUARD_OBJ(c, VpCreateRbObject(a->Prec *(VpBaseFig() + 1), "0", true));
1778
+ GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
1585
1779
  VpAsgn(c, a, -1);
1586
1780
  return VpCheckGetValue(c);
1587
1781
  }
@@ -1608,7 +1802,7 @@ BigDecimal_mult(VALUE self, VALUE r)
1608
1802
  SAVE(b);
1609
1803
 
1610
1804
  mx = a->Prec + b->Prec;
1611
- GUARD_OBJ(c, VpCreateRbObject(mx *(VpBaseFig() + 1), "0", true));
1805
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
1612
1806
  VpMult(c, a, b);
1613
1807
  return VpCheckGetValue(c);
1614
1808
  }
@@ -1619,6 +1813,7 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1619
1813
  {
1620
1814
  ENTER(5);
1621
1815
  Real *a, *b;
1816
+ ssize_t a_prec, b_prec;
1622
1817
  size_t mx;
1623
1818
 
1624
1819
  TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
@@ -1644,18 +1839,25 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1644
1839
 
1645
1840
  TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
1646
1841
  SAVE(b);
1647
-
1648
1842
  *div = b;
1649
- mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
1650
- mx *= BASE_FIG;
1843
+
1844
+ BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
1845
+ BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
1846
+ mx = (a_prec > b_prec) ? a_prec : b_prec;
1847
+ mx *= 2;
1848
+
1651
1849
  if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1652
1850
  mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1653
- GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
1654
- GUARD_OBJ((*res), VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
1851
+
1852
+ GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
1853
+ GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
1655
1854
  VpDivd(*c, *res, a, b);
1855
+
1656
1856
  return Qnil;
1657
1857
  }
1658
1858
 
1859
+ static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
1860
+
1659
1861
  /* call-seq:
1660
1862
  * a / b -> bigdecimal
1661
1863
  *
@@ -1713,7 +1915,7 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1713
1915
 
1714
1916
  argc = rb_scan_args(argc, argv, "11", &value, &digits);
1715
1917
  if (argc > 1) {
1716
- n = GetPrecisionInt(digits);
1918
+ n = check_int_precision(digits);
1717
1919
  }
1718
1920
 
1719
1921
  if (n > 0) {
@@ -1736,6 +1938,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1736
1938
  ENTER(8);
1737
1939
  Real *c=NULL, *d=NULL, *res=NULL;
1738
1940
  Real *a, *b;
1941
+ ssize_t a_prec, b_prec;
1739
1942
  size_t mx;
1740
1943
 
1741
1944
  TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
@@ -1793,17 +1996,21 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1793
1996
  return Qtrue;
1794
1997
  }
1795
1998
 
1796
- mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
1797
- mx *= BASE_FIG;
1999
+ BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
2000
+ BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
2001
+
2002
+ mx = (a_prec > b_prec) ? a_prec : b_prec;
2003
+ mx *= 2;
2004
+
1798
2005
  if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1799
2006
  mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1800
2007
 
1801
- GUARD_OBJ(c, VpCreateRbObject(mx + 2*BASE_FIG, "0", true));
1802
- GUARD_OBJ(res, VpCreateRbObject(mx*2 + 2*BASE_FIG, "#0", true));
2008
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
2009
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
1803
2010
  VpDivd(c, res, a, b);
1804
2011
 
1805
2012
  mx = c->Prec * BASE_FIG;
1806
- GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
2013
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
1807
2014
  VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1808
2015
 
1809
2016
  VpMult(res, d, b);
@@ -1811,10 +2018,10 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1811
2018
 
1812
2019
  if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1813
2020
  /* result adjustment for negative case */
1814
- res = VpReallocReal(res, d->MaxPrec);
2021
+ res = rbd_reallocate_struct(res, d->MaxPrec);
1815
2022
  res->MaxPrec = d->MaxPrec;
1816
2023
  VpAddSub(res, d, VpOne(), -1);
1817
- GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b) * 2*BASE_FIG, "0", true));
2024
+ GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
1818
2025
  VpAddSub(d, c, b, 1);
1819
2026
  *div = res;
1820
2027
  *mod = d;
@@ -1877,18 +2084,25 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1877
2084
  if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
1878
2085
  SAVE(b);
1879
2086
 
2087
+ if (VpIsPosInf(b) || VpIsNegInf(b)) {
2088
+ GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
2089
+ VpSetZero(*dv, 1);
2090
+ *rv = a;
2091
+ return Qnil;
2092
+ }
2093
+
1880
2094
  mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
1881
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
1882
- GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0", true));
1883
- GUARD_OBJ(rr, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0", true));
1884
- GUARD_OBJ(ff, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0", true));
2095
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2096
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2097
+ GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
2098
+ GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
1885
2099
 
1886
2100
  VpDivd(c, res, a, b);
1887
2101
 
1888
2102
  mx = c->Prec *(VpBaseFig() + 1);
1889
2103
 
1890
- GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
1891
- GUARD_OBJ(f, VpCreateRbObject(mx, "0", true));
2104
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2105
+ GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
1892
2106
 
1893
2107
  VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
1894
2108
 
@@ -1973,7 +2187,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1973
2187
  }
1974
2188
 
1975
2189
  /* div in BigDecimal sense */
1976
- ix = GetPrecisionInt(n);
2190
+ ix = check_int_precision(n);
1977
2191
  if (ix == 0) {
1978
2192
  return BigDecimal_div(self, b);
1979
2193
  }
@@ -1984,7 +2198,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1984
2198
  size_t b_prec = ix;
1985
2199
  size_t pl = VpSetPrecLimit(0);
1986
2200
 
1987
- GUARD_OBJ(cv, VpCreateRbObject(mx + VpBaseFig(), "0", true));
2201
+ GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig()));
1988
2202
  GUARD_OBJ(av, GetVpValue(self, 1));
1989
2203
  /* TODO: I want to refactor this precision control for a float value later
1990
2204
  * by introducing an implicit conversion function instead of
@@ -1995,7 +2209,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1995
2209
  GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
1996
2210
  mx = av->Prec + bv->Prec + 2;
1997
2211
  if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
1998
- GUARD_OBJ(res, VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0", true));
2212
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
1999
2213
  VpDivd(cv, res, av, bv);
2000
2214
  VpSetPrecLimit(pl);
2001
2215
  VpLeftRound(cv, VpGetRoundMode(), ix);
@@ -2078,7 +2292,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2078
2292
  {
2079
2293
  ENTER(2);
2080
2294
  Real *cv;
2081
- SIGNED_VALUE mx = GetPrecisionInt(n);
2295
+ SIGNED_VALUE mx = check_int_precision(n);
2082
2296
  if (mx == 0) return BigDecimal_add(self, b);
2083
2297
  else {
2084
2298
  size_t pl = VpSetPrecLimit(0);
@@ -2108,7 +2322,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2108
2322
  {
2109
2323
  ENTER(2);
2110
2324
  Real *cv;
2111
- SIGNED_VALUE mx = GetPrecisionInt(n);
2325
+ SIGNED_VALUE mx = check_int_precision(n);
2112
2326
  if (mx == 0) return BigDecimal_sub(self, b);
2113
2327
  else {
2114
2328
  size_t pl = VpSetPrecLimit(0);
@@ -2151,7 +2365,7 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2151
2365
  {
2152
2366
  ENTER(2);
2153
2367
  Real *cv;
2154
- SIGNED_VALUE mx = GetPrecisionInt(n);
2368
+ SIGNED_VALUE mx = check_int_precision(n);
2155
2369
  if (mx == 0) return BigDecimal_mult(self, b);
2156
2370
  else {
2157
2371
  size_t pl = VpSetPrecLimit(0);
@@ -2183,7 +2397,7 @@ BigDecimal_abs(VALUE self)
2183
2397
 
2184
2398
  GUARD_OBJ(a, GetVpValue(self, 1));
2185
2399
  mx = a->Prec *(VpBaseFig() + 1);
2186
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2400
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2187
2401
  VpAsgn(c, a, 1);
2188
2402
  VpChangeSign(c, 1);
2189
2403
  return VpCheckGetValue(c);
@@ -2206,9 +2420,10 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2206
2420
  GUARD_OBJ(a, GetVpValue(self, 1));
2207
2421
  mx = a->Prec * (VpBaseFig() + 1);
2208
2422
 
2209
- n = GetPrecisionInt(nFig) + VpDblFig() + BASE_FIG;
2423
+ n = check_int_precision(nFig);
2424
+ n += VpDblFig() + VpBaseFig();
2210
2425
  if (mx <= n) mx = n;
2211
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2426
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2212
2427
  VpSqrt(c, a);
2213
2428
  return VpCheckGetValue(c);
2214
2429
  }
@@ -2224,7 +2439,7 @@ BigDecimal_fix(VALUE self)
2224
2439
 
2225
2440
  GUARD_OBJ(a, GetVpValue(self, 1));
2226
2441
  mx = a->Prec *(VpBaseFig() + 1);
2227
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2442
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2228
2443
  VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2229
2444
  return VpCheckGetValue(c);
2230
2445
  }
@@ -2297,7 +2512,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2297
2512
  pl = VpSetPrecLimit(0);
2298
2513
  GUARD_OBJ(a, GetVpValue(self, 1));
2299
2514
  mx = a->Prec * (VpBaseFig() + 1);
2300
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2515
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2301
2516
  VpSetPrecLimit(pl);
2302
2517
  VpActiveRound(c, a, sw, iLoc);
2303
2518
  if (round_to_int) {
@@ -2343,7 +2558,7 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2343
2558
 
2344
2559
  GUARD_OBJ(a, GetVpValue(self, 1));
2345
2560
  mx = a->Prec * (VpBaseFig() + 1);
2346
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2561
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2347
2562
  VpSetPrecLimit(pl);
2348
2563
  VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2349
2564
  if (argc == 0) {
@@ -2363,7 +2578,7 @@ BigDecimal_frac(VALUE self)
2363
2578
 
2364
2579
  GUARD_OBJ(a, GetVpValue(self, 1));
2365
2580
  mx = a->Prec * (VpBaseFig() + 1);
2366
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2581
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2367
2582
  VpFrac(c, a);
2368
2583
  return VpCheckGetValue(c);
2369
2584
  }
@@ -2403,7 +2618,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2403
2618
 
2404
2619
  GUARD_OBJ(a, GetVpValue(self, 1));
2405
2620
  mx = a->Prec * (VpBaseFig() + 1);
2406
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2621
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2407
2622
  VpSetPrecLimit(pl);
2408
2623
  VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2409
2624
  #ifdef BIGDECIMAL_DEBUG
@@ -2449,7 +2664,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2449
2664
 
2450
2665
  GUARD_OBJ(a, GetVpValue(self, 1));
2451
2666
  mx = a->Prec * (VpBaseFig() + 1);
2452
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2667
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2453
2668
  VpSetPrecLimit(pl);
2454
2669
  VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2455
2670
  if (argc == 0) {
@@ -2474,7 +2689,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2474
2689
  * A space at the start of s returns positive values with a leading space.
2475
2690
  *
2476
2691
  * If s contains a number, a space is inserted after each group of that many
2477
- * fractional digits.
2692
+ * digits, starting from '.' and counting outwards.
2478
2693
  *
2479
2694
  * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
2480
2695
  *
@@ -2482,14 +2697,14 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2482
2697
  *
2483
2698
  * Examples:
2484
2699
  *
2485
- * BigDecimal('-123.45678901234567890').to_s('5F')
2486
- * #=> '-123.45678 90123 45678 9'
2700
+ * BigDecimal('-1234567890123.45678901234567890').to_s('5F')
2701
+ * #=> '-123 45678 90123.45678 90123 45678 9'
2487
2702
  *
2488
- * BigDecimal('123.45678901234567890').to_s('+8F')
2489
- * #=> '+123.45678901 23456789'
2703
+ * BigDecimal('1234567890123.45678901234567890').to_s('+8F')
2704
+ * #=> '+12345 67890123.45678901 23456789'
2490
2705
  *
2491
- * BigDecimal('123.45678901234567890').to_s(' F')
2492
- * #=> ' 123.4567890123456789'
2706
+ * BigDecimal('1234567890123.45678901234567890').to_s(' F')
2707
+ * #=> ' 1234567890123.4567890123456789'
2493
2708
  */
2494
2709
  static VALUE
2495
2710
  BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
@@ -2553,10 +2768,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2553
2768
  psz = RSTRING_PTR(str);
2554
2769
 
2555
2770
  if (fmt) {
2556
- VpToFString(vp, psz, mc, fPlus);
2771
+ VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2557
2772
  }
2558
2773
  else {
2559
- VpToString (vp, psz, mc, fPlus);
2774
+ VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2560
2775
  }
2561
2776
  rb_str_resize(str, strlen(psz));
2562
2777
  return str;
@@ -2598,7 +2813,7 @@ BigDecimal_split(VALUE self)
2598
2813
  GUARD_OBJ(vp, GetVpValue(self, 1));
2599
2814
  str = rb_str_new(0, VpNumOfChars(vp, "E"));
2600
2815
  psz1 = RSTRING_PTR(str);
2601
- VpSzMantissa(vp, psz1);
2816
+ VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2602
2817
  s = 1;
2603
2818
  if(psz1[0] == '-') {
2604
2819
  size_t len = strlen(psz1 + 1);
@@ -2647,7 +2862,7 @@ BigDecimal_inspect(VALUE self)
2647
2862
  nc = VpNumOfChars(vp, "E");
2648
2863
 
2649
2864
  str = rb_str_new(0, nc);
2650
- VpToString(vp, RSTRING_PTR(str), 0, 0);
2865
+ VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2651
2866
  rb_str_resize(str, strlen(RSTRING_PTR(str)));
2652
2867
  return str;
2653
2868
  }
@@ -2757,7 +2972,7 @@ bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2757
2972
  volatile VALUE obj = exp->obj;
2758
2973
 
2759
2974
  if (VpIsZero(exp)) {
2760
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2975
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
2761
2976
  }
2762
2977
 
2763
2978
  log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
@@ -2795,9 +3010,9 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2795
3010
  n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2796
3011
 
2797
3012
  if (VpIsNaN(x)) {
2798
- y = VpCreateRbObject(n, "0", true);
2799
- RB_GC_GUARD(y->obj);
2800
- VpSetNaN(y);
3013
+ y = NewZeroWrapLimited(1, n);
3014
+ VpSetNaN(y);
3015
+ RB_GC_GUARD(y->obj);
2801
3016
  return VpCheckGetValue(y);
2802
3017
  }
2803
3018
 
@@ -2866,136 +3081,126 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2866
3081
  }
2867
3082
 
2868
3083
  if (VpIsZero(x)) {
2869
- if (is_negative(vexp)) {
2870
- y = VpCreateRbObject(n, "#0", true);
2871
- RB_GC_GUARD(y->obj);
2872
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2873
- if (is_integer(vexp)) {
2874
- if (is_even(vexp)) {
2875
- /* (-0) ** (-even_integer) -> Infinity */
2876
- VpSetPosInf(y);
2877
- }
2878
- else {
2879
- /* (-0) ** (-odd_integer) -> -Infinity */
2880
- VpSetNegInf(y);
2881
- }
2882
- }
2883
- else {
2884
- /* (-0) ** (-non_integer) -> Infinity */
2885
- VpSetPosInf(y);
2886
- }
2887
- }
2888
- else {
2889
- /* (+0) ** (-num) -> Infinity */
2890
- VpSetPosInf(y);
2891
- }
3084
+ if (is_negative(vexp)) {
3085
+ y = NewZeroWrapNolimit(1, n);
3086
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
3087
+ if (is_integer(vexp)) {
3088
+ if (is_even(vexp)) {
3089
+ /* (-0) ** (-even_integer) -> Infinity */
3090
+ VpSetPosInf(y);
3091
+ }
3092
+ else {
3093
+ /* (-0) ** (-odd_integer) -> -Infinity */
3094
+ VpSetNegInf(y);
3095
+ }
3096
+ }
3097
+ else {
3098
+ /* (-0) ** (-non_integer) -> Infinity */
3099
+ VpSetPosInf(y);
3100
+ }
3101
+ }
3102
+ else {
3103
+ /* (+0) ** (-num) -> Infinity */
3104
+ VpSetPosInf(y);
3105
+ }
3106
+ RB_GC_GUARD(y->obj);
2892
3107
  return VpCheckGetValue(y);
2893
- }
2894
- else if (is_zero(vexp)) {
2895
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2896
- }
2897
- else {
2898
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2899
- }
3108
+ }
3109
+ else if (is_zero(vexp)) {
3110
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
3111
+ }
3112
+ else {
3113
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3114
+ }
2900
3115
  }
2901
3116
 
2902
3117
  if (is_zero(vexp)) {
2903
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
3118
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
2904
3119
  }
2905
3120
  else if (is_one(vexp)) {
2906
- return self;
3121
+ return self;
2907
3122
  }
2908
3123
 
2909
3124
  if (VpIsInf(x)) {
2910
- if (is_negative(vexp)) {
2911
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2912
- if (is_integer(vexp)) {
2913
- if (is_even(vexp)) {
2914
- /* (-Infinity) ** (-even_integer) -> +0 */
2915
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2916
- }
2917
- else {
2918
- /* (-Infinity) ** (-odd_integer) -> -0 */
2919
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2920
- }
2921
- }
2922
- else {
2923
- /* (-Infinity) ** (-non_integer) -> -0 */
2924
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2925
- }
2926
- }
2927
- else {
2928
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2929
- }
2930
- }
2931
- else {
2932
- y = VpCreateRbObject(n, "0", true);
2933
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2934
- if (is_integer(vexp)) {
2935
- if (is_even(vexp)) {
2936
- VpSetPosInf(y);
2937
- }
2938
- else {
2939
- VpSetNegInf(y);
2940
- }
2941
- }
2942
- else {
2943
- /* TODO: support complex */
2944
- rb_raise(rb_eMathDomainError,
2945
- "a non-integral exponent for a negative base");
2946
- }
2947
- }
2948
- else {
2949
- VpSetPosInf(y);
2950
- }
3125
+ if (is_negative(vexp)) {
3126
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
3127
+ if (is_integer(vexp)) {
3128
+ if (is_even(vexp)) {
3129
+ /* (-Infinity) ** (-even_integer) -> +0 */
3130
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3131
+ }
3132
+ else {
3133
+ /* (-Infinity) ** (-odd_integer) -> -0 */
3134
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3135
+ }
3136
+ }
3137
+ else {
3138
+ /* (-Infinity) ** (-non_integer) -> -0 */
3139
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3140
+ }
3141
+ }
3142
+ else {
3143
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3144
+ }
3145
+ }
3146
+ else {
3147
+ y = NewZeroWrapLimited(1, n);
3148
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
3149
+ if (is_integer(vexp)) {
3150
+ if (is_even(vexp)) {
3151
+ VpSetPosInf(y);
3152
+ }
3153
+ else {
3154
+ VpSetNegInf(y);
3155
+ }
3156
+ }
3157
+ else {
3158
+ /* TODO: support complex */
3159
+ rb_raise(rb_eMathDomainError,
3160
+ "a non-integral exponent for a negative base");
3161
+ }
3162
+ }
3163
+ else {
3164
+ VpSetPosInf(y);
3165
+ }
2951
3166
  return VpCheckGetValue(y);
2952
- }
3167
+ }
2953
3168
  }
2954
3169
 
2955
3170
  if (exp != NULL) {
2956
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3171
+ return bigdecimal_power_by_bigdecimal(x, exp, n);
2957
3172
  }
2958
3173
  else if (RB_TYPE_P(vexp, T_BIGNUM)) {
2959
- VALUE abs_value = BigDecimal_abs(self);
2960
- if (is_one(abs_value)) {
2961
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2962
- }
2963
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
2964
- if (is_negative(vexp)) {
2965
- y = VpCreateRbObject(n, "0", true);
2966
- if (is_even(vexp)) {
2967
- VpSetInf(y, VpGetSign(x));
2968
- }
2969
- else {
2970
- VpSetInf(y, -VpGetSign(x));
2971
- }
3174
+ VALUE abs_value = BigDecimal_abs(self);
3175
+ if (is_one(abs_value)) {
3176
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
3177
+ }
3178
+ else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
3179
+ if (is_negative(vexp)) {
3180
+ y = NewZeroWrapLimited(1, n);
3181
+ VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
2972
3182
  return VpCheckGetValue(y);
2973
- }
2974
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
2975
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2976
- }
2977
- else {
2978
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2979
- }
2980
- }
2981
- else {
2982
- if (is_positive(vexp)) {
2983
- y = VpCreateRbObject(n, "0", true);
2984
- if (is_even(vexp)) {
2985
- VpSetInf(y, VpGetSign(x));
2986
- }
2987
- else {
2988
- VpSetInf(y, -VpGetSign(x));
2989
- }
3183
+ }
3184
+ else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3185
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3186
+ }
3187
+ else {
3188
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3189
+ }
3190
+ }
3191
+ else {
3192
+ if (is_positive(vexp)) {
3193
+ y = NewZeroWrapLimited(1, n);
3194
+ VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
2990
3195
  return VpCheckGetValue(y);
2991
- }
2992
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
2993
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2994
- }
2995
- else {
2996
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2997
- }
2998
- }
3196
+ }
3197
+ else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3198
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
3199
+ }
3200
+ else {
3201
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3202
+ }
3203
+ }
2999
3204
  }
3000
3205
 
3001
3206
  int_exp = FIX2LONG(vexp);
@@ -3004,15 +3209,15 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
3004
3209
  if (ma == 0) ma = 1;
3005
3210
 
3006
3211
  if (VpIsDef(x)) {
3007
- mp = x->Prec * (VpBaseFig() + 1);
3008
- GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0", true));
3212
+ mp = x->Prec * (VpBaseFig() + 1);
3213
+ GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
3009
3214
  }
3010
3215
  else {
3011
- GUARD_OBJ(y, VpCreateRbObject(1, "0", true));
3216
+ GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3012
3217
  }
3013
3218
  VpPowerByInt(y, x, int_exp);
3014
3219
  if (!NIL_P(prec) && VpIsDef(y)) {
3015
- VpMidRound(y, VpGetRoundMode(), n);
3220
+ VpMidRound(y, VpGetRoundMode(), n);
3016
3221
  }
3017
3222
  return VpCheckGetValue(y);
3018
3223
  }
@@ -3101,7 +3306,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3101
3306
 
3102
3307
  Real *vp;
3103
3308
  if (uval == 0) {
3104
- vp = VpAllocReal(1);
3309
+ vp = rbd_allocate_struct(1);
3105
3310
  vp->MaxPrec = 1;
3106
3311
  vp->Prec = 1;
3107
3312
  vp->exponent = 1;
@@ -3109,7 +3314,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3109
3314
  vp->frac[0] = 0;
3110
3315
  }
3111
3316
  else if (uval < BASE) {
3112
- vp = VpAllocReal(1);
3317
+ vp = rbd_allocate_struct(1);
3113
3318
  vp->MaxPrec = 1;
3114
3319
  vp->Prec = 1;
3115
3320
  vp->exponent = 1;
@@ -3135,7 +3340,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3135
3340
  }
3136
3341
 
3137
3342
  const size_t exp = len + ntz;
3138
- vp = VpAllocReal(len);
3343
+ vp = rbd_allocate_struct(len);
3139
3344
  vp->MaxPrec = len;
3140
3345
  vp->Prec = len;
3141
3346
  vp->exponent = exp;
@@ -3268,7 +3473,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3268
3473
 
3269
3474
  VALUE inum;
3270
3475
  size_t RB_UNUSED_VAR(prec) = 0;
3271
- size_t exp = 0;
3476
+ SIGNED_VALUE exp = 0;
3272
3477
  if (decpt > 0) {
3273
3478
  if (decpt < len10) {
3274
3479
  /*
@@ -3480,12 +3685,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3480
3685
  * BigDecimal(value, exception: true) -> bigdecimal
3481
3686
  * BigDecimal(value, ndigits, exception: true) -> bigdecimal
3482
3687
  *
3483
- * Returns the \BigDecimal converted from +value+
3484
- * with a precision of +ndigits+ decimal digits.
3688
+ * Returns the \BigDecimal converted from +value+
3689
+ * with a precision of +ndigits+ decimal digits.
3690
+ *
3691
+ * When +ndigits+ is less than the number of significant digits
3692
+ * in the value, the result is rounded to that number of digits,
3693
+ * according to the current rounding mode; see BigDecimal.mode.
3485
3694
  *
3486
- * When +ndigits+ is less than the number of significant digits
3487
- * in the value, the result is rounded to that number of digits,
3488
- * according to the current rounding mode; see BigDecimal.mode.
3695
+ * When +ndigits+ is 0, the number of digits to correctly represent a float number
3696
+ * is determined automatically.
3489
3697
  *
3490
3698
  * Returns +value+ converted to a \BigDecimal, depending on the type of +value+:
3491
3699
  *
@@ -3514,7 +3722,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3514
3722
  * - Other type:
3515
3723
  *
3516
3724
  * - Raises an exception if keyword argument +exception+ is +true+.
3517
- * - Returns +nil+ if keyword argument +exception+ is +true+.
3725
+ * - Returns +nil+ if keyword argument +exception+ is +false+.
3518
3726
  *
3519
3727
  * Raises an exception if +value+ evaluates to a Float
3520
3728
  * and +digits+ is larger than Float::DIG + 1.
@@ -3593,8 +3801,10 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3593
3801
 
3594
3802
  /* Returns the sign of the value.
3595
3803
  *
3596
- * Returns a positive value if > 0, a negative value if < 0, and a
3597
- * zero if == 0.
3804
+ * Returns a positive value if > 0, a negative value if < 0.
3805
+ * It behaves the same with zeros -
3806
+ * it returns a positive value for a positive zero (BigDecimal('0')) and
3807
+ * a negative value for a negative zero (BigDecimal('-0')).
3598
3808
  *
3599
3809
  * The specific value returned indicates the type and sign of the BigDecimal,
3600
3810
  * as follows:
@@ -3758,18 +3968,16 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3758
3968
  return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3759
3969
  }
3760
3970
  else {
3761
- Real* vy;
3762
- vy = VpCreateRbObject(prec, "#0", true);
3971
+ Real* vy = NewZeroWrapNolimit(1, prec);
3763
3972
  VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3764
3973
  RB_GC_GUARD(vy->obj);
3765
3974
  return VpCheckGetValue(vy);
3766
3975
  }
3767
3976
  }
3768
3977
  else if (nan) {
3769
- Real* vy;
3770
- vy = VpCreateRbObject(prec, "#0", true);
3771
- VpSetNaN(vy);
3772
- RB_GC_GUARD(vy->obj);
3978
+ Real* vy = NewZeroWrapNolimit(1, prec);
3979
+ VpSetNaN(vy);
3980
+ RB_GC_GUARD(vy->obj);
3773
3981
  return VpCheckGetValue(vy);
3774
3982
  }
3775
3983
  else if (vx == NULL) {
@@ -3787,7 +3995,7 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3787
3995
  VpSetSign(vx, 1);
3788
3996
  }
3789
3997
 
3790
- one = VpCheckGetValue(VpCreateRbObject(1, "1", true));
3998
+ one = VpCheckGetValue(NewOneWrapLimited(1, 1));
3791
3999
  y = one;
3792
4000
  d = y;
3793
4001
  i = 1;
@@ -3914,15 +4122,13 @@ get_vp_value:
3914
4122
  break;
3915
4123
  }
3916
4124
  if (infinite && !negative) {
3917
- Real* vy;
3918
- vy = VpCreateRbObject(prec, "#0", true);
4125
+ Real *vy = NewZeroWrapNolimit(1, prec);
3919
4126
  RB_GC_GUARD(vy->obj);
3920
4127
  VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3921
4128
  return VpCheckGetValue(vy);
3922
4129
  }
3923
4130
  else if (nan) {
3924
- Real* vy;
3925
- vy = VpCreateRbObject(prec, "#0", true);
4131
+ Real* vy = NewZeroWrapNolimit(1, prec);
3926
4132
  RB_GC_GUARD(vy->obj);
3927
4133
  VpSetNaN(vy);
3928
4134
  return VpCheckGetValue(vy);
@@ -3936,11 +4142,11 @@ get_vp_value:
3936
4142
  }
3937
4143
  x = VpCheckGetValue(vx);
3938
4144
 
3939
- RB_GC_GUARD(one) = VpCheckGetValue(VpCreateRbObject(1, "1", true));
3940
- RB_GC_GUARD(two) = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4145
+ one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4146
+ two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
3941
4147
 
3942
4148
  n = prec + BIGDECIMAL_DOUBLE_FIGURES;
3943
- RB_GC_GUARD(vn) = SSIZET2NUM(n);
4149
+ vn = SSIZET2NUM(n);
3944
4150
  expo = VpExponent10(vx);
3945
4151
  if (expo < 0 || expo >= 3) {
3946
4152
  char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
@@ -3952,9 +4158,9 @@ get_vp_value:
3952
4158
  }
3953
4159
  w = BigDecimal_sub(x, one);
3954
4160
  x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
3955
- RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
3956
- RB_GC_GUARD(y) = x;
3957
- RB_GC_GUARD(d) = y;
4161
+ x2 = BigDecimal_mult2(x, x, vn);
4162
+ y = x;
4163
+ d = y;
3958
4164
  i = 1;
3959
4165
  while (!VpIsZero((Real*)DATA_PTR(d))) {
3960
4166
  SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
@@ -3982,6 +4188,13 @@ get_vp_value:
3982
4188
  y = BigDecimal_add(y, dy);
3983
4189
  }
3984
4190
 
4191
+ RB_GC_GUARD(one);
4192
+ RB_GC_GUARD(two);
4193
+ RB_GC_GUARD(vn);
4194
+ RB_GC_GUARD(x2);
4195
+ RB_GC_GUARD(y);
4196
+ RB_GC_GUARD(d);
4197
+
3985
4198
  return y;
3986
4199
  }
3987
4200
 
@@ -4150,7 +4363,20 @@ BigDecimal_negative_zero(void)
4150
4363
  * (2/3r).to_d(3) # => 0.667e0
4151
4364
  * "0.5".to_d # => 0.5e0
4152
4365
  *
4153
- * == License
4366
+ * == Methods for Working with \JSON
4367
+ *
4368
+ * - {::json_create}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-c-json_create]:
4369
+ * Returns a new \BigDecimal object constructed from the given object.
4370
+ * - {#as_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-as_json]:
4371
+ * Returns a 2-element hash representing +self+.
4372
+ * - {#to_json}[https://docs.ruby-lang.org/en/master/BigDecimal.html#method-i-to_json]:
4373
+ * Returns a \JSON string representing +self+.
4374
+ *
4375
+ * These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available:
4376
+ *
4377
+ * require 'json/add/bigdecimal'
4378
+ *
4379
+ * * == License
4154
4380
  *
4155
4381
  * Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
4156
4382
  *
@@ -4198,13 +4424,10 @@ Init_bigdecimal(void)
4198
4424
 
4199
4425
  /* Constants definition */
4200
4426
 
4201
- #ifndef RUBY_BIGDECIMAL_VERSION
4202
- # error RUBY_BIGDECIMAL_VERSION is not defined
4203
- #endif
4204
4427
  /*
4205
4428
  * The version of bigdecimal library
4206
4429
  */
4207
- rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(RUBY_BIGDECIMAL_VERSION));
4430
+ rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION));
4208
4431
 
4209
4432
  /*
4210
4433
  * Base value used in internal calculations. On a 32 bit system, BASE
@@ -4401,20 +4624,31 @@ Init_bigdecimal(void)
4401
4624
  rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4402
4625
  rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
4403
4626
 
4404
- id_up = rb_intern_const("up");
4405
- id_down = rb_intern_const("down");
4406
- id_truncate = rb_intern_const("truncate");
4407
- id_half_up = rb_intern_const("half_up");
4408
- id_default = rb_intern_const("default");
4409
- id_half_down = rb_intern_const("half_down");
4410
- id_half_even = rb_intern_const("half_even");
4411
- id_banker = rb_intern_const("banker");
4412
- id_ceiling = rb_intern_const("ceiling");
4413
- id_ceil = rb_intern_const("ceil");
4414
- id_floor = rb_intern_const("floor");
4627
+ #define ROUNDING_MODE(i, name, value) \
4628
+ id_##name = rb_intern_const(#name); \
4629
+ rbd_rounding_modes[i].id = id_##name; \
4630
+ rbd_rounding_modes[i].mode = value;
4631
+
4632
+ ROUNDING_MODE(0, up, RBD_ROUND_UP);
4633
+ ROUNDING_MODE(1, down, RBD_ROUND_DOWN);
4634
+ ROUNDING_MODE(2, half_up, RBD_ROUND_HALF_UP);
4635
+ ROUNDING_MODE(3, half_down, RBD_ROUND_HALF_DOWN);
4636
+ ROUNDING_MODE(4, ceil, RBD_ROUND_CEIL);
4637
+ ROUNDING_MODE(5, floor, RBD_ROUND_FLOOR);
4638
+ ROUNDING_MODE(6, half_even, RBD_ROUND_HALF_EVEN);
4639
+
4640
+ ROUNDING_MODE(7, default, RBD_ROUND_DEFAULT);
4641
+ ROUNDING_MODE(8, truncate, RBD_ROUND_TRUNCATE);
4642
+ ROUNDING_MODE(9, banker, RBD_ROUND_BANKER);
4643
+ ROUNDING_MODE(10, ceiling, RBD_ROUND_CEILING);
4644
+
4645
+ #undef ROUNDING_MODE
4646
+
4415
4647
  id_to_r = rb_intern_const("to_r");
4416
4648
  id_eq = rb_intern_const("==");
4417
4649
  id_half = rb_intern_const("half");
4650
+
4651
+ (void)VPrint; /* suppress unused warning */
4418
4652
  }
4419
4653
 
4420
4654
  /*
@@ -4434,7 +4668,7 @@ static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4434
4668
  #endif /* BIGDECIMAL_DEBUG */
4435
4669
 
4436
4670
  static Real *VpConstOne; /* constant 1.0 */
4437
- static Real *VpPt5; /* constant 0.5 */
4671
+ static Real *VpConstPt5; /* constant 0.5 */
4438
4672
  #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4439
4673
  /* used in VpSqrt() */
4440
4674
 
@@ -4465,42 +4699,6 @@ static int VpRdup(Real *m, size_t ind_m);
4465
4699
  static int gnAlloc = 0; /* Memory allocation counter */
4466
4700
  #endif /* BIGDECIMAL_DEBUG */
4467
4701
 
4468
- VP_EXPORT void *
4469
- VpMemAlloc(size_t mb)
4470
- {
4471
- void *p = xmalloc(mb);
4472
- memset(p, 0, mb);
4473
- #ifdef BIGDECIMAL_DEBUG
4474
- gnAlloc++; /* Count allocation call */
4475
- #endif /* BIGDECIMAL_DEBUG */
4476
- return p;
4477
- }
4478
-
4479
- VP_EXPORT void *
4480
- VpMemRealloc(void *ptr, size_t mb)
4481
- {
4482
- return xrealloc(ptr, mb);
4483
- }
4484
-
4485
- VP_EXPORT void
4486
- VpFree(Real *pv)
4487
- {
4488
- if (pv != NULL) {
4489
- xfree(pv);
4490
- #ifdef BIGDECIMAL_DEBUG
4491
- gnAlloc--; /* Decrement allocation count */
4492
- if (gnAlloc == 0) {
4493
- printf(" *************** All memories allocated freed ****************\n");
4494
- /*getchar();*/
4495
- }
4496
- if (gnAlloc < 0) {
4497
- printf(" ??????????? Too many memory free calls(%d) ?????????????\n", gnAlloc);
4498
- /*getchar();*/
4499
- }
4500
- #endif /* BIGDECIMAL_DEBUG */
4501
- }
4502
- }
4503
-
4504
4702
  /*
4505
4703
  * EXCEPTION Handling.
4506
4704
  */
@@ -4889,9 +5087,13 @@ VpInit(DECDIG BaseVal)
4889
5087
  /* Setup +/- Inf NaN -0 */
4890
5088
  VpGetDoubleNegZero();
4891
5089
 
4892
- /* Allocates Vp constants. */
4893
- VpConstOne = VpAlloc(1UL, "1", 1, 1);
4894
- VpPt5 = VpAlloc(1UL, ".5", 1, 1);
5090
+ /* Const 1.0 */
5091
+ VpConstOne = NewOneNolimit(1, 1);
5092
+
5093
+ /* Const 0.5 */
5094
+ VpConstPt5 = NewOneNolimit(1, 1);
5095
+ VpConstPt5->exponent = 0;
5096
+ VpConstPt5->frac[0] = 5*BASE1;
4895
5097
 
4896
5098
  #ifdef BIGDECIMAL_DEBUG
4897
5099
  gnAlloc = 0;
@@ -4980,7 +5182,7 @@ bigdecimal_parse_special_string(const char *str)
4980
5182
  p = str + table[i].len;
4981
5183
  while (*p && ISSPACE(*p)) ++p;
4982
5184
  if (*p == '\0') {
4983
- Real *vp = VpAllocReal(1);
5185
+ Real *vp = rbd_allocate_struct(1);
4984
5186
  vp->MaxPrec = 1;
4985
5187
  switch (table[i].sign) {
4986
5188
  default:
@@ -5004,11 +5206,11 @@ bigdecimal_parse_special_string(const char *str)
5004
5206
  /*
5005
5207
  * Allocates variable.
5006
5208
  * [Input]
5007
- * mx ... allocation unit, if zero then mx is determined by szVal.
5008
- * The mx is the number of effective digits can to be stored.
5009
- * szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
5010
- * If szVal[0]=='#' then Max. Prec. will not be considered(1.1.7),
5011
- * full precision specified by szVal is allocated.
5209
+ * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5210
+ * The mx will be the number of significant digits can to be stored.
5211
+ * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5212
+ * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5213
+ * so that the full precision specified by szVal is allocated.
5012
5214
  *
5013
5215
  * [Returns]
5014
5216
  * Pointer to the newly allocated variable, or
@@ -5019,48 +5221,40 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5019
5221
  {
5020
5222
  const char *orig_szVal = szVal;
5021
5223
  size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
5224
+ size_t len;
5022
5225
  char v, *psz;
5023
5226
  int sign=1;
5024
5227
  Real *vp = NULL;
5025
- size_t mf = VpGetPrecLimit();
5026
5228
  VALUE buf;
5027
5229
 
5028
- mx = (mx + BASE_FIG - 1) / BASE_FIG; /* Determine allocation unit. */
5029
- if (mx == 0) ++mx;
5030
-
5031
- if (szVal) {
5032
- /* Skipping leading spaces */
5033
- while (ISSPACE(*szVal)) szVal++;
5034
-
5035
- /* Processing the leading one `#` */
5036
- if (*szVal != '#') {
5037
- if (mf) {
5038
- mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
5039
- if (mx > mf) {
5040
- mx = mf;
5041
- }
5042
- }
5043
- }
5044
- else {
5045
- ++szVal;
5046
- }
5047
- }
5048
- else {
5230
+ if (szVal == NULL) {
5049
5231
  return_zero:
5050
5232
  /* necessary to be able to store */
5051
5233
  /* at least mx digits. */
5052
5234
  /* szVal==NULL ==> allocate zero value. */
5053
- vp = VpAllocReal(mx);
5054
- vp->MaxPrec = mx; /* set max precision */
5235
+ vp = rbd_allocate_struct(mx);
5236
+ vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5055
5237
  VpSetZero(vp, 1); /* initialize vp to zero. */
5056
5238
  return vp;
5057
5239
  }
5058
5240
 
5241
+ /* Skipping leading spaces */
5242
+ while (ISSPACE(*szVal)) szVal++;
5243
+
5059
5244
  /* Check on Inf & NaN */
5060
5245
  if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
5061
5246
  return vp;
5062
5247
  }
5063
5248
 
5249
+ /* Processing the leading one `#` */
5250
+ if (*szVal != '#') {
5251
+ len = rbd_calculate_internal_digits(mx, true);
5252
+ }
5253
+ else {
5254
+ len = rbd_calculate_internal_digits(mx, false);
5255
+ ++szVal;
5256
+ }
5257
+
5064
5258
  /* Scanning digits */
5065
5259
 
5066
5260
  /* A buffer for keeping scanned digits */
@@ -5222,11 +5416,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5222
5416
 
5223
5417
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5224
5418
  /* units for szVal[] */
5225
- if (mx == 0) mx = 1;
5226
- nalloc = Max(nalloc, mx);
5227
- mx = nalloc;
5228
- vp = VpAllocReal(mx);
5229
- vp->MaxPrec = mx; /* set max precision */
5419
+ if (len == 0) len = 1;
5420
+ nalloc = Max(nalloc, len);
5421
+ len = nalloc;
5422
+ vp = rbd_allocate_struct(len);
5423
+ vp->MaxPrec = len; /* set max precision */
5230
5424
  VpSetZero(vp, sign);
5231
5425
  VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
5232
5426
  rb_str_resize(buf, 0);
@@ -5791,7 +5985,7 @@ VpMult(Real *c, Real *a, Real *b)
5791
5985
 
5792
5986
  if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
5793
5987
  w = c;
5794
- c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1, 1);
5988
+ c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
5795
5989
  MxIndC = MxIndAB;
5796
5990
  }
5797
5991
 
@@ -5799,8 +5993,8 @@ VpMult(Real *c, Real *a, Real *b)
5799
5993
 
5800
5994
  c->exponent = a->exponent; /* set exponent */
5801
5995
  if (!AddExponent(c, b->exponent)) {
5802
- if (w) VpFree(c);
5803
- return 0;
5996
+ if (w) rbd_free_struct(c);
5997
+ return 0;
5804
5998
  }
5805
5999
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
5806
6000
  carry = 0;
@@ -5850,10 +6044,10 @@ VpMult(Real *c, Real *a, Real *b)
5850
6044
  }
5851
6045
  }
5852
6046
  if (w != NULL) { /* free work variable */
5853
- VpNmlz(c);
5854
- VpAsgn(w, c, 1);
5855
- VpFree(c);
5856
- c = w;
6047
+ VpNmlz(c);
6048
+ VpAsgn(w, c, 1);
6049
+ rbd_free_struct(c);
6050
+ c = w;
5857
6051
  }
5858
6052
  else {
5859
6053
  VpLimitRound(c,0);
@@ -5918,18 +6112,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
5918
6112
  word_c = c->MaxPrec;
5919
6113
  word_r = r->MaxPrec;
5920
6114
 
5921
- ind_c = 0;
5922
- ind_r = 1;
5923
-
5924
6115
  if (word_a >= word_r) goto space_error;
5925
6116
 
6117
+ ind_r = 1;
5926
6118
  r->frac[0] = 0;
5927
6119
  while (ind_r <= word_a) {
5928
6120
  r->frac[ind_r] = a->frac[ind_r - 1];
5929
6121
  ++ind_r;
5930
6122
  }
5931
-
5932
6123
  while (ind_r < word_r) r->frac[ind_r++] = 0;
6124
+
6125
+ ind_c = 0;
5933
6126
  while (ind_c < word_c) c->frac[ind_c++] = 0;
5934
6127
 
5935
6128
  /* initial procedure */
@@ -6223,7 +6416,6 @@ Exit:
6223
6416
  * Note: % must not appear more than once
6224
6417
  * a ... VP variable to be printed
6225
6418
  */
6226
- #ifdef BIGDECIMAL_ENABLE_VPRINT
6227
6419
  static int
6228
6420
  VPrint(FILE *fp, const char *cntl_chr, Real *a)
6229
6421
  {
@@ -6236,95 +6428,94 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6236
6428
  /* nc : number of characters printed */
6237
6429
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6238
6430
  while (*(cntl_chr + j)) {
6239
- if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
6240
- nc = 0;
6241
- if (VpIsNaN(a)) {
6242
- fprintf(fp, SZ_NaN);
6243
- nc += 8;
6244
- }
6245
- else if (VpIsPosInf(a)) {
6246
- fprintf(fp, SZ_INF);
6247
- nc += 8;
6248
- }
6249
- else if (VpIsNegInf(a)) {
6250
- fprintf(fp, SZ_NINF);
6251
- nc += 9;
6252
- }
6253
- else if (!VpIsZero(a)) {
6254
- if (BIGDECIMAL_NEGATIVE_P(a)) {
6255
- fprintf(fp, "-");
6256
- ++nc;
6257
- }
6258
- nc += fprintf(fp, "0.");
6259
- switch (*(cntl_chr + j + 1)) {
6260
- default:
6261
- break;
6431
+ if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
6432
+ nc = 0;
6433
+ if (VpIsNaN(a)) {
6434
+ fprintf(fp, SZ_NaN);
6435
+ nc += 8;
6436
+ }
6437
+ else if (VpIsPosInf(a)) {
6438
+ fprintf(fp, SZ_INF);
6439
+ nc += 8;
6440
+ }
6441
+ else if (VpIsNegInf(a)) {
6442
+ fprintf(fp, SZ_NINF);
6443
+ nc += 9;
6444
+ }
6445
+ else if (!VpIsZero(a)) {
6446
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6447
+ fprintf(fp, "-");
6448
+ ++nc;
6449
+ }
6450
+ nc += fprintf(fp, "0.");
6451
+ switch (*(cntl_chr + j + 1)) {
6452
+ default:
6453
+ break;
6262
6454
 
6263
- case '0': case 'z':
6264
- ZeroSup = 0;
6265
- ++j;
6266
- sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
6267
- break;
6268
- }
6269
- for (i = 0; i < a->Prec; ++i) {
6270
- m = BASE1;
6271
- e = a->frac[i];
6272
- while (m) {
6273
- nn = e / m;
6274
- if (!ZeroSup || nn) {
6275
- nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
6276
- /* as 0.00xx will not */
6277
- /* be printed. */
6278
- ++nd;
6279
- ZeroSup = 0; /* Set to print succeeding zeros */
6280
- }
6281
- if (nd >= sep) { /* print ' ' after every 10 digits */
6282
- nd = 0;
6283
- nc += fprintf(fp, " ");
6284
- }
6285
- e = e - nn * m;
6286
- m /= 10;
6287
- }
6288
- }
6289
- nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
6290
- nc += fprintf(fp, " (%"PRIdVALUE", %lu, %lu)", a->exponent, a->Prec, a->MaxPrec);
6291
- }
6292
- else {
6293
- nc += fprintf(fp, "0.0");
6294
- }
6295
- }
6296
- else {
6297
- ++nc;
6298
- if (*(cntl_chr + j) == '\\') {
6299
- switch (*(cntl_chr + j + 1)) {
6300
- case 'n':
6301
- fprintf(fp, "\n");
6302
- ++j;
6303
- break;
6304
- case 't':
6305
- fprintf(fp, "\t");
6306
- ++j;
6307
- break;
6308
- case 'b':
6309
- fprintf(fp, "\n");
6310
- ++j;
6311
- break;
6312
- default:
6313
- fprintf(fp, "%c", *(cntl_chr + j));
6314
- break;
6315
- }
6316
- }
6317
- else {
6318
- fprintf(fp, "%c", *(cntl_chr + j));
6319
- if (*(cntl_chr + j) == '%') ++j;
6320
- }
6321
- }
6322
- j++;
6455
+ case '0': case 'z':
6456
+ ZeroSup = 0;
6457
+ ++j;
6458
+ sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
6459
+ break;
6460
+ }
6461
+ for (i = 0; i < a->Prec; ++i) {
6462
+ m = BASE1;
6463
+ e = a->frac[i];
6464
+ while (m) {
6465
+ nn = e / m;
6466
+ if (!ZeroSup || nn) {
6467
+ nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
6468
+ /* as 0.00xx will not */
6469
+ /* be printed. */
6470
+ ++nd;
6471
+ ZeroSup = 0; /* Set to print succeeding zeros */
6472
+ }
6473
+ if (nd >= sep) { /* print ' ' after every 10 digits */
6474
+ nd = 0;
6475
+ nc += fprintf(fp, " ");
6476
+ }
6477
+ e = e - nn * m;
6478
+ m /= 10;
6479
+ }
6480
+ }
6481
+ nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
6482
+ nc += fprintf(fp, " (%"PRIdVALUE", %"PRIuSIZE", %"PRIuSIZE")", a->exponent, a->Prec, a->MaxPrec);
6483
+ }
6484
+ else {
6485
+ nc += fprintf(fp, "0.0");
6486
+ }
6487
+ }
6488
+ else {
6489
+ ++nc;
6490
+ if (*(cntl_chr + j) == '\\') {
6491
+ switch (*(cntl_chr + j + 1)) {
6492
+ case 'n':
6493
+ fprintf(fp, "\n");
6494
+ ++j;
6495
+ break;
6496
+ case 't':
6497
+ fprintf(fp, "\t");
6498
+ ++j;
6499
+ break;
6500
+ case 'b':
6501
+ fprintf(fp, "\n");
6502
+ ++j;
6503
+ break;
6504
+ default:
6505
+ fprintf(fp, "%c", *(cntl_chr + j));
6506
+ break;
6507
+ }
6508
+ }
6509
+ else {
6510
+ fprintf(fp, "%c", *(cntl_chr + j));
6511
+ if (*(cntl_chr + j) == '%') ++j;
6512
+ }
6513
+ }
6514
+ j++;
6323
6515
  }
6324
6516
 
6325
6517
  return (int)nc;
6326
6518
  }
6327
- #endif
6328
6519
 
6329
6520
  static void
6330
6521
  VpFormatSt(char *psz, size_t fFmt)
@@ -6369,188 +6560,249 @@ VpExponent10(Real *a)
6369
6560
  }
6370
6561
 
6371
6562
  VP_EXPORT void
6372
- VpSzMantissa(Real *a,char *psz)
6563
+ VpSzMantissa(Real *a, char *buf, size_t buflen)
6373
6564
  {
6374
6565
  size_t i, n, ZeroSup;
6375
6566
  DECDIG_DBL m, e, nn;
6376
6567
 
6377
6568
  if (VpIsNaN(a)) {
6378
- sprintf(psz, SZ_NaN);
6379
- return;
6569
+ snprintf(buf, buflen, SZ_NaN);
6570
+ return;
6380
6571
  }
6381
6572
  if (VpIsPosInf(a)) {
6382
- sprintf(psz, SZ_INF);
6573
+ snprintf(buf, buflen, SZ_INF);
6383
6574
  return;
6384
6575
  }
6385
6576
  if (VpIsNegInf(a)) {
6386
- sprintf(psz, SZ_NINF);
6577
+ snprintf(buf, buflen, SZ_NINF);
6387
6578
  return;
6388
6579
  }
6389
6580
 
6390
6581
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6391
6582
  if (!VpIsZero(a)) {
6392
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6393
- n = a->Prec;
6394
- for (i = 0; i < n; ++i) {
6395
- m = BASE1;
6396
- e = a->frac[i];
6397
- while (m) {
6398
- nn = e / m;
6399
- if (!ZeroSup || nn) {
6400
- sprintf(psz, "%lu", (unsigned long)nn); /* The leading zero(s) */
6401
- psz += strlen(psz);
6402
- /* as 0.00xx will be ignored. */
6403
- ZeroSup = 0; /* Set to print succeeding zeros */
6404
- }
6405
- e = e - nn * m;
6406
- m /= 10;
6407
- }
6408
- }
6409
- *psz = 0;
6410
- while (psz[-1] == '0') *(--psz) = 0;
6583
+ if (BIGDECIMAL_NEGATIVE_P(a)) *buf++ = '-';
6584
+ n = a->Prec;
6585
+ for (i = 0; i < n; ++i) {
6586
+ m = BASE1;
6587
+ e = a->frac[i];
6588
+ while (m) {
6589
+ nn = e / m;
6590
+ if (!ZeroSup || nn) {
6591
+ snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */
6592
+ buf += strlen(buf);
6593
+ /* as 0.00xx will be ignored. */
6594
+ ZeroSup = 0; /* Set to print succeeding zeros */
6595
+ }
6596
+ e = e - nn * m;
6597
+ m /= 10;
6598
+ }
6599
+ }
6600
+ *buf = 0;
6601
+ while (buf[-1] == '0') *(--buf) = 0;
6411
6602
  }
6412
6603
  else {
6413
- if (VpIsPosZero(a)) sprintf(psz, "0");
6414
- else sprintf(psz, "-0");
6604
+ if (VpIsPosZero(a)) snprintf(buf, buflen, "0");
6605
+ else snprintf(buf, buflen, "-0");
6415
6606
  }
6416
6607
  }
6417
6608
 
6418
6609
  VP_EXPORT int
6419
- VpToSpecialString(Real *a,char *psz,int fPlus)
6610
+ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
6420
6611
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6421
6612
  {
6422
6613
  if (VpIsNaN(a)) {
6423
- sprintf(psz,SZ_NaN);
6424
- return 1;
6614
+ snprintf(buf, buflen, SZ_NaN);
6615
+ return 1;
6425
6616
  }
6426
6617
 
6427
6618
  if (VpIsPosInf(a)) {
6428
- if (fPlus == 1) {
6429
- *psz++ = ' ';
6430
- }
6431
- else if (fPlus == 2) {
6432
- *psz++ = '+';
6433
- }
6434
- sprintf(psz, SZ_INF);
6435
- return 1;
6619
+ if (fPlus == 1) {
6620
+ *buf++ = ' ';
6621
+ }
6622
+ else if (fPlus == 2) {
6623
+ *buf++ = '+';
6624
+ }
6625
+ snprintf(buf, buflen, SZ_INF);
6626
+ return 1;
6436
6627
  }
6437
6628
  if (VpIsNegInf(a)) {
6438
- sprintf(psz, SZ_NINF);
6439
- return 1;
6629
+ snprintf(buf, buflen, SZ_NINF);
6630
+ return 1;
6440
6631
  }
6441
6632
  if (VpIsZero(a)) {
6442
- if (VpIsPosZero(a)) {
6443
- if (fPlus == 1) sprintf(psz, " 0.0");
6444
- else if (fPlus == 2) sprintf(psz, "+0.0");
6445
- else sprintf(psz, "0.0");
6446
- }
6447
- else sprintf(psz, "-0.0");
6448
- return 1;
6633
+ if (VpIsPosZero(a)) {
6634
+ if (fPlus == 1) snprintf(buf, buflen, " 0.0");
6635
+ else if (fPlus == 2) snprintf(buf, buflen, "+0.0");
6636
+ else snprintf(buf, buflen, "0.0");
6637
+ }
6638
+ else snprintf(buf, buflen, "-0.0");
6639
+ return 1;
6449
6640
  }
6450
6641
  return 0;
6451
6642
  }
6452
6643
 
6453
6644
  VP_EXPORT void
6454
- VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
6645
+ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6455
6646
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6456
6647
  {
6457
6648
  size_t i, n, ZeroSup;
6458
6649
  DECDIG shift, m, e, nn;
6459
- char *pszSav = psz;
6650
+ char *p = buf;
6651
+ size_t plen = buflen;
6460
6652
  ssize_t ex;
6461
6653
 
6462
- if (VpToSpecialString(a, psz, fPlus)) return;
6654
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
6463
6655
 
6464
6656
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6465
6657
 
6466
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6467
- else if (fPlus == 1) *psz++ = ' ';
6468
- else if (fPlus == 2) *psz++ = '+';
6658
+ #define ADVANCE(n) do { \
6659
+ if (plen < n) goto overflow; \
6660
+ p += n; \
6661
+ plen -= n; \
6662
+ } while (0)
6663
+
6664
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6665
+ *p = '-';
6666
+ ADVANCE(1);
6667
+ }
6668
+ else if (fPlus == 1) {
6669
+ *p = ' ';
6670
+ ADVANCE(1);
6671
+ }
6672
+ else if (fPlus == 2) {
6673
+ *p = '+';
6674
+ ADVANCE(1);
6675
+ }
6676
+
6677
+ *p = '0'; ADVANCE(1);
6678
+ *p = '.'; ADVANCE(1);
6469
6679
 
6470
- *psz++ = '0';
6471
- *psz++ = '.';
6472
6680
  n = a->Prec;
6473
6681
  for (i = 0; i < n; ++i) {
6474
- m = BASE1;
6475
- e = a->frac[i];
6476
- while (m) {
6477
- nn = e / m;
6478
- if (!ZeroSup || nn) {
6479
- sprintf(psz, "%lu", (unsigned long)nn); /* The reading zero(s) */
6480
- psz += strlen(psz);
6481
- /* as 0.00xx will be ignored. */
6482
- ZeroSup = 0; /* Set to print succeeding zeros */
6483
- }
6484
- e = e - nn * m;
6485
- m /= 10;
6486
- }
6682
+ m = BASE1;
6683
+ e = a->frac[i];
6684
+ while (m) {
6685
+ nn = e / m;
6686
+ if (!ZeroSup || nn) {
6687
+ /* The reading zero(s) */
6688
+ size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn);
6689
+ if (n > plen) goto overflow;
6690
+ ADVANCE(n);
6691
+ /* as 0.00xx will be ignored. */
6692
+ ZeroSup = 0; /* Set to print succeeding zeros */
6693
+ }
6694
+ e = e - nn * m;
6695
+ m /= 10;
6696
+ }
6487
6697
  }
6698
+
6488
6699
  ex = a->exponent * (ssize_t)BASE_FIG;
6489
6700
  shift = BASE1;
6490
6701
  while (a->frac[0] / shift == 0) {
6491
- --ex;
6492
- shift /= 10;
6702
+ --ex;
6703
+ shift /= 10;
6493
6704
  }
6494
- while (psz[-1] == '0') {
6495
- *(--psz) = 0;
6705
+ while (p - 1 > buf && p[-1] == '0') {
6706
+ *(--p) = '\0';
6707
+ ++plen;
6496
6708
  }
6497
- sprintf(psz, "e%"PRIdSIZE, ex);
6498
- if (fFmt) VpFormatSt(pszSav, fFmt);
6709
+ snprintf(p, plen, "e%"PRIdSIZE, ex);
6710
+ if (fFmt) VpFormatSt(buf, fFmt);
6711
+
6712
+ overflow:
6713
+ return;
6714
+ #undef ADVANCE
6499
6715
  }
6500
6716
 
6501
6717
  VP_EXPORT void
6502
- VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
6718
+ VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6503
6719
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6504
6720
  {
6505
6721
  size_t i, n;
6506
- DECDIG m, e, nn;
6507
- char *pszSav = psz;
6722
+ DECDIG m, e;
6723
+ char *p = buf;
6724
+ size_t plen = buflen, delim = fFmt;
6508
6725
  ssize_t ex;
6509
6726
 
6510
- if (VpToSpecialString(a, psz, fPlus)) return;
6727
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
6728
+
6729
+ #define APPEND(c, group) do { \
6730
+ if (plen < 1) goto overflow; \
6731
+ if (group && delim == 0) { \
6732
+ *p = ' '; \
6733
+ p += 1; \
6734
+ plen -= 1; \
6735
+ } \
6736
+ if (plen < 1) goto overflow; \
6737
+ *p = c; \
6738
+ p += 1; \
6739
+ plen -= 1; \
6740
+ if (group) delim = (delim + 1) % fFmt; \
6741
+ } while (0)
6742
+
6511
6743
 
6512
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6513
- else if (fPlus == 1) *psz++ = ' ';
6514
- else if (fPlus == 2) *psz++ = '+';
6744
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6745
+ APPEND('-', false);
6746
+ }
6747
+ else if (fPlus == 1) {
6748
+ APPEND(' ', false);
6749
+ }
6750
+ else if (fPlus == 2) {
6751
+ APPEND('+', false);
6752
+ }
6515
6753
 
6516
6754
  n = a->Prec;
6517
6755
  ex = a->exponent;
6518
6756
  if (ex <= 0) {
6519
- *psz++ = '0';*psz++ = '.';
6520
- while (ex < 0) {
6521
- for (i=0; i < BASE_FIG; ++i) *psz++ = '0';
6522
- ++ex;
6523
- }
6524
- ex = -1;
6757
+ APPEND('0', false);
6758
+ APPEND('.', false);
6759
+ }
6760
+ while (ex < 0) {
6761
+ for (i=0; i < BASE_FIG; ++i) {
6762
+ APPEND('0', fFmt > 0);
6763
+ }
6764
+ ++ex;
6525
6765
  }
6526
6766
 
6527
6767
  for (i = 0; i < n; ++i) {
6528
- --ex;
6529
- if (i == 0 && ex >= 0) {
6530
- sprintf(psz, "%lu", (unsigned long)a->frac[i]);
6531
- psz += strlen(psz);
6532
- }
6533
- else {
6534
- m = BASE1;
6535
- e = a->frac[i];
6536
- while (m) {
6537
- nn = e / m;
6538
- *psz++ = (char)(nn + '0');
6539
- e = e - nn * m;
6540
- m /= 10;
6541
- }
6542
- }
6543
- if (ex == 0) *psz++ = '.';
6768
+ m = BASE1;
6769
+ e = a->frac[i];
6770
+ if (i == 0 && ex > 0) {
6771
+ for (delim = 0; e / m == 0; delim++) {
6772
+ m /= 10;
6773
+ }
6774
+ if (fFmt > 0) {
6775
+ delim = 2*fFmt - (ex * BASE_FIG - delim) % fFmt;
6776
+ }
6777
+ }
6778
+ while (m && (e || (i < n - 1) || ex > 0)) {
6779
+ APPEND((char)(e / m + '0'), fFmt > 0);
6780
+ e %= m;
6781
+ m /= 10;
6782
+ }
6783
+ if (--ex == 0) {
6784
+ APPEND('.', false);
6785
+ delim = fFmt;
6786
+ }
6544
6787
  }
6545
- while (--ex>=0) {
6546
- m = BASE;
6547
- while (m /= 10) *psz++ = '0';
6548
- if (ex == 0) *psz++ = '.';
6788
+
6789
+ while (ex > 0) {
6790
+ for (i=0; i < BASE_FIG; ++i) {
6791
+ APPEND('0', fFmt > 0);
6792
+ }
6793
+ if (--ex == 0) {
6794
+ APPEND('.', false);
6795
+ }
6549
6796
  }
6550
- *psz = 0;
6551
- while (psz[-1] == '0') *(--psz) = 0;
6552
- if (psz[-1] == '.') sprintf(psz, "0");
6553
- if (fFmt) VpFormatSt(pszSav, fFmt);
6797
+
6798
+ *p = '\0';
6799
+ if (p - 1 > buf && p[-1] == '.') {
6800
+ snprintf(p, plen, "0");
6801
+ }
6802
+
6803
+ overflow:
6804
+ return;
6805
+ #undef APPEND
6554
6806
  }
6555
6807
 
6556
6808
  /*
@@ -6927,7 +7179,6 @@ VpSqrt(Real *y, Real *x)
6927
7179
  Real *r = NULL;
6928
7180
  size_t y_prec;
6929
7181
  SIGNED_VALUE n, e;
6930
- SIGNED_VALUE prec;
6931
7182
  ssize_t nr;
6932
7183
  double val;
6933
7184
 
@@ -6959,18 +7210,13 @@ VpSqrt(Real *y, Real *x)
6959
7210
  if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
6960
7211
 
6961
7212
  /* allocate temporally variables */
6962
- f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1, 1);
6963
- r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1, 1);
7213
+ /* TODO: reconsider MaxPrec of f and r */
7214
+ f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7215
+ r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
6964
7216
 
6965
7217
  nr = 0;
6966
7218
  y_prec = y->MaxPrec;
6967
7219
 
6968
- prec = x->exponent - (ssize_t)y_prec;
6969
- if (x->exponent > 0)
6970
- ++prec;
6971
- else
6972
- --prec;
6973
-
6974
7220
  VpVtoD(&val, &e, x); /* val <- x */
6975
7221
  e /= (SIGNED_VALUE)BASE_FIG;
6976
7222
  n = e / 2;
@@ -6984,17 +7230,22 @@ VpSqrt(Real *y, Real *x)
6984
7230
  y->MaxPrec = Min((size_t)n , y_prec);
6985
7231
  f->MaxPrec = y->MaxPrec + 1;
6986
7232
  n = (SIGNED_VALUE)(y_prec * BASE_FIG);
6987
- if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7233
+ if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7234
+
7235
+ /*
7236
+ * Perform: y_{n+1} = (y_n - x/y_n) / 2
7237
+ */
6988
7238
  do {
6989
- y->MaxPrec *= 2;
6990
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
6991
- f->MaxPrec = y->MaxPrec;
6992
- VpDivd(f, r, x, y); /* f = x/y */
6993
- VpAddSub(r, f, y, -1); /* r = f - y */
6994
- VpMult(f, VpPt5, r); /* f = 0.5*r */
6995
- if (VpIsZero(f)) goto converge;
6996
- VpAddSub(r, f, y, 1); /* r = y + f */
6997
- VpAsgn(y, r, 1); /* y = r */
7239
+ y->MaxPrec *= 2;
7240
+ if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7241
+ f->MaxPrec = y->MaxPrec;
7242
+ VpDivd(f, r, x, y); /* f = x/y */
7243
+ VpAddSub(r, f, y, -1); /* r = f - y */
7244
+ VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7245
+ if (VpIsZero(f))
7246
+ goto converge;
7247
+ VpAddSub(r, f, y, 1); /* r = y + f */
7248
+ VpAsgn(y, r, 1); /* y = r */
6998
7249
  } while (++nr < n);
6999
7250
 
7000
7251
  #ifdef BIGDECIMAL_DEBUG
@@ -7019,8 +7270,8 @@ converge:
7019
7270
  y->MaxPrec = y_prec;
7020
7271
 
7021
7272
  Exit:
7022
- VpFree(f);
7023
- VpFree(r);
7273
+ rbd_free_struct(f);
7274
+ rbd_free_struct(r);
7024
7275
  return 1;
7025
7276
  }
7026
7277
 
@@ -7411,9 +7662,10 @@ VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7411
7662
  }
7412
7663
 
7413
7664
  /* Allocate working variables */
7665
+ /* TODO: reconsider MaxPrec of w1 and w2 */
7666
+ w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7667
+ w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7414
7668
 
7415
- w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1);
7416
- w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1);
7417
7669
  /* calculation start */
7418
7670
 
7419
7671
  VpAsgn(y, x, 1);
@@ -7442,8 +7694,8 @@ Exit:
7442
7694
  printf(" n=%"PRIdVALUE"\n", n);
7443
7695
  }
7444
7696
  #endif /* BIGDECIMAL_DEBUG */
7445
- VpFree(w2);
7446
- VpFree(w1);
7697
+ rbd_free_struct(w2);
7698
+ rbd_free_struct(w1);
7447
7699
  return 1;
7448
7700
  }
7449
7701