bigdecimal 3.1.1 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bigdecimal.gemspec +28 -12
- data/ext/bigdecimal/bigdecimal.c +832 -594
- data/ext/bigdecimal/bigdecimal.h +32 -16
- data/ext/bigdecimal/extconf.rb +0 -29
- data/ext/bigdecimal/missing.h +6 -45
- data/lib/bigdecimal/jacobian.rb +3 -3
- data/lib/bigdecimal/util.rb +5 -1
- data/lib/bigdecimal.rb +5 -1
- metadata +4 -3
data/ext/bigdecimal/bigdecimal.c
CHANGED
@@ -7,9 +7,7 @@
|
|
7
7
|
*/
|
8
8
|
|
9
9
|
/* #define BIGDECIMAL_DEBUG 1 */
|
10
|
-
|
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
|
-
|
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
|
-
|
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").
|
490
|
-
* BigDecimal("1").
|
491
|
-
* BigDecimal("1.1").
|
492
|
-
* BigDecimal("3.1415").
|
493
|
-
* BigDecimal("-1e20").
|
494
|
-
* BigDecimal("1e-20").
|
495
|
-
* BigDecimal("Infinity").
|
496
|
-
* BigDecimal("-Infinity").
|
497
|
-
* BigDecimal("NaN").
|
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
|
-
|
582
|
-
|
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
|
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
|
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
|
-
|
636
|
-
|
637
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
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
|
-
|
694
|
-
|
695
|
-
|
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
|
-
|
1138
|
+
static inline SIGNED_VALUE
|
1139
|
+
check_int_precision(VALUE v)
|
938
1140
|
{
|
939
1141
|
SIGNED_VALUE n;
|
940
|
-
|
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 =
|
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,
|
1280
|
-
|
1473
|
+
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
1474
|
+
VpAddSub(c, a, b, 1);
|
1281
1475
|
}
|
1282
1476
|
else {
|
1283
|
-
GUARD_OBJ(c,
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
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,
|
1335
|
-
|
1528
|
+
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
1529
|
+
VpAddSub(c, a, b, -1);
|
1336
1530
|
}
|
1337
1531
|
else {
|
1338
|
-
GUARD_OBJ(c,
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
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,
|
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,
|
1805
|
+
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
1612
1806
|
VpMult(c, a, b);
|
1613
1807
|
return VpCheckGetValue(c);
|
1614
1808
|
}
|
@@ -1618,7 +1812,7 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
|
1618
1812
|
/* For c = self.div(r): with round operation */
|
1619
1813
|
{
|
1620
1814
|
ENTER(5);
|
1621
|
-
Real *a, *b
|
1815
|
+
Real *a, *b;
|
1622
1816
|
ssize_t a_prec, b_prec;
|
1623
1817
|
size_t mx;
|
1624
1818
|
|
@@ -1647,18 +1841,16 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
|
1647
1841
|
SAVE(b);
|
1648
1842
|
*div = b;
|
1649
1843
|
|
1650
|
-
mx = (a->Prec > b->Prec) ? a->Prec : b->Prec;
|
1651
|
-
mx *= BASE_FIG;
|
1652
|
-
|
1653
1844
|
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
1654
1845
|
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
1655
1846
|
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
1847
|
+
mx *= 2;
|
1656
1848
|
|
1657
1849
|
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
1658
1850
|
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
1659
1851
|
|
1660
|
-
GUARD_OBJ((*c),
|
1661
|
-
GUARD_OBJ((*res),
|
1852
|
+
GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
|
1853
|
+
GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
|
1662
1854
|
VpDivd(*c, *res, a, b);
|
1663
1855
|
|
1664
1856
|
return Qnil;
|
@@ -1723,7 +1915,7 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
1723
1915
|
|
1724
1916
|
argc = rb_scan_args(argc, argv, "11", &value, &digits);
|
1725
1917
|
if (argc > 1) {
|
1726
|
-
n =
|
1918
|
+
n = check_int_precision(digits);
|
1727
1919
|
}
|
1728
1920
|
|
1729
1921
|
if (n > 0) {
|
@@ -1808,15 +2000,17 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
1808
2000
|
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
1809
2001
|
|
1810
2002
|
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
2003
|
+
mx *= 2;
|
2004
|
+
|
1811
2005
|
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
1812
2006
|
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
1813
2007
|
|
1814
|
-
GUARD_OBJ(c,
|
1815
|
-
GUARD_OBJ(res,
|
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,
|
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 =
|
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,
|
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,
|
1895
|
-
GUARD_OBJ(res,
|
1896
|
-
GUARD_OBJ(rr,
|
1897
|
-
GUARD_OBJ(ff,
|
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,
|
1904
|
-
GUARD_OBJ(f,
|
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 =
|
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,
|
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,
|
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 =
|
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 =
|
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 =
|
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,
|
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 =
|
2423
|
+
n = check_int_precision(nFig);
|
2424
|
+
n += VpDblFig() + VpBaseFig();
|
2223
2425
|
if (mx <= n) mx = n;
|
2224
|
-
GUARD_OBJ(c,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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(
|
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 =
|
2812
|
-
|
2813
|
-
|
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
|
-
|
2883
|
-
y =
|
2884
|
-
|
2885
|
-
|
2886
|
-
|
2887
|
-
|
2888
|
-
|
2889
|
-
|
2890
|
-
|
2891
|
-
|
2892
|
-
|
2893
|
-
|
2894
|
-
|
2895
|
-
|
2896
|
-
|
2897
|
-
|
2898
|
-
|
2899
|
-
|
2900
|
-
|
2901
|
-
|
2902
|
-
|
2903
|
-
|
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
|
-
|
2908
|
-
return VpCheckGetValue(
|
2909
|
-
|
2910
|
-
|
2911
|
-
return VpCheckGetValue(
|
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(
|
3118
|
+
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
2917
3119
|
}
|
2918
3120
|
else if (is_one(vexp)) {
|
2919
|
-
|
3121
|
+
return self;
|
2920
3122
|
}
|
2921
3123
|
|
2922
3124
|
if (VpIsInf(x)) {
|
2923
|
-
|
2924
|
-
|
2925
|
-
|
2926
|
-
|
2927
|
-
|
2928
|
-
return VpCheckGetValue(
|
2929
|
-
|
2930
|
-
|
2931
|
-
|
2932
|
-
return VpCheckGetValue(
|
2933
|
-
|
2934
|
-
|
2935
|
-
|
2936
|
-
|
2937
|
-
return VpCheckGetValue(
|
2938
|
-
|
2939
|
-
|
2940
|
-
|
2941
|
-
return VpCheckGetValue(
|
2942
|
-
|
2943
|
-
|
2944
|
-
|
2945
|
-
y =
|
2946
|
-
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
2950
|
-
|
2951
|
-
|
2952
|
-
|
2953
|
-
|
2954
|
-
|
2955
|
-
|
2956
|
-
|
2957
|
-
|
2958
|
-
|
2959
|
-
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
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
|
-
|
3171
|
+
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
2970
3172
|
}
|
2971
3173
|
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
2972
|
-
|
2973
|
-
|
2974
|
-
return VpCheckGetValue(
|
2975
|
-
|
2976
|
-
|
2977
|
-
|
2978
|
-
y =
|
2979
|
-
|
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
|
-
|
2988
|
-
return VpCheckGetValue(
|
2989
|
-
|
2990
|
-
|
2991
|
-
return VpCheckGetValue(
|
2992
|
-
|
2993
|
-
|
2994
|
-
|
2995
|
-
|
2996
|
-
y =
|
2997
|
-
|
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
|
-
|
3006
|
-
return VpCheckGetValue(
|
3007
|
-
|
3008
|
-
|
3009
|
-
return VpCheckGetValue(
|
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
|
-
|
3021
|
-
GUARD_OBJ(y,
|
3212
|
+
mp = x->Prec * (VpBaseFig() + 1);
|
3213
|
+
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
3022
3214
|
}
|
3023
3215
|
else {
|
3024
|
-
GUARD_OBJ(y,
|
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
|
-
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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
|
-
*
|
3497
|
-
*
|
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
|
-
*
|
3500
|
-
*
|
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
|
3610
|
-
*
|
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
|
-
|
3783
|
-
vy
|
3784
|
-
|
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(
|
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
|
-
|
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
|
-
|
3953
|
-
|
4145
|
+
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
4146
|
+
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
3954
4147
|
|
3955
4148
|
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
3956
|
-
|
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
|
-
|
3969
|
-
|
3970
|
-
|
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(
|
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
|
-
|
4418
|
-
|
4419
|
-
|
4420
|
-
|
4421
|
-
|
4422
|
-
|
4423
|
-
|
4424
|
-
|
4425
|
-
|
4426
|
-
|
4427
|
-
|
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 *
|
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
|
-
/*
|
4906
|
-
VpConstOne =
|
4907
|
-
|
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 =
|
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 ...
|
5021
|
-
*
|
5022
|
-
* szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
|
5023
|
-
*
|
5024
|
-
*
|
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
|
-
|
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 =
|
5067
|
-
vp->MaxPrec = mx;
|
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 (
|
5239
|
-
nalloc = Max(nalloc,
|
5240
|
-
|
5241
|
-
vp =
|
5242
|
-
vp->MaxPrec =
|
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
|
-
|
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
|
-
|
5816
|
-
|
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
|
-
|
5867
|
-
|
5868
|
-
|
5869
|
-
|
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);
|
@@ -5931,18 +6099,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
5931
6099
|
word_c = c->MaxPrec;
|
5932
6100
|
word_r = r->MaxPrec;
|
5933
6101
|
|
5934
|
-
ind_c = 0;
|
5935
|
-
ind_r = 1;
|
5936
|
-
|
5937
6102
|
if (word_a >= word_r) goto space_error;
|
5938
6103
|
|
6104
|
+
ind_r = 1;
|
5939
6105
|
r->frac[0] = 0;
|
5940
6106
|
while (ind_r <= word_a) {
|
5941
6107
|
r->frac[ind_r] = a->frac[ind_r - 1];
|
5942
6108
|
++ind_r;
|
5943
6109
|
}
|
5944
|
-
|
5945
6110
|
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
6111
|
+
|
6112
|
+
ind_c = 0;
|
5946
6113
|
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
5947
6114
|
|
5948
6115
|
/* initial procedure */
|
@@ -6236,7 +6403,6 @@ Exit:
|
|
6236
6403
|
* Note: % must not appear more than once
|
6237
6404
|
* a ... VP variable to be printed
|
6238
6405
|
*/
|
6239
|
-
#ifdef BIGDECIMAL_ENABLE_VPRINT
|
6240
6406
|
static int
|
6241
6407
|
VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
6242
6408
|
{
|
@@ -6249,95 +6415,94 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
6249
6415
|
/* nc : number of characters printed */
|
6250
6416
|
ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
|
6251
6417
|
while (*(cntl_chr + j)) {
|
6252
|
-
|
6253
|
-
|
6254
|
-
|
6255
|
-
|
6256
|
-
|
6257
|
-
|
6258
|
-
|
6259
|
-
|
6260
|
-
|
6261
|
-
|
6262
|
-
|
6263
|
-
|
6264
|
-
|
6265
|
-
|
6266
|
-
|
6267
|
-
|
6268
|
-
|
6269
|
-
|
6270
|
-
|
6271
|
-
|
6272
|
-
|
6273
|
-
|
6274
|
-
|
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;
|
6275
6441
|
|
6276
|
-
|
6277
|
-
|
6278
|
-
|
6279
|
-
|
6280
|
-
|
6281
|
-
|
6282
|
-
|
6283
|
-
|
6284
|
-
|
6285
|
-
|
6286
|
-
|
6287
|
-
|
6288
|
-
|
6289
|
-
|
6290
|
-
|
6291
|
-
|
6292
|
-
|
6293
|
-
|
6294
|
-
|
6295
|
-
|
6296
|
-
|
6297
|
-
|
6298
|
-
|
6299
|
-
|
6300
|
-
|
6301
|
-
|
6302
|
-
|
6303
|
-
|
6304
|
-
|
6305
|
-
|
6306
|
-
|
6307
|
-
|
6308
|
-
|
6309
|
-
|
6310
|
-
|
6311
|
-
|
6312
|
-
|
6313
|
-
|
6314
|
-
|
6315
|
-
|
6316
|
-
|
6317
|
-
|
6318
|
-
|
6319
|
-
|
6320
|
-
|
6321
|
-
|
6322
|
-
|
6323
|
-
|
6324
|
-
|
6325
|
-
|
6326
|
-
|
6327
|
-
|
6328
|
-
|
6329
|
-
|
6330
|
-
|
6331
|
-
|
6332
|
-
|
6333
|
-
|
6334
|
-
|
6335
|
-
|
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++;
|
6336
6502
|
}
|
6337
6503
|
|
6338
6504
|
return (int)nc;
|
6339
6505
|
}
|
6340
|
-
#endif
|
6341
6506
|
|
6342
6507
|
static void
|
6343
6508
|
VpFormatSt(char *psz, size_t fFmt)
|
@@ -6382,188 +6547,254 @@ VpExponent10(Real *a)
|
|
6382
6547
|
}
|
6383
6548
|
|
6384
6549
|
VP_EXPORT void
|
6385
|
-
VpSzMantissa(Real *a,char *
|
6550
|
+
VpSzMantissa(Real *a, char *buf, size_t buflen)
|
6386
6551
|
{
|
6387
6552
|
size_t i, n, ZeroSup;
|
6388
6553
|
DECDIG_DBL m, e, nn;
|
6389
6554
|
|
6390
6555
|
if (VpIsNaN(a)) {
|
6391
|
-
|
6392
|
-
|
6556
|
+
snprintf(buf, buflen, SZ_NaN);
|
6557
|
+
return;
|
6393
6558
|
}
|
6394
6559
|
if (VpIsPosInf(a)) {
|
6395
|
-
|
6560
|
+
snprintf(buf, buflen, SZ_INF);
|
6396
6561
|
return;
|
6397
6562
|
}
|
6398
6563
|
if (VpIsNegInf(a)) {
|
6399
|
-
|
6564
|
+
snprintf(buf, buflen, SZ_NINF);
|
6400
6565
|
return;
|
6401
6566
|
}
|
6402
6567
|
|
6403
6568
|
ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
|
6404
6569
|
if (!VpIsZero(a)) {
|
6405
|
-
|
6406
|
-
|
6407
|
-
|
6408
|
-
|
6409
|
-
|
6410
|
-
|
6411
|
-
|
6412
|
-
|
6413
|
-
|
6414
|
-
|
6415
|
-
|
6416
|
-
|
6417
|
-
|
6418
|
-
|
6419
|
-
|
6420
|
-
|
6421
|
-
|
6422
|
-
|
6423
|
-
|
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;
|
6424
6589
|
}
|
6425
6590
|
else {
|
6426
|
-
if (VpIsPosZero(a))
|
6427
|
-
else
|
6591
|
+
if (VpIsPosZero(a)) snprintf(buf, buflen, "0");
|
6592
|
+
else snprintf(buf, buflen, "-0");
|
6428
6593
|
}
|
6429
6594
|
}
|
6430
6595
|
|
6431
6596
|
VP_EXPORT int
|
6432
|
-
VpToSpecialString(Real *a,char *
|
6597
|
+
VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
|
6433
6598
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
6434
6599
|
{
|
6435
6600
|
if (VpIsNaN(a)) {
|
6436
|
-
|
6437
|
-
|
6601
|
+
snprintf(buf, buflen, SZ_NaN);
|
6602
|
+
return 1;
|
6438
6603
|
}
|
6439
6604
|
|
6440
6605
|
if (VpIsPosInf(a)) {
|
6441
|
-
|
6442
|
-
|
6443
|
-
|
6444
|
-
|
6445
|
-
|
6446
|
-
|
6447
|
-
|
6448
|
-
|
6606
|
+
if (fPlus == 1) {
|
6607
|
+
*buf++ = ' ';
|
6608
|
+
}
|
6609
|
+
else if (fPlus == 2) {
|
6610
|
+
*buf++ = '+';
|
6611
|
+
}
|
6612
|
+
snprintf(buf, buflen, SZ_INF);
|
6613
|
+
return 1;
|
6449
6614
|
}
|
6450
6615
|
if (VpIsNegInf(a)) {
|
6451
|
-
|
6452
|
-
|
6616
|
+
snprintf(buf, buflen, SZ_NINF);
|
6617
|
+
return 1;
|
6453
6618
|
}
|
6454
6619
|
if (VpIsZero(a)) {
|
6455
|
-
|
6456
|
-
|
6457
|
-
|
6458
|
-
|
6459
|
-
|
6460
|
-
|
6461
|
-
|
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;
|
6462
6627
|
}
|
6463
6628
|
return 0;
|
6464
6629
|
}
|
6465
6630
|
|
6466
6631
|
VP_EXPORT void
|
6467
|
-
VpToString(Real *a, char *
|
6632
|
+
VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
6468
6633
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
6469
6634
|
{
|
6470
6635
|
size_t i, n, ZeroSup;
|
6471
6636
|
DECDIG shift, m, e, nn;
|
6472
|
-
char *
|
6637
|
+
char *p = buf;
|
6638
|
+
size_t plen = buflen;
|
6473
6639
|
ssize_t ex;
|
6474
6640
|
|
6475
|
-
if (VpToSpecialString(a,
|
6641
|
+
if (VpToSpecialString(a, buf, buflen, fPlus)) return;
|
6476
6642
|
|
6477
6643
|
ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
|
6478
6644
|
|
6479
|
-
|
6480
|
-
|
6481
|
-
|
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);
|
6482
6666
|
|
6483
|
-
*psz++ = '0';
|
6484
|
-
*psz++ = '.';
|
6485
6667
|
n = a->Prec;
|
6486
6668
|
for (i = 0; i < n; ++i) {
|
6487
|
-
|
6488
|
-
|
6489
|
-
|
6490
|
-
|
6491
|
-
|
6492
|
-
|
6493
|
-
|
6494
|
-
|
6495
|
-
|
6496
|
-
|
6497
|
-
|
6498
|
-
|
6499
|
-
|
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
|
+
}
|
6500
6684
|
}
|
6685
|
+
|
6501
6686
|
ex = a->exponent * (ssize_t)BASE_FIG;
|
6502
6687
|
shift = BASE1;
|
6503
6688
|
while (a->frac[0] / shift == 0) {
|
6504
|
-
|
6505
|
-
|
6689
|
+
--ex;
|
6690
|
+
shift /= 10;
|
6506
6691
|
}
|
6507
|
-
while (
|
6508
|
-
|
6692
|
+
while (p - 1 > buf && p[-1] == '0') {
|
6693
|
+
*(--p) = '\0';
|
6694
|
+
++plen;
|
6509
6695
|
}
|
6510
|
-
|
6511
|
-
if (fFmt) VpFormatSt(
|
6696
|
+
snprintf(p, plen, "e%"PRIdSIZE, ex);
|
6697
|
+
if (fFmt) VpFormatSt(buf, fFmt);
|
6698
|
+
|
6699
|
+
overflow:
|
6700
|
+
return;
|
6701
|
+
#undef ADVANCE
|
6512
6702
|
}
|
6513
6703
|
|
6514
6704
|
VP_EXPORT void
|
6515
|
-
VpToFString(Real *a, char *
|
6705
|
+
VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
6516
6706
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
6517
6707
|
{
|
6518
6708
|
size_t i, n;
|
6519
6709
|
DECDIG m, e, nn;
|
6520
|
-
char *
|
6710
|
+
char *p = buf;
|
6711
|
+
size_t plen = buflen;
|
6521
6712
|
ssize_t ex;
|
6522
6713
|
|
6523
|
-
if (VpToSpecialString(a,
|
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)
|
6524
6721
|
|
6525
|
-
|
6526
|
-
|
6527
|
-
|
6722
|
+
|
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
|
+
}
|
6528
6735
|
|
6529
6736
|
n = a->Prec;
|
6530
6737
|
ex = a->exponent;
|
6531
6738
|
if (ex <= 0) {
|
6532
|
-
|
6533
|
-
|
6534
|
-
|
6535
|
-
|
6536
|
-
|
6537
|
-
|
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;
|
6538
6748
|
}
|
6539
6749
|
|
6540
6750
|
for (i = 0; i < n; ++i) {
|
6541
|
-
|
6542
|
-
|
6543
|
-
|
6544
|
-
|
6545
|
-
|
6546
|
-
|
6547
|
-
|
6548
|
-
|
6549
|
-
|
6550
|
-
|
6551
|
-
|
6552
|
-
|
6553
|
-
|
6554
|
-
|
6555
|
-
|
6556
|
-
|
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
|
+
}
|
6557
6772
|
}
|
6558
6773
|
while (--ex>=0) {
|
6559
|
-
|
6560
|
-
|
6561
|
-
|
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;
|
6562
6789
|
}
|
6563
|
-
|
6564
|
-
|
6565
|
-
|
6566
|
-
if (fFmt) VpFormatSt(
|
6790
|
+
if (p - 1 > buf && p[-1] == '.') {
|
6791
|
+
snprintf(p, plen, "0");
|
6792
|
+
}
|
6793
|
+
if (fFmt) VpFormatSt(buf, fFmt);
|
6794
|
+
|
6795
|
+
overflow:
|
6796
|
+
return;
|
6797
|
+
#undef ADVANCE
|
6567
6798
|
}
|
6568
6799
|
|
6569
6800
|
/*
|
@@ -6972,8 +7203,9 @@ VpSqrt(Real *y, Real *x)
|
|
6972
7203
|
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
6973
7204
|
|
6974
7205
|
/* allocate temporally variables */
|
6975
|
-
|
6976
|
-
|
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));
|
6977
7209
|
|
6978
7210
|
nr = 0;
|
6979
7211
|
y_prec = y->MaxPrec;
|
@@ -6998,16 +7230,21 @@ VpSqrt(Real *y, Real *x)
|
|
6998
7230
|
f->MaxPrec = y->MaxPrec + 1;
|
6999
7231
|
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
7000
7232
|
if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
7233
|
+
|
7234
|
+
/*
|
7235
|
+
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
7236
|
+
*/
|
7001
7237
|
do {
|
7002
|
-
|
7003
|
-
|
7004
|
-
|
7005
|
-
|
7006
|
-
|
7007
|
-
|
7008
|
-
|
7009
|
-
|
7010
|
-
|
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 */
|
7011
7248
|
} while (++nr < n);
|
7012
7249
|
|
7013
7250
|
#ifdef BIGDECIMAL_DEBUG
|
@@ -7032,8 +7269,8 @@ converge:
|
|
7032
7269
|
y->MaxPrec = y_prec;
|
7033
7270
|
|
7034
7271
|
Exit:
|
7035
|
-
|
7036
|
-
|
7272
|
+
rbd_free_struct(f);
|
7273
|
+
rbd_free_struct(r);
|
7037
7274
|
return 1;
|
7038
7275
|
}
|
7039
7276
|
|
@@ -7424,9 +7661,10 @@ VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
|
7424
7661
|
}
|
7425
7662
|
|
7426
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);
|
7427
7667
|
|
7428
|
-
w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1);
|
7429
|
-
w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1);
|
7430
7668
|
/* calculation start */
|
7431
7669
|
|
7432
7670
|
VpAsgn(y, x, 1);
|
@@ -7455,8 +7693,8 @@ Exit:
|
|
7455
7693
|
printf(" n=%"PRIdVALUE"\n", n);
|
7456
7694
|
}
|
7457
7695
|
#endif /* BIGDECIMAL_DEBUG */
|
7458
|
-
|
7459
|
-
|
7696
|
+
rbd_free_struct(w2);
|
7697
|
+
rbd_free_struct(w1);
|
7460
7698
|
return 1;
|
7461
7699
|
}
|
7462
7700
|
|