bigdecimal 3.1.2 → 3.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.4"
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());
@@ -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
  }
@@ -1655,8 +1849,8 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
1655
1849
  if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1656
1850
  mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1657
1851
 
1658
- GUARD_OBJ((*c), VpCreateRbObject(mx + 2*BASE_FIG, "#0", true));
1659
- GUARD_OBJ((*res), VpCreateRbObject((mx + 1)*2 + 2*BASE_FIG, "#0", true));
1852
+ GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
1853
+ GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
1660
1854
  VpDivd(*c, *res, a, b);
1661
1855
 
1662
1856
  return Qnil;
@@ -1721,7 +1915,7 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
1721
1915
 
1722
1916
  argc = rb_scan_args(argc, argv, "11", &value, &digits);
1723
1917
  if (argc > 1) {
1724
- n = GetPrecisionInt(digits);
1918
+ n = check_int_precision(digits);
1725
1919
  }
1726
1920
 
1727
1921
  if (n > 0) {
@@ -1811,12 +2005,12 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1811
2005
  if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
1812
2006
  mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
1813
2007
 
1814
- GUARD_OBJ(c, VpCreateRbObject(mx + 2*BASE_FIG, "0", true));
1815
- 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));
1816
2010
  VpDivd(c, res, a, b);
1817
2011
 
1818
2012
  mx = c->Prec * BASE_FIG;
1819
- GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
2013
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
1820
2014
  VpActiveRound(d, c, VP_ROUND_DOWN, 0);
1821
2015
 
1822
2016
  VpMult(res, d, b);
@@ -1824,10 +2018,10 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1824
2018
 
1825
2019
  if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
1826
2020
  /* result adjustment for negative case */
1827
- res = VpReallocReal(res, d->MaxPrec);
2021
+ res = rbd_reallocate_struct(res, d->MaxPrec);
1828
2022
  res->MaxPrec = d->MaxPrec;
1829
2023
  VpAddSub(res, d, VpOne(), -1);
1830
- GUARD_OBJ(d, VpCreateRbObject(GetAddSubPrec(c, b) * 2*BASE_FIG, "0", true));
2024
+ GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
1831
2025
  VpAddSub(d, c, b, 1);
1832
2026
  *div = res;
1833
2027
  *mod = d;
@@ -1890,18 +2084,25 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1890
2084
  if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
1891
2085
  SAVE(b);
1892
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
+
1893
2094
  mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
1894
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
1895
- GUARD_OBJ(res, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0", true));
1896
- GUARD_OBJ(rr, VpCreateRbObject((mx+1) * 2 + (VpBaseFig() + 1), "#0", true));
1897
- 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)));
1898
2099
 
1899
2100
  VpDivd(c, res, a, b);
1900
2101
 
1901
2102
  mx = c->Prec *(VpBaseFig() + 1);
1902
2103
 
1903
- GUARD_OBJ(d, VpCreateRbObject(mx, "0", true));
1904
- GUARD_OBJ(f, VpCreateRbObject(mx, "0", true));
2104
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
2105
+ GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
1905
2106
 
1906
2107
  VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
1907
2108
 
@@ -1986,7 +2187,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1986
2187
  }
1987
2188
 
1988
2189
  /* div in BigDecimal sense */
1989
- ix = GetPrecisionInt(n);
2190
+ ix = check_int_precision(n);
1990
2191
  if (ix == 0) {
1991
2192
  return BigDecimal_div(self, b);
1992
2193
  }
@@ -1997,7 +2198,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
1997
2198
  size_t b_prec = ix;
1998
2199
  size_t pl = VpSetPrecLimit(0);
1999
2200
 
2000
- GUARD_OBJ(cv, VpCreateRbObject(mx + VpBaseFig(), "0", true));
2201
+ GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig()));
2001
2202
  GUARD_OBJ(av, GetVpValue(self, 1));
