bigdecimal 3.1.0 → 3.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +56 -0
- data/bigdecimal.gemspec +29 -12
- data/ext/bigdecimal/bigdecimal.c +867 -615
- 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 +10 -6
- data/lib/bigdecimal.rb +5 -1
- metadata +8 -6
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.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
|
-
|
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());
|
@@ -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 # =>
|
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").
|
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
|
}
|
@@ -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
|
-
|
1650
|
-
|
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
|
-
|
1654
|
-
GUARD_OBJ((*
|
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 =
|
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
|
-
|
1797
|
-
|
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,
|
1802
|
-
GUARD_OBJ(res,
|
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,
|
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 =
|
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,
|
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,
|
1882
|
-
GUARD_OBJ(res,
|
1883
|
-
GUARD_OBJ(rr,
|
1884
|
-
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)));
|
1885
2099
|
|
1886
2100
|
VpDivd(c, res, a, b);
|
1887
2101
|
|
1888
2102
|
mx = c->Prec *(VpBaseFig() + 1);
|
1889
2103
|
|
1890
|
-
GUARD_OBJ(d,
|
1891
|
-
GUARD_OBJ(f,
|
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 =
|
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,
|
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,
|
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 =
|
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 =
|
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 =
|
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,
|
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 =
|
2423
|
+
n = check_int_precision(nFig);
|
2424
|
+
n += VpDblFig() + VpBaseFig();
|
2210
2425
|
if (mx <= n) mx = n;
|
2211
|
-
GUARD_OBJ(c,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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
|
-
*
|
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('-
|
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('
|
2489
|
-
* #=> '+
|
2703
|
+
* BigDecimal('1234567890123.45678901234567890').to_s('+8F')
|
2704
|
+
* #=> '+12345 67890123.45678901 23456789'
|
2490
2705
|
*
|
2491
|
-
* BigDecimal('
|
2492
|
-
* #=> '
|
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(
|
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 =
|
2799
|
-
|
2800
|
-
|
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
|
-
|
2870
|
-
y =
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2875
|
-
|
2876
|
-
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
2885
|
-
|
2886
|
-
|
2887
|
-
|
2888
|
-
|
2889
|
-
|
2890
|
-
|
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
|
-
|
2895
|
-
return VpCheckGetValue(
|
2896
|
-
|
2897
|
-
|
2898
|
-
return VpCheckGetValue(
|
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(
|
3118
|
+
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
2904
3119
|
}
|
2905
3120
|
else if (is_one(vexp)) {
|
2906
|
-
|
3121
|
+
return self;
|
2907
3122
|
}
|
2908
3123
|
|
2909
3124
|
if (VpIsInf(x)) {
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
2915
|
-
return VpCheckGetValue(
|
2916
|
-
|
2917
|
-
|
2918
|
-
|
2919
|
-
return VpCheckGetValue(
|
2920
|
-
|
2921
|
-
|
2922
|
-
|
2923
|
-
|
2924
|
-
return VpCheckGetValue(
|
2925
|
-
|
2926
|
-
|
2927
|
-
|
2928
|
-
return VpCheckGetValue(
|
2929
|
-
|
2930
|
-
|
2931
|
-
|
2932
|
-
y =
|
2933
|
-
|
2934
|
-
|
2935
|
-
|
2936
|
-
|
2937
|
-
|
2938
|
-
|
2939
|
-
|
2940
|
-
|
2941
|
-
|
2942
|
-
|
2943
|
-
|
2944
|
-
|
2945
|
-
|
2946
|
-
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
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
|
-
|
3171
|
+
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
2957
3172
|
}
|
2958
3173
|
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
2959
|
-
|
2960
|
-
|
2961
|
-
return VpCheckGetValue(
|
2962
|
-
|
2963
|
-
|
2964
|
-
|
2965
|
-
y =
|
2966
|
-
|
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
|
-
|
2975
|
-
return VpCheckGetValue(
|
2976
|
-
|
2977
|
-
|
2978
|
-
return VpCheckGetValue(
|
2979
|
-
|
2980
|
-
|
2981
|
-
|
2982
|
-
|
2983
|
-
y =
|
2984
|
-
|
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
|
-
|
2993
|
-
return VpCheckGetValue(
|
2994
|
-
|
2995
|
-
|
2996
|
-
return VpCheckGetValue(
|
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
|
-
|
3008
|
-
GUARD_OBJ(y,
|
3212
|
+
mp = x->Prec * (VpBaseFig() + 1);
|
3213
|
+
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
3009
3214
|
}
|
3010
3215
|
else {
|
3011
|
-
GUARD_OBJ(y,
|
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
|
-
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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
|
-
*
|
3484
|
-
*
|
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
|
-
*
|
3487
|
-
*
|
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 +
|
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
|
3597
|
-
*
|
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
|
-
|
3770
|
-
vy
|
3771
|
-
|
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(
|
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
|
-
|
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
|
-
|
3940
|
-
|
4145
|
+
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
4146
|
+
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
3941
4147
|
|
3942
4148
|
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
3943
|
-
|
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
|
-
|
3956
|
-
|
3957
|
-
|
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
|
-
* ==
|
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(
|
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
|
-
|
4405
|
-
|
4406
|
-
|
4407
|
-
|
4408
|
-
|
4409
|
-
|
4410
|
-
|
4411
|
-
|
4412
|
-
|
4413
|
-
|
4414
|
-
|
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 *
|
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
|
-
/*
|
4893
|
-
VpConstOne =
|
4894
|
-
|
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 =
|
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 ...
|
5008
|
-
*
|
5009
|
-
* szVal ... value assigned(char). If szVal==NULL,then zero is assumed.
|
5010
|
-
*
|
5011
|
-
*
|
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
|
-
|
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 =
|
5054
|
-
vp->MaxPrec = mx;
|
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 (
|
5226
|
-
nalloc = Max(nalloc,
|
5227
|
-
|
5228
|
-
vp =
|
5229
|
-
vp->MaxPrec =
|
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
|
-
|
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
|
-
|
5803
|
-
|
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
|
-
|
5854
|
-
|
5855
|
-
|
5856
|
-
|
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
|
-
|
6240
|
-
|
6241
|
-
|
6242
|
-
|
6243
|
-
|
6244
|
-
|
6245
|
-
|
6246
|
-
|
6247
|
-
|
6248
|
-
|
6249
|
-
|
6250
|
-
|
6251
|
-
|
6252
|
-
|
6253
|
-
|
6254
|
-
|
6255
|
-
|
6256
|
-
|
6257
|
-
|
6258
|
-
|
6259
|
-
|
6260
|
-
|
6261
|
-
|
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
|
-
|
6264
|
-
|
6265
|
-
|
6266
|
-
|
6267
|
-
|
6268
|
-
|
6269
|
-
|
6270
|
-
|
6271
|
-
|
6272
|
-
|
6273
|
-
|
6274
|
-
|
6275
|
-
|
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
|
-
|
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 *
|
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
|
-
|
6379
|
-
|
6569
|
+
snprintf(buf, buflen, SZ_NaN);
|
6570
|
+
return;
|
6380
6571
|
}
|
6381
6572
|
if (VpIsPosInf(a)) {
|
6382
|
-
|
6573
|
+
snprintf(buf, buflen, SZ_INF);
|
6383
6574
|
return;
|
6384
6575
|
}
|
6385
6576
|
if (VpIsNegInf(a)) {
|
6386
|
-
|
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
|
-
|
6393
|
-
|
6394
|
-
|
6395
|
-
|
6396
|
-
|
6397
|
-
|
6398
|
-
|
6399
|
-
|
6400
|
-
|
6401
|
-
|
6402
|
-
|
6403
|
-
|
6404
|
-
|
6405
|
-
|
6406
|
-
|
6407
|
-
|
6408
|
-
|
6409
|
-
|
6410
|
-
|
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))
|
6414
|
-
else
|
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 *
|
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
|
-
|
6424
|
-
|
6614
|
+
snprintf(buf, buflen, SZ_NaN);
|
6615
|
+
return 1;
|
6425
6616
|
}
|
6426
6617
|
|
6427
6618
|
if (VpIsPosInf(a)) {
|
6428
|
-
|
6429
|
-
|
6430
|
-
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
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
|
-
|
6439
|
-
|
6629
|
+
snprintf(buf, buflen, SZ_NINF);
|
6630
|
+
return 1;
|
6440
6631
|
}
|
6441
6632
|
if (VpIsZero(a)) {
|
6442
|
-
|
6443
|
-
|
6444
|
-
|
6445
|
-
|
6446
|
-
|
6447
|
-
|
6448
|
-
|
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 *
|
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 *
|
6650
|
+
char *p = buf;
|
6651
|
+
size_t plen = buflen;
|
6460
6652
|
ssize_t ex;
|
6461
6653
|
|
6462
|
-
if (VpToSpecialString(a,
|
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
|
-
|
6467
|
-
|
6468
|
-
|
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
|
-
|
6475
|
-
|
6476
|
-
|
6477
|
-
|
6478
|
-
|
6479
|
-
|
6480
|
-
|
6481
|
-
|
6482
|
-
|
6483
|
-
|
6484
|
-
|
6485
|
-
|
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
|
-
|
6492
|
-
|
6702
|
+
--ex;
|
6703
|
+
shift /= 10;
|
6493
6704
|
}
|
6494
|
-
while (
|
6495
|
-
|
6705
|
+
while (p - 1 > buf && p[-1] == '0') {
|
6706
|
+
*(--p) = '\0';
|
6707
|
+
++plen;
|
6496
6708
|
}
|
6497
|
-
|
6498
|
-
if (fFmt) VpFormatSt(
|
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 *
|
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
|
6507
|
-
char *
|
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,
|
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))
|
6513
|
-
|
6514
|
-
|
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
|
-
|
6520
|
-
|
6521
|
-
|
6522
|
-
|
6523
|
-
|
6524
|
-
|
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
|
-
|
6529
|
-
|
6530
|
-
|
6531
|
-
|
6532
|
-
|
6533
|
-
|
6534
|
-
|
6535
|
-
|
6536
|
-
|
6537
|
-
|
6538
|
-
|
6539
|
-
|
6540
|
-
|
6541
|
-
|
6542
|
-
|
6543
|
-
|
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
|
-
|
6546
|
-
|
6547
|
-
|
6548
|
-
|
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
|
-
|
6551
|
-
|
6552
|
-
if (
|
6553
|
-
|
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
|
-
|
6963
|
-
|
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
|
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
|
-
|
6990
|
-
|
6991
|
-
|
6992
|
-
|
6993
|
-
|
6994
|
-
|
6995
|
-
|
6996
|
-
|
6997
|
-
|
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
|
-
|
7023
|
-
|
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
|
-
|
7446
|
-
|
7697
|
+
rbd_free_struct(w2);
|
7698
|
+
rbd_free_struct(w1);
|
7447
7699
|
return 1;
|
7448
7700
|
}
|
7449
7701
|
|