bigdecimal 3.1.0 → 3.1.6

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.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