2002
2203
  /* TODO: I want to refactor this precision control for a float value later
2003
2204
  * by introducing an implicit conversion function instead of
@@ -2008,7 +2209,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
2008
2209
  GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
2009
2210
  mx = av->Prec + bv->Prec + 2;
2010
2211
  if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
2011
- GUARD_OBJ(res, VpCreateRbObject((mx * 2 + 2)*VpBaseFig(), "#0", true));
2212
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
2012
2213
  VpDivd(cv, res, av, bv);
2013
2214
  VpSetPrecLimit(pl);
2014
2215
  VpLeftRound(cv, VpGetRoundMode(), ix);
@@ -2091,7 +2292,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
2091
2292
  {
2092
2293
  ENTER(2);
2093
2294
  Real *cv;
2094
- SIGNED_VALUE mx = GetPrecisionInt(n);
2295
+ SIGNED_VALUE mx = check_int_precision(n);
2095
2296
  if (mx == 0) return BigDecimal_add(self, b);
2096
2297
  else {
2097
2298
  size_t pl = VpSetPrecLimit(0);
@@ -2121,7 +2322,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
2121
2322
  {
2122
2323
  ENTER(2);
2123
2324
  Real *cv;
2124
- SIGNED_VALUE mx = GetPrecisionInt(n);
2325
+ SIGNED_VALUE mx = check_int_precision(n);
2125
2326
  if (mx == 0) return BigDecimal_sub(self, b);
2126
2327
  else {
2127
2328
  size_t pl = VpSetPrecLimit(0);
@@ -2164,7 +2365,7 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
2164
2365
  {
2165
2366
  ENTER(2);
2166
2367
  Real *cv;
2167
- SIGNED_VALUE mx = GetPrecisionInt(n);
2368
+ SIGNED_VALUE mx = check_int_precision(n);
2168
2369
  if (mx == 0) return BigDecimal_mult(self, b);
2169
2370
  else {
2170
2371
  size_t pl = VpSetPrecLimit(0);
@@ -2196,7 +2397,7 @@ BigDecimal_abs(VALUE self)
2196
2397
 
2197
2398
  GUARD_OBJ(a, GetVpValue(self, 1));
2198
2399
  mx = a->Prec *(VpBaseFig() + 1);
2199
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2400
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2200
2401
  VpAsgn(c, a, 1);
2201
2402
  VpChangeSign(c, 1);
2202
2403
  return VpCheckGetValue(c);
@@ -2219,9 +2420,10 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
2219
2420
  GUARD_OBJ(a, GetVpValue(self, 1));
2220
2421
  mx = a->Prec * (VpBaseFig() + 1);
2221
2422
 
2222
- n = GetPrecisionInt(nFig) + VpDblFig() + BASE_FIG;
2423
+ n = check_int_precision(nFig);
2424
+ n += VpDblFig() + VpBaseFig();
2223
2425
  if (mx <= n) mx = n;
2224
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2426
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2225
2427
  VpSqrt(c, a);
2226
2428
  return VpCheckGetValue(c);
2227
2429
  }
@@ -2237,7 +2439,7 @@ BigDecimal_fix(VALUE self)
2237
2439
 
2238
2440
  GUARD_OBJ(a, GetVpValue(self, 1));
2239
2441
  mx = a->Prec *(VpBaseFig() + 1);
2240
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2442
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2241
2443
  VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
2242
2444
  return VpCheckGetValue(c);
2243
2445
  }
@@ -2310,7 +2512,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
2310
2512
  pl = VpSetPrecLimit(0);
2311
2513
  GUARD_OBJ(a, GetVpValue(self, 1));
2312
2514
  mx = a->Prec * (VpBaseFig() + 1);
2313
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2515
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2314
2516
  VpSetPrecLimit(pl);
2315
2517
  VpActiveRound(c, a, sw, iLoc);
2316
2518
  if (round_to_int) {
@@ -2356,7 +2558,7 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
2356
2558
 
2357
2559
  GUARD_OBJ(a, GetVpValue(self, 1));
2358
2560
  mx = a->Prec * (VpBaseFig() + 1);
2359
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2561
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2360
2562
  VpSetPrecLimit(pl);
2361
2563
  VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
2362
2564
  if (argc == 0) {
@@ -2376,7 +2578,7 @@ BigDecimal_frac(VALUE self)
2376
2578
 
2377
2579
  GUARD_OBJ(a, GetVpValue(self, 1));
2378
2580
  mx = a->Prec * (VpBaseFig() + 1);
2379
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2581
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2380
2582
  VpFrac(c, a);
2381
2583
  return VpCheckGetValue(c);
2382
2584
  }
@@ -2416,7 +2618,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
2416
2618
 
2417
2619
  GUARD_OBJ(a, GetVpValue(self, 1));
2418
2620
  mx = a->Prec * (VpBaseFig() + 1);
2419
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2621
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2420
2622
  VpSetPrecLimit(pl);
2421
2623
  VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
2422
2624
  #ifdef BIGDECIMAL_DEBUG
@@ -2462,7 +2664,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
2462
2664
 
2463
2665
  GUARD_OBJ(a, GetVpValue(self, 1));
2464
2666
  mx = a->Prec * (VpBaseFig() + 1);
2465
- GUARD_OBJ(c, VpCreateRbObject(mx, "0", true));
2667
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
2466
2668
  VpSetPrecLimit(pl);
2467
2669
  VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
2468
2670
  if (argc == 0) {
@@ -2566,10 +2768,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2566
2768
  psz = RSTRING_PTR(str);
2567
2769
 
2568
2770
  if (fmt) {
2569
- VpToFString(vp, psz, mc, fPlus);
2771
+ VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
2570
2772
  }
2571
2773
  else {
2572
- VpToString (vp, psz, mc, fPlus);
2774
+ VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
2573
2775
  }
2574
2776
  rb_str_resize(str, strlen(psz));
2575
2777
  return str;
@@ -2611,7 +2813,7 @@ BigDecimal_split(VALUE self)
2611
2813
  GUARD_OBJ(vp, GetVpValue(self, 1));
2612
2814
  str = rb_str_new(0, VpNumOfChars(vp, "E"));
2613
2815
  psz1 = RSTRING_PTR(str);
2614
- VpSzMantissa(vp, psz1);
2816
+ VpSzMantissa(vp, psz1, RSTRING_LEN(str));
2615
2817
  s = 1;
2616
2818
  if(psz1[0] == '-') {
2617
2819
  size_t len = strlen(psz1 + 1);
@@ -2660,7 +2862,7 @@ BigDecimal_inspect(VALUE self)
2660
2862
  nc = VpNumOfChars(vp, "E");
2661
2863
 
2662
2864
  str = rb_str_new(0, nc);
2663
- VpToString(vp, RSTRING_PTR(str), 0, 0);
2865
+ VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
2664
2866
  rb_str_resize(str, strlen(RSTRING_PTR(str)));
2665
2867
  return str;
2666
2868
  }
@@ -2770,7 +2972,7 @@ bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
2770
2972
  volatile VALUE obj = exp->obj;
2771
2973
 
2772
2974
  if (VpIsZero(exp)) {
2773
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2975
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
2774
2976
  }
2775
2977
 
2776
2978
  log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
@@ -2808,9 +3010,9 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2808
3010
  n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2809
3011
 
2810
3012
  if (VpIsNaN(x)) {
2811
- y = VpCreateRbObject(n, "0", true);
2812
- RB_GC_GUARD(y->obj);
2813
- VpSetNaN(y);
3013
+ y = NewZeroWrapLimited(1, n);
3014
+ VpSetNaN(y);
3015
+ RB_GC_GUARD(y->obj);
2814
3016
  return VpCheckGetValue(y);
2815
3017
  }
2816
3018
 
@@ -2879,136 +3081,126 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2879
3081
  }
2880
3082
 
2881
3083
  if (VpIsZero(x)) {
2882
- if (is_negative(vexp)) {
2883
- y = VpCreateRbObject(n, "#0", true);
2884
- RB_GC_GUARD(y->obj);
2885
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2886
- if (is_integer(vexp)) {
2887
- if (is_even(vexp)) {
2888
- /* (-0) ** (-even_integer) -> Infinity */
2889
- VpSetPosInf(y);
2890
- }
2891
- else {
2892
- /* (-0) ** (-odd_integer) -> -Infinity */
2893
- VpSetNegInf(y);
2894
- }
2895
- }
2896
- else {
2897
- /* (-0) ** (-non_integer) -> Infinity */
2898
- VpSetPosInf(y);
2899
- }
2900
- }
2901
- else {
2902
- /* (+0) ** (-num) -> Infinity */
2903
- VpSetPosInf(y);
2904
- }
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);
2905
3107
  return VpCheckGetValue(y);
2906
- }
2907
- else if (is_zero(vexp)) {
2908
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2909
- }
2910
- else {
2911
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2912
- }
3108
+ }
3109
+ else if (is_zero(vexp)) {
3110
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
3111
+ }
3112
+ else {
3113
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
3114
+ }
2913
3115
  }
2914
3116
 
2915
3117
  if (is_zero(vexp)) {
2916
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
3118
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
2917
3119
  }
2918
3120
  else if (is_one(vexp)) {
2919
- return self;
3121
+ return self;
2920
3122
  }
2921
3123
 
2922
3124
  if (VpIsInf(x)) {
2923
- if (is_negative(vexp)) {
2924
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2925
- if (is_integer(vexp)) {
2926
- if (is_even(vexp)) {
2927
- /* (-Infinity) ** (-even_integer) -> +0 */
2928
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2929
- }
2930
- else {
2931
- /* (-Infinity) ** (-odd_integer) -> -0 */
2932
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2933
- }
2934
- }
2935
- else {
2936
- /* (-Infinity) ** (-non_integer) -> -0 */
2937
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2938
- }
2939
- }
2940
- else {
2941
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2942
- }
2943
- }
2944
- else {
2945
- y = VpCreateRbObject(n, "0", true);
2946
- if (BIGDECIMAL_NEGATIVE_P(x)) {
2947
- if (is_integer(vexp)) {
2948
- if (is_even(vexp)) {
2949
- VpSetPosInf(y);
2950
- }
2951
- else {
2952
- VpSetNegInf(y);
2953
- }
2954
- }
2955
- else {
2956
- /* TODO: support complex */
2957
- rb_raise(rb_eMathDomainError,
2958
- "a non-integral exponent for a negative base");
2959
- }
2960
- }
2961
- else {
2962
- VpSetPosInf(y);
2963
- }
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
+ }
2964
3166
  return VpCheckGetValue(y);
2965
- }
3167
+ }
2966
3168
  }
2967
3169
 
2968
3170
  if (exp != NULL) {
2969
- return bigdecimal_power_by_bigdecimal(x, exp, n);
3171
+ return bigdecimal_power_by_bigdecimal(x, exp, n);
2970
3172
  }
