bigdecimal 3.1.0 → 3.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|