2971
3173
  else if (RB_TYPE_P(vexp, T_BIGNUM)) {
2972
- VALUE abs_value = BigDecimal_abs(self);
2973
- if (is_one(abs_value)) {
2974
- return VpCheckGetValue(VpCreateRbObject(n, "1", true));
2975
- }
2976
- else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
2977
- if (is_negative(vexp)) {
2978
- y = VpCreateRbObject(n, "0", true);
2979
- if (is_even(vexp)) {
2980
- VpSetInf(y, VpGetSign(x));
2981
- }
2982
- else {
2983
- VpSetInf(y, -VpGetSign(x));
2984
- }
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));
2985
3182
  return VpCheckGetValue(y);
2986
- }
2987
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
2988
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
2989
- }
2990
- else {
2991
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
2992
- }
2993
- }
2994
- else {
2995
- if (is_positive(vexp)) {
2996
- y = VpCreateRbObject(n, "0", true);
2997
- if (is_even(vexp)) {
2998
- VpSetInf(y, VpGetSign(x));
2999
- }
3000
- else {
3001
- VpSetInf(y, -VpGetSign(x));
3002
- }
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));
3003
3195
  return VpCheckGetValue(y);
3004
- }
3005
- else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
3006
- return VpCheckGetValue(VpCreateRbObject(n, "-0", true));
3007
- }
3008
- else {
3009
- return VpCheckGetValue(VpCreateRbObject(n, "0", true));
3010
- }
3011
- }
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
+ }
3012
3204
  }
3013
3205
 
3014
3206
  int_exp = FIX2LONG(vexp);
@@ -3017,15 +3209,15 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
3017
3209
  if (ma == 0) ma = 1;
3018
3210
 
3019
3211
  if (VpIsDef(x)) {
3020
- mp = x->Prec * (VpBaseFig() + 1);
3021
- GUARD_OBJ(y, VpCreateRbObject(mp * (ma + 1), "0", true));
3212
+ mp = x->Prec * (VpBaseFig() + 1);
3213
+ GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
3022
3214
  }
3023
3215
  else {
3024
- GUARD_OBJ(y, VpCreateRbObject(1, "0", true));
3216
+ GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
3025
3217
  }
3026
3218
  VpPowerByInt(y, x, int_exp);
3027
3219
  if (!NIL_P(prec) && VpIsDef(y)) {
3028
- VpMidRound(y, VpGetRoundMode(), n);
3220
+ VpMidRound(y, VpGetRoundMode(), n);
3029
3221
  }
3030
3222
  return VpCheckGetValue(y);
3031
3223
  }
@@ -3114,7 +3306,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3114
3306
 
3115
3307
  Real *vp;
3116
3308
  if (uval == 0) {
3117
- vp = VpAllocReal(1);
3309
+ vp = rbd_allocate_struct(1);
3118
3310
  vp->MaxPrec = 1;
3119
3311
  vp->Prec = 1;
3120
3312
  vp->exponent = 1;
@@ -3122,7 +3314,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3122
3314
  vp->frac[0] = 0;
3123
3315
  }
3124
3316
  else if (uval < BASE) {
3125
- vp = VpAllocReal(1);
3317
+ vp = rbd_allocate_struct(1);
3126
3318
  vp->MaxPrec = 1;
3127
3319
  vp->Prec = 1;
3128
3320
  vp->exponent = 1;
@@ -3148,7 +3340,7 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
3148
3340
  }
3149
3341
 
3150
3342
  const size_t exp = len + ntz;
3151
- vp = VpAllocReal(len);
3343
+ vp = rbd_allocate_struct(len);
3152
3344
  vp->MaxPrec = len;
3153
3345
  vp->Prec = len;
3154
3346
  vp->exponent = exp;
@@ -3281,7 +3473,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3281
3473
 
3282
3474
  VALUE inum;
3283
3475
  size_t RB_UNUSED_VAR(prec) = 0;
3284
- size_t exp = 0;
3476
+ SIGNED_VALUE exp = 0;
3285
3477
  if (decpt > 0) {
3286
3478
  if (decpt < len10) {
3287
3479
  /*
@@ -3493,12 +3685,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
3493
3685
  * BigDecimal(value, exception: true) -> bigdecimal
3494
3686
  * BigDecimal(value, ndigits, exception: true) -> bigdecimal
3495
3687
  *
3496
- * Returns the \BigDecimal converted from +value+
3497
- * 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.
3498
3694
  *
3499
- * When +ndigits+ is less than the number of significant digits
3500
- * in the value, the result is rounded to that number of digits,
3501
- * 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.
3502
3697
  *
3503
3698
  * Returns +value+ converted to a \BigDecimal, depending on the type of +value+:
3504
3699
  *
@@ -3606,8 +3801,10 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
3606
3801
 
3607
3802
  /* Returns the sign of the value.
3608
3803
  *
3609
- * Returns a positive value if > 0, a negative value if < 0, and a
3610
- * 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')).
3611
3808
  *
3612
3809
  * The specific value returned indicates the type and sign of the BigDecimal,
3613
3810
  * as follows:
@@ -3771,18 +3968,16 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3771
3968
  return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
3772
3969
  }
3773
3970
  else {
3774
- Real* vy;
3775
- vy = VpCreateRbObject(prec, "#0", true);
3971
+ Real* vy = NewZeroWrapNolimit(1, prec);
3776
3972
  VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3777
3973
  RB_GC_GUARD(vy->obj);
3778
3974
  return VpCheckGetValue(vy);
3779
3975
  }
3780
3976
  }
3781
3977
  else if (nan) {
3782
- Real* vy;
3783
- vy = VpCreateRbObject(prec, "#0", true);
3784
- VpSetNaN(vy);
3785
- RB_GC_GUARD(vy->obj);
3978
+ Real* vy = NewZeroWrapNolimit(1, prec);
3979
+ VpSetNaN(vy);
3980
+ RB_GC_GUARD(vy->obj);
3786
3981
  return VpCheckGetValue(vy);
3787
3982
  }
3788
3983
  else if (vx == NULL) {
@@ -3800,7 +3995,7 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
3800
3995
  VpSetSign(vx, 1);
3801
3996
  }
3802
3997
 
3803
- one = VpCheckGetValue(VpCreateRbObject(1, "1", true));
3998
+ one = VpCheckGetValue(NewOneWrapLimited(1, 1));
3804
3999
  y = one;
3805
4000
  d = y;
3806
4001
  i = 1;
@@ -3927,15 +4122,13 @@ get_vp_value:
3927
4122
  break;
3928
4123
  }
3929
4124
  if (infinite && !negative) {
3930
- Real* vy;
3931
- vy = VpCreateRbObject(prec, "#0", true);
4125
+ Real *vy = NewZeroWrapNolimit(1, prec);
3932
4126
  RB_GC_GUARD(vy->obj);
3933
4127
  VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
3934
4128
  return VpCheckGetValue(vy);
3935
4129
  }
3936
4130
  else if (nan) {
3937
- Real* vy;
3938
- vy = VpCreateRbObject(prec, "#0", true);
4131
+ Real* vy = NewZeroWrapNolimit(1, prec);
3939
4132
  RB_GC_GUARD(vy->obj);
3940
4133
  VpSetNaN(vy);
3941
4134
  return VpCheckGetValue(vy);
@@ -3949,11 +4142,11 @@ get_vp_value:
3949
4142
  }
3950
4143
  x = VpCheckGetValue(vx);
3951
4144
 
3952
- RB_GC_GUARD(one) = VpCheckGetValue(VpCreateRbObject(1, "1", true));
3953
- RB_GC_GUARD(two) = VpCheckGetValue(VpCreateRbObject(1, "2", true));
4145
+ one = VpCheckGetValue(NewOneWrapLimited(1, 1));
4146
+ two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
3954
4147
 
3955
4148
  n = prec + BIGDECIMAL_DOUBLE_FIGURES;
3956
- RB_GC_GUARD(vn) = SSIZET2NUM(n);
4149
+ vn = SSIZET2NUM(n);
3957
4150
  expo = VpExponent10(vx);
3958
4151
  if (expo < 0 || expo >= 3) {
3959
4152
  char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
@@ -3965,9 +4158,9 @@ get_vp_value:
3965
4158
  }
3966
4159
  w = BigDecimal_sub(x, one);
3967
4160
  x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
3968
- RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
3969
- RB_GC_GUARD(y) = x;
3970
- RB_GC_GUARD(d) = y;
4161
+ x2 = BigDecimal_mult2(x, x, vn);
4162
+ y = x;
4163
+ d = y;
3971
4164
  i = 1;
3972
4165
  while (!VpIsZero((Real*)DATA_PTR(d))) {
3973
4166
  SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
@@ -3995,6 +4188,13 @@ get_vp_value:
3995
4188
  y = BigDecimal_add(y, dy);
3996
4189
  }
3997
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
+
3998
4198
  return y;
3999
4199
  }
4000
4200
 
@@ -4211,13 +4411,10 @@ Init_bigdecimal(void)
4211
4411
 
4212
4412
  /* Constants definition */
4213
4413
 
4214
- #ifndef RUBY_BIGDECIMAL_VERSION
4215
- # error RUBY_BIGDECIMAL_VERSION is not defined
4216
- #endif
4217
4414
  /*
4218
4415
  * The version of bigdecimal library
4219
4416
  */
4220
- rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(RUBY_BIGDECIMAL_VERSION));
4417
+ rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(BIGDECIMAL_VERSION));
4221
4418
 
4222
4419
  /*
4223
4420
  * Base value used in internal calculations. On a 32 bit system, BASE
@@ -4414,20 +4611,31 @@ Init_bigdecimal(void)
4414
4611
  rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
4415
4612
  rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
4416
4613
 
4417
- id_up = rb_intern_const("up");
4418
- id_down = rb_intern_const("down");
4419
- id_truncate = rb_intern_const("truncate");
4420
- id_half_up = rb_intern_const("half_up");
4421
- id_default = rb_intern_const("default");
4422
- id_half_down = rb_intern_const("half_down");
4423
- id_half_even = rb_intern_const("half_even");
4424
- id_banker = rb_intern_const("banker");
4425
- id_ceiling = rb_intern_const("ceiling");
4426
- id_ceil = rb_intern_const("ceil");
4427
- id_floor = rb_intern_const("floor");
4614
+ #define ROUNDING_MODE(i, name, value) \
4615
+ id_##name = rb_intern_const(#name); \
4616
+ rbd_rounding_modes[i].id = id_##name; \
4617
+ rbd_rounding_modes[i].mode = value;
4618
+
4619
+ ROUNDING_MODE(0, up, RBD_ROUND_UP);
4620
+ ROUNDING_MODE(1, down, RBD_ROUND_DOWN);
4621
+ ROUNDING_MODE(2, half_up, RBD_ROUND_HALF_UP);
4622
+ ROUNDING_MODE(3, half_down, RBD_ROUND_HALF_DOWN);
4623
+ ROUNDING_MODE(4, ceil, RBD_ROUND_CEIL);
4624
+ ROUNDING_MODE(5, floor, RBD_ROUND_FLOOR);
4625
+ ROUNDING_MODE(6, half_even, RBD_ROUND_HALF_EVEN);
4626
+
4627
+ ROUNDING_MODE(7, default, RBD_ROUND_DEFAULT);
4628
+ ROUNDING_MODE(8, truncate, RBD_ROUND_TRUNCATE);
4629
+ ROUNDING_MODE(9, banker, RBD_ROUND_BANKER);
4630
+ ROUNDING_MODE(10, ceiling, RBD_ROUND_CEILING);
4631
+
4632
+ #undef ROUNDING_MODE
4633
+
4428
4634
  id_to_r = rb_intern_const("to_r");
4429
4635
  id_eq = rb_intern_const("==");
4430
4636
  id_half = rb_intern_const("half");
4637
+
4638
+ (void)VPrint; /* suppress unused warning */
4431
4639
  }
4432
4640
 
4433
4641
  /*
@@ -4447,7 +4655,7 @@ static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
4447
4655
  #endif /* BIGDECIMAL_DEBUG */
4448
4656
 
4449
4657
  static Real *VpConstOne; /* constant 1.0 */
4450
- static Real *VpPt5; /* constant 0.5 */
4658
+ static Real *VpConstPt5; /* constant 0.5 */
4451
4659
  #define maxnr 100UL /* Maximum iterations for calculating sqrt. */
4452
4660
  /* used in VpSqrt() */
4453
4661
 
@@ -4478,42 +4686,6 @@ static int VpRdup(Real *m, size_t ind_m);
4478
4686
  static int gnAlloc = 0; /* Memory allocation counter */
4479
4687
  #endif /* BIGDECIMAL_DEBUG */
4480
4688
 
4481
- VP_EXPORT void *
4482
- VpMemAlloc(size_t mb)
4483
- {
4484
- void *p = xmalloc(mb);
4485
- memset(p, 0, mb);
4486
- #ifdef BIGDECIMAL_DEBUG
4487
- gnAlloc++; /* Count allocation call */
4488
- #endif /* BIGDECIMAL_DEBUG */
4489
- return p;
4490
- }
4491
-
4492
- VP_EXPORT void *
4493
- VpMemRealloc(void *ptr, size_t mb)
4494
- {
4495
- return xrealloc(ptr, mb);
4496
- }
4497
-
4498
- VP_EXPORT void
4499
- VpFree(Real *pv)
4500
- {
4501
- if (pv != NULL) {
4502
- xfree(pv);
4503
- #ifdef BIGDECIMAL_DEBUG
4504
- gnAlloc--; /* Decrement allocation count */
4505
- if (gnAlloc == 0) {
4506
- printf(" *************** All memories allocated freed ****************\n");
4507
- /*getchar();*/
4508
- }
4509
- if (gnAlloc < 0) {
4510
- printf(" ??????????? Too many memory free calls(%d) ?????????????\n", gnAlloc);
4511
- /*getchar();*/
4512
- }
4513
- #endif /* BIGDECIMAL_DEBUG */
4514
- }
4515
- }
4516
-
4517
4689
  /*
4518
4690
  * EXCEPTION Handling.
4519
4691
  */
@@ -4902,9 +5074,13 @@ VpInit(DECDIG BaseVal)
4902
5074
  /* Setup +/- Inf NaN -0 */
4903
5075
  VpGetDoubleNegZero();
4904
5076
 
4905
- /* Allocates Vp constants. */
4906
- VpConstOne = VpAlloc(1UL, "1", 1, 1);
4907
- VpPt5 = VpAlloc(1UL, ".5", 1, 1);
5077
+ /* Const 1.0 */
5078
+ VpConstOne = NewOneNolimit(1, 1);
5079
+
5080
+ /* Const 0.5 */
5081
+ VpConstPt5 = NewOneNolimit(1, 1);
5082
+ VpConstPt5->exponent = 0;
5083
+ VpConstPt5->frac[0] = 5*BASE1;
4908
5084
 
4909
5085
  #ifdef BIGDECIMAL_DEBUG
4910
5086
  gnAlloc = 0;
@@ -4993,7 +5169,7 @@ bigdecimal_parse_special_string(const char *str)
4993
5169
  p = str + table[i].len;
4994
5170
  while (*p && ISSPACE(*p)) ++p;
4995
5171
  if (*p == '\0') {
4996
- Real *vp = VpAllocReal(1);
5172
+ Real *vp = rbd_allocate_struct(1);
4997
5173
  vp->MaxPrec = 1;
4998
5174
  switch (table[i].sign) {
4999
5175
  default:
@@ -5017,11 +5193,11 @@ bigdecimal_parse_special_string(const char *str)
5017
5193
  /*
5018
5194
  * Allocates variable.
5019
5195
  * [Input]
5020
- * mx ... allocation unit, if zero then mx is determined by szVal.
5021
- * The mx is the number of effective digits can to be stored.
5022
- * szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
5023
- * If szVal[0]=='#' then Max. Prec. will not be considered(1.1.7),
5024
- * full precision specified by szVal is allocated.
5196
+ * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
5197
+ * The mx will be the number of significant digits can to be stored.
5198
+ * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
5199
+ * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
5200
+ * so that the full precision specified by szVal is allocated.
5025
5201
  *
5026
5202
  * [Returns]
5027
5203
  * Pointer to the newly allocated variable, or
@@ -5032,48 +5208,40 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5032
5208
  {
5033
5209
  const char *orig_szVal = szVal;
5034
5210
  size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
5211
+ size_t len;
5035
5212
  char v, *psz;
5036
5213
  int sign=1;
5037
5214
  Real *vp = NULL;
5038
- size_t mf = VpGetPrecLimit();
5039
5215
  VALUE buf;
5040
5216
 
5041
- mx = (mx + BASE_FIG - 1) / BASE_FIG; /* Determine allocation unit. */
5042
- if (mx == 0) ++mx;
5043
-
5044
- if (szVal) {
5045
- /* Skipping leading spaces */
5046
- while (ISSPACE(*szVal)) szVal++;
5047
-
5048
- /* Processing the leading one `#` */
5049
- if (*szVal != '#') {
5050
- if (mf) {
5051
- mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
5052
- if (mx > mf) {
5053
- mx = mf;
5054
- }
5055
- }
5056
- }
5057
- else {
5058
- ++szVal;
5059
- }
5060
- }
5061
- else {
5217
+ if (szVal == NULL) {
5062
5218
  return_zero:
5063
5219
  /* necessary to be able to store */
5064
5220
  /* at least mx digits. */
5065
5221
  /* szVal==NULL ==> allocate zero value. */
5066
- vp = VpAllocReal(mx);
5067
- vp->MaxPrec = mx; /* set max precision */
5222
+ vp = rbd_allocate_struct(mx);
5223
+ vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
5068
5224
  VpSetZero(vp, 1); /* initialize vp to zero. */
5069
5225
  return vp;
5070
5226
  }
5071
5227
 
5228
+ /* Skipping leading spaces */
5229
+ while (ISSPACE(*szVal)) szVal++;
5230
+
5072
5231
  /* Check on Inf & NaN */
5073
5232
  if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
5074
5233
  return vp;
5075
5234
  }
5076
5235
 
5236
+ /* Processing the leading one `#` */
5237
+ if (*szVal != '#') {
5238
+ len = rbd_calculate_internal_digits(mx, true);
5239
+ }
5240
+ else {
5241
+ len = rbd_calculate_internal_digits(mx, false);
5242
+ ++szVal;
5243
+ }
5244
+
5077
5245
  /* Scanning digits */
5078
5246
 
5079
5247
  /* A buffer for keeping scanned digits */
@@ -5235,11 +5403,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
5235
5403
 
5236
5404
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
5237
5405
  /* units for szVal[] */
5238
- if (mx == 0) mx = 1;
5239
- nalloc = Max(nalloc, mx);
5240
- mx = nalloc;
5241
- vp = VpAllocReal(mx);
5242
- vp->MaxPrec = mx; /* set max precision */
5406
+ if (len == 0) len = 1;
5407
+ nalloc = Max(nalloc, len);
5408
+ len = nalloc;
5409
+ vp = rbd_allocate_struct(len);
5410
+ vp->MaxPrec = len; /* set max precision */
5243
5411
  VpSetZero(vp, sign);
5244
5412
  VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
5245
5413
  rb_str_resize(buf, 0);
@@ -5804,7 +5972,7 @@ VpMult(Real *c, Real *a, Real *b)
5804
5972
 
5805
5973
  if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
5806
5974
  w = c;
5807
- c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1, 1);
5975
+ c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
5808
5976
  MxIndC = MxIndAB;
5809
5977
  }
5810
5978
 
@@ -5812,8 +5980,8 @@ VpMult(Real *c, Real *a, Real *b)
5812
5980
 
5813
5981
  c->exponent = a->exponent; /* set exponent */
5814
5982
  if (!AddExponent(c, b->exponent)) {
5815
- if (w) VpFree(c);
5816
- return 0;
5983
+ if (w) rbd_free_struct(c);
5984
+ return 0;
5817
5985
  }
5818
5986
  VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
5819
5987
  carry = 0;
@@ -5863,10 +6031,10 @@ VpMult(Real *c, Real *a, Real *b)
5863
6031
  }
5864
6032
  }
5865
6033
  if (w != NULL) { /* free work variable */
5866
- VpNmlz(c);
5867
- VpAsgn(w, c, 1);
5868
- VpFree(c);
5869
- c = w;
6034
+ VpNmlz(c);
6035
+ VpAsgn(w, c, 1);
6036
+ rbd_free_struct(c);
6037
+ c = w;
5870
6038
  }
5871
6039
  else {
5872
6040
  VpLimitRound(c,0);
@@ -6235,7 +6403,6 @@ Exit:
6235
6403
  * Note: % must not appear more than once
6236
6404
  * a ... VP variable to be printed
6237
6405
  */
6238
- #ifdef BIGDECIMAL_ENABLE_VPRINT
6239
6406
  static int
6240
6407
  VPrint(FILE *fp, const char *cntl_chr, Real *a)
6241
6408
  {
@@ -6248,95 +6415,94 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
6248
6415
  /* nc : number of characters printed */
6249
6416
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6250
6417
  while (*(cntl_chr + j)) {
6251
- if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
6252
- nc = 0;
6253
- if (VpIsNaN(a)) {
6254
- fprintf(fp, SZ_NaN);
6255
- nc += 8;
6256
- }
6257
- else if (VpIsPosInf(a)) {
6258
- fprintf(fp, SZ_INF);
6259
- nc += 8;
6260
- }
6261
- else if (VpIsNegInf(a)) {
6262
- fprintf(fp, SZ_NINF);
6263
- nc += 9;
6264
- }
6265
- else if (!VpIsZero(a)) {
6266
- if (BIGDECIMAL_NEGATIVE_P(a)) {
6267
- fprintf(fp, "-");
6268
- ++nc;
6269
- }
6270
- nc += fprintf(fp, "0.");
6271
- switch (*(cntl_chr + j + 1)) {
6272
- default:
6273
- break;
6418
+ if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
6419
+ nc = 0;
6420
+ if (VpIsNaN(a)) {
6421
+ fprintf(fp, SZ_NaN);
6422
+ nc += 8;
6423
+ }
6424
+ else if (VpIsPosInf(a)) {
6425
+ fprintf(fp, SZ_INF);
6426
+ nc += 8;
6427
+ }
6428
+ else if (VpIsNegInf(a)) {
6429
+ fprintf(fp, SZ_NINF);
6430
+ nc += 9;
6431
+ }
6432
+ else if (!VpIsZero(a)) {
6433
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6434
+ fprintf(fp, "-");
6435
+ ++nc;
6436
+ }
6437
+ nc += fprintf(fp, "0.");
6438
+ switch (*(cntl_chr + j + 1)) {
6439
+ default:
6440
+ break;
6274
6441
 
6275
- case '0': case 'z':
6276
- ZeroSup = 0;
6277
- ++j;
6278
- sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
6279
- break;
6280
- }
6281
- for (i = 0; i < a->Prec; ++i) {
6282
- m = BASE1;
6283
- e = a->frac[i];
6284
- while (m) {
6285
- nn = e / m;
6286
- if (!ZeroSup || nn) {
6287
- nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
6288
- /* as 0.00xx will not */
6289
- /* be printed. */
6290
- ++nd;
6291
- ZeroSup = 0; /* Set to print succeeding zeros */
6292
- }
6293
- if (nd >= sep) { /* print ' ' after every 10 digits */
6294
- nd = 0;
6295
- nc += fprintf(fp, " ");
6296
- }
6297
- e = e - nn * m;
6298
- m /= 10;
6299
- }
6300
- }
6301
- nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
6302
- nc += fprintf(fp, " (%"PRIdVALUE", %lu, %lu)", a->exponent, a->Prec, a->MaxPrec);
6303
- }
6304
- else {
6305
- nc += fprintf(fp, "0.0");
6306
- }
6307
- }
6308
- else {
6309
- ++nc;
6310
- if (*(cntl_chr + j) == '\\') {
6311
- switch (*(cntl_chr + j + 1)) {
6312
- case 'n':
6313
- fprintf(fp, "\n");
6314
- ++j;
6315
- break;
6316
- case 't':
6317
- fprintf(fp, "\t");
6318
- ++j;
6319
- break;
6320
- case 'b':
6321
- fprintf(fp, "\n");
6322
- ++j;
6323
- break;
6324
- default:
6325
- fprintf(fp, "%c", *(cntl_chr + j));
6326
- break;
6327
- }
6328
- }
6329
- else {
6330
- fprintf(fp, "%c", *(cntl_chr + j));
6331
- if (*(cntl_chr + j) == '%') ++j;
6332
- }
6333
- }
6334
- j++;
6442
+ case '0': case 'z':
6443
+ ZeroSup = 0;
6444
+ ++j;
6445
+ sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
6446
+ break;
6447
+ }
6448
+ for (i = 0; i < a->Prec; ++i) {
6449
+ m = BASE1;
6450
+ e = a->frac[i];
6451
+ while (m) {
6452
+ nn = e / m;
6453
+ if (!ZeroSup || nn) {
6454
+ nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
6455
+ /* as 0.00xx will not */
6456
+ /* be printed. */
6457
+ ++nd;
6458
+ ZeroSup = 0; /* Set to print succeeding zeros */
6459
+ }
6460
+ if (nd >= sep) { /* print ' ' after every 10 digits */
6461
+ nd = 0;
6462
+ nc += fprintf(fp, " ");
6463
+ }
6464
+ e = e - nn * m;
6465
+ m /= 10;
6466
+ }
6467
+ }
6468
+ nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
6469
+ nc += fprintf(fp, " (%"PRIdVALUE", %"PRIuSIZE", %"PRIuSIZE")", a->exponent, a->Prec, a->MaxPrec);
6470
+ }
6471
+ else {
6472
+ nc += fprintf(fp, "0.0");
6473
+ }
6474
+ }
6475
+ else {
6476
+ ++nc;
6477
+ if (*(cntl_chr + j) == '\\') {
6478
+ switch (*(cntl_chr + j + 1)) {
6479
+ case 'n':
6480
+ fprintf(fp, "\n");
6481
+ ++j;
6482
+ break;
6483
+ case 't':
6484
+ fprintf(fp, "\t");
6485
+ ++j;
6486
+ break;
6487
+ case 'b':
6488
+ fprintf(fp, "\n");
6489
+ ++j;
6490
+ break;
6491
+ default:
6492
+ fprintf(fp, "%c", *(cntl_chr + j));
6493
+ break;
6494
+ }
6495
+ }
6496
+ else {
6497
+ fprintf(fp, "%c", *(cntl_chr + j));
6498
+ if (*(cntl_chr + j) == '%') ++j;
6499
+ }
6500
+ }
6501
+ j++;
6335
6502
  }
6336
6503
 
6337
6504
  return (int)nc;
6338
6505
  }
6339
- #endif
6340
6506
 
6341
6507
  static void
6342
6508
  VpFormatSt(char *psz, size_t fFmt)
@@ -6381,188 +6547,254 @@ VpExponent10(Real *a)
6381
6547
  }
6382
6548
 
6383
6549
  VP_EXPORT void
6384
- VpSzMantissa(Real *a,char *psz)
6550
+ VpSzMantissa(Real *a, char *buf, size_t buflen)
6385
6551
  {
6386
6552
  size_t i, n, ZeroSup;
6387
6553
  DECDIG_DBL m, e, nn;
6388
6554
 
6389
6555
  if (VpIsNaN(a)) {
6390
- sprintf(psz, SZ_NaN);
6391
- return;
6556
+ snprintf(buf, buflen, SZ_NaN);
6557
+ return;
6392
6558
  }
6393
6559
  if (VpIsPosInf(a)) {
6394
- sprintf(psz, SZ_INF);
6560
+ snprintf(buf, buflen, SZ_INF);
6395
6561
  return;
6396
6562
  }
6397
6563
  if (VpIsNegInf(a)) {
6398
- sprintf(psz, SZ_NINF);
6564
+ snprintf(buf, buflen, SZ_NINF);
6399
6565
  return;
6400
6566
  }
6401
6567
 
6402
6568
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6403
6569
  if (!VpIsZero(a)) {
6404
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6405
- n = a->Prec;
6406
- for (i = 0; i < n; ++i) {
6407
- m = BASE1;
6408
- e = a->frac[i];
6409
- while (m) {
6410
- nn = e / m;
6411
- if (!ZeroSup || nn) {
6412
- sprintf(psz, "%lu", (unsigned long)nn); /* The leading zero(s) */
6413
- psz += strlen(psz);
6414
- /* as 0.00xx will be ignored. */
6415
- ZeroSup = 0; /* Set to print succeeding zeros */
6416
- }
6417
- e = e - nn * m;
6418
- m /= 10;
6419
- }
6420
- }
6421
- *psz = 0;
6422
- while (psz[-1] == '0') *(--psz) = 0;
6570
+ if (BIGDECIMAL_NEGATIVE_P(a)) *buf++ = '-';
6571
+ n = a->Prec;
6572
+ for (i = 0; i < n; ++i) {
6573
+ m = BASE1;
6574
+ e = a->frac[i];
6575
+ while (m) {
6576
+ nn = e / m;
6577
+ if (!ZeroSup || nn) {
6578
+ snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */
6579
+ buf += strlen(buf);
6580
+ /* as 0.00xx will be ignored. */
6581
+ ZeroSup = 0; /* Set to print succeeding zeros */
6582
+ }
6583
+ e = e - nn * m;
6584
+ m /= 10;
6585
+ }
6586
+ }
6587
+ *buf = 0;
6588
+ while (buf[-1] == '0') *(--buf) = 0;
6423
6589
  }
6424
6590
  else {
6425
- if (VpIsPosZero(a)) sprintf(psz, "0");
6426
- else sprintf(psz, "-0");
6591
+ if (VpIsPosZero(a)) snprintf(buf, buflen, "0");
6592
+ else snprintf(buf, buflen, "-0");
6427
6593
  }
6428
6594
  }
6429
6595
 
6430
6596
  VP_EXPORT int
6431
- VpToSpecialString(Real *a,char *psz,int fPlus)
6597
+ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
6432
6598
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6433
6599
  {
6434
6600
  if (VpIsNaN(a)) {
6435
- sprintf(psz,SZ_NaN);
6436
- return 1;
6601
+ snprintf(buf, buflen, SZ_NaN);
6602
+ return 1;
6437
6603
  }
6438
6604
 
6439
6605
  if (VpIsPosInf(a)) {
6440
- if (fPlus == 1) {
6441
- *psz++ = ' ';
6442
- }
6443
- else if (fPlus == 2) {
6444
- *psz++ = '+';
6445
- }
6446
- sprintf(psz, SZ_INF);
6447
- return 1;
6606
+ if (fPlus == 1) {
6607
+ *buf++ = ' ';
6608
+ }
6609
+ else if (fPlus == 2) {
6610
+ *buf++ = '+';
6611
+ }
6612
+ snprintf(buf, buflen, SZ_INF);
6613
+ return 1;
6448
6614
  }
6449
6615
  if (VpIsNegInf(a)) {
6450
- sprintf(psz, SZ_NINF);
6451
- return 1;
6616
+ snprintf(buf, buflen, SZ_NINF);
6617
+ return 1;
6452
6618
  }
6453
6619
  if (VpIsZero(a)) {
6454
- if (VpIsPosZero(a)) {
6455
- if (fPlus == 1) sprintf(psz, " 0.0");
6456
- else if (fPlus == 2) sprintf(psz, "+0.0");
6457
- else sprintf(psz, "0.0");
6458
- }
6459
- else sprintf(psz, "-0.0");
6460
- return 1;
6620
+ if (VpIsPosZero(a)) {
6621
+ if (fPlus == 1) snprintf(buf, buflen, " 0.0");
6622
+ else if (fPlus == 2) snprintf(buf, buflen, "+0.0");
6623
+ else snprintf(buf, buflen, "0.0");
6624
+ }
6625
+ else snprintf(buf, buflen, "-0.0");
6626
+ return 1;
6461
6627
  }
6462
6628
  return 0;
6463
6629
  }
6464
6630
 
6465
6631
  VP_EXPORT void
6466
- VpToString(Real *a, char *psz, size_t fFmt, int fPlus)
6632
+ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6467
6633
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6468
6634
  {
6469
6635
  size_t i, n, ZeroSup;
6470
6636
  DECDIG shift, m, e, nn;
6471
- char *pszSav = psz;
6637
+ char *p = buf;
6638
+ size_t plen = buflen;
6472
6639
  ssize_t ex;
6473
6640
 
6474
- if (VpToSpecialString(a, psz, fPlus)) return;
6641
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
6475
6642
 
6476
6643
  ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
6477
6644
 
6478
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6479
- else if (fPlus == 1) *psz++ = ' ';
6480
- else if (fPlus == 2) *psz++ = '+';
6645
+ #define ADVANCE(n) do { \
6646
+ if (plen < n) goto overflow; \
6647
+ p += n; \
6648
+ plen -= n; \
6649
+ } while (0)
6650
+
6651
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6652
+ *p = '-';
6653
+ ADVANCE(1);
6654
+ }
6655
+ else if (fPlus == 1) {
6656
+ *p = ' ';
6657
+ ADVANCE(1);
6658
+ }
6659
+ else if (fPlus == 2) {
6660
+ *p = '+';
6661
+ ADVANCE(1);
6662
+ }
6663
+
6664
+ *p = '0'; ADVANCE(1);
6665
+ *p = '.'; ADVANCE(1);
6481
6666
 
6482
- *psz++ = '0';
6483
- *psz++ = '.';
6484
6667
  n = a->Prec;
6485
6668
  for (i = 0; i < n; ++i) {
6486
- m = BASE1;
6487
- e = a->frac[i];
6488
- while (m) {
6489
- nn = e / m;
6490
- if (!ZeroSup || nn) {
6491
- sprintf(psz, "%lu", (unsigned long)nn); /* The reading zero(s) */
6492
- psz += strlen(psz);
6493
- /* as 0.00xx will be ignored. */
6494
- ZeroSup = 0; /* Set to print succeeding zeros */
6495
- }
6496
- e = e - nn * m;
6497
- m /= 10;
6498
- }
6669
+ m = BASE1;
6670
+ e = a->frac[i];
6671
+ while (m) {
6672
+ nn = e / m;
6673
+ if (!ZeroSup || nn) {
6674
+ /* The reading zero(s) */
6675
+ size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn);
6676
+ if (n > plen) goto overflow;
6677
+ ADVANCE(n);
6678
+ /* as 0.00xx will be ignored. */
6679
+ ZeroSup = 0; /* Set to print succeeding zeros */
6680
+ }
6681
+ e = e - nn * m;
6682
+ m /= 10;
6683
+ }
6499
6684
  }
6685
+
6500
6686
  ex = a->exponent * (ssize_t)BASE_FIG;
6501
6687
  shift = BASE1;
6502
6688
  while (a->frac[0] / shift == 0) {
6503
- --ex;
6504
- shift /= 10;
6689
+ --ex;
6690
+ shift /= 10;
6505
6691
  }
6506
- while (psz[-1] == '0') {
6507
- *(--psz) = 0;
6692
+ while (p - 1 > buf && p[-1] == '0') {
6693
+ *(--p) = '\0';
6694
+ ++plen;
6508
6695
  }
6509
- sprintf(psz, "e%"PRIdSIZE, ex);
6510
- if (fFmt) VpFormatSt(pszSav, fFmt);
6696
+ snprintf(p, plen, "e%"PRIdSIZE, ex);
6697
+ if (fFmt) VpFormatSt(buf, fFmt);
6698
+
6699
+ overflow:
6700
+ return;
6701
+ #undef ADVANCE
6511
6702
  }
6512
6703
 
6513
6704
  VP_EXPORT void
6514
- VpToFString(Real *a, char *psz, size_t fFmt, int fPlus)
6705
+ VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
6515
6706
  /* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
6516
6707
  {
6517
6708
  size_t i, n;
6518
6709
  DECDIG m, e, nn;
6519
- char *pszSav = psz;
6710
+ char *p = buf;
6711
+ size_t plen = buflen;
6520
6712
  ssize_t ex;
6521
6713
 
6522
- if (VpToSpecialString(a, psz, fPlus)) return;
6714
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
6715
+
6716
+ #define ADVANCE(n) do { \
6717
+ if (plen < n) goto overflow; \
6718
+ p += n; \
6719
+ plen -= n; \
6720
+ } while (0)
6721
+
6523
6722
 
6524
- if (BIGDECIMAL_NEGATIVE_P(a)) *psz++ = '-';
6525
- else if (fPlus == 1) *psz++ = ' ';
6526
- else if (fPlus == 2) *psz++ = '+';
6723
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
6724
+ *p = '-';
6725
+ ADVANCE(1);
6726
+ }
6727
+ else if (fPlus == 1) {
6728
+ *p = ' ';
6729
+ ADVANCE(1);
6730
+ }
6731
+ else if (fPlus == 2) {
6732
+ *p = '+';
6733
+ ADVANCE(1);
6734
+ }
6527
6735
 
6528
6736
  n = a->Prec;
6529
6737
  ex = a->exponent;
6530
6738
  if (ex <= 0) {
6531
- *psz++ = '0';*psz++ = '.';
6532
- while (ex < 0) {
6533
- for (i=0; i < BASE_FIG; ++i) *psz++ = '0';
6534
- ++ex;
6535
- }
6536
- ex = -1;
6739
+ *p = '0'; ADVANCE(1);
6740
+ *p = '.'; ADVANCE(1);
6741
+ while (ex < 0) {
6742
+ for (i=0; i < BASE_FIG; ++i) {
6743
+ *p = '0'; ADVANCE(1);
6744
+ }
6745
+ ++ex;
6746
+ }
6747
+ ex = -1;
6537
6748
  }
6538
6749
 
6539
6750
  for (i = 0; i < n; ++i) {
6540
- --ex;
6541
- if (i == 0 && ex >= 0) {
6542
- sprintf(psz, "%lu", (unsigned long)a->frac[i]);
6543
- psz += strlen(psz);
6544
- }
6545
- else {
6546
- m = BASE1;
6547
- e = a->frac[i];
6548
- while (m) {
6549
- nn = e / m;
6550
- *psz++ = (char)(nn + '0');
6551
- e = e - nn * m;
6552
- m /= 10;
6553
- }
6554
- }
6555
- if (ex == 0) *psz++ = '.';
6751
+ --ex;
6752
+ if (i == 0 && ex >= 0) {
6753
+ size_t n = snprintf(p, plen, "%lu", (unsigned long)a->frac[i]);
6754
+ if (n > plen) goto overflow;
6755
+ ADVANCE(n);
6756
+ }
6757
+ else {
6758
+ m = BASE1;
6759
+ e = a->frac[i];
6760
+ while (m) {
6761
+ nn = e / m;
6762
+ *p = (char)(nn + '0');
6763
+ ADVANCE(1);
6764
+ e = e - nn * m;
6765
+ m /= 10;
6766
+ }
6767
+ }
6768
+ if (ex == 0) {
6769
+ *p = '.';
6770
+ ADVANCE(1);
6771
+ }
6556
6772
  }
6557
6773
  while (--ex>=0) {
6558
- m = BASE;
6559
- while (m /= 10) *psz++ = '0';
6560
- if (ex == 0) *psz++ = '.';
6774
+ m = BASE;
6775
+ while (m /= 10) {
6776
+ *p = '0';
6777
+ ADVANCE(1);
6778
+ }
6779
+ if (ex == 0) {
6780
+ *p = '.';
6781
+ ADVANCE(1);
6782
+ }
6783
+ }
6784
+
6785
+ *p = '\0';
6786
+ while (p - 1 > buf && p[-1] == '0') {
6787
+ *(--p) = '\0';
6788
+ ++plen;
6789
+ }
6790
+ if (p - 1 > buf && p[-1] == '.') {
6791
+ snprintf(p, plen, "0");
6561
6792
  }
6562
- *psz = 0;
6563
- while (psz[-1] == '0') *(--psz) = 0;
6564
- if (psz[-1] == '.') sprintf(psz, "0");
6565
- if (fFmt) VpFormatSt(pszSav, fFmt);
6793
+ if (fFmt) VpFormatSt(buf, fFmt);
6794
+
6795
+ overflow:
6796
+ return;
6797
+ #undef ADVANCE
6566
6798
  }
6567
6799
 
6568
6800
  /*
@@ -6971,8 +7203,9 @@ VpSqrt(Real *y, Real *x)
6971
7203
  if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
6972
7204
 
6973
7205
  /* allocate temporally variables */
6974
- f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1, 1);
6975
- r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1, 1);
7206
+ /* TODO: reconsider MaxPrec of f and r */
7207
+ f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
7208
+ r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
6976
7209
 
6977
7210
  nr = 0;
6978
7211
  y_prec = y->MaxPrec;
@@ -6997,16 +7230,21 @@ VpSqrt(Real *y, Real *x)
6997
7230
  f->MaxPrec = y->MaxPrec + 1;
6998
7231
  n = (SIGNED_VALUE)(y_prec * BASE_FIG);
6999
7232
  if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
7233
+
7234
+ /*
7235
+ * Perform: y_{n+1} = (y_n - x/y_n) / 2
7236
+ */
7000
7237
  do {
7001
- y->MaxPrec *= 2;
7002
- if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7003
- f->MaxPrec = y->MaxPrec;
7004
- VpDivd(f, r, x, y); /* f = x/y */
7005
- VpAddSub(r, f, y, -1); /* r = f - y */
7006
- VpMult(f, VpPt5, r); /* f = 0.5*r */
7007
- if (VpIsZero(f)) goto converge;
7008
- VpAddSub(r, f, y, 1); /* r = y + f */
7009
- VpAsgn(y, r, 1); /* y = r */
7238
+ y->MaxPrec *= 2;
7239
+ if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
7240
+ f->MaxPrec = y->MaxPrec;
7241
+ VpDivd(f, r, x, y); /* f = x/y */
7242
+ VpAddSub(r, f, y, -1); /* r = f - y */
7243
+ VpMult(f, VpConstPt5, r); /* f = 0.5*r */
7244
+ if (VpIsZero(f))
7245
+ goto converge;
7246
+ VpAddSub(r, f, y, 1); /* r = y + f */
7247
+ VpAsgn(y, r, 1); /* y = r */
7010
7248
  } while (++nr < n);
7011
7249
 
7012
7250
  #ifdef BIGDECIMAL_DEBUG
@@ -7031,8 +7269,8 @@ converge:
7031
7269
  y->MaxPrec = y_prec;
7032
7270
 
7033
7271
  Exit:
7034
- VpFree(f);
7035
- VpFree(r);
7272
+ rbd_free_struct(f);
7273
+ rbd_free_struct(r);
7036
7274
  return 1;
7037
7275
  }
7038
7276
 
@@ -7423,9 +7661,10 @@ VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
7423
7661
  }
7424
7662
 
7425
7663
  /* Allocate working variables */
7664
+ /* TODO: reconsider MaxPrec of w1 and w2 */
7665
+ w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
7666
+ w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
7426
7667
 
7427
- w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1);
7428
- w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1);
7429
7668
  /* calculation start */
7430
7669
 
7431
7670
  VpAsgn(y, x, 1);
@@ -7454,8 +7693,8 @@ Exit:
7454
7693
  printf(" n=%"PRIdVALUE"\n", n);
7455
7694
  }
7456
7695
  #endif /* BIGDECIMAL_DEBUG */
7457
- VpFree(w2);
7458
- VpFree(w1);
7696
+ rbd_free_struct(w2);
7697
+ rbd_free_struct(w1);
7459
7698
  return 1;
7460
7699
  }
7461
7700