bigdecimal 3.1.8 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bigdecimal.gemspec +6 -1
- data/ext/bigdecimal/bigdecimal.c +1020 -2607
- data/ext/bigdecimal/bigdecimal.h +45 -60
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/div.h +192 -0
- data/ext/bigdecimal/extconf.rb +17 -16
- data/ext/bigdecimal/missing/dtoa.c +184 -137
- data/ext/bigdecimal/missing.c +2 -1
- data/ext/bigdecimal/missing.h +5 -95
- data/ext/bigdecimal/ntt.h +191 -0
- data/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math.rb +829 -134
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +17 -16
- data/lib/bigdecimal.rb +399 -0
- data/sample/linear.rb +73 -37
- data/sample/nlsolve.rb +47 -30
- data/sample/pi.rb +2 -7
- data/sig/big_decimal.rbs +1502 -0
- data/sig/big_decimal_util.rbs +158 -0
- data/sig/big_math.rbs +423 -0
- metadata +9 -7
data/ext/bigdecimal/bigdecimal.c
CHANGED
|
@@ -29,18 +29,29 @@
|
|
|
29
29
|
#endif
|
|
30
30
|
|
|
31
31
|
#include "bits.h"
|
|
32
|
+
#include "ntt.h"
|
|
33
|
+
#include "div.h"
|
|
32
34
|
#include "static_assert.h"
|
|
33
35
|
|
|
34
|
-
#define BIGDECIMAL_VERSION "
|
|
35
|
-
|
|
36
|
-
/* #define ENABLE_NUMERIC_STRING */
|
|
36
|
+
#define BIGDECIMAL_VERSION "4.1.2"
|
|
37
37
|
|
|
38
|
+
/* Make sure VPMULT_BATCH_SIZE*BASE*BASE does not overflow DECDIG_DBL */
|
|
39
|
+
#define VPMULT_BATCH_SIZE 16
|
|
40
|
+
#define NTT_MULTIPLICATION_THRESHOLD 450
|
|
41
|
+
#define NEWTON_RAPHSON_DIVISION_THRESHOLD 100
|
|
38
42
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
|
39
43
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
|
40
44
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
45
|
+
#define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
46
|
+
|
|
47
|
+
/* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
|
|
48
|
+
#define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
|
|
49
|
+
/* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
|
|
50
|
+
#define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
|
|
51
|
+
#define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
|
|
52
|
+
#define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
|
|
41
53
|
|
|
42
54
|
VALUE rb_cBigDecimal;
|
|
43
|
-
VALUE rb_mBigMath;
|
|
44
55
|
|
|
45
56
|
static ID id_BigDecimal_exception_mode;
|
|
46
57
|
static ID id_BigDecimal_rounding_mode;
|
|
@@ -68,15 +79,18 @@ static struct {
|
|
|
68
79
|
uint8_t mode;
|
|
69
80
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
static inline BDVALUE
|
|
83
|
+
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
84
|
+
{
|
|
85
|
+
assert(v.real_or_null != NULL);
|
|
86
|
+
return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static inline NULLABLE_BDVALUE
|
|
90
|
+
bdvalue_nullable(BDVALUE v)
|
|
91
|
+
{
|
|
92
|
+
return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
|
|
93
|
+
}
|
|
80
94
|
|
|
81
95
|
#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
|
|
82
96
|
#define BASE BIGDECIMAL_BASE
|
|
@@ -84,31 +98,6 @@ static struct {
|
|
|
84
98
|
#define HALF_BASE (BASE/2)
|
|
85
99
|
#define BASE1 (BASE/10)
|
|
86
100
|
|
|
87
|
-
#define LOG10_2 0.3010299956639812
|
|
88
|
-
|
|
89
|
-
#ifndef RRATIONAL_ZERO_P
|
|
90
|
-
# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
|
|
91
|
-
FIX2LONG(rb_rational_num(x)) == 0)
|
|
92
|
-
#endif
|
|
93
|
-
|
|
94
|
-
#ifndef RRATIONAL_NEGATIVE_P
|
|
95
|
-
# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
|
|
96
|
-
#endif
|
|
97
|
-
|
|
98
|
-
#ifndef DECIMAL_SIZE_OF_BITS
|
|
99
|
-
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
|
|
100
|
-
/* an approximation of ceil(n * log10(2)), upto 65536 at least */
|
|
101
|
-
#endif
|
|
102
|
-
|
|
103
|
-
#ifdef PRIsVALUE
|
|
104
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
|
105
|
-
# define RB_OBJ_STRING(obj) (obj)
|
|
106
|
-
#else
|
|
107
|
-
# define PRIsVALUE "s"
|
|
108
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
|
109
|
-
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
|
110
|
-
#endif
|
|
111
|
-
|
|
112
101
|
#ifndef MAYBE_UNUSED
|
|
113
102
|
# define MAYBE_UNUSED(x) x
|
|
114
103
|
#endif
|
|
@@ -145,6 +134,17 @@ check_allocation_count_nonzero(void)
|
|
|
145
134
|
# define check_allocation_count_nonzero() /* nothing */
|
|
146
135
|
#endif /* BIGDECIMAL_DEBUG */
|
|
147
136
|
|
|
137
|
+
/* VpMult VpDivd helpers */
|
|
138
|
+
#define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
|
|
139
|
+
/* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
|
|
140
|
+
/* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
|
|
141
|
+
#define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
|
|
142
|
+
/* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
|
|
143
|
+
#define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
|
|
144
|
+
|
|
145
|
+
static NULLABLE_BDVALUE
|
|
146
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
|
|
147
|
+
|
|
148
148
|
PUREFUNC(static inline size_t rbd_struct_size(size_t const));
|
|
149
149
|
|
|
150
150
|
static inline size_t
|
|
@@ -154,118 +154,6 @@ rbd_struct_size(size_t const internal_digits)
|
|
|
154
154
|
return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
|
|
155
155
|
}
|
|
156
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
|
-
|
|
269
157
|
/*
|
|
270
158
|
* ================== Ruby Interface part ==========================
|
|
271
159
|
*/
|
|
@@ -277,10 +165,9 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
|
|
277
165
|
static unsigned short VpGetException(void);
|
|
278
166
|
static void VpSetException(unsigned short f);
|
|
279
167
|
static void VpCheckException(Real *p, bool always);
|
|
280
|
-
static VALUE
|
|
168
|
+
static VALUE CheckGetValue(BDVALUE v);
|
|
281
169
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
282
170
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
283
|
-
static Real *VpCopy(Real *pv, Real const* const x);
|
|
284
171
|
static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
|
|
285
172
|
|
|
286
173
|
/*
|
|
@@ -292,85 +179,81 @@ static VALUE BigDecimal_positive_infinity(void);
|
|
|
292
179
|
static VALUE BigDecimal_negative_infinity(void);
|
|
293
180
|
static VALUE BigDecimal_positive_zero(void);
|
|
294
181
|
static VALUE BigDecimal_negative_zero(void);
|
|
182
|
+
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
183
|
+
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
295
184
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
185
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
186
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
187
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
188
|
+
#endif
|
|
189
|
+
|
|
190
|
+
#ifdef RUBY_TYPED_EMBEDDABLE
|
|
191
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
192
|
+
#else
|
|
193
|
+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
|
|
194
|
+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
|
|
195
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
196
|
+
# else
|
|
197
|
+
# define RUBY_TYPED_EMBEDDABLE 0
|
|
198
|
+
# endif
|
|
199
|
+
#endif
|
|
301
200
|
|
|
302
201
|
static size_t
|
|
303
202
|
BigDecimal_memsize(const void *ptr)
|
|
304
203
|
{
|
|
204
|
+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
205
|
+
return 0; // Entirely embedded
|
|
206
|
+
#else
|
|
305
207
|
const Real *pv = ptr;
|
|
306
208
|
return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
310
|
-
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
311
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
312
209
|
#endif
|
|
210
|
+
}
|
|
313
211
|
|
|
314
212
|
static const rb_data_type_t BigDecimal_data_type = {
|
|
315
|
-
"BigDecimal",
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
213
|
+
.wrap_struct_name = "BigDecimal",
|
|
214
|
+
.function = {
|
|
215
|
+
.dmark = 0,
|
|
216
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
217
|
+
.dsize = BigDecimal_memsize,
|
|
218
|
+
},
|
|
219
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
|
|
320
220
|
};
|
|
321
221
|
|
|
322
|
-
static
|
|
323
|
-
|
|
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)
|
|
222
|
+
static VALUE
|
|
223
|
+
BigDecimal_allocate(size_t const internal_digits)
|
|
337
224
|
{
|
|
338
|
-
|
|
225
|
+
const size_t size = rbd_struct_size(internal_digits);
|
|
226
|
+
VALUE bd = rb_data_typed_object_zalloc(rb_cBigDecimal, size, &BigDecimal_data_type);
|
|
227
|
+
Real *vp;
|
|
228
|
+
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
229
|
+
vp->MaxPrec = internal_digits;
|
|
230
|
+
RB_OBJ_FREEZE(bd);
|
|
231
|
+
return bd;
|
|
339
232
|
}
|
|
340
233
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
static inline Real *
|
|
344
|
-
rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
|
|
234
|
+
static VALUE
|
|
235
|
+
BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
|
|
345
236
|
{
|
|
346
|
-
return
|
|
237
|
+
return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
|
|
347
238
|
}
|
|
348
239
|
|
|
349
240
|
static Real *
|
|
350
|
-
|
|
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)
|
|
241
|
+
VpPtr(VALUE obj)
|
|
364
242
|
{
|
|
365
|
-
|
|
243
|
+
Real *vp;
|
|
244
|
+
TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
|
|
245
|
+
return vp;
|
|
366
246
|
}
|
|
367
247
|
|
|
368
|
-
MAYBE_UNUSED(static inline
|
|
369
|
-
#define
|
|
370
|
-
static
|
|
371
|
-
|
|
248
|
+
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
249
|
+
#define NewZeroWrap rbd_allocate_struct_zero_wrap
|
|
250
|
+
static BDVALUE
|
|
251
|
+
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
372
252
|
{
|
|
373
|
-
|
|
253
|
+
VALUE obj = BigDecimal_allocate_decimal_digits(digits);
|
|
254
|
+
Real *real = VpPtr(obj);
|
|
255
|
+
VpSetZero(real, sign);
|
|
256
|
+
return (BDVALUE) { obj, real };
|
|
374
257
|
}
|
|
375
258
|
|
|
376
259
|
static inline int
|
|
@@ -398,24 +281,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
|
|
|
398
281
|
}
|
|
399
282
|
|
|
400
283
|
static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
|
|
401
|
-
static VALUE rb_inum_convert_to_BigDecimal(VALUE val
|
|
284
|
+
static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
|
|
402
285
|
static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
403
286
|
static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
404
|
-
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
287
|
+
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
|
|
405
288
|
static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
406
289
|
|
|
407
|
-
static
|
|
408
|
-
|
|
290
|
+
static NULLABLE_BDVALUE
|
|
291
|
+
GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
409
292
|
{
|
|
410
|
-
const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
|
|
411
|
-
|
|
412
293
|
switch(TYPE(v)) {
|
|
413
294
|
case T_FLOAT:
|
|
414
|
-
v = rb_float_convert_to_BigDecimal(v,
|
|
295
|
+
v = rb_float_convert_to_BigDecimal(v, 0, true);
|
|
415
296
|
break;
|
|
416
297
|
|
|
417
298
|
case T_RATIONAL:
|
|
418
|
-
v = rb_rational_convert_to_BigDecimal(v,
|
|
299
|
+
v = rb_rational_convert_to_BigDecimal(v, prec, true);
|
|
419
300
|
break;
|
|
420
301
|
|
|
421
302
|
case T_DATA:
|
|
@@ -424,25 +305,9 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
|
|
|
424
305
|
}
|
|
425
306
|
break;
|
|
426
307
|
|
|
427
|
-
case T_FIXNUM:
|
|
428
|
-
char szD[128];
|
|
429
|
-
snprintf(szD, 128, "%ld", FIX2LONG(v));
|
|
430
|
-
v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
#ifdef ENABLE_NUMERIC_STRING
|
|
435
|
-
case T_STRING: {
|
|
436
|
-
const char *c_str = StringValueCStr(v);
|
|
437
|
-
v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
#endif /* ENABLE_NUMERIC_STRING */
|
|
441
|
-
|
|
308
|
+
case T_FIXNUM:
|
|
442
309
|
case T_BIGNUM: {
|
|
443
|
-
|
|
444
|
-
v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
|
|
445
|
-
RB_GC_GUARD(bg);
|
|
310
|
+
v = rb_inum_convert_to_BigDecimal(v);
|
|
446
311
|
break;
|
|
447
312
|
}
|
|
448
313
|
|
|
@@ -450,21 +315,40 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
|
|
|
450
315
|
goto SomeOneMayDoIt;
|
|
451
316
|
}
|
|
452
317
|
|
|
453
|
-
Real *vp;
|
|
454
|
-
|
|
455
|
-
return vp;
|
|
318
|
+
Real *vp = VpPtr(v);
|
|
319
|
+
return (NULLABLE_BDVALUE) { v, vp };
|
|
456
320
|
|
|
457
321
|
SomeOneMayDoIt:
|
|
458
322
|
if (must) {
|
|
459
323
|
cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
|
|
460
324
|
}
|
|
461
|
-
return NULL; /* NULL means to coerce */
|
|
325
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
static inline NULLABLE_BDVALUE
|
|
329
|
+
GetBDValueWithPrec(VALUE v, size_t prec)
|
|
330
|
+
{
|
|
331
|
+
return GetBDValueWithPrecInternal(v, prec, 0);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
static inline BDVALUE
|
|
336
|
+
GetBDValueWithPrecMust(VALUE v, size_t prec)
|
|
337
|
+
{
|
|
338
|
+
return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
|
|
462
339
|
}
|
|
463
340
|
|
|
341
|
+
// self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
|
|
464
342
|
static inline Real*
|
|
465
|
-
|
|
343
|
+
GetSelfVpValue(VALUE self)
|
|
344
|
+
{
|
|
345
|
+
return GetBDValueWithPrecMust(self, 0).real;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
static inline BDVALUE
|
|
349
|
+
GetBDValueMust(VALUE v)
|
|
466
350
|
{
|
|
467
|
-
return
|
|
351
|
+
return GetBDValueWithPrecMust(v, 0);
|
|
468
352
|
}
|
|
469
353
|
|
|
470
354
|
/* call-seq:
|
|
@@ -479,49 +363,14 @@ GetVpValue(VALUE v, int must)
|
|
|
479
363
|
static inline VALUE
|
|
480
364
|
BigDecimal_double_fig(VALUE self)
|
|
481
365
|
{
|
|
482
|
-
return INT2FIX(
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/* call-seq:
|
|
486
|
-
* precs -> array
|
|
487
|
-
*
|
|
488
|
-
* Returns an Array of two Integer values that represent platform-dependent
|
|
489
|
-
* internal storage properties.
|
|
490
|
-
*
|
|
491
|
-
* This method is deprecated and will be removed in the future.
|
|
492
|
-
* Instead, use BigDecimal#n_significant_digits for obtaining the number of
|
|
493
|
-
* significant digits in scientific notation, and BigDecimal#precision for
|
|
494
|
-
* obtaining the number of digits in decimal notation.
|
|
495
|
-
*
|
|
496
|
-
*/
|
|
497
|
-
|
|
498
|
-
static VALUE
|
|
499
|
-
BigDecimal_prec(VALUE self)
|
|
500
|
-
{
|
|
501
|
-
ENTER(1);
|
|
502
|
-
Real *p;
|
|
503
|
-
VALUE obj;
|
|
504
|
-
|
|
505
|
-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
|
|
506
|
-
"BigDecimal#precs is deprecated and will be removed in the future; "
|
|
507
|
-
"use BigDecimal#precision instead.");
|
|
508
|
-
|
|
509
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
510
|
-
obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
|
|
511
|
-
SIZET2NUM(p->MaxPrec*VpBaseFig()));
|
|
512
|
-
return obj;
|
|
366
|
+
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
513
367
|
}
|
|
514
368
|
|
|
515
369
|
static void
|
|
516
|
-
|
|
370
|
+
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
517
371
|
{
|
|
518
|
-
ENTER(1);
|
|
519
|
-
|
|
520
372
|
if (out_precision == NULL && out_scale == NULL)
|
|
521
373
|
return;
|
|
522
|
-
|
|
523
|
-
Real *p;
|
|
524
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
525
374
|
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
526
375
|
zero:
|
|
527
376
|
if (out_precision) *out_precision = 0;
|
|
@@ -625,6 +474,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
|
|
|
625
474
|
}
|
|
626
475
|
}
|
|
627
476
|
|
|
477
|
+
static void
|
|
478
|
+
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
|
479
|
+
{
|
|
480
|
+
BDVALUE v = GetBDValueMust(self);
|
|
481
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
|
482
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
483
|
+
}
|
|
484
|
+
|
|
628
485
|
/*
|
|
629
486
|
* call-seq:
|
|
630
487
|
* precision -> integer
|
|
@@ -660,8 +517,8 @@ BigDecimal_precision(VALUE self)
|
|
|
660
517
|
* BigDecimal("1").scale # => 0
|
|
661
518
|
* BigDecimal("1.1").scale # => 1
|
|
662
519
|
* BigDecimal("3.1415").scale # => 4
|
|
663
|
-
* BigDecimal("-1e20").
|
|
664
|
-
* BigDecimal("1e-20").
|
|
520
|
+
* BigDecimal("-1e20").scale # => 0
|
|
521
|
+
* BigDecimal("1e-20").scale # => 20
|
|
665
522
|
* BigDecimal("Infinity").scale # => 0
|
|
666
523
|
* BigDecimal("-Infinity").scale # => 0
|
|
667
524
|
* BigDecimal("NaN").scale # => 0
|
|
@@ -711,25 +568,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
|
711
568
|
static VALUE
|
|
712
569
|
BigDecimal_n_significant_digits(VALUE self)
|
|
713
570
|
{
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
Real *p;
|
|
717
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
718
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
571
|
+
BDVALUE v = GetBDValueMust(self);
|
|
572
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
|
719
573
|
return INT2FIX(0);
|
|
720
574
|
}
|
|
721
575
|
|
|
722
|
-
ssize_t n =
|
|
723
|
-
for (n =
|
|
576
|
+
ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
|
|
577
|
+
for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
|
|
724
578
|
if (n == 0) return INT2FIX(0);
|
|
725
579
|
|
|
726
580
|
DECDIG x;
|
|
727
581
|
int nlz = BASE_FIG;
|
|
728
|
-
for (x =
|
|
582
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
|
729
583
|
|
|
730
584
|
int ntz = 0;
|
|
731
|
-
for (x =
|
|
585
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
|
732
586
|
|
|
587
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
733
588
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
|
734
589
|
return SSIZET2NUM(n_significant_digits);
|
|
735
590
|
}
|
|
@@ -751,17 +606,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
|
751
606
|
static VALUE
|
|
752
607
|
BigDecimal_hash(VALUE self)
|
|
753
608
|
{
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
st_index_t hash;
|
|
757
|
-
|
|
758
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
759
|
-
hash = (st_index_t)p->sign;
|
|
609
|
+
BDVALUE v = GetBDValueMust(self);
|
|
610
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
|
760
611
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
|
761
612
|
if(hash == 2 || hash == (st_index_t)-2) {
|
|
762
|
-
hash ^= rb_memhash(
|
|
763
|
-
hash +=
|
|
613
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
|
614
|
+
hash += v.real->exponent;
|
|
764
615
|
}
|
|
616
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
765
617
|
return ST2FIX(hash);
|
|
766
618
|
}
|
|
767
619
|
|
|
@@ -780,21 +632,22 @@ BigDecimal_hash(VALUE self)
|
|
|
780
632
|
static VALUE
|
|
781
633
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
782
634
|
{
|
|
783
|
-
|
|
784
|
-
Real *vp;
|
|
635
|
+
BDVALUE v;
|
|
785
636
|
char *psz;
|
|
786
637
|
VALUE dummy;
|
|
787
638
|
volatile VALUE dump;
|
|
788
639
|
size_t len;
|
|
789
640
|
|
|
790
641
|
rb_scan_args(argc, argv, "01", &dummy);
|
|
791
|
-
|
|
792
|
-
dump = rb_str_new(0, VpNumOfChars(
|
|
642
|
+
v = GetBDValueMust(self);
|
|
643
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
|
793
644
|
psz = RSTRING_PTR(dump);
|
|
794
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
|
645
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
|
795
646
|
len = strlen(psz);
|
|
796
|
-
VpToString(
|
|
647
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
|
797
648
|
rb_str_resize(dump, strlen(psz));
|
|
649
|
+
|
|
650
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
798
651
|
return dump;
|
|
799
652
|
}
|
|
800
653
|
|
|
@@ -804,27 +657,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
|
804
657
|
static VALUE
|
|
805
658
|
BigDecimal_load(VALUE self, VALUE str)
|
|
806
659
|
{
|
|
807
|
-
|
|
808
|
-
Real *pv;
|
|
660
|
+
BDVALUE v;
|
|
809
661
|
unsigned char *pch;
|
|
810
662
|
unsigned char ch;
|
|
811
|
-
unsigned long m=0;
|
|
812
663
|
|
|
813
664
|
pch = (unsigned char *)StringValueCStr(str);
|
|
814
|
-
/* First
|
|
665
|
+
/* First skip max prec. Don't trust the value. */
|
|
815
666
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
|
816
667
|
if(!ISDIGIT(ch)) {
|
|
817
668
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
|
818
669
|
}
|
|
819
|
-
m = m*10 + (unsigned long)(ch-'0');
|
|
820
|
-
}
|
|
821
|
-
if (m > VpBaseFig()) m -= VpBaseFig();
|
|
822
|
-
GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
|
|
823
|
-
m /= VpBaseFig();
|
|
824
|
-
if (m && pv->MaxPrec > m) {
|
|
825
|
-
pv->MaxPrec = m+1;
|
|
826
670
|
}
|
|
827
|
-
|
|
671
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
672
|
+
return CheckGetValue(v);
|
|
828
673
|
}
|
|
829
674
|
|
|
830
675
|
static unsigned short
|
|
@@ -1117,22 +962,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1117
962
|
static size_t
|
|
1118
963
|
GetAddSubPrec(Real *a, Real *b)
|
|
1119
964
|
{
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
|
1125
|
-
if (mx < b->Prec) mx = b->Prec;
|
|
1126
|
-
if (a->exponent != b->exponent) {
|
|
1127
|
-
mxs = mx;
|
|
1128
|
-
d = a->exponent - b->exponent;
|
|
1129
|
-
if (d < 0) d = -d;
|
|
1130
|
-
mx = mx + (size_t)d;
|
|
1131
|
-
if (mx < mxs) {
|
|
1132
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
return mx;
|
|
965
|
+
if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
|
|
966
|
+
ssize_t min_a = a->exponent - a->Prec;
|
|
967
|
+
ssize_t min_b = b->exponent - b->Prec;
|
|
968
|
+
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
1136
969
|
}
|
|
1137
970
|
|
|
1138
971
|
static inline SIGNED_VALUE
|
|
@@ -1152,62 +985,28 @@ check_int_precision(VALUE v)
|
|
|
1152
985
|
return n;
|
|
1153
986
|
}
|
|
1154
987
|
|
|
1155
|
-
static
|
|
1156
|
-
|
|
1157
|
-
{
|
|
1158
|
-
assert(is_kind_of_BigDecimal(obj));
|
|
1159
|
-
assert(vp != NULL);
|
|
1160
|
-
|
|
1161
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
|
1162
|
-
return obj;
|
|
1163
|
-
|
|
1164
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
1165
|
-
assert(vp->obj == 0);
|
|
1166
|
-
|
|
1167
|
-
RTYPEDDATA_DATA(obj) = vp;
|
|
1168
|
-
vp->obj = obj;
|
|
1169
|
-
RB_OBJ_FREEZE(obj);
|
|
1170
|
-
return obj;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
VP_EXPORT Real *
|
|
1174
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1175
|
-
{
|
|
1176
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
1177
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
|
1178
|
-
if (!pv)
|
|
1179
|
-
return NULL;
|
|
1180
|
-
BigDecimal_wrap_struct(obj, pv);
|
|
1181
|
-
return pv;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
VP_EXPORT Real *
|
|
1185
|
-
VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
|
|
988
|
+
static NULLABLE_BDVALUE
|
|
989
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1186
990
|
{
|
|
1187
|
-
return
|
|
991
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1188
992
|
}
|
|
1189
993
|
|
|
1190
|
-
|
|
1191
|
-
|
|
994
|
+
void
|
|
995
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1192
996
|
{
|
|
1193
|
-
assert(x != NULL);
|
|
1194
|
-
|
|
1195
|
-
pv = rbd_reallocate_struct(pv, x->MaxPrec);
|
|
1196
997
|
pv->MaxPrec = x->MaxPrec;
|
|
1197
998
|
pv->Prec = x->Prec;
|
|
1198
999
|
pv->exponent = x->exponent;
|
|
1199
1000
|
pv->sign = x->sign;
|
|
1200
1001
|
pv->flag = x->flag;
|
|
1201
1002
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1202
|
-
|
|
1203
|
-
return pv;
|
|
1204
1003
|
}
|
|
1205
1004
|
|
|
1206
1005
|
/* Returns True if the value is Not a Number. */
|
|
1207
1006
|
static VALUE
|
|
1208
1007
|
BigDecimal_IsNaN(VALUE self)
|
|
1209
1008
|
{
|
|
1210
|
-
Real *p =
|
|
1009
|
+
Real *p = GetSelfVpValue(self);
|
|
1211
1010
|
if (VpIsNaN(p)) return Qtrue;
|
|
1212
1011
|
return Qfalse;
|
|
1213
1012
|
}
|
|
@@ -1218,7 +1017,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
|
1218
1017
|
static VALUE
|
|
1219
1018
|
BigDecimal_IsInfinite(VALUE self)
|
|
1220
1019
|
{
|
|
1221
|
-
Real *p =
|
|
1020
|
+
Real *p = GetSelfVpValue(self);
|
|
1222
1021
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
|
1223
1022
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
|
1224
1023
|
return Qnil;
|
|
@@ -1228,7 +1027,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
|
1228
1027
|
static VALUE
|
|
1229
1028
|
BigDecimal_IsFinite(VALUE self)
|
|
1230
1029
|
{
|
|
1231
|
-
Real *p =
|
|
1030
|
+
Real *p = GetSelfVpValue(self);
|
|
1232
1031
|
if (VpIsNaN(p)) return Qfalse;
|
|
1233
1032
|
if (VpIsInf(p)) return Qfalse;
|
|
1234
1033
|
return Qtrue;
|
|
@@ -1240,8 +1039,6 @@ BigDecimal_check_num(Real *p)
|
|
|
1240
1039
|
VpCheckException(p, true);
|
|
1241
1040
|
}
|
|
1242
1041
|
|
|
1243
|
-
static VALUE BigDecimal_split(VALUE self);
|
|
1244
|
-
|
|
1245
1042
|
/* Returns the value as an Integer.
|
|
1246
1043
|
*
|
|
1247
1044
|
* If the BigDecimal is infinity or NaN, raises FloatDomainError.
|
|
@@ -1249,44 +1046,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
|
1249
1046
|
static VALUE
|
|
1250
1047
|
BigDecimal_to_i(VALUE self)
|
|
1251
1048
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
Real *p;
|
|
1049
|
+
BDVALUE v;
|
|
1050
|
+
VALUE ret;
|
|
1255
1051
|
|
|
1256
|
-
|
|
1257
|
-
BigDecimal_check_num(
|
|
1052
|
+
v = GetBDValueMust(self);
|
|
1053
|
+
BigDecimal_check_num(v.real);
|
|
1258
1054
|
|
|
1259
|
-
|
|
1260
|
-
if (
|
|
1261
|
-
|
|
1262
|
-
if (e <= nf) {
|
|
1263
|
-
return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
|
|
1055
|
+
if (v.real->exponent <= 0) return INT2FIX(0);
|
|
1056
|
+
if (v.real->exponent == 1) {
|
|
1057
|
+
ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
|
|
1264
1058
|
}
|
|
1265
1059
|
else {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
ret = rb_funcall(numerator, '*', 1,
|
|
1282
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
|
1283
|
-
INT2FIX(dpower)));
|
|
1284
|
-
}
|
|
1285
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
|
1286
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1287
|
-
}
|
|
1288
|
-
return ret;
|
|
1060
|
+
VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
|
|
1061
|
+
VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
|
|
1062
|
+
ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
|
|
1063
|
+
ret = rb_funcall(digits, rb_intern("to_i"), 0);
|
|
1064
|
+
|
|
1065
|
+
if (BIGDECIMAL_NEGATIVE_P(v.real)) {
|
|
1066
|
+
ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
|
|
1067
|
+
}
|
|
1068
|
+
if (dpower) {
|
|
1069
|
+
VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
|
|
1070
|
+
// In Ruby < 3.4, int**int may return Float::INFINITY
|
|
1071
|
+
if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1072
|
+
|
|
1073
|
+
ret = rb_funcall(ret, '*', 1, pow10);
|
|
1074
|
+
}
|
|
1289
1075
|
}
|
|
1076
|
+
|
|
1077
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1078
|
+
return ret;
|
|
1290
1079
|
}
|
|
1291
1080
|
|
|
1292
1081
|
/* Returns a new Float object having approximately the same value as the
|
|
@@ -1296,24 +1085,26 @@ BigDecimal_to_i(VALUE self)
|
|
|
1296
1085
|
static VALUE
|
|
1297
1086
|
BigDecimal_to_f(VALUE self)
|
|
1298
1087
|
{
|
|
1299
|
-
ENTER(1);
|
|
1300
|
-
Real *p;
|
|
1301
1088
|
double d;
|
|
1302
1089
|
SIGNED_VALUE e;
|
|
1303
1090
|
char *buf;
|
|
1304
1091
|
volatile VALUE str;
|
|
1092
|
+
BDVALUE v = GetBDValueMust(self);
|
|
1093
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
|
1305
1094
|
|
|
1306
|
-
|
|
1307
|
-
if (VpVtoD(&d, &e, p) != 1)
|
|
1095
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
|
1308
1096
|
return rb_float_new(d);
|
|
1309
1097
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
|
1310
1098
|
goto overflow;
|
|
1311
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
|
1099
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
|
1312
1100
|
goto underflow;
|
|
1313
1101
|
|
|
1314
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
1102
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
1315
1103
|
buf = RSTRING_PTR(str);
|
|
1316
|
-
VpToString(
|
|
1104
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
|
1105
|
+
|
|
1106
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1107
|
+
|
|
1317
1108
|
errno = 0;
|
|
1318
1109
|
d = strtod(buf, 0);
|
|
1319
1110
|
if (errno == ERANGE) {
|
|
@@ -1324,14 +1115,14 @@ BigDecimal_to_f(VALUE self)
|
|
|
1324
1115
|
|
|
1325
1116
|
overflow:
|
|
1326
1117
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
|
1327
|
-
if (
|
|
1118
|
+
if (negative)
|
|
1328
1119
|
return rb_float_new(VpGetDoubleNegInf());
|
|
1329
1120
|
else
|
|
1330
1121
|
return rb_float_new(VpGetDoublePosInf());
|
|
1331
1122
|
|
|
1332
1123
|
underflow:
|
|
1333
1124
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
|
1334
|
-
if (
|
|
1125
|
+
if (negative)
|
|
1335
1126
|
return rb_float_new(-0.0);
|
|
1336
1127
|
else
|
|
1337
1128
|
return rb_float_new(0.0);
|
|
@@ -1343,15 +1134,16 @@ underflow:
|
|
|
1343
1134
|
static VALUE
|
|
1344
1135
|
BigDecimal_to_r(VALUE self)
|
|
1345
1136
|
{
|
|
1346
|
-
|
|
1137
|
+
BDVALUE v;
|
|
1347
1138
|
ssize_t sign, power, denomi_power;
|
|
1348
1139
|
VALUE a, digits, numerator;
|
|
1349
1140
|
|
|
1350
|
-
|
|
1351
|
-
BigDecimal_check_num(
|
|
1141
|
+
v = GetBDValueMust(self);
|
|
1142
|
+
BigDecimal_check_num(v.real);
|
|
1143
|
+
sign = VpGetSign(v.real);
|
|
1144
|
+
power = VpExponent10(v.real);
|
|
1145
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1352
1146
|
|
|
1353
|
-
sign = VpGetSign(p);
|
|
1354
|
-
power = VpExponent10(p);
|
|
1355
1147
|
a = BigDecimal_split(self);
|
|
1356
1148
|
digits = RARRAY_AREF(a, 1);
|
|
1357
1149
|
denomi_power = power - RSTRING_LEN(digits);
|
|
@@ -1372,6 +1164,14 @@ BigDecimal_to_r(VALUE self)
|
|
|
1372
1164
|
}
|
|
1373
1165
|
}
|
|
1374
1166
|
|
|
1167
|
+
static size_t
|
|
1168
|
+
GetCoercePrec(Real *a, size_t prec)
|
|
1169
|
+
{
|
|
1170
|
+
if (prec == 0) prec = a->Prec * BASE_FIG;
|
|
1171
|
+
if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1172
|
+
return prec;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1375
1175
|
/* The coerce method provides support for Ruby type coercion. It is not
|
|
1376
1176
|
* enabled by default.
|
|
1377
1177
|
*
|
|
@@ -1389,26 +1189,9 @@ BigDecimal_to_r(VALUE self)
|
|
|
1389
1189
|
static VALUE
|
|
1390
1190
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1391
1191
|
{
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
|
1397
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
|
1398
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
|
1399
|
-
}
|
|
1400
|
-
else {
|
|
1401
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
|
1402
|
-
Real* pv = DATA_PTR(self);
|
|
1403
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
|
1404
|
-
}
|
|
1405
|
-
else {
|
|
1406
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
|
1407
|
-
}
|
|
1408
|
-
obj = rb_assoc_new(b->obj, self);
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
return obj;
|
|
1192
|
+
Real* pv = VpPtr(self);
|
|
1193
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1194
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
|
1412
1195
|
}
|
|
1413
1196
|
|
|
1414
1197
|
/*
|
|
@@ -1428,6 +1211,15 @@ BigDecimal_uplus(VALUE self)
|
|
|
1428
1211
|
return self;
|
|
1429
1212
|
}
|
|
1430
1213
|
|
|
1214
|
+
static bool
|
|
1215
|
+
is_coerceable_to_BigDecimal(VALUE r)
|
|
1216
|
+
{
|
|
1217
|
+
return is_kind_of_BigDecimal(r) ||
|
|
1218
|
+
RB_INTEGER_TYPE_P(r) ||
|
|
1219
|
+
RB_TYPE_P(r, T_FLOAT) ||
|
|
1220
|
+
RB_TYPE_P(r, T_RATIONAL);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1431
1223
|
/*
|
|
1432
1224
|
* call-seq:
|
|
1433
1225
|
* self + value -> bigdecimal
|
|
@@ -1447,45 +1239,63 @@ BigDecimal_uplus(VALUE self)
|
|
|
1447
1239
|
static VALUE
|
|
1448
1240
|
BigDecimal_add(VALUE self, VALUE r)
|
|
1449
1241
|
{
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1242
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
|
1243
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
|
1244
|
+
}
|
|
1453
1245
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1460
|
-
}
|
|
1461
|
-
else {
|
|
1462
|
-
b = GetVpValue(r, 0);
|
|
1463
|
-
}
|
|
1246
|
+
static VALUE
|
|
1247
|
+
BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
1248
|
+
{
|
|
1249
|
+
BDVALUE a, b, c;
|
|
1250
|
+
size_t mx;
|
|
1464
1251
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1252
|
+
a = GetBDValueMust(self);
|
|
1253
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1467
1254
|
|
|
1468
|
-
if (VpIsNaN(
|
|
1469
|
-
if (VpIsNaN(
|
|
1255
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1256
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1470
1257
|
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
VpAddSub(c, a, b, 1);
|
|
1258
|
+
if (VpIsInf(a.real) || VpIsInf(b.real)) {
|
|
1259
|
+
c = NewZeroWrap(1, BASE_FIG);
|
|
1260
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1475
1261
|
}
|
|
1476
1262
|
else {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1263
|
+
|
|
1264
|
+
// Optimization when exponent difference is large
|
|
1265
|
+
// (1.234e+1000).add(5.678e-1000, 10) == (1.234e+1000).add(0.1e+990, 10) in every rounding mode
|
|
1266
|
+
if (prec && !VpIsZero(a.real) && !VpIsZero(b.real)) {
|
|
1267
|
+
size_t precRoom = roomof(prec, BASE_FIG);
|
|
1268
|
+
if (a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1 > b.real->exponent) {
|
|
1269
|
+
BDVALUE b2 = NewZeroWrap(1, BASE_FIG);
|
|
1270
|
+
VpSetOne(b2.real)
|
|
1271
|
+
VpSetSign(b2.real, b.real->sign);
|
|
1272
|
+
b2.real->exponent = a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1;
|
|
1273
|
+
b = b2;
|
|
1274
|
+
} else if (b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1 > a.real->exponent) {
|
|
1275
|
+
BDVALUE a2 = NewZeroWrap(1, BASE_FIG);
|
|
1276
|
+
VpSetOne(a2.real)
|
|
1277
|
+
VpSetSign(a2.real, a.real->sign);
|
|
1278
|
+
a2.real->exponent = b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1;
|
|
1279
|
+
a = a2;
|
|
1280
|
+
}
|
|
1483
1281
|
}
|
|
1282
|
+
|
|
1283
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1284
|
+
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1285
|
+
size_t pl = VpGetPrecLimit();
|
|
1286
|
+
if (prec) VpSetPrecLimit(prec);
|
|
1287
|
+
// Let VpAddSub round the result
|
|
1288
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1289
|
+
if (prec) VpSetPrecLimit(pl);
|
|
1484
1290
|
}
|
|
1485
|
-
|
|
1291
|
+
|
|
1292
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1293
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1294
|
+
return CheckGetValue(c);
|
|
1486
1295
|
}
|
|
1487
1296
|
|
|
1488
|
-
/*
|
|
1297
|
+
/*
|
|
1298
|
+
* call-seq:
|
|
1489
1299
|
* self - value -> bigdecimal
|
|
1490
1300
|
*
|
|
1491
1301
|
* Returns the \BigDecimal difference of +self+ and +value+:
|
|
@@ -1502,73 +1312,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
|
1502
1312
|
static VALUE
|
|
1503
1313
|
BigDecimal_sub(VALUE self, VALUE r)
|
|
1504
1314
|
{
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
size_t mx;
|
|
1508
|
-
|
|
1509
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
|
1510
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1511
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1512
|
-
}
|
|
1513
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1514
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1515
|
-
}
|
|
1516
|
-
else {
|
|
1517
|
-
b = GetVpValue(r,0);
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
if (!b) return DoSomeOne(self,r,'-');
|
|
1521
|
-
SAVE(b);
|
|
1522
|
-
|
|
1523
|
-
if (VpIsNaN(b)) return b->obj;
|
|
1524
|
-
if (VpIsNaN(a)) return a->obj;
|
|
1525
|
-
|
|
1526
|
-
mx = GetAddSubPrec(a,b);
|
|
1527
|
-
if (mx == (size_t)-1L) {
|
|
1528
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
|
1529
|
-
VpAddSub(c, a, b, -1);
|
|
1530
|
-
}
|
|
1531
|
-
else {
|
|
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
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
return VpCheckGetValue(c);
|
|
1315
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
|
1316
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
|
1541
1317
|
}
|
|
1542
1318
|
|
|
1543
1319
|
static VALUE
|
|
1544
1320
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1545
1321
|
{
|
|
1546
|
-
ENTER(5);
|
|
1547
1322
|
SIGNED_VALUE e;
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
switch (TYPE(r)) {
|
|
1551
|
-
case T_DATA:
|
|
1552
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
|
1553
|
-
/* fall through */
|
|
1554
|
-
case T_FIXNUM:
|
|
1555
|
-
/* fall through */
|
|
1556
|
-
case T_BIGNUM:
|
|
1557
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
|
1558
|
-
break;
|
|
1559
|
-
|
|
1560
|
-
case T_FLOAT:
|
|
1561
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
|
1562
|
-
break;
|
|
1323
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1324
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1563
1325
|
|
|
1564
|
-
|
|
1565
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
|
1566
|
-
break;
|
|
1567
|
-
|
|
1568
|
-
default:
|
|
1569
|
-
break;
|
|
1570
|
-
}
|
|
1571
|
-
if (b == NULL) {
|
|
1326
|
+
if (b.real_or_null == NULL) {
|
|
1572
1327
|
ID f = 0;
|
|
1573
1328
|
|
|
1574
1329
|
switch (op) {
|
|
@@ -1597,8 +1352,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1597
1352
|
}
|
|
1598
1353
|
return rb_num_coerce_relop(self, r, f);
|
|
1599
1354
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1355
|
+
e = VpComp(a.real, b.real_or_null);
|
|
1356
|
+
|
|
1357
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1358
|
+
RB_GC_GUARD(b.bigdecimal_or_nil);
|
|
1359
|
+
|
|
1602
1360
|
if (e == 999)
|
|
1603
1361
|
return (op == '*') ? Qnil : Qfalse;
|
|
1604
1362
|
switch (op) {
|
|
@@ -1638,7 +1396,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1638
1396
|
static VALUE
|
|
1639
1397
|
BigDecimal_zero(VALUE self)
|
|
1640
1398
|
{
|
|
1641
|
-
Real *a =
|
|
1399
|
+
Real *a = GetSelfVpValue(self);
|
|
1642
1400
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
|
1643
1401
|
}
|
|
1644
1402
|
|
|
@@ -1646,7 +1404,7 @@ BigDecimal_zero(VALUE self)
|
|
|
1646
1404
|
static VALUE
|
|
1647
1405
|
BigDecimal_nonzero(VALUE self)
|
|
1648
1406
|
{
|
|
1649
|
-
Real *a =
|
|
1407
|
+
Real *a = GetSelfVpValue(self);
|
|
1650
1408
|
return VpIsZero(a) ? Qnil : self;
|
|
1651
1409
|
}
|
|
1652
1410
|
|
|
@@ -1772,12 +1530,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
|
1772
1530
|
static VALUE
|
|
1773
1531
|
BigDecimal_neg(VALUE self)
|
|
1774
1532
|
{
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
return VpCheckGetValue(c);
|
|
1533
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1534
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
1535
|
+
VpAsgn(c.real, a.real, -10);
|
|
1536
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1537
|
+
return CheckGetValue(c);
|
|
1781
1538
|
}
|
|
1782
1539
|
|
|
1783
1540
|
/*
|
|
@@ -1790,84 +1547,36 @@ BigDecimal_neg(VALUE self)
|
|
|
1790
1547
|
*
|
|
1791
1548
|
* See BigDecimal#mult.
|
|
1792
1549
|
*/
|
|
1793
|
-
|
|
1794
1550
|
static VALUE
|
|
1795
1551
|
BigDecimal_mult(VALUE self, VALUE r)
|
|
1796
1552
|
{
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
size_t mx;
|
|
1800
|
-
|
|
1801
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
1802
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1803
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1804
|
-
}
|
|
1805
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1806
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1807
|
-
}
|
|
1808
|
-
else {
|
|
1809
|
-
b = GetVpValue(r,0);
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
if (!b) return DoSomeOne(self, r, '*');
|
|
1813
|
-
SAVE(b);
|
|
1814
|
-
|
|
1815
|
-
mx = a->Prec + b->Prec;
|
|
1816
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
|
1817
|
-
VpMult(c, a, b);
|
|
1818
|
-
return VpCheckGetValue(c);
|
|
1553
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
|
1554
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
|
1819
1555
|
}
|
|
1820
1556
|
|
|
1821
1557
|
static VALUE
|
|
1822
|
-
|
|
1823
|
-
/* For c = self.div(r): with round operation */
|
|
1558
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
|
1824
1559
|
{
|
|
1825
|
-
|
|
1826
|
-
Real *a, *b;
|
|
1827
|
-
ssize_t a_prec, b_prec;
|
|
1828
|
-
size_t mx;
|
|
1560
|
+
BDVALUE a, b, c;
|
|
1829
1561
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1562
|
+
a = GetBDValueMust(self);
|
|
1563
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1832
1564
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1838
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1565
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
1566
|
+
VpMult(c.real, a.real, b.real);
|
|
1567
|
+
if (prec) {
|
|
1568
|
+
VpLeftRound(c.real, VpGetRoundMode(), prec);
|
|
1839
1569
|
}
|
|
1840
|
-
else
|
|
1841
|
-
|
|
1842
|
-
}
|
|
1843
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1844
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1570
|
+
else {
|
|
1571
|
+
VpLimitRound(c.real, 0);
|
|
1845
1572
|
}
|
|
1846
1573
|
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
|
1852
|
-
SAVE(b);
|
|
1853
|
-
*div = b;
|
|
1854
|
-
|
|
1855
|
-
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
|
1856
|
-
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
|
1857
|
-
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
|
1858
|
-
mx *= 2;
|
|
1859
|
-
|
|
1860
|
-
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
|
1861
|
-
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
|
1862
|
-
|
|
1863
|
-
GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
|
|
1864
|
-
GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
|
|
1865
|
-
VpDivd(*c, *res, a, b);
|
|
1866
|
-
|
|
1867
|
-
return Qnil;
|
|
1574
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1575
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1576
|
+
return CheckGetValue(c);
|
|
1868
1577
|
}
|
|
1869
1578
|
|
|
1870
|
-
static
|
|
1579
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
|
1871
1580
|
|
|
1872
1581
|
/* call-seq:
|
|
1873
1582
|
* a / b -> bigdecimal
|
|
@@ -1884,20 +1593,8 @@ static VALUE
|
|
|
1884
1593
|
BigDecimal_div(VALUE self, VALUE r)
|
|
1885
1594
|
/* For c = self/r: with round operation */
|
|
1886
1595
|
{
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
r = BigDecimal_divide(self, r, &c, &res, &div);
|
|
1890
|
-
if (!NIL_P(r)) return r; /* coerced by other */
|
|
1891
|
-
SAVE(c); SAVE(res); SAVE(div);
|
|
1892
|
-
/* a/b = c + r/b */
|
|
1893
|
-
/* c xxxxx
|
|
1894
|
-
r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
|
|
1895
|
-
*/
|
|
1896
|
-
/* Round */
|
|
1897
|
-
if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
|
|
1898
|
-
VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
|
|
1899
|
-
}
|
|
1900
|
-
return VpCheckGetValue(c);
|
|
1596
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
|
1597
|
+
return BigDecimal_div2(self, r, INT2FIX(0));
|
|
1901
1598
|
}
|
|
1902
1599
|
|
|
1903
1600
|
static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
|
|
@@ -1942,119 +1639,115 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
|
1942
1639
|
/*
|
|
1943
1640
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
|
1944
1641
|
* div = (a.to_f/b).floor
|
|
1642
|
+
* In truncate mode, use truncate instead of floor.
|
|
1945
1643
|
*/
|
|
1946
|
-
static
|
|
1947
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
|
1644
|
+
static bool
|
|
1645
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
|
1948
1646
|
{
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
size_t mx;
|
|
1647
|
+
BDVALUE a, b, dv, md, res;
|
|
1648
|
+
NULLABLE_BDVALUE b2;
|
|
1649
|
+
ssize_t a_exponent, b_exponent;
|
|
1650
|
+
size_t mx, rx, pl;
|
|
1954
1651
|
|
|
1955
|
-
|
|
1956
|
-
SAVE(a);
|
|
1652
|
+
a = GetBDValueMust(self);
|
|
1957
1653
|
|
|
1958
|
-
|
|
1959
|
-
if (
|
|
1960
|
-
|
|
1961
|
-
}
|
|
1962
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1963
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1964
|
-
}
|
|
1965
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1966
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1967
|
-
}
|
|
1968
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1969
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1970
|
-
}
|
|
1654
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1655
|
+
if (!b2.real_or_null) return false;
|
|
1656
|
+
b = bdvalue_nonnullable(b2);
|
|
1971
1657
|
|
|
1972
|
-
if (
|
|
1973
|
-
|
|
1658
|
+
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1659
|
+
VALUE nan = BigDecimal_nan();
|
|
1660
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1661
|
+
goto Done;
|
|
1974
1662
|
}
|
|
1975
|
-
|
|
1976
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
|
1977
|
-
SAVE(b);
|
|
1978
|
-
|
|
1979
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
|
1980
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
|
1981
|
-
if (VpIsZero(b)) {
|
|
1663
|
+
if (VpIsZero(b.real)) {
|
|
1982
1664
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
|
1983
1665
|
}
|
|
1984
|
-
if (VpIsInf(a)) {
|
|
1985
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
|
1666
|
+
if (VpIsInf(a.real)) {
|
|
1667
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1986
1668
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1987
|
-
|
|
1669
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1988
1670
|
}
|
|
1989
1671
|
else {
|
|
1990
1672
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1991
|
-
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1992
1674
|
}
|
|
1993
1675
|
VALUE nan = BigDecimal_nan();
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
}
|
|
1997
|
-
if (VpIsInf(b)) {
|
|
1998
|
-
VALUE zero = BigDecimal_positive_zero();
|
|
1999
|
-
TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
|
|
2000
|
-
*mod = a;
|
|
2001
|
-
return Qtrue;
|
|
1676
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1677
|
+
goto Done;
|
|
2002
1678
|
}
|
|
2003
|
-
if (VpIsZero(a)) {
|
|
1679
|
+
if (VpIsZero(a.real)) {
|
|
2004
1680
|
VALUE zero = BigDecimal_positive_zero();
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
1681
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1682
|
+
*mod = bdvalue_nullable(a);
|
|
1683
|
+
goto Done;
|
|
1684
|
+
}
|
|
1685
|
+
if (VpIsInf(b.real)) {
|
|
1686
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
|
1687
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
|
1688
|
+
VpSetOne(minus_one.real);
|
|
1689
|
+
VpSetSign(minus_one.real, -1);
|
|
1690
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
|
1691
|
+
*div = bdvalue_nullable(minus_one);
|
|
1692
|
+
*mod = bdvalue_nullable(b);
|
|
1693
|
+
} else {
|
|
1694
|
+
VALUE zero = BigDecimal_positive_zero();
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1696
|
+
*mod = bdvalue_nullable(a);
|
|
1697
|
+
}
|
|
1698
|
+
goto Done;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
a_exponent = VpExponent10(a.real);
|
|
1702
|
+
b_exponent = VpExponent10(b.real);
|
|
1703
|
+
mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
|
|
1704
|
+
dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
|
|
1705
|
+
|
|
1706
|
+
/* res is reused for VpDivd remainder and VpMult result */
|
|
1707
|
+
rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
|
|
1708
|
+
mx = VPMULT_RESULT_PREC(dv.real, b.real);
|
|
1709
|
+
res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
|
|
1710
|
+
/* AddSub needs one more prec */
|
|
1711
|
+
md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
|
|
1712
|
+
|
|
1713
|
+
VpDivd(dv.real, res.real, a.real, b.real);
|
|
1714
|
+
VpMidRound(dv.real, VP_ROUND_DOWN, 0);
|
|
1715
|
+
VpMult(res.real, dv.real, b.real);
|
|
1716
|
+
pl = VpGetPrecLimit();
|
|
1717
|
+
VpSetPrecLimit(0);
|
|
1718
|
+
VpAddSub(md.real, a.real, res.real, -1);
|
|
1719
|
+
VpSetPrecLimit(pl);
|
|
2029
1720
|
|
|
2030
|
-
if (!VpIsZero(
|
|
1721
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
|
2031
1722
|
/* result adjustment for negative case */
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
VpAddSub(
|
|
2037
|
-
|
|
2038
|
-
*
|
|
1723
|
+
BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
|
|
1724
|
+
BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
|
|
1725
|
+
VpSetPrecLimit(0);
|
|
1726
|
+
VpAddSub(dv2.real, dv.real, VpOne(), -1);
|
|
1727
|
+
VpAddSub(md2.real, md.real, b.real, 1);
|
|
1728
|
+
VpSetPrecLimit(pl);
|
|
1729
|
+
*div = bdvalue_nullable(dv2);
|
|
1730
|
+
*mod = bdvalue_nullable(md2);
|
|
1731
|
+
RB_GC_GUARD(dv2.bigdecimal);
|
|
1732
|
+
RB_GC_GUARD(md2.bigdecimal);
|
|
2039
1733
|
}
|
|
2040
1734
|
else {
|
|
2041
|
-
*div =
|
|
2042
|
-
*mod =
|
|
1735
|
+
*div = bdvalue_nullable(dv);
|
|
1736
|
+
*mod = bdvalue_nullable(md);
|
|
2043
1737
|
}
|
|
2044
|
-
return Qtrue;
|
|
2045
1738
|
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
return
|
|
1739
|
+
Done:
|
|
1740
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1741
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1742
|
+
RB_GC_GUARD(dv.bigdecimal);
|
|
1743
|
+
RB_GC_GUARD(md.bigdecimal);
|
|
1744
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1745
|
+
return true;
|
|
2053
1746
|
}
|
|
2054
1747
|
|
|
2055
1748
|
/* call-seq:
|
|
2056
|
-
*
|
|
2057
|
-
*
|
|
1749
|
+
* a % b
|
|
1750
|
+
* a.modulo(b)
|
|
2058
1751
|
*
|
|
2059
1752
|
* Returns the modulus from dividing by b.
|
|
2060
1753
|
*
|
|
@@ -2063,71 +1756,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
|
2063
1756
|
static VALUE
|
|
2064
1757
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
|
2065
1758
|
{
|
|
2066
|
-
|
|
2067
|
-
Real *div = NULL, *mod = NULL;
|
|
1759
|
+
NULLABLE_BDVALUE div, mod;
|
|
2068
1760
|
|
|
2069
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2070
|
-
|
|
2071
|
-
return VpCheckGetValue(mod);
|
|
1761
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1762
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
2072
1763
|
}
|
|
2073
1764
|
return DoSomeOne(self, r, '%');
|
|
2074
1765
|
}
|
|
2075
1766
|
|
|
2076
|
-
static VALUE
|
|
2077
|
-
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
2078
|
-
{
|
|
2079
|
-
ENTER(10);
|
|
2080
|
-
size_t mx;
|
|
2081
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
|
2082
|
-
Real *f = NULL;
|
|
2083
|
-
|
|
2084
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2085
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
2086
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
2087
|
-
}
|
|
2088
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
2089
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
2090
|
-
}
|
|
2091
|
-
else {
|
|
2092
|
-
b = GetVpValue(r, 0);
|
|
2093
|
-
}
|
|
2094
|
-
|
|
2095
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2096
|
-
SAVE(b);
|
|
2097
|
-
|
|
2098
|
-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
|
|
2099
|
-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
|
|
2100
|
-
VpSetZero(*dv, 1);
|
|
2101
|
-
*rv = a;
|
|
2102
|
-
return Qnil;
|
|
2103
|
-
}
|
|
2104
|
-
|
|
2105
|
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
|
|
2106
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2107
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2108
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2109
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2110
|
-
|
|
2111
|
-
VpDivd(c, res, a, b);
|
|
2112
|
-
|
|
2113
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
|
2114
|
-
|
|
2115
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
|
2116
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
|
2117
|
-
|
|
2118
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2119
|
-
|
|
2120
|
-
VpFrac(f, c);
|
|
2121
|
-
VpMult(rr, f, b);
|
|
2122
|
-
VpAddSub(ff, res, rr, 1);
|
|
2123
|
-
|
|
2124
|
-
*dv = d;
|
|
2125
|
-
*rv = ff;
|
|
2126
|
-
return Qnil;
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
1767
|
/* call-seq:
|
|
2130
|
-
*
|
|
1768
|
+
* remainder(value)
|
|
2131
1769
|
*
|
|
2132
1770
|
* Returns the remainder from dividing by the value.
|
|
2133
1771
|
*
|
|
@@ -2136,15 +1774,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
|
2136
1774
|
static VALUE
|
|
2137
1775
|
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2138
1776
|
{
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
1777
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
|
1778
|
+
|
|
1779
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
|
1780
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
1781
|
+
}
|
|
1782
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2144
1783
|
}
|
|
2145
1784
|
|
|
2146
1785
|
/* call-seq:
|
|
2147
|
-
*
|
|
1786
|
+
* divmod(value)
|
|
2148
1787
|
*
|
|
2149
1788
|
* Divides by the specified value, and returns the quotient and modulus
|
|
2150
1789
|
* as BigDecimal numbers. The quotient is rounded towards negative infinity.
|
|
@@ -2168,12 +1807,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
|
2168
1807
|
static VALUE
|
|
2169
1808
|
BigDecimal_divmod(VALUE self, VALUE r)
|
|
2170
1809
|
{
|
|
2171
|
-
|
|
2172
|
-
Real *div = NULL, *mod = NULL;
|
|
1810
|
+
NULLABLE_BDVALUE div, mod;
|
|
2173
1811
|
|
|
2174
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2175
|
-
|
|
2176
|
-
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
|
|
1812
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1813
|
+
return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
2177
1814
|
}
|
|
2178
1815
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
2179
1816
|
}
|
|
@@ -2185,47 +1822,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
2185
1822
|
static inline VALUE
|
|
2186
1823
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2187
1824
|
{
|
|
2188
|
-
ENTER(5);
|
|
2189
1825
|
SIGNED_VALUE ix;
|
|
1826
|
+
BDVALUE av, bv, cv, res;
|
|
2190
1827
|
|
|
2191
1828
|
if (NIL_P(n)) { /* div in Float sense */
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
|
2195
|
-
return BigDecimal_to_i(
|
|
1829
|
+
NULLABLE_BDVALUE div;
|
|
1830
|
+
NULLABLE_BDVALUE mod;
|
|
1831
|
+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
|
|
1832
|
+
return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
|
|
2196
1833
|
}
|
|
2197
1834
|
return DoSomeOne(self, b, rb_intern("div"));
|
|
2198
1835
|
}
|
|
2199
1836
|
|
|
2200
1837
|
/* div in BigDecimal sense */
|
|
2201
1838
|
ix = check_int_precision(n);
|
|
1839
|
+
|
|
1840
|
+
av = GetBDValueMust(self);
|
|
1841
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
|
1842
|
+
|
|
2202
1843
|
if (ix == 0) {
|
|
2203
|
-
|
|
1844
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
|
1845
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
|
1846
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
|
1847
|
+
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
|
1848
|
+
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
|
1849
|
+
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1850
|
+
if (limit && limit < ix) ix = limit;
|
|
2204
1851
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2220
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
|
|
2221
|
-
mx = av->Prec + bv->Prec + 2;
|
|
2222
|
-
if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
|
|
2223
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
|
|
2224
|
-
VpDivd(cv, res, av, bv);
|
|
2225
|
-
VpSetPrecLimit(pl);
|
|
2226
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
|
2227
|
-
return VpCheckGetValue(cv);
|
|
1852
|
+
|
|
1853
|
+
// Needs to calculate 1 extra digit for rounding.
|
|
1854
|
+
cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
|
|
1855
|
+
res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
|
|
1856
|
+
VpDivd(cv.real, res.real, av.real, bv.real);
|
|
1857
|
+
|
|
1858
|
+
if (!VpIsZero(res.real)) {
|
|
1859
|
+
// Remainder value affects rounding result.
|
|
1860
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
|
1861
|
+
// 0.1e0 if remainder == 0
|
|
1862
|
+
// 0.1000000001e0 if remainder != 0
|
|
1863
|
+
size_t idx = roomof(ix, BASE_FIG);
|
|
1864
|
+
while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
|
|
1865
|
+
if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
|
|
2228
1866
|
}
|
|
1867
|
+
VpLeftRound(cv.real, VpGetRoundMode(), ix);
|
|
1868
|
+
|
|
1869
|
+
RB_GC_GUARD(av.bigdecimal);
|
|
1870
|
+
RB_GC_GUARD(bv.bigdecimal);
|
|
1871
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1872
|
+
return CheckGetValue(cv);
|
|
2229
1873
|
}
|
|
2230
1874
|
|
|
2231
1875
|
/*
|
|
@@ -2301,22 +1945,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
|
2301
1945
|
static VALUE
|
|
2302
1946
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2303
1947
|
{
|
|
2304
|
-
|
|
2305
|
-
Real *cv;
|
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2307
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
|
2308
|
-
else {
|
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2310
|
-
VALUE c = BigDecimal_add(self, b);
|
|
2311
|
-
VpSetPrecLimit(pl);
|
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2314
|
-
return VpCheckGetValue(cv);
|
|
2315
|
-
}
|
|
1948
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
|
2316
1949
|
}
|
|
2317
1950
|
|
|
2318
1951
|
/* call-seq:
|
|
2319
|
-
*
|
|
1952
|
+
* sub(value, digits) -> bigdecimal
|
|
2320
1953
|
*
|
|
2321
1954
|
* Subtract the specified value.
|
|
2322
1955
|
*
|
|
@@ -2331,18 +1964,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
|
2331
1964
|
static VALUE
|
|
2332
1965
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2333
1966
|
{
|
|
2334
|
-
|
|
2335
|
-
Real *cv;
|
|
2336
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2337
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
|
2338
|
-
else {
|
|
2339
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2340
|
-
VALUE c = BigDecimal_sub(self, b);
|
|
2341
|
-
VpSetPrecLimit(pl);
|
|
2342
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2343
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2344
|
-
return VpCheckGetValue(cv);
|
|
2345
|
-
}
|
|
1967
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
|
2346
1968
|
}
|
|
2347
1969
|
|
|
2348
1970
|
/*
|
|
@@ -2374,18 +1996,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
|
2374
1996
|
static VALUE
|
|
2375
1997
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2376
1998
|
{
|
|
2377
|
-
|
|
2378
|
-
Real *cv;
|
|
2379
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2380
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
|
2381
|
-
else {
|
|
2382
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2383
|
-
VALUE c = BigDecimal_mult(self, b);
|
|
2384
|
-
VpSetPrecLimit(pl);
|
|
2385
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2386
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2387
|
-
return VpCheckGetValue(cv);
|
|
2388
|
-
}
|
|
1999
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
|
2389
2000
|
}
|
|
2390
2001
|
|
|
2391
2002
|
/*
|
|
@@ -2402,41 +2013,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
|
2402
2013
|
static VALUE
|
|
2403
2014
|
BigDecimal_abs(VALUE self)
|
|
2404
2015
|
{
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2412
|
-
VpAsgn(c, a, 1);
|
|
2413
|
-
VpChangeSign(c, 1);
|
|
2414
|
-
return VpCheckGetValue(c);
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
/* call-seq:
|
|
2418
|
-
* sqrt(n)
|
|
2419
|
-
*
|
|
2420
|
-
* Returns the square root of the value.
|
|
2421
|
-
*
|
|
2422
|
-
* Result has at least n significant digits.
|
|
2423
|
-
*/
|
|
2424
|
-
static VALUE
|
|
2425
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2426
|
-
{
|
|
2427
|
-
ENTER(5);
|
|
2428
|
-
Real *c, *a;
|
|
2429
|
-
size_t mx, n;
|
|
2430
|
-
|
|
2431
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2432
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2433
|
-
|
|
2434
|
-
n = check_int_precision(nFig);
|
|
2435
|
-
n += VpDblFig() + VpBaseFig();
|
|
2436
|
-
if (mx <= n) mx = n;
|
|
2437
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2438
|
-
VpSqrt(c, a);
|
|
2439
|
-
return VpCheckGetValue(c);
|
|
2016
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2017
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
2018
|
+
VpAsgn(c.real, a.real, 10);
|
|
2019
|
+
VpChangeSign(c.real, 1);
|
|
2020
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2021
|
+
return CheckGetValue(c);
|
|
2440
2022
|
}
|
|
2441
2023
|
|
|
2442
2024
|
/* Return the integer part of the number, as a BigDecimal.
|
|
@@ -2444,22 +2026,18 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
|
2444
2026
|
static VALUE
|
|
2445
2027
|
BigDecimal_fix(VALUE self)
|
|
2446
2028
|
{
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
|
2453
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2454
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2455
|
-
return VpCheckGetValue(c);
|
|
2029
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2030
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2031
|
+
VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2032
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2033
|
+
return CheckGetValue(c);
|
|
2456
2034
|
}
|
|
2457
2035
|
|
|
2458
2036
|
/* call-seq:
|
|
2459
|
-
*
|
|
2037
|
+
* round(n, mode)
|
|
2460
2038
|
*
|
|
2461
2039
|
* Round to the nearest integer (by default), returning the result as a
|
|
2462
|
-
* BigDecimal if n is specified, or as an Integer if it isn't.
|
|
2040
|
+
* BigDecimal if n is specified and positive, or as an Integer if it isn't.
|
|
2463
2041
|
*
|
|
2464
2042
|
* BigDecimal('3.14159').round #=> 3
|
|
2465
2043
|
* BigDecimal('8.7').round #=> 9
|
|
@@ -2467,6 +2045,7 @@ BigDecimal_fix(VALUE self)
|
|
|
2467
2045
|
*
|
|
2468
2046
|
* BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
|
|
2469
2047
|
* BigDecimal('3.14159').round.class.name #=> "Integer"
|
|
2048
|
+
* BigDecimal('3.14159').round(0).class.name #=> "Integer"
|
|
2470
2049
|
*
|
|
2471
2050
|
* If n is specified and positive, the fractional part of the result has no
|
|
2472
2051
|
* more than that many digits.
|
|
@@ -2483,13 +2062,12 @@ BigDecimal_fix(VALUE self)
|
|
|
2483
2062
|
static VALUE
|
|
2484
2063
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2485
2064
|
{
|
|
2486
|
-
|
|
2487
|
-
Real *c, *a;
|
|
2065
|
+
BDVALUE c, a;
|
|
2488
2066
|
int iLoc = 0;
|
|
2489
2067
|
VALUE vLoc;
|
|
2490
2068
|
VALUE vRound;
|
|
2491
2069
|
int round_to_int = 0;
|
|
2492
|
-
size_t mx
|
|
2070
|
+
size_t mx;
|
|
2493
2071
|
|
|
2494
2072
|
unsigned short sw = VpGetRoundMode();
|
|
2495
2073
|
|
|
@@ -2520,20 +2098,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2520
2098
|
break;
|
|
2521
2099
|
}
|
|
2522
2100
|
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2101
|
+
a = GetBDValueMust(self);
|
|
2102
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2103
|
+
c = NewZeroWrap(1, mx);
|
|
2104
|
+
|
|
2105
|
+
VpActiveRound(c.real, a.real, sw, iLoc);
|
|
2106
|
+
|
|
2107
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2108
|
+
|
|
2529
2109
|
if (round_to_int) {
|
|
2530
|
-
return BigDecimal_to_i(
|
|
2110
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2531
2111
|
}
|
|
2532
|
-
return
|
|
2112
|
+
return CheckGetValue(c);
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
static VALUE
|
|
2116
|
+
BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
|
|
2117
|
+
{
|
|
2118
|
+
BDVALUE c, a;
|
|
2119
|
+
int iLoc;
|
|
2120
|
+
VALUE vLoc;
|
|
2121
|
+
size_t mx;
|
|
2122
|
+
|
|
2123
|
+
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2124
|
+
iLoc = 0;
|
|
2125
|
+
}
|
|
2126
|
+
else {
|
|
2127
|
+
iLoc = NUM2INT(vLoc);
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
a = GetBDValueMust(self);
|
|
2131
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2132
|
+
c = NewZeroWrap(1, mx);
|
|
2133
|
+
VpActiveRound(c.real, a.real, rounding_mode, iLoc);
|
|
2134
|
+
|
|
2135
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2136
|
+
|
|
2137
|
+
if (argc == 0) {
|
|
2138
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2139
|
+
}
|
|
2140
|
+
return CheckGetValue(c);
|
|
2533
2141
|
}
|
|
2534
2142
|
|
|
2535
2143
|
/* call-seq:
|
|
2536
|
-
*
|
|
2144
|
+
* truncate(n)
|
|
2537
2145
|
*
|
|
2538
2146
|
* Truncate to the nearest integer (by default), returning the result as a
|
|
2539
2147
|
* BigDecimal.
|
|
@@ -2554,28 +2162,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2554
2162
|
static VALUE
|
|
2555
2163
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2556
2164
|
{
|
|
2557
|
-
|
|
2558
|
-
Real *c, *a;
|
|
2559
|
-
int iLoc;
|
|
2560
|
-
VALUE vLoc;
|
|
2561
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2562
|
-
|
|
2563
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2564
|
-
iLoc = 0;
|
|
2565
|
-
}
|
|
2566
|
-
else {
|
|
2567
|
-
iLoc = NUM2INT(vLoc);
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2571
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2572
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2573
|
-
VpSetPrecLimit(pl);
|
|
2574
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
|
2575
|
-
if (argc == 0) {
|
|
2576
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2577
|
-
}
|
|
2578
|
-
return VpCheckGetValue(c);
|
|
2165
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
|
2579
2166
|
}
|
|
2580
2167
|
|
|
2581
2168
|
/* Return the fractional part of the number, as a BigDecimal.
|
|
@@ -2583,19 +2170,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
|
2583
2170
|
static VALUE
|
|
2584
2171
|
BigDecimal_frac(VALUE self)
|
|
2585
2172
|
{
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2592
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2593
|
-
VpFrac(c, a);
|
|
2594
|
-
return VpCheckGetValue(c);
|
|
2173
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2174
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2175
|
+
VpFrac(c.real, a.real);
|
|
2176
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2177
|
+
return CheckGetValue(c);
|
|
2595
2178
|
}
|
|
2596
2179
|
|
|
2597
2180
|
/* call-seq:
|
|
2598
|
-
*
|
|
2181
|
+
* floor(n)
|
|
2599
2182
|
*
|
|
2600
2183
|
* Return the largest integer less than or equal to the value, as a BigDecimal.
|
|
2601
2184
|
*
|
|
@@ -2614,35 +2197,11 @@ BigDecimal_frac(VALUE self)
|
|
|
2614
2197
|
static VALUE
|
|
2615
2198
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2616
2199
|
{
|
|
2617
|
-
|
|
2618
|
-
Real *c, *a;
|
|
2619
|
-
int iLoc;
|
|
2620
|
-
VALUE vLoc;
|
|
2621
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2622
|
-
|
|
2623
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
|
2624
|
-
iLoc = 0;
|
|
2625
|
-
}
|
|
2626
|
-
else {
|
|
2627
|
-
iLoc = NUM2INT(vLoc);
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2631
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2632
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2633
|
-
VpSetPrecLimit(pl);
|
|
2634
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
|
2635
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
2636
|
-
VPrint(stderr, "floor: c=%\n", c);
|
|
2637
|
-
#endif
|
|
2638
|
-
if (argc == 0) {
|
|
2639
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2640
|
-
}
|
|
2641
|
-
return VpCheckGetValue(c);
|
|
2200
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
|
2642
2201
|
}
|
|
2643
2202
|
|
|
2644
2203
|
/* call-seq:
|
|
2645
|
-
*
|
|
2204
|
+
* ceil(n)
|
|
2646
2205
|
*
|
|
2647
2206
|
* Return the smallest integer greater than or equal to the value, as a BigDecimal.
|
|
2648
2207
|
*
|
|
@@ -2661,31 +2220,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
|
2661
2220
|
static VALUE
|
|
2662
2221
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2663
2222
|
{
|
|
2664
|
-
|
|
2665
|
-
Real *c, *a;
|
|
2666
|
-
int iLoc;
|
|
2667
|
-
VALUE vLoc;
|
|
2668
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2669
|
-
|
|
2670
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2671
|
-
iLoc = 0;
|
|
2672
|
-
} else {
|
|
2673
|
-
iLoc = NUM2INT(vLoc);
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2677
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2678
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2679
|
-
VpSetPrecLimit(pl);
|
|
2680
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
|
2681
|
-
if (argc == 0) {
|
|
2682
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2683
|
-
}
|
|
2684
|
-
return VpCheckGetValue(c);
|
|
2223
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
|
2685
2224
|
}
|
|
2686
2225
|
|
|
2687
2226
|
/* call-seq:
|
|
2688
|
-
*
|
|
2227
|
+
* to_s(s)
|
|
2689
2228
|
*
|
|
2690
2229
|
* Converts the value to a string.
|
|
2691
2230
|
*
|
|
@@ -2702,7 +2241,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2702
2241
|
* If s contains a number, a space is inserted after each group of that many
|
|
2703
2242
|
* digits, starting from '.' and counting outwards.
|
|
2704
2243
|
*
|
|
2705
|
-
* If s ends with an 'E',
|
|
2244
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
|
2706
2245
|
*
|
|
2707
2246
|
* If s ends with an 'F', conventional floating point notation is used.
|
|
2708
2247
|
*
|
|
@@ -2720,10 +2259,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2720
2259
|
static VALUE
|
|
2721
2260
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2722
2261
|
{
|
|
2723
|
-
ENTER(5);
|
|
2724
2262
|
int fmt = 0; /* 0: E format, 1: F format */
|
|
2725
2263
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
2726
|
-
|
|
2264
|
+
BDVALUE v;
|
|
2727
2265
|
volatile VALUE str;
|
|
2728
2266
|
char *psz;
|
|
2729
2267
|
char ch;
|
|
@@ -2731,7 +2269,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2731
2269
|
SIGNED_VALUE m;
|
|
2732
2270
|
VALUE f;
|
|
2733
2271
|
|
|
2734
|
-
|
|
2272
|
+
v = GetBDValueMust(self);
|
|
2735
2273
|
|
|
2736
2274
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
|
2737
2275
|
if (RB_TYPE_P(f, T_STRING)) {
|
|
@@ -2766,10 +2304,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2766
2304
|
}
|
|
2767
2305
|
}
|
|
2768
2306
|
if (fmt) {
|
|
2769
|
-
nc = VpNumOfChars(
|
|
2307
|
+
nc = VpNumOfChars(v.real, "F");
|
|
2770
2308
|
}
|
|
2771
2309
|
else {
|
|
2772
|
-
nc = VpNumOfChars(
|
|
2310
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2773
2311
|
}
|
|
2774
2312
|
if (mc > 0) {
|
|
2775
2313
|
nc += (nc + mc - 1) / mc + 1;
|
|
@@ -2779,12 +2317,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2779
2317
|
psz = RSTRING_PTR(str);
|
|
2780
2318
|
|
|
2781
2319
|
if (fmt) {
|
|
2782
|
-
VpToFString(
|
|
2320
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2783
2321
|
}
|
|
2784
2322
|
else {
|
|
2785
|
-
VpToString (
|
|
2323
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2786
2324
|
}
|
|
2787
2325
|
rb_str_resize(str, strlen(psz));
|
|
2326
|
+
|
|
2327
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2788
2328
|
return str;
|
|
2789
2329
|
}
|
|
2790
2330
|
|
|
@@ -2801,471 +2341,163 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2801
2341
|
*
|
|
2802
2342
|
* The fourth value is an Integer exponent.
|
|
2803
2343
|
*
|
|
2804
|
-
* If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
|
|
2805
|
-
* string of significant digits with no leading zeros, and n is the exponent.
|
|
2806
|
-
*
|
|
2807
|
-
* From these values, you can translate a BigDecimal to a float as follows:
|
|
2808
|
-
*
|
|
2809
|
-
* sign, significant_digits, base, exponent = a.split
|
|
2810
|
-
* f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
|
|
2811
|
-
*
|
|
2812
|
-
* (Note that the to_f method is provided as a more convenient way to translate
|
|
2813
|
-
* a BigDecimal to a Float.)
|
|
2814
|
-
*/
|
|
2815
|
-
static VALUE
|
|
2816
|
-
BigDecimal_split(VALUE self)
|
|
2817
|
-
{
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
char *psz1;
|
|
2823
|
-
|
|
2824
|
-
GUARD_OBJ(vp, GetVpValue(self, 1));
|
|
2825
|
-
str = rb_str_new(0, VpNumOfChars(vp, "E"));
|
|
2826
|
-
psz1 = RSTRING_PTR(str);
|
|
2827
|
-
VpSzMantissa(vp, psz1, RSTRING_LEN(str));
|
|
2828
|
-
s = 1;
|
|
2829
|
-
if(psz1[0] == '-') {
|
|
2830
|
-
size_t len = strlen(psz1 + 1);
|
|
2831
|
-
|
|
2832
|
-
memmove(psz1, psz1 + 1, len);
|
|
2833
|
-
psz1[len] = '\0';
|
|
2834
|
-
s = -1;
|
|
2835
|
-
}
|
|
2836
|
-
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2837
|
-
e = VpExponent10(vp);
|
|
2838
|
-
obj = rb_ary_new2(4);
|
|
2839
|
-
rb_ary_push(obj, INT2FIX(s));
|
|
2840
|
-
rb_ary_push(obj, str);
|
|
2841
|
-
rb_str_resize(str, strlen(psz1));
|
|
2842
|
-
rb_ary_push(obj, INT2FIX(10));
|
|
2843
|
-
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2844
|
-
return obj;
|
|
2845
|
-
}
|
|
2846
|
-
|
|
2847
|
-
/* Returns the exponent of the BigDecimal number, as an Integer.
|
|
2848
|
-
*
|
|
2849
|
-
* If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
|
|
2850
|
-
* of digits with no leading zeros, then n is the exponent.
|
|
2851
|
-
*/
|
|
2852
|
-
static VALUE
|
|
2853
|
-
BigDecimal_exponent(VALUE self)
|
|
2854
|
-
{
|
|
2855
|
-
ssize_t e = VpExponent10(GetVpValue(self, 1));
|
|
2856
|
-
return SSIZET2NUM(e);
|
|
2857
|
-
}
|
|
2858
|
-
|
|
2859
|
-
/* Returns a string representation of self.
|
|
2860
|
-
*
|
|
2861
|
-
* BigDecimal("1234.5678").inspect
|
|
2862
|
-
* #=> "0.12345678e4"
|
|
2863
|
-
*/
|
|
2864
|
-
static VALUE
|
|
2865
|
-
BigDecimal_inspect(VALUE self)
|
|
2866
|
-
{
|
|
2867
|
-
ENTER(5);
|
|
2868
|
-
Real *vp;
|
|
2869
|
-
volatile VALUE str;
|
|
2870
|
-
size_t nc;
|
|
2871
|
-
|
|
2872
|
-
GUARD_OBJ(vp, GetVpValue(self, 1));
|
|
2873
|
-
nc = VpNumOfChars(vp, "E");
|
|
2874
|
-
|
|
2875
|
-
str = rb_str_new(0, nc);
|
|
2876
|
-
VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2877
|
-
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
|
2878
|
-
return str;
|
|
2879
|
-
}
|
|
2880
|
-
|
|
2881
|
-
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
|
2882
|
-
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
|
2883
|
-
|
|
2884
|
-
#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
|
|
2885
|
-
#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
|
|
2886
|
-
|
|
2887
|
-
inline static int
|
|
2888
|
-
is_integer(VALUE x)
|
|
2889
|
-
{
|
|
2890
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
|
2891
|
-
}
|
|
2892
|
-
|
|
2893
|
-
inline static int
|
|
2894
|
-
is_negative(VALUE x)
|
|
2895
|
-
{
|
|
2896
|
-
if (FIXNUM_P(x)) {
|
|
2897
|
-
return FIX2LONG(x) < 0;
|
|
2898
|
-
}
|
|
2899
|
-
else if (RB_TYPE_P(x, T_BIGNUM)) {
|
|
2900
|
-
return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
|
|
2901
|
-
}
|
|
2902
|
-
else if (RB_TYPE_P(x, T_FLOAT)) {
|
|
2903
|
-
return RFLOAT_VALUE(x) < 0.0;
|
|
2904
|
-
}
|
|
2905
|
-
return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
|
|
2906
|
-
}
|
|
2907
|
-
|
|
2908
|
-
#define is_positive(x) (!is_negative(x))
|
|
2909
|
-
|
|
2910
|
-
inline static int
|
|
2911
|
-
is_zero(VALUE x)
|
|
2912
|
-
{
|
|
2913
|
-
VALUE num;
|
|
2914
|
-
|
|
2915
|
-
switch (TYPE(x)) {
|
|
2916
|
-
case T_FIXNUM:
|
|
2917
|
-
return FIX2LONG(x) == 0;
|
|
2918
|
-
|
|
2919
|
-
case T_BIGNUM:
|
|
2920
|
-
return Qfalse;
|
|
2921
|
-
|
|
2922
|
-
case T_RATIONAL:
|
|
2923
|
-
num = rb_rational_num(x);
|
|
2924
|
-
return FIXNUM_P(num) && FIX2LONG(num) == 0;
|
|
2925
|
-
|
|
2926
|
-
default:
|
|
2927
|
-
break;
|
|
2928
|
-
}
|
|
2929
|
-
|
|
2930
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
2931
|
-
}
|
|
2932
|
-
|
|
2933
|
-
inline static int
|
|
2934
|
-
is_one(VALUE x)
|
|
2935
|
-
{
|
|
2936
|
-
VALUE num, den;
|
|
2937
|
-
|
|
2938
|
-
switch (TYPE(x)) {
|
|
2939
|
-
case T_FIXNUM:
|
|
2940
|
-
return FIX2LONG(x) == 1;
|
|
2941
|
-
|
|
2942
|
-
case T_BIGNUM:
|
|
2943
|
-
return Qfalse;
|
|
2944
|
-
|
|
2945
|
-
case T_RATIONAL:
|
|
2946
|
-
num = rb_rational_num(x);
|
|
2947
|
-
den = rb_rational_den(x);
|
|
2948
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
|
2949
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
|
2950
|
-
|
|
2951
|
-
default:
|
|
2952
|
-
break;
|
|
2953
|
-
}
|
|
2954
|
-
|
|
2955
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
|
2956
|
-
}
|
|
2957
|
-
|
|
2958
|
-
inline static int
|
|
2959
|
-
is_even(VALUE x)
|
|
2960
|
-
{
|
|
2961
|
-
switch (TYPE(x)) {
|
|
2962
|
-
case T_FIXNUM:
|
|
2963
|
-
return (FIX2LONG(x) % 2) == 0;
|
|
2964
|
-
|
|
2965
|
-
case T_BIGNUM:
|
|
2966
|
-
{
|
|
2967
|
-
unsigned long l;
|
|
2968
|
-
rb_big_pack(x, &l, 1);
|
|
2969
|
-
return l % 2 == 0;
|
|
2970
|
-
}
|
|
2971
|
-
|
|
2972
|
-
default:
|
|
2973
|
-
break;
|
|
2974
|
-
}
|
|
2975
|
-
|
|
2976
|
-
return 0;
|
|
2977
|
-
}
|
|
2978
|
-
|
|
2979
|
-
static VALUE
|
|
2980
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
|
2981
|
-
{
|
|
2982
|
-
VALUE log_x, multiplied, y;
|
|
2983
|
-
volatile VALUE obj = exp->obj;
|
|
2984
|
-
|
|
2985
|
-
if (VpIsZero(exp)) {
|
|
2986
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
2987
|
-
}
|
|
2988
|
-
|
|
2989
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
|
2990
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
|
2991
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
|
2992
|
-
RB_GC_GUARD(obj);
|
|
2993
|
-
|
|
2994
|
-
return y;
|
|
2995
|
-
}
|
|
2996
|
-
|
|
2997
|
-
/* call-seq:
|
|
2998
|
-
* power(n)
|
|
2999
|
-
* power(n, prec)
|
|
3000
|
-
*
|
|
3001
|
-
* Returns the value raised to the power of n.
|
|
3002
|
-
*
|
|
3003
|
-
* Note that n must be an Integer.
|
|
3004
|
-
*
|
|
3005
|
-
* Also available as the operator **.
|
|
3006
|
-
*/
|
|
3007
|
-
static VALUE
|
|
3008
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
|
3009
|
-
{
|
|
3010
|
-
ENTER(5);
|
|
3011
|
-
VALUE vexp, prec;
|
|
3012
|
-
Real* exp = NULL;
|
|
3013
|
-
Real *x, *y;
|
|
3014
|
-
ssize_t mp, ma, n;
|
|
3015
|
-
SIGNED_VALUE int_exp;
|
|
3016
|
-
double d;
|
|
3017
|
-
|
|
3018
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
|
3019
|
-
|
|
3020
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
|
3021
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
|
3022
|
-
|
|
3023
|
-
if (VpIsNaN(x)) {
|
|
3024
|
-
y = NewZeroWrapLimited(1, n);
|
|
3025
|
-
VpSetNaN(y);
|
|
3026
|
-
RB_GC_GUARD(y->obj);
|
|
3027
|
-
return VpCheckGetValue(y);
|
|
3028
|
-
}
|
|
3029
|
-
|
|
3030
|
-
retry:
|
|
3031
|
-
switch (TYPE(vexp)) {
|
|
3032
|
-
case T_FIXNUM:
|
|
3033
|
-
break;
|
|
3034
|
-
|
|
3035
|
-
case T_BIGNUM:
|
|
3036
|
-
break;
|
|
3037
|
-
|
|
3038
|
-
case T_FLOAT:
|
|
3039
|
-
d = RFLOAT_VALUE(vexp);
|
|
3040
|
-
if (d == round(d)) {
|
|
3041
|
-
if (FIXABLE(d)) {
|
|
3042
|
-
vexp = LONG2FIX((long)d);
|
|
3043
|
-
}
|
|
3044
|
-
else {
|
|
3045
|
-
vexp = rb_dbl2big(d);
|
|
3046
|
-
}
|
|
3047
|
-
goto retry;
|
|
3048
|
-
}
|
|
3049
|
-
if (NIL_P(prec)) {
|
|
3050
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
|
3051
|
-
}
|
|
3052
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
|
3053
|
-
break;
|
|
3054
|
-
|
|
3055
|
-
case T_RATIONAL:
|
|
3056
|
-
if (is_zero(rb_rational_num(vexp))) {
|
|
3057
|
-
if (is_positive(vexp)) {
|
|
3058
|
-
vexp = INT2FIX(0);
|
|
3059
|
-
goto retry;
|
|
3060
|
-
}
|
|
3061
|
-
}
|
|
3062
|
-
else if (is_one(rb_rational_den(vexp))) {
|
|
3063
|
-
vexp = rb_rational_num(vexp);
|
|
3064
|
-
goto retry;
|
|
3065
|
-
}
|
|
3066
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
|
3067
|
-
if (NIL_P(prec)) {
|
|
3068
|
-
n += n;
|
|
3069
|
-
}
|
|
3070
|
-
break;
|
|
3071
|
-
|
|
3072
|
-
case T_DATA:
|
|
3073
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
|
3074
|
-
VALUE zero = INT2FIX(0);
|
|
3075
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
|
3076
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
|
3077
|
-
vexp = BigDecimal_to_i(vexp);
|
|
3078
|
-
goto retry;
|
|
3079
|
-
}
|
|
3080
|
-
if (NIL_P(prec)) {
|
|
3081
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
|
3082
|
-
n += y->Prec*VpBaseFig();
|
|
3083
|
-
}
|
|
3084
|
-
exp = DATA_PTR(vexp);
|
|
3085
|
-
break;
|
|
3086
|
-
}
|
|
3087
|
-
/* fall through */
|
|
3088
|
-
default:
|
|
3089
|
-
rb_raise(rb_eTypeError,
|
|
3090
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
|
3091
|
-
RB_OBJ_CLASSNAME(vexp));
|
|
3092
|
-
}
|
|
3093
|
-
|
|
3094
|
-
if (VpIsZero(x)) {
|
|
3095
|
-
if (is_negative(vexp)) {
|
|
3096
|
-
y = NewZeroWrapNolimit(1, n);
|
|
3097
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3098
|
-
if (is_integer(vexp)) {
|
|
3099
|
-
if (is_even(vexp)) {
|
|
3100
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
|
3101
|
-
VpSetPosInf(y);
|
|
3102
|
-
}
|
|
3103
|
-
else {
|
|
3104
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
|
3105
|
-
VpSetNegInf(y);
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
else {
|
|
3109
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
|
3110
|
-
VpSetPosInf(y);
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
else {
|
|
3114
|
-
/* (+0) ** (-num) -> Infinity */
|
|
3115
|
-
VpSetPosInf(y);
|
|
3116
|
-
}
|
|
3117
|
-
RB_GC_GUARD(y->obj);
|
|
3118
|
-
return VpCheckGetValue(y);
|
|
3119
|
-
}
|
|
3120
|
-
else if (is_zero(vexp)) {
|
|
3121
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3122
|
-
}
|
|
3123
|
-
else {
|
|
3124
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3125
|
-
}
|
|
3126
|
-
}
|
|
3127
|
-
|
|
3128
|
-
if (is_zero(vexp)) {
|
|
3129
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3130
|
-
}
|
|
3131
|
-
else if (is_one(vexp)) {
|
|
3132
|
-
return self;
|
|
3133
|
-
}
|
|
3134
|
-
|
|
3135
|
-
if (VpIsInf(x)) {
|
|
3136
|
-
if (is_negative(vexp)) {
|
|
3137
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3138
|
-
if (is_integer(vexp)) {
|
|
3139
|
-
if (is_even(vexp)) {
|
|
3140
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
|
3141
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3142
|
-
}
|
|
3143
|
-
else {
|
|
3144
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
|
3145
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3146
|
-
}
|
|
3147
|
-
}
|
|
3148
|
-
else {
|
|
3149
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
|
3150
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3151
|
-
}
|
|
3152
|
-
}
|
|
3153
|
-
else {
|
|
3154
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3155
|
-
}
|
|
3156
|
-
}
|
|
3157
|
-
else {
|
|
3158
|
-
y = NewZeroWrapLimited(1, n);
|
|
3159
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3160
|
-
if (is_integer(vexp)) {
|
|
3161
|
-
if (is_even(vexp)) {
|
|
3162
|
-
VpSetPosInf(y);
|
|
3163
|
-
}
|
|
3164
|
-
else {
|
|
3165
|
-
VpSetNegInf(y);
|
|
3166
|
-
}
|
|
3167
|
-
}
|
|
3168
|
-
else {
|
|
3169
|
-
/* TODO: support complex */
|
|
3170
|
-
rb_raise(rb_eMathDomainError,
|
|
3171
|
-
"a non-integral exponent for a negative base");
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
else {
|
|
3175
|
-
VpSetPosInf(y);
|
|
3176
|
-
}
|
|
3177
|
-
return VpCheckGetValue(y);
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
if (exp != NULL) {
|
|
3182
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
|
3183
|
-
}
|
|
3184
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
|
3185
|
-
VALUE abs_value = BigDecimal_abs(self);
|
|
3186
|
-
if (is_one(abs_value)) {
|
|
3187
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3188
|
-
}
|
|
3189
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
|
3190
|
-
if (is_negative(vexp)) {
|
|
3191
|
-
y = NewZeroWrapLimited(1, n);
|
|
3192
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3193
|
-
return VpCheckGetValue(y);
|
|
3194
|
-
}
|
|
3195
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3196
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3197
|
-
}
|
|
3198
|
-
else {
|
|
3199
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
else {
|
|
3203
|
-
if (is_positive(vexp)) {
|
|
3204
|
-
y = NewZeroWrapLimited(1, n);
|
|
3205
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3206
|
-
return VpCheckGetValue(y);
|
|
3207
|
-
}
|
|
3208
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3209
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3210
|
-
}
|
|
3211
|
-
else {
|
|
3212
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
2344
|
+
* If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
|
|
2345
|
+
* string of significant digits with no leading zeros, and n is the exponent.
|
|
2346
|
+
*
|
|
2347
|
+
* From these values, you can translate a BigDecimal to a float as follows:
|
|
2348
|
+
*
|
|
2349
|
+
* sign, significant_digits, base, exponent = a.split
|
|
2350
|
+
* f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
|
|
2351
|
+
*
|
|
2352
|
+
* (Note that the to_f method is provided as a more convenient way to translate
|
|
2353
|
+
* a BigDecimal to a Float.)
|
|
2354
|
+
*/
|
|
2355
|
+
static VALUE
|
|
2356
|
+
BigDecimal_split(VALUE self)
|
|
2357
|
+
{
|
|
2358
|
+
BDVALUE v;
|
|
2359
|
+
VALUE obj,str;
|
|
2360
|
+
ssize_t e, s;
|
|
2361
|
+
char *psz1;
|
|
3216
2362
|
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
2363
|
+
v = GetBDValueMust(self);
|
|
2364
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
2365
|
+
psz1 = RSTRING_PTR(str);
|
|
2366
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
|
2367
|
+
s = 1;
|
|
2368
|
+
if(psz1[0] == '-') {
|
|
2369
|
+
size_t len = strlen(psz1 + 1);
|
|
3221
2370
|
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
}
|
|
3226
|
-
else {
|
|
3227
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
|
3228
|
-
}
|
|
3229
|
-
VpPowerByInt(y, x, int_exp);
|
|
3230
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
|
3231
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
|
2371
|
+
memmove(psz1, psz1 + 1, len);
|
|
2372
|
+
psz1[len] = '\0';
|
|
2373
|
+
s = -1;
|
|
3232
2374
|
}
|
|
3233
|
-
|
|
2375
|
+
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2376
|
+
e = VpExponent10(v.real);
|
|
2377
|
+
obj = rb_ary_new2(4);
|
|
2378
|
+
rb_ary_push(obj, INT2FIX(s));
|
|
2379
|
+
rb_ary_push(obj, str);
|
|
2380
|
+
rb_str_resize(str, strlen(psz1));
|
|
2381
|
+
rb_ary_push(obj, INT2FIX(10));
|
|
2382
|
+
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2383
|
+
|
|
2384
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2385
|
+
return obj;
|
|
3234
2386
|
}
|
|
3235
2387
|
|
|
3236
|
-
/*
|
|
3237
|
-
* self ** other -> bigdecimal
|
|
3238
|
-
*
|
|
3239
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
|
3240
|
-
*
|
|
3241
|
-
* b = BigDecimal('3.14')
|
|
3242
|
-
* b ** 2 # => 0.98596e1
|
|
3243
|
-
* b ** 2.0 # => 0.98596e1
|
|
3244
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
|
2388
|
+
/* Returns the exponent of the BigDecimal number, as an Integer.
|
|
3245
2389
|
*
|
|
3246
|
-
*
|
|
2390
|
+
* If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
|
|
2391
|
+
* of digits with no leading zeros, then n is the exponent.
|
|
2392
|
+
*/
|
|
2393
|
+
static VALUE
|
|
2394
|
+
BigDecimal_exponent(VALUE self)
|
|
2395
|
+
{
|
|
2396
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
|
2397
|
+
return SSIZET2NUM(e);
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
/* Returns a string representation of self.
|
|
3247
2401
|
*
|
|
2402
|
+
* BigDecimal("1234.5678").inspect
|
|
2403
|
+
* #=> "0.12345678e4"
|
|
3248
2404
|
*/
|
|
3249
2405
|
static VALUE
|
|
3250
|
-
|
|
2406
|
+
BigDecimal_inspect(VALUE self)
|
|
3251
2407
|
{
|
|
3252
|
-
|
|
2408
|
+
BDVALUE v;
|
|
2409
|
+
volatile VALUE str;
|
|
2410
|
+
size_t nc;
|
|
2411
|
+
|
|
2412
|
+
v = GetBDValueMust(self);
|
|
2413
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2414
|
+
|
|
2415
|
+
str = rb_str_new(0, nc);
|
|
2416
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2417
|
+
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
|
2418
|
+
|
|
2419
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2420
|
+
return str;
|
|
3253
2421
|
}
|
|
3254
2422
|
|
|
3255
|
-
/*
|
|
2423
|
+
/* Returns self * 10**v without changing the precision.
|
|
2424
|
+
* This method is currently for internal use.
|
|
3256
2425
|
*
|
|
3257
|
-
*
|
|
2426
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
|
2427
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
|
3258
2428
|
*/
|
|
3259
2429
|
static VALUE
|
|
3260
|
-
|
|
2430
|
+
BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
2431
|
+
{
|
|
2432
|
+
BDVALUE a, c;
|
|
2433
|
+
ssize_t shift, exponentShift;
|
|
2434
|
+
bool shiftDown;
|
|
2435
|
+
size_t prec;
|
|
2436
|
+
DECDIG ex, iex;
|
|
2437
|
+
|
|
2438
|
+
a = GetBDValueMust(self);
|
|
2439
|
+
shift = NUM2SSIZET(rb_to_int(v));
|
|
2440
|
+
|
|
2441
|
+
if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
|
|
2442
|
+
|
|
2443
|
+
exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
|
|
2444
|
+
shift -= exponentShift * BASE_FIG;
|
|
2445
|
+
ex = 1;
|
|
2446
|
+
for (int i = 0; i < shift; i++) ex *= 10;
|
|
2447
|
+
shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
|
|
2448
|
+
iex = BASE / ex;
|
|
2449
|
+
|
|
2450
|
+
prec = a.real->Prec + shiftDown;
|
|
2451
|
+
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2452
|
+
if (shift == 0) {
|
|
2453
|
+
VpAsgn(c.real, a.real, 10);
|
|
2454
|
+
} else if (shiftDown) {
|
|
2455
|
+
DECDIG carry = 0;
|
|
2456
|
+
exponentShift++;
|
|
2457
|
+
for (size_t i = 0; i < a.real->Prec; i++) {
|
|
2458
|
+
DECDIG v = a.real->frac[i];
|
|
2459
|
+
c.real->frac[i] = carry * ex + v / iex;
|
|
2460
|
+
carry = v % iex;
|
|
2461
|
+
}
|
|
2462
|
+
c.real->frac[a.real->Prec] = carry * ex;
|
|
2463
|
+
} else {
|
|
2464
|
+
DECDIG carry = 0;
|
|
2465
|
+
for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
|
|
2466
|
+
DECDIG v = a.real->frac[i];
|
|
2467
|
+
c.real->frac[i] = v % iex * ex + carry;
|
|
2468
|
+
carry = v / iex;
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
while (c.real->frac[prec - 1] == 0) prec--;
|
|
2472
|
+
c.real->Prec = prec;
|
|
2473
|
+
c.real->sign = a.real->sign;
|
|
2474
|
+
c.real->exponent = a.real->exponent;
|
|
2475
|
+
AddExponent(c.real, exponentShift);
|
|
2476
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2477
|
+
return CheckGetValue(c);
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
inline static int
|
|
2481
|
+
is_zero(VALUE x)
|
|
3261
2482
|
{
|
|
3262
|
-
|
|
3263
|
-
|
|
2483
|
+
VALUE num;
|
|
2484
|
+
|
|
2485
|
+
switch (TYPE(x)) {
|
|
2486
|
+
case T_FIXNUM:
|
|
2487
|
+
return FIX2LONG(x) == 0;
|
|
2488
|
+
|
|
2489
|
+
case T_BIGNUM:
|
|
2490
|
+
return Qfalse;
|
|
2491
|
+
|
|
2492
|
+
case T_RATIONAL:
|
|
2493
|
+
num = rb_rational_num(x);
|
|
2494
|
+
return FIXNUM_P(num) && FIX2LONG(num) == 0;
|
|
3264
2495
|
|
|
3265
|
-
|
|
3266
|
-
|
|
2496
|
+
default:
|
|
2497
|
+
break;
|
|
3267
2498
|
}
|
|
3268
|
-
|
|
2499
|
+
|
|
2500
|
+
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
3269
2501
|
}
|
|
3270
2502
|
|
|
3271
2503
|
/* :nodoc: */
|
|
@@ -3304,30 +2536,27 @@ check_exception(VALUE bd)
|
|
|
3304
2536
|
{
|
|
3305
2537
|
assert(is_kind_of_BigDecimal(bd));
|
|
3306
2538
|
|
|
3307
|
-
|
|
3308
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3309
|
-
VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
|
|
2539
|
+
VpCheckException(VpPtr(bd), false);
|
|
3310
2540
|
|
|
3311
2541
|
return bd;
|
|
3312
2542
|
}
|
|
3313
2543
|
|
|
3314
2544
|
static VALUE
|
|
3315
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
|
2545
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
3316
2546
|
{
|
|
3317
|
-
VALUE
|
|
3318
|
-
|
|
2547
|
+
VALUE bd;
|
|
3319
2548
|
Real *vp;
|
|
3320
2549
|
if (uval == 0) {
|
|
3321
|
-
|
|
3322
|
-
vp
|
|
2550
|
+
bd = BigDecimal_allocate(1);
|
|
2551
|
+
vp = VpPtr(bd);
|
|
3323
2552
|
vp->Prec = 1;
|
|
3324
2553
|
vp->exponent = 1;
|
|
3325
2554
|
VpSetZero(vp, 1);
|
|
3326
2555
|
vp->frac[0] = 0;
|
|
3327
2556
|
}
|
|
3328
2557
|
else if (uval < BASE) {
|
|
3329
|
-
|
|
3330
|
-
vp
|
|
2558
|
+
bd = BigDecimal_allocate(1);
|
|
2559
|
+
vp = VpPtr(bd);
|
|
3331
2560
|
vp->Prec = 1;
|
|
3332
2561
|
vp->exponent = 1;
|
|
3333
2562
|
VpSetSign(vp, 1);
|
|
@@ -3352,32 +2581,31 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3352
2581
|
}
|
|
3353
2582
|
|
|
3354
2583
|
const size_t exp = len + ntz;
|
|
3355
|
-
|
|
3356
|
-
vp
|
|
2584
|
+
bd = BigDecimal_allocate(len);
|
|
2585
|
+
vp = VpPtr(bd);
|
|
3357
2586
|
vp->Prec = len;
|
|
3358
2587
|
vp->exponent = exp;
|
|
3359
2588
|
VpSetSign(vp, 1);
|
|
3360
2589
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
3361
2590
|
}
|
|
3362
2591
|
|
|
3363
|
-
return
|
|
2592
|
+
return bd;
|
|
3364
2593
|
}
|
|
3365
2594
|
|
|
3366
2595
|
static VALUE
|
|
3367
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
|
2596
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
3368
2597
|
{
|
|
3369
2598
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
3370
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
|
2599
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
3371
2600
|
if (ival < 0) {
|
|
3372
|
-
Real *vp;
|
|
3373
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2601
|
+
Real *vp = VpPtr(bd);
|
|
3374
2602
|
VpSetSign(vp, -1);
|
|
3375
2603
|
}
|
|
3376
2604
|
return bd;
|
|
3377
2605
|
}
|
|
3378
2606
|
|
|
3379
2607
|
static VALUE
|
|
3380
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
|
2608
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
|
3381
2609
|
{
|
|
3382
2610
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
|
3383
2611
|
|
|
@@ -3389,40 +2617,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
|
3389
2617
|
}
|
|
3390
2618
|
if (size <= sizeof(long)) {
|
|
3391
2619
|
if (sign < 0) {
|
|
3392
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
|
2620
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
|
3393
2621
|
}
|
|
3394
2622
|
else {
|
|
3395
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
|
2623
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
|
3396
2624
|
}
|
|
3397
2625
|
}
|
|
3398
2626
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
|
3399
2627
|
else if (size <= sizeof(LONG_LONG)) {
|
|
3400
2628
|
if (sign < 0) {
|
|
3401
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
|
2629
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
|
3402
2630
|
}
|
|
3403
2631
|
else {
|
|
3404
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
|
2632
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
|
3405
2633
|
}
|
|
3406
2634
|
}
|
|
3407
2635
|
#endif
|
|
3408
2636
|
else {
|
|
3409
2637
|
VALUE str = rb_big2str(val, 10);
|
|
3410
|
-
|
|
3411
|
-
|
|
2638
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
|
2639
|
+
RSTRING_PTR(str),
|
|
2640
|
+
rb_cBigDecimal,
|
|
2641
|
+
true,
|
|
2642
|
+
true
|
|
2643
|
+
));
|
|
3412
2644
|
RB_GC_GUARD(str);
|
|
3413
|
-
return
|
|
2645
|
+
return CheckGetValue(v);
|
|
3414
2646
|
}
|
|
3415
2647
|
}
|
|
3416
2648
|
|
|
3417
2649
|
static VALUE
|
|
3418
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
|
2650
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
|
3419
2651
|
{
|
|
3420
2652
|
assert(RB_INTEGER_TYPE_P(val));
|
|
3421
2653
|
if (FIXNUM_P(val)) {
|
|
3422
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
|
2654
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
|
3423
2655
|
}
|
|
3424
2656
|
else {
|
|
3425
|
-
return rb_big_convert_to_BigDecimal(val
|
|
2657
|
+
return rb_big_convert_to_BigDecimal(val);
|
|
3426
2658
|
}
|
|
3427
2659
|
}
|
|
3428
2660
|
|
|
@@ -3457,11 +2689,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3457
2689
|
}
|
|
3458
2690
|
|
|
3459
2691
|
if (digs == SIZE_MAX) {
|
|
3460
|
-
|
|
3461
|
-
return Qnil;
|
|
3462
|
-
rb_raise(rb_eArgError,
|
|
3463
|
-
"can't omit precision for a %"PRIsVALUE".",
|
|
3464
|
-
CLASS_OF(val));
|
|
2692
|
+
digs = 0;
|
|
3465
2693
|
}
|
|
3466
2694
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
3467
2695
|
if (!raise_exception)
|
|
@@ -3481,7 +2709,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3481
2709
|
len10 = BIGDECIMAL_DOUBLE_FIGURES;
|
|
3482
2710
|
}
|
|
3483
2711
|
memcpy(buf, p, len10);
|
|
3484
|
-
|
|
2712
|
+
free(p);
|
|
3485
2713
|
|
|
3486
2714
|
VALUE inum;
|
|
3487
2715
|
size_t RB_UNUSED_VAR(prec) = 0;
|
|
@@ -3576,9 +2804,8 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3576
2804
|
exp = -exp;
|
|
3577
2805
|
}
|
|
3578
2806
|
|
|
3579
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
|
3580
|
-
Real *vp;
|
|
3581
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2807
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2808
|
+
Real *vp = VpPtr(bd);
|
|
3582
2809
|
assert(vp->Prec == prec);
|
|
3583
2810
|
vp->exponent = exp;
|
|
3584
2811
|
|
|
@@ -3599,28 +2826,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3599
2826
|
CLASS_OF(val));
|
|
3600
2827
|
}
|
|
3601
2828
|
|
|
3602
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
|
2829
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
|
3603
2830
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
|
3604
2831
|
return d;
|
|
3605
2832
|
}
|
|
3606
2833
|
|
|
3607
2834
|
static VALUE
|
|
3608
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
2835
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
3609
2836
|
{
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
|
3614
|
-
if (!vp)
|
|
3615
|
-
return Qnil;
|
|
3616
|
-
return VpCheckGetValue(vp);
|
|
2837
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
|
|
2838
|
+
if (v.bigdecimal_or_nil == Qnil) return Qnil;
|
|
2839
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3617
2840
|
}
|
|
3618
2841
|
|
|
3619
2842
|
static inline VALUE
|
|
3620
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
|
2843
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
3621
2844
|
{
|
|
3622
2845
|
const char *c_str = StringValueCStr(val);
|
|
3623
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
|
2846
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
3624
2847
|
}
|
|
3625
2848
|
|
|
3626
2849
|
static VALUE
|
|
@@ -3648,17 +2871,20 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3648
2871
|
if (digs == SIZE_MAX)
|
|
3649
2872
|
return check_exception(val);
|
|
3650
2873
|
|
|
3651
|
-
Real *vp;
|
|
3652
|
-
|
|
2874
|
+
Real *vp = VpPtr(val);
|
|
2875
|
+
|
|
2876
|
+
VALUE copy = BigDecimal_allocate(vp->MaxPrec);
|
|
2877
|
+
Real *vp_copy = VpPtr(copy);
|
|
2878
|
+
|
|
2879
|
+
VpMemCopy(vp_copy, vp);
|
|
2880
|
+
|
|
2881
|
+
RB_GC_GUARD(val);
|
|
3653
2882
|
|
|
3654
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
|
3655
|
-
vp = VpCopy(NULL, vp);
|
|
3656
2883
|
/* TODO: rounding */
|
|
3657
|
-
|
|
3658
|
-
return VpCheckGetValue(vp);
|
|
2884
|
+
return check_exception(copy);
|
|
3659
2885
|
}
|
|
3660
2886
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
3661
|
-
return rb_inum_convert_to_BigDecimal(val
|
|
2887
|
+
return rb_inum_convert_to_BigDecimal(val);
|
|
3662
2888
|
}
|
|
3663
2889
|
else if (RB_FLOAT_TYPE_P(val)) {
|
|
3664
2890
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
|
@@ -3676,7 +2902,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3676
2902
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
|
3677
2903
|
}
|
|
3678
2904
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
3679
|
-
return rb_str_convert_to_BigDecimal(val,
|
|
2905
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
|
3680
2906
|
}
|
|
3681
2907
|
|
|
3682
2908
|
/* TODO: chheck to_d */
|
|
@@ -3690,7 +2916,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3690
2916
|
}
|
|
3691
2917
|
return Qnil;
|
|
3692
2918
|
}
|
|
3693
|
-
return rb_str_convert_to_BigDecimal(str,
|
|
2919
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
|
3694
2920
|
}
|
|
3695
2921
|
|
|
3696
2922
|
/* call-seq:
|
|
@@ -3711,12 +2937,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3711
2937
|
*
|
|
3712
2938
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
|
3713
2939
|
*
|
|
3714
|
-
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
|
|
2940
|
+
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
|
|
3715
2941
|
* BigDecimal(2) # => 0.2e1
|
|
3716
2942
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
|
3717
2943
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
|
3718
|
-
* #
|
|
3719
|
-
*
|
|
2944
|
+
* BigDecimal(2.0) # => 0.2e1
|
|
2945
|
+
* # Rational value requires ndigits.
|
|
3720
2946
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
|
3721
2947
|
*
|
|
3722
2948
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
|
@@ -3780,15 +3006,16 @@ static VALUE
|
|
|
3780
3006
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3781
3007
|
{
|
|
3782
3008
|
char const *c_str = StringValueCStr(str);
|
|
3783
|
-
|
|
3784
|
-
if (
|
|
3009
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3010
|
+
if (v.bigdecimal_or_nil == Qnil)
|
|
3785
3011
|
return Qnil;
|
|
3786
3012
|
else
|
|
3787
|
-
return
|
|
3013
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3788
3014
|
}
|
|
3789
3015
|
|
|
3790
|
-
/*
|
|
3791
|
-
*
|
|
3016
|
+
/*
|
|
3017
|
+
* call-seq:
|
|
3018
|
+
* BigDecimal.limit(digits)
|
|
3792
3019
|
*
|
|
3793
3020
|
* Limit the number of significant digits in newly created BigDecimal
|
|
3794
3021
|
* numbers to the specified value. Rounding is performed as necessary,
|
|
@@ -3838,7 +3065,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
|
3838
3065
|
static VALUE
|
|
3839
3066
|
BigDecimal_sign(VALUE self)
|
|
3840
3067
|
{ /* sign */
|
|
3841
|
-
int s =
|
|
3068
|
+
int s = GetSelfVpValue(self)->sign;
|
|
3842
3069
|
return INT2FIX(s);
|
|
3843
3070
|
}
|
|
3844
3071
|
|
|
@@ -3921,301 +3148,6 @@ BigDecimal_save_limit(VALUE self)
|
|
|
3921
3148
|
return ret;
|
|
3922
3149
|
}
|
|
3923
3150
|
|
|
3924
|
-
/* call-seq:
|
|
3925
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
|
3926
|
-
*
|
|
3927
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
|
3928
|
-
* power of +decimal+, to the specified number of digits of precision.
|
|
3929
|
-
*
|
|
3930
|
-
* If +decimal+ is infinity, returns Infinity.
|
|
3931
|
-
*
|
|
3932
|
-
* If +decimal+ is NaN, returns NaN.
|
|
3933
|
-
*/
|
|
3934
|
-
static VALUE
|
|
3935
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
|
3936
|
-
{
|
|
3937
|
-
ssize_t prec, n, i;
|
|
3938
|
-
Real* vx = NULL;
|
|
3939
|
-
VALUE one, d, y;
|
|
3940
|
-
int negative = 0;
|
|
3941
|
-
int infinite = 0;
|
|
3942
|
-
int nan = 0;
|
|
3943
|
-
double flo;
|
|
3944
|
-
|
|
3945
|
-
prec = NUM2SSIZET(vprec);
|
|
3946
|
-
if (prec <= 0) {
|
|
3947
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
3948
|
-
}
|
|
3949
|
-
|
|
3950
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
3951
|
-
* BigDecimalCmp function. */
|
|
3952
|
-
switch (TYPE(x)) {
|
|
3953
|
-
case T_DATA:
|
|
3954
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
3955
|
-
vx = DATA_PTR(x);
|
|
3956
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
3957
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
3958
|
-
nan = VpIsNaN(vx);
|
|
3959
|
-
break;
|
|
3960
|
-
|
|
3961
|
-
case T_FIXNUM:
|
|
3962
|
-
/* fall through */
|
|
3963
|
-
case T_BIGNUM:
|
|
3964
|
-
vx = GetVpValue(x, 0);
|
|
3965
|
-
break;
|
|
3966
|
-
|
|
3967
|
-
case T_FLOAT:
|
|
3968
|
-
flo = RFLOAT_VALUE(x);
|
|
3969
|
-
negative = flo < 0;
|
|
3970
|
-
infinite = isinf(flo);
|
|
3971
|
-
nan = isnan(flo);
|
|
3972
|
-
if (!infinite && !nan) {
|
|
3973
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
|
3974
|
-
}
|
|
3975
|
-
break;
|
|
3976
|
-
|
|
3977
|
-
case T_RATIONAL:
|
|
3978
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
|
3979
|
-
break;
|
|
3980
|
-
|
|
3981
|
-
default:
|
|
3982
|
-
break;
|
|
3983
|
-
}
|
|
3984
|
-
if (infinite) {
|
|
3985
|
-
if (negative) {
|
|
3986
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
|
3987
|
-
}
|
|
3988
|
-
else {
|
|
3989
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3990
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
3991
|
-
RB_GC_GUARD(vy->obj);
|
|
3992
|
-
return VpCheckGetValue(vy);
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
|
-
else if (nan) {
|
|
3996
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3997
|
-
VpSetNaN(vy);
|
|
3998
|
-
RB_GC_GUARD(vy->obj);
|
|
3999
|
-
return VpCheckGetValue(vy);
|
|
4000
|
-
}
|
|
4001
|
-
else if (vx == NULL) {
|
|
4002
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4003
|
-
}
|
|
4004
|
-
x = vx->obj;
|
|
4005
|
-
|
|
4006
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4007
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4008
|
-
if (negative) {
|
|
4009
|
-
VALUE x_zero = INT2NUM(1);
|
|
4010
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
|
4011
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
|
4012
|
-
vx = DATA_PTR(x);
|
|
4013
|
-
VpSetSign(vx, 1);
|
|
4014
|
-
}
|
|
4015
|
-
|
|
4016
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4017
|
-
y = one;
|
|
4018
|
-
d = y;
|
|
4019
|
-
i = 1;
|
|
4020
|
-
|
|
4021
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4022
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4023
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4024
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4025
|
-
|
|
4026
|
-
rb_thread_check_ints();
|
|
4027
|
-
|
|
4028
|
-
if (m <= 0) {
|
|
4029
|
-
break;
|
|
4030
|
-
}
|
|
4031
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4032
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4033
|
-
}
|
|
4034
|
-
|
|
4035
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
|
4036
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
|
4037
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
|
4038
|
-
++i; /* i <- i + 1 */
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
|
-
if (negative) {
|
|
4042
|
-
return BigDecimal_div2(one, y, vprec);
|
|
4043
|
-
}
|
|
4044
|
-
else {
|
|
4045
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
|
4046
|
-
return BigDecimal_round(1, &vprec, y);
|
|
4047
|
-
}
|
|
4048
|
-
|
|
4049
|
-
RB_GC_GUARD(one);
|
|
4050
|
-
RB_GC_GUARD(x);
|
|
4051
|
-
RB_GC_GUARD(y);
|
|
4052
|
-
RB_GC_GUARD(d);
|
|
4053
|
-
}
|
|
4054
|
-
|
|
4055
|
-
/* call-seq:
|
|
4056
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
|
4057
|
-
*
|
|
4058
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
|
4059
|
-
* digits of precision, +numeric+.
|
|
4060
|
-
*
|
|
4061
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
|
4062
|
-
*
|
|
4063
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
|
4064
|
-
*
|
|
4065
|
-
* If +decimal+ is NaN, returns NaN.
|
|
4066
|
-
*/
|
|
4067
|
-
static VALUE
|
|
4068
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
|
4069
|
-
{
|
|
4070
|
-
ssize_t prec, n, i;
|
|
4071
|
-
SIGNED_VALUE expo;
|
|
4072
|
-
Real* vx = NULL;
|
|
4073
|
-
VALUE vn, one, two, w, x2, y, d;
|
|
4074
|
-
int zero = 0;
|
|
4075
|
-
int negative = 0;
|
|
4076
|
-
int infinite = 0;
|
|
4077
|
-
int nan = 0;
|
|
4078
|
-
double flo;
|
|
4079
|
-
long fix;
|
|
4080
|
-
|
|
4081
|
-
if (!is_integer(vprec)) {
|
|
4082
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
|
4083
|
-
}
|
|
4084
|
-
|
|
4085
|
-
prec = NUM2SSIZET(vprec);
|
|
4086
|
-
if (prec <= 0) {
|
|
4087
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
4088
|
-
}
|
|
4089
|
-
|
|
4090
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
4091
|
-
* BigDecimalCmp function. */
|
|
4092
|
-
switch (TYPE(x)) {
|
|
4093
|
-
case T_DATA:
|
|
4094
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
4095
|
-
vx = DATA_PTR(x);
|
|
4096
|
-
zero = VpIsZero(vx);
|
|
4097
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4098
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
4099
|
-
nan = VpIsNaN(vx);
|
|
4100
|
-
break;
|
|
4101
|
-
|
|
4102
|
-
case T_FIXNUM:
|
|
4103
|
-
fix = FIX2LONG(x);
|
|
4104
|
-
zero = fix == 0;
|
|
4105
|
-
negative = fix < 0;
|
|
4106
|
-
goto get_vp_value;
|
|
4107
|
-
|
|
4108
|
-
case T_BIGNUM:
|
|
4109
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
|
4110
|
-
zero = i == 0;
|
|
4111
|
-
negative = i < 0;
|
|
4112
|
-
get_vp_value:
|
|
4113
|
-
if (zero || negative) break;
|
|
4114
|
-
vx = GetVpValue(x, 0);
|
|
4115
|
-
break;
|
|
4116
|
-
|
|
4117
|
-
case T_FLOAT:
|
|
4118
|
-
flo = RFLOAT_VALUE(x);
|
|
4119
|
-
zero = flo == 0;
|
|
4120
|
-
negative = flo < 0;
|
|
4121
|
-
infinite = isinf(flo);
|
|
4122
|
-
nan = isnan(flo);
|
|
4123
|
-
if (!zero && !negative && !infinite && !nan) {
|
|
4124
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
|
4125
|
-
}
|
|
4126
|
-
break;
|
|
4127
|
-
|
|
4128
|
-
case T_RATIONAL:
|
|
4129
|
-
zero = RRATIONAL_ZERO_P(x);
|
|
4130
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
|
4131
|
-
if (zero || negative) break;
|
|
4132
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
|
4133
|
-
break;
|
|
4134
|
-
|
|
4135
|
-
case T_COMPLEX:
|
|
4136
|
-
rb_raise(rb_eMathDomainError,
|
|
4137
|
-
"Complex argument for BigMath.log");
|
|
4138
|
-
|
|
4139
|
-
default:
|
|
4140
|
-
break;
|
|
4141
|
-
}
|
|
4142
|
-
if (infinite && !negative) {
|
|
4143
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
|
4144
|
-
RB_GC_GUARD(vy->obj);
|
|
4145
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
4146
|
-
return VpCheckGetValue(vy);
|
|
4147
|
-
}
|
|
4148
|
-
else if (nan) {
|
|
4149
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
4150
|
-
RB_GC_GUARD(vy->obj);
|
|
4151
|
-
VpSetNaN(vy);
|
|
4152
|
-
return VpCheckGetValue(vy);
|
|
4153
|
-
}
|
|
4154
|
-
else if (zero || negative) {
|
|
4155
|
-
rb_raise(rb_eMathDomainError,
|
|
4156
|
-
"Zero or negative argument for log");
|
|
4157
|
-
}
|
|
4158
|
-
else if (vx == NULL) {
|
|
4159
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4160
|
-
}
|
|
4161
|
-
x = VpCheckGetValue(vx);
|
|
4162
|
-
|
|
4163
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4164
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
|
4165
|
-
|
|
4166
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4167
|
-
vn = SSIZET2NUM(n);
|
|
4168
|
-
expo = VpExponent10(vx);
|
|
4169
|
-
if (expo < 0 || expo >= 3) {
|
|
4170
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
|
4171
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
|
4172
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
|
4173
|
-
}
|
|
4174
|
-
else {
|
|
4175
|
-
expo = 0;
|
|
4176
|
-
}
|
|
4177
|
-
w = BigDecimal_sub(x, one);
|
|
4178
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
|
4179
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
|
4180
|
-
y = x;
|
|
4181
|
-
d = y;
|
|
4182
|
-
i = 1;
|
|
4183
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4184
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4185
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4186
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4187
|
-
if (m <= 0) {
|
|
4188
|
-
break;
|
|
4189
|
-
}
|
|
4190
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4191
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4192
|
-
}
|
|
4193
|
-
|
|
4194
|
-
x = BigDecimal_mult2(x2, x, vn);
|
|
4195
|
-
i += 2;
|
|
4196
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
|
4197
|
-
y = BigDecimal_add(y, d);
|
|
4198
|
-
}
|
|
4199
|
-
|
|
4200
|
-
y = BigDecimal_mult(y, two);
|
|
4201
|
-
if (expo != 0) {
|
|
4202
|
-
VALUE log10, vexpo, dy;
|
|
4203
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
|
4204
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
|
4205
|
-
dy = BigDecimal_mult(log10, vexpo);
|
|
4206
|
-
y = BigDecimal_add(y, dy);
|
|
4207
|
-
}
|
|
4208
|
-
|
|
4209
|
-
RB_GC_GUARD(one);
|
|
4210
|
-
RB_GC_GUARD(two);
|
|
4211
|
-
RB_GC_GUARD(vn);
|
|
4212
|
-
RB_GC_GUARD(x2);
|
|
4213
|
-
RB_GC_GUARD(y);
|
|
4214
|
-
RB_GC_GUARD(d);
|
|
4215
|
-
|
|
4216
|
-
return y;
|
|
4217
|
-
}
|
|
4218
|
-
|
|
4219
3151
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
|
4220
3152
|
|
|
4221
3153
|
static VALUE
|
|
@@ -4267,6 +3199,71 @@ BigDecimal_literal(const char *str)
|
|
|
4267
3199
|
|
|
4268
3200
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
|
4269
3201
|
|
|
3202
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3203
|
+
VALUE
|
|
3204
|
+
BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
|
|
3205
|
+
BDVALUE a, b, c, d;
|
|
3206
|
+
size_t cn = NUM2INT(cprec);
|
|
3207
|
+
a = GetBDValueMust(self);
|
|
3208
|
+
b = GetBDValueMust(r);
|
|
3209
|
+
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3210
|
+
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3211
|
+
vpdivd_func(c.real, d.real, a.real, b.real);
|
|
3212
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3213
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3214
|
+
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
void
|
|
3218
|
+
VpDivdNormal(Real *c, Real *r, Real *a, Real *b) {
|
|
3219
|
+
VpDivd(c, r, a, b);
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
VALUE
|
|
3223
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3224
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNormal);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
VALUE
|
|
3228
|
+
BigDecimal_vpdivd_newton(VALUE self, VALUE r, VALUE cprec) {
|
|
3229
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNewton);
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
VALUE
|
|
3233
|
+
BigDecimal_newton_raphson_inverse(VALUE self, VALUE prec) {
|
|
3234
|
+
return newton_raphson_inverse(self, NUM2SIZET(prec));
|
|
3235
|
+
}
|
|
3236
|
+
|
|
3237
|
+
VALUE
|
|
3238
|
+
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3239
|
+
BDVALUE a,b,c;
|
|
3240
|
+
a = GetBDValueMust(self);
|
|
3241
|
+
b = GetBDValueMust(v);
|
|
3242
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3243
|
+
VpMult(c.real, a.real, b.real);
|
|
3244
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3245
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3246
|
+
return c.bigdecimal;
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
VALUE
|
|
3250
|
+
BigDecimal_nttmult(VALUE self, VALUE v) {
|
|
3251
|
+
BDVALUE a,b,c;
|
|
3252
|
+
a = GetBDValueMust(self);
|
|
3253
|
+
b = GetBDValueMust(v);
|
|
3254
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3255
|
+
ntt_multiply(a.real->Prec, b.real->Prec, a.real->frac, b.real->frac, c.real->frac);
|
|
3256
|
+
VpSetSign(c.real, a.real->sign * b.real->sign);
|
|
3257
|
+
c.real->exponent = a.real->exponent + b.real->exponent;
|
|
3258
|
+
c.real->Prec = a.real->Prec + b.real->Prec;
|
|
3259
|
+
VpNmlz(c.real);
|
|
3260
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3261
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3262
|
+
return c.bigdecimal;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3266
|
+
|
|
4270
3267
|
/* Document-class: BigDecimal
|
|
4271
3268
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
|
4272
3269
|
*
|
|
@@ -4383,14 +3380,16 @@ BigDecimal_literal(const char *str)
|
|
|
4383
3380
|
*
|
|
4384
3381
|
* When you require +bigdecimal/util+, the #to_d method will be
|
|
4385
3382
|
* available on BigDecimal and the native Integer, Float, Rational,
|
|
4386
|
-
* and
|
|
3383
|
+
* String, Complex, and NilClass classes:
|
|
4387
3384
|
*
|
|
4388
3385
|
* require 'bigdecimal/util'
|
|
4389
3386
|
*
|
|
4390
|
-
* 42.to_d
|
|
4391
|
-
* 0.5.to_d
|
|
4392
|
-
* (2/3r).to_d(3)
|
|
4393
|
-
* "0.5".to_d
|
|
3387
|
+
* 42.to_d # => 0.42e2
|
|
3388
|
+
* 0.5.to_d # => 0.5e0
|
|
3389
|
+
* (2/3r).to_d(3) # => 0.667e0
|
|
3390
|
+
* "0.5".to_d # => 0.5e0
|
|
3391
|
+
* Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
|
3392
|
+
* nil.to_d # => 0.0
|
|
4394
3393
|
*
|
|
4395
3394
|
* == Methods for Working with \JSON
|
|
4396
3395
|
*
|
|
@@ -4464,7 +3463,7 @@ Init_bigdecimal(void)
|
|
|
4464
3463
|
* guarantee that two groups could always be multiplied together without
|
|
4465
3464
|
* overflow.)
|
|
4466
3465
|
*/
|
|
4467
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
|
3466
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
|
4468
3467
|
|
|
4469
3468
|
/* Exceptions */
|
|
4470
3469
|
|
|
@@ -4575,7 +3574,6 @@ Init_bigdecimal(void)
|
|
|
4575
3574
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
4576
3575
|
|
|
4577
3576
|
/* instance methods */
|
|
4578
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
4579
3577
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
4580
3578
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
4581
3579
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -4606,14 +3604,11 @@ Init_bigdecimal(void)
|
|
|
4606
3604
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
|
4607
3605
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
|
4608
3606
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
|
4609
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
|
4610
3607
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
|
4611
3608
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
|
4612
3609
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
|
4613
3610
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
|
4614
3611
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
|
4615
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
|
4616
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
|
4617
3612
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
|
4618
3613
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
|
4619
3614
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
|
@@ -4632,11 +3627,16 @@ Init_bigdecimal(void)
|
|
|
4632
3627
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
|
4633
3628
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
|
4634
3629
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
|
3630
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
|
4635
3631
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
|
4636
3632
|
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
3633
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3634
|
+
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3635
|
+
rb_define_method(rb_cBigDecimal, "vpdivd_newton", BigDecimal_vpdivd_newton, 2);
|
|
3636
|
+
rb_define_method(rb_cBigDecimal, "newton_raphson_inverse", BigDecimal_newton_raphson_inverse, 1);
|
|
3637
|
+
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3638
|
+
rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
|
|
3639
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
4640
3640
|
|
|
4641
3641
|
#define ROUNDING_MODE(i, name, value) \
|
|
4642
3642
|
id_##name = rb_intern_const(#name); \
|
|
@@ -4676,19 +3676,9 @@ Init_bigdecimal(void)
|
|
|
4676
3676
|
*/
|
|
4677
3677
|
#ifdef BIGDECIMAL_DEBUG
|
|
4678
3678
|
static int gfDebug = 1; /* Debug switch */
|
|
4679
|
-
#if 0
|
|
4680
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
|
4681
|
-
#endif
|
|
4682
3679
|
#endif /* BIGDECIMAL_DEBUG */
|
|
4683
3680
|
|
|
4684
|
-
static
|
|
4685
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
|
4686
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
|
4687
|
-
/* used in VpSqrt() */
|
|
4688
|
-
|
|
4689
|
-
/* ETC */
|
|
4690
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
|
4691
|
-
#define StrCmp(x,y) strcmp(x,y)
|
|
3681
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
4692
3682
|
|
|
4693
3683
|
enum op_sw {
|
|
4694
3684
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4698,11 +3688,9 @@ enum op_sw {
|
|
|
4698
3688
|
};
|
|
4699
3689
|
|
|
4700
3690
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
|
4701
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
4702
3691
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
|
4703
3692
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
|
4704
3693
|
static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
|
|
4705
|
-
static int VpNmlz(Real *a);
|
|
4706
3694
|
static void VpFormatSt(char *psz, size_t fFmt);
|
|
4707
3695
|
static int VpRdup(Real *m, size_t ind_m);
|
|
4708
3696
|
|
|
@@ -4761,10 +3749,10 @@ VpCheckException(Real *p, bool always)
|
|
|
4761
3749
|
}
|
|
4762
3750
|
|
|
4763
3751
|
static VALUE
|
|
4764
|
-
|
|
3752
|
+
CheckGetValue(BDVALUE v)
|
|
4765
3753
|
{
|
|
4766
|
-
VpCheckException(
|
|
4767
|
-
return
|
|
3754
|
+
VpCheckException(v.real, false);
|
|
3755
|
+
return v.bigdecimal;
|
|
4768
3756
|
}
|
|
4769
3757
|
|
|
4770
3758
|
/*
|
|
@@ -4796,12 +3784,10 @@ VpGetPrecLimit(void)
|
|
|
4796
3784
|
return NUM2SIZET(vlimit);
|
|
4797
3785
|
}
|
|
4798
3786
|
|
|
4799
|
-
VP_EXPORT
|
|
3787
|
+
VP_EXPORT void
|
|
4800
3788
|
VpSetPrecLimit(size_t n)
|
|
4801
3789
|
{
|
|
4802
|
-
size_t const s = VpGetPrecLimit();
|
|
4803
3790
|
bigdecimal_set_thread_local_precision_limit(n);
|
|
4804
|
-
return s;
|
|
4805
3791
|
}
|
|
4806
3792
|
|
|
4807
3793
|
/*
|
|
@@ -4916,15 +3902,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
|
4916
3902
|
return nzero;
|
|
4917
3903
|
}
|
|
4918
3904
|
|
|
4919
|
-
#if 0 /* unused */
|
|
4920
|
-
VP_EXPORT int
|
|
4921
|
-
VpIsNegDoubleZero(double v)
|
|
4922
|
-
{
|
|
4923
|
-
double z = VpGetDoubleNegZero();
|
|
4924
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
|
4925
|
-
}
|
|
4926
|
-
#endif
|
|
4927
|
-
|
|
4928
3905
|
VP_EXPORT int
|
|
4929
3906
|
VpException(unsigned short f, const char *str,int always)
|
|
4930
3907
|
{
|
|
@@ -5076,7 +4053,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
|
5076
4053
|
case 'E':
|
|
5077
4054
|
/* fall through */
|
|
5078
4055
|
default:
|
|
5079
|
-
nc = BASE_FIG*
|
|
4056
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
|
5080
4057
|
}
|
|
5081
4058
|
return nc;
|
|
5082
4059
|
}
|
|
@@ -5102,35 +4079,21 @@ VpInit(DECDIG BaseVal)
|
|
|
5102
4079
|
VpGetDoubleNegZero();
|
|
5103
4080
|
|
|
5104
4081
|
/* Const 1.0 */
|
|
5105
|
-
VpConstOne
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
|
5109
|
-
VpConstPt5->exponent = 0;
|
|
5110
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
|
4082
|
+
rb_global_variable(&VpConstOne);
|
|
4083
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4084
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
5111
4085
|
|
|
5112
4086
|
#ifdef BIGDECIMAL_DEBUG
|
|
5113
4087
|
gnAlloc = 0;
|
|
5114
4088
|
#endif /* BIGDECIMAL_DEBUG */
|
|
5115
4089
|
|
|
5116
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5117
|
-
if (gfDebug) {
|
|
5118
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
|
5119
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
|
5120
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
|
5121
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
|
5122
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
|
5123
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
5124
|
-
}
|
|
5125
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5126
|
-
|
|
5127
4090
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
|
5128
4091
|
}
|
|
5129
4092
|
|
|
5130
4093
|
VP_EXPORT Real *
|
|
5131
4094
|
VpOne(void)
|
|
5132
4095
|
{
|
|
5133
|
-
return VpConstOne;
|
|
4096
|
+
return VpPtr(VpConstOne);
|
|
5134
4097
|
}
|
|
5135
4098
|
|
|
5136
4099
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -5139,24 +4102,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
|
5139
4102
|
{
|
|
5140
4103
|
SIGNED_VALUE e = a->exponent;
|
|
5141
4104
|
SIGNED_VALUE m = e+n;
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
if (eb - mb > 0) goto overflow;
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
else if (n < 0) {
|
|
5154
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
|
5155
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
5156
|
-
goto underflow;
|
|
5157
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
|
5158
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
|
5159
|
-
if (mb - eb > 0) goto underflow;
|
|
4105
|
+
if (e > 0 && n > 0) {
|
|
4106
|
+
if (n > VP_EXPONENT_MAX - e) goto overflow;
|
|
4107
|
+
} else if (e < 0 && n < 0) {
|
|
4108
|
+
if (n < VP_EXPONENT_MIN - e) goto underflow;
|
|
4109
|
+
} else if (m > VP_EXPONENT_MAX) {
|
|
4110
|
+
goto overflow;
|
|
4111
|
+
} else if (m < VP_EXPONENT_MIN) {
|
|
4112
|
+
goto underflow;
|
|
5160
4113
|
}
|
|
5161
4114
|
a->exponent = m;
|
|
5162
4115
|
return 1;
|
|
@@ -5171,7 +4124,7 @@ overflow:
|
|
|
5171
4124
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
5172
4125
|
}
|
|
5173
4126
|
|
|
5174
|
-
|
|
4127
|
+
NULLABLE_BDVALUE
|
|
5175
4128
|
bigdecimal_parse_special_string(const char *str)
|
|
5176
4129
|
{
|
|
5177
4130
|
static const struct {
|
|
@@ -5196,120 +4149,61 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
5196
4149
|
p = str + table[i].len;
|
|
5197
4150
|
while (*p && ISSPACE(*p)) ++p;
|
|
5198
4151
|
if (*p == '\0') {
|
|
5199
|
-
|
|
5200
|
-
vp
|
|
4152
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4153
|
+
Real *vp = VpPtr(obj);
|
|
5201
4154
|
switch (table[i].sign) {
|
|
5202
4155
|
default:
|
|
5203
|
-
UNREACHABLE;
|
|
4156
|
+
UNREACHABLE;
|
|
4157
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5204
4158
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
5205
4159
|
VpSetPosInf(vp);
|
|
5206
|
-
|
|
4160
|
+
break;
|
|
5207
4161
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
5208
4162
|
VpSetNegInf(vp);
|
|
5209
|
-
|
|
4163
|
+
break;
|
|
5210
4164
|
case VP_SIGN_NaN:
|
|
5211
4165
|
VpSetNaN(vp);
|
|
5212
|
-
|
|
4166
|
+
break;
|
|
5213
4167
|
}
|
|
4168
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
5214
4169
|
}
|
|
5215
4170
|
}
|
|
5216
4171
|
|
|
5217
|
-
return NULL;
|
|
5218
|
-
}
|
|
5219
|
-
|
|
5220
|
-
struct VpCtoV_args {
|
|
5221
|
-
Real *a;
|
|
5222
|
-
const char *int_chr;
|
|
5223
|
-
size_t ni;
|
|
5224
|
-
const char *frac;
|
|
5225
|
-
size_t nf;
|
|
5226
|
-
const char *exp_chr;
|
|
5227
|
-
size_t ne;
|
|
5228
|
-
};
|
|
5229
|
-
|
|
5230
|
-
static VALUE
|
|
5231
|
-
call_VpCtoV(VALUE arg)
|
|
5232
|
-
{
|
|
5233
|
-
struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
|
|
5234
|
-
return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
|
|
5235
|
-
}
|
|
5236
|
-
|
|
5237
|
-
static int
|
|
5238
|
-
protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne, int free_on_error)
|
|
5239
|
-
{
|
|
5240
|
-
struct VpCtoV_args args;
|
|
5241
|
-
int state = 0;
|
|
5242
|
-
|
|
5243
|
-
args.a = a;
|
|
5244
|
-
args.int_chr = int_chr;
|
|
5245
|
-
args.ni = ni;
|
|
5246
|
-
args.frac = frac;
|
|
5247
|
-
args.nf = nf;
|
|
5248
|
-
args.exp_chr = exp_chr;
|
|
5249
|
-
args.ne = ne;
|
|
5250
|
-
|
|
5251
|
-
VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
|
|
5252
|
-
if (state) {
|
|
5253
|
-
if (free_on_error) {
|
|
5254
|
-
rbd_free_struct(a);
|
|
5255
|
-
}
|
|
5256
|
-
rb_jump_tag(state);
|
|
5257
|
-
}
|
|
5258
|
-
|
|
5259
|
-
return (int)result;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5260
4173
|
}
|
|
5261
4174
|
|
|
5262
4175
|
/*
|
|
5263
4176
|
* Allocates variable.
|
|
5264
4177
|
* [Input]
|
|
5265
|
-
*
|
|
5266
|
-
* The mx will be the number of significant digits can to be stored.
|
|
5267
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
|
5268
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
|
5269
|
-
* so that the full precision specified by szVal is allocated.
|
|
4178
|
+
* szVal ... The value assigned(char).
|
|
5270
4179
|
*
|
|
5271
4180
|
* [Returns]
|
|
5272
|
-
*
|
|
5273
|
-
*
|
|
4181
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4182
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
5274
4183
|
*/
|
|
5275
|
-
VP_EXPORT
|
|
5276
|
-
VpAlloc(
|
|
4184
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4185
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
5277
4186
|
{
|
|
5278
4187
|
const char *orig_szVal = szVal;
|
|
5279
|
-
size_t i, j, ni, ipf, nf, ipe, ne,
|
|
5280
|
-
size_t len;
|
|
4188
|
+
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
5281
4189
|
char v, *psz;
|
|
5282
4190
|
int sign=1;
|
|
5283
|
-
Real *vp = NULL;
|
|
5284
4191
|
VALUE buf;
|
|
5285
4192
|
|
|
5286
|
-
if (szVal == NULL) {
|
|
5287
|
-
return_zero:
|
|
5288
|
-
/* necessary to be able to store */
|
|
5289
|
-
/* at least mx digits. */
|
|
5290
|
-
/* szVal==NULL ==> allocate zero value. */
|
|
5291
|
-
vp = rbd_allocate_struct(mx);
|
|
5292
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
|
5293
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
|
5294
|
-
return vp;
|
|
5295
|
-
}
|
|
5296
|
-
|
|
5297
4193
|
/* Skipping leading spaces */
|
|
5298
4194
|
while (ISSPACE(*szVal)) szVal++;
|
|
5299
4195
|
|
|
5300
4196
|
/* Check on Inf & NaN */
|
|
5301
|
-
|
|
5302
|
-
|
|
4197
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4198
|
+
if (special_bd.real_or_null != NULL) {
|
|
4199
|
+
return special_bd;
|
|
5303
4200
|
}
|
|
5304
4201
|
|
|
5305
|
-
/*
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
len = rbd_calculate_internal_digits(mx, false);
|
|
5311
|
-
++szVal;
|
|
5312
|
-
}
|
|
4202
|
+
/* Skip leading `#`.
|
|
4203
|
+
* It used to be a mark to indicate that an extra MaxPrec should be allocated,
|
|
4204
|
+
* but now it has no effect.
|
|
4205
|
+
*/
|
|
4206
|
+
if (*szVal == '#') ++szVal;
|
|
5313
4207
|
|
|
5314
4208
|
/* Scanning digits */
|
|
5315
4209
|
|
|
@@ -5362,13 +4256,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5362
4256
|
ne = 0; /* number of digits in the exponential part */
|
|
5363
4257
|
ipf = 0; /* index of the beginning of the fractional part */
|
|
5364
4258
|
ipe = 0; /* index of the beginning of the exponential part */
|
|
5365
|
-
dot_seen = 0;
|
|
5366
4259
|
exp_seen = 0;
|
|
5367
4260
|
|
|
5368
4261
|
if (v != '\0') {
|
|
5369
4262
|
/* Scanning fractional part */
|
|
5370
4263
|
if ((psz[i] = szVal[j]) == '.') {
|
|
5371
|
-
dot_seen = 1;
|
|
5372
4264
|
++i;
|
|
5373
4265
|
++j;
|
|
5374
4266
|
ipf = i;
|
|
@@ -5384,9 +4276,6 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5384
4276
|
}
|
|
5385
4277
|
if (!strict_p) {
|
|
5386
4278
|
v = psz[i] = '\0';
|
|
5387
|
-
if (nf == 0) {
|
|
5388
|
-
dot_seen = 0;
|
|
5389
|
-
}
|
|
5390
4279
|
break;
|
|
5391
4280
|
}
|
|
5392
4281
|
goto invalid_value;
|
|
@@ -5457,14 +4346,15 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5457
4346
|
|
|
5458
4347
|
psz[i] = '\0';
|
|
5459
4348
|
|
|
5460
|
-
if (strict_p && ((
|
|
4349
|
+
if (strict_p && ((ni == 0 && nf == 0) || (exp_seen && ne == 0))) {
|
|
5461
4350
|
VALUE str;
|
|
5462
4351
|
invalid_value:
|
|
5463
4352
|
if (!strict_p) {
|
|
5464
|
-
|
|
4353
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4354
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
5465
4355
|
}
|
|
5466
4356
|
if (!exc) {
|
|
5467
|
-
return NULL;
|
|
4357
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5468
4358
|
}
|
|
5469
4359
|
str = rb_str_new2(orig_szVal);
|
|
5470
4360
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -5472,15 +4362,12 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5472
4362
|
|
|
5473
4363
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
5474
4364
|
/* units for szVal[] */
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
len = nalloc;
|
|
5478
|
-
vp = rbd_allocate_struct(len);
|
|
5479
|
-
vp->MaxPrec = len; /* set max precision */
|
|
4365
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4366
|
+
Real *vp = VpPtr(obj);
|
|
5480
4367
|
VpSetZero(vp, sign);
|
|
5481
|
-
|
|
4368
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
5482
4369
|
rb_str_resize(buf, 0);
|
|
5483
|
-
return vp;
|
|
4370
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
5484
4371
|
}
|
|
5485
4372
|
|
|
5486
4373
|
/*
|
|
@@ -5516,7 +4403,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5516
4403
|
c->Prec = n;
|
|
5517
4404
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
|
5518
4405
|
/* Needs round ? */
|
|
5519
|
-
if (isw != 10) {
|
|
4406
|
+
if (isw != 10 && isw != -10) {
|
|
5520
4407
|
/* Not in ActiveRound */
|
|
5521
4408
|
if(c->Prec < a->Prec) {
|
|
5522
4409
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
|
@@ -5542,19 +4429,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5542
4429
|
VP_EXPORT size_t
|
|
5543
4430
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
|
5544
4431
|
{
|
|
5545
|
-
short sw, isw;
|
|
4432
|
+
short sw, isw, sign;
|
|
5546
4433
|
Real *a_ptr, *b_ptr;
|
|
5547
4434
|
size_t n, na, nb, i;
|
|
5548
4435
|
DECDIG mrv;
|
|
5549
4436
|
|
|
5550
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5551
|
-
if (gfDebug) {
|
|
5552
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
|
5553
|
-
VPrint(stdout, " b=% \n", b);
|
|
5554
|
-
printf(" operation=%d\n", operation);
|
|
5555
|
-
}
|
|
5556
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5557
|
-
|
|
5558
4437
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
|
5559
4438
|
|
|
5560
4439
|
/* check if a or b is zero */
|
|
@@ -5643,28 +4522,21 @@ end_if:
|
|
|
5643
4522
|
if (isw) { /* addition */
|
|
5644
4523
|
VpSetSign(c, 1);
|
|
5645
4524
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
|
5646
|
-
|
|
4525
|
+
sign = isw / 2;
|
|
5647
4526
|
}
|
|
5648
4527
|
else { /* subtraction */
|
|
5649
4528
|
VpSetSign(c, 1);
|
|
5650
4529
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
|
5651
|
-
|
|
5652
|
-
VpSetSign(c,VpGetSign(a));
|
|
5653
|
-
}
|
|
5654
|
-
else {
|
|
5655
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
|
5656
|
-
}
|
|
4530
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
|
5657
4531
|
}
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5661
|
-
if (gfDebug) {
|
|
5662
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
|
5663
|
-
VPrint(stdout, " a=% \n", a);
|
|
5664
|
-
VPrint(stdout, " b=% \n", b);
|
|
5665
|
-
printf(" operation=%d\n", operation);
|
|
4532
|
+
if (VpIsInf(c)) {
|
|
4533
|
+
VpSetInf(c, sign);
|
|
5666
4534
|
}
|
|
5667
|
-
|
|
4535
|
+
else {
|
|
4536
|
+
VpSetSign(c, sign);
|
|
4537
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
|
4538
|
+
}
|
|
4539
|
+
|
|
5668
4540
|
return c->Prec * BASE_FIG;
|
|
5669
4541
|
}
|
|
5670
4542
|
|
|
@@ -5685,13 +4557,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
|
5685
4557
|
size_t c_pos;
|
|
5686
4558
|
DECDIG av, bv, carry, mrv;
|
|
5687
4559
|
|
|
5688
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5689
|
-
if (gfDebug) {
|
|
5690
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
|
5691
|
-
VPrint(stdout, " b = %\n", b);
|
|
5692
|
-
}
|
|
5693
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5694
|
-
|
|
5695
4560
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5696
4561
|
a_pos = ap;
|
|
5697
4562
|
b_pos = bp;
|
|
@@ -5757,11 +4622,6 @@ Assign_a:
|
|
|
5757
4622
|
|
|
5758
4623
|
Exit:
|
|
5759
4624
|
|
|
5760
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5761
|
-
if (gfDebug) {
|
|
5762
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
|
5763
|
-
}
|
|
5764
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5765
4625
|
return mrv;
|
|
5766
4626
|
}
|
|
5767
4627
|
|
|
@@ -5780,13 +4640,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
|
5780
4640
|
size_t c_pos;
|
|
5781
4641
|
DECDIG av, bv, borrow, mrv;
|
|
5782
4642
|
|
|
5783
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5784
|
-
if (gfDebug) {
|
|
5785
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
|
5786
|
-
VPrint(stdout, " b = %\n", b);
|
|
5787
|
-
}
|
|
5788
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5789
|
-
|
|
5790
4643
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5791
4644
|
a_pos = ap;
|
|
5792
4645
|
b_pos = bp;
|
|
@@ -5862,11 +4715,6 @@ Assign_a:
|
|
|
5862
4715
|
mrv = 0;
|
|
5863
4716
|
|
|
5864
4717
|
Exit:
|
|
5865
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5866
|
-
if (gfDebug) {
|
|
5867
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
|
5868
|
-
}
|
|
5869
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5870
4718
|
return mrv;
|
|
5871
4719
|
}
|
|
5872
4720
|
|
|
@@ -5991,25 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
5991
4839
|
* a0 a1 .... an * b0
|
|
5992
4840
|
* +_____________________________
|
|
5993
4841
|
* c0 c1 c2 ...... cl
|
|
5994
|
-
* nc <---|
|
|
5995
|
-
* MaxAB |--------------------|
|
|
5996
4842
|
*/
|
|
5997
4843
|
VP_EXPORT size_t
|
|
5998
4844
|
VpMult(Real *c, Real *a, Real *b)
|
|
5999
4845
|
{
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
6003
|
-
DECDIG carry;
|
|
6004
|
-
DECDIG_DBL s;
|
|
6005
|
-
Real *w;
|
|
6006
|
-
|
|
6007
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6008
|
-
if (gfDebug) {
|
|
6009
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
|
6010
|
-
VPrint(stdout, " b=% \n", b);
|
|
6011
|
-
}
|
|
6012
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
4846
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4847
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
6013
4848
|
|
|
6014
4849
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
6015
4850
|
|
|
@@ -6020,108 +4855,82 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6020
4855
|
}
|
|
6021
4856
|
|
|
6022
4857
|
if (VpIsOne(a)) {
|
|
6023
|
-
VpAsgn(c, b, VpGetSign(a));
|
|
4858
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
|
6024
4859
|
goto Exit;
|
|
6025
4860
|
}
|
|
6026
4861
|
if (VpIsOne(b)) {
|
|
6027
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
4862
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
|
6028
4863
|
goto Exit;
|
|
6029
4864
|
}
|
|
6030
4865
|
if (b->Prec > a->Prec) {
|
|
6031
4866
|
/* Adjust so that digits(a)>digits(b) */
|
|
6032
|
-
w = a;
|
|
4867
|
+
Real *w = a;
|
|
6033
4868
|
a = b;
|
|
6034
4869
|
b = w;
|
|
6035
4870
|
}
|
|
6036
|
-
w = NULL;
|
|
6037
|
-
MxIndA = a->Prec - 1;
|
|
6038
|
-
MxIndB = b->Prec - 1;
|
|
6039
|
-
MxIndC = c->MaxPrec - 1;
|
|
6040
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
6041
|
-
|
|
6042
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
|
6043
|
-
w = c;
|
|
6044
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
|
6045
|
-
MxIndC = MxIndAB;
|
|
6046
|
-
}
|
|
6047
4871
|
|
|
6048
4872
|
/* set LHSV c info */
|
|
6049
4873
|
|
|
6050
4874
|
c->exponent = a->exponent; /* set exponent */
|
|
6051
|
-
if (!AddExponent(c, b->exponent)) {
|
|
6052
|
-
if (w) rbd_free_struct(c);
|
|
6053
|
-
return 0;
|
|
6054
|
-
}
|
|
6055
4875
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
4876
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
|
4877
|
+
|
|
4878
|
+
if (b->Prec >= NTT_MULTIPLICATION_THRESHOLD) {
|
|
4879
|
+
ntt_multiply(a->Prec, b->Prec, a->frac, b->frac, c->frac);
|
|
4880
|
+
c->Prec = a->Prec + b->Prec;
|
|
4881
|
+
goto Cleanup;
|
|
4882
|
+
}
|
|
4883
|
+
|
|
4884
|
+
c->Prec = a->Prec + b->Prec; /* set precision */
|
|
4885
|
+
memset(c->frac, 0, c->Prec * sizeof(DECDIG)); /* Initialize c */
|
|
4886
|
+
|
|
4887
|
+
// Process VPMULT_BATCH_SIZE decdigits at a time to reduce the number of carry operations.
|
|
4888
|
+
a_batch_max = (a->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4889
|
+
b_batch_max = (b->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4890
|
+
for (ssize_t ibatch = a_batch_max; ibatch >= 0; ibatch--) {
|
|
4891
|
+
int isize = ibatch == a_batch_max ? (a->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4892
|
+
for (ssize_t jbatch = b_batch_max; jbatch >= 0; jbatch--) {
|
|
4893
|
+
int jsize = jbatch == b_batch_max ? (b->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4894
|
+
memset(batch, 0, (isize + jsize - 1) * sizeof(DECDIG_DBL));
|
|
4895
|
+
|
|
4896
|
+
// Perform multiplication without carry calculation.
|
|
4897
|
+
// BASE * BASE * VPMULT_BATCH_SIZE < 2**64 should be satisfied so that
|
|
4898
|
+
// DECDIG_DBL can hold the intermediate sum without overflow.
|
|
4899
|
+
for (int i = 0; i < isize; i++) {
|
|
4900
|
+
for (int j = 0; j < jsize; j++) {
|
|
4901
|
+
batch[i + j] += (DECDIG_DBL)a->frac[ibatch * VPMULT_BATCH_SIZE + i] * b->frac[jbatch * VPMULT_BATCH_SIZE + j];
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
6076
4904
|
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
carry += (DECDIG)s;
|
|
6085
|
-
c->frac[ind_c] -= (DECDIG)(s * BASE);
|
|
4905
|
+
// Add the batch result to c with carry calculation.
|
|
4906
|
+
DECDIG_DBL carry = 0;
|
|
4907
|
+
for (int k = isize + jsize - 2; k >= 0; k--) {
|
|
4908
|
+
size_t l = (ibatch + jbatch) * VPMULT_BATCH_SIZE + k + 1;
|
|
4909
|
+
DECDIG_DBL s = c->frac[l] + batch[k] + carry;
|
|
4910
|
+
c->frac[l] = (DECDIG)(s % BASE);
|
|
4911
|
+
carry = (DECDIG_DBL)(s / BASE);
|
|
6086
4912
|
}
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
c->frac[ii] -= (carry * BASE);
|
|
6094
|
-
}
|
|
6095
|
-
else {
|
|
6096
|
-
break;
|
|
6097
|
-
}
|
|
6098
|
-
}
|
|
6099
|
-
}
|
|
6100
|
-
}
|
|
6101
|
-
}
|
|
6102
|
-
if (w != NULL) { /* free work variable */
|
|
6103
|
-
VpNmlz(c);
|
|
6104
|
-
VpAsgn(w, c, 1);
|
|
6105
|
-
rbd_free_struct(c);
|
|
6106
|
-
c = w;
|
|
6107
|
-
}
|
|
6108
|
-
else {
|
|
6109
|
-
VpLimitRound(c,0);
|
|
4913
|
+
|
|
4914
|
+
// Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
|
|
4915
|
+
// Exceeded value will be resolved in the carry operation of next (ibatch + jbatch - 1) batch.
|
|
4916
|
+
// WARNING: This safety strongly relies on the current nested loop execution order.
|
|
4917
|
+
c->frac[(ibatch + jbatch) * VPMULT_BATCH_SIZE] += (DECDIG)carry;
|
|
4918
|
+
}
|
|
6110
4919
|
}
|
|
6111
4920
|
|
|
4921
|
+
Cleanup:
|
|
4922
|
+
VpNmlz(c);
|
|
4923
|
+
|
|
6112
4924
|
Exit:
|
|
6113
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6114
|
-
if (gfDebug) {
|
|
6115
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
|
6116
|
-
VPrint(stdout, " a=% \n", a);
|
|
6117
|
-
VPrint(stdout, " b=% \n", b);
|
|
6118
|
-
}
|
|
6119
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6120
4925
|
return c->Prec*BASE_FIG;
|
|
6121
4926
|
}
|
|
6122
4927
|
|
|
6123
4928
|
/*
|
|
6124
4929
|
* c = a / b, remainder = r
|
|
4930
|
+
* XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
|
|
4931
|
+
* XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
|
|
4932
|
+
* 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
|
|
4933
|
+
* 0001_0000_0000 / 9999 = 0000_0001_0001
|
|
6125
4934
|
*/
|
|
6126
4935
|
VP_EXPORT size_t
|
|
6127
4936
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
@@ -6130,16 +4939,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6130
4939
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
|
6131
4940
|
size_t nLoop;
|
|
6132
4941
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
|
6133
|
-
DECDIG
|
|
4942
|
+
DECDIG borrow1, borrow2;
|
|
6134
4943
|
DECDIG_DBL qb;
|
|
6135
4944
|
|
|
6136
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6137
|
-
if (gfDebug) {
|
|
6138
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
|
6139
|
-
VPrint(stdout, " b=% \n", b);
|
|
6140
|
-
}
|
|
6141
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6142
|
-
|
|
6143
4945
|
VpSetNaN(r);
|
|
6144
4946
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
|
6145
4947
|
if (VpIsZero(a) && VpIsZero(b)) {
|
|
@@ -6156,30 +4958,22 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6156
4958
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
|
6157
4959
|
goto Exit;
|
|
6158
4960
|
}
|
|
6159
|
-
if (VpIsOne(b)) {
|
|
6160
|
-
/* divide by one */
|
|
6161
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
6162
|
-
VpSetZero(r, VpGetSign(a));
|
|
6163
|
-
goto Exit;
|
|
6164
|
-
}
|
|
6165
4961
|
|
|
6166
4962
|
word_a = a->Prec;
|
|
6167
4963
|
word_b = b->Prec;
|
|
6168
4964
|
word_c = c->MaxPrec;
|
|
6169
4965
|
word_r = r->MaxPrec;
|
|
6170
4966
|
|
|
6171
|
-
if (word_a >= word_r) goto space_error;
|
|
4967
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
6172
4968
|
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
|
6177
|
-
++ind_r;
|
|
4969
|
+
if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
|
|
4970
|
+
VpDivdNewton(c, r, a, b);
|
|
4971
|
+
goto Exit;
|
|
6178
4972
|
}
|
|
6179
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
|
6180
4973
|
|
|
6181
|
-
|
|
6182
|
-
|
|
4974
|
+
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
4975
|
+
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
4976
|
+
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
6183
4977
|
|
|
6184
4978
|
/* initial procedure */
|
|
6185
4979
|
b1 = b1p1 = b->frac[0];
|
|
@@ -6194,15 +4988,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6194
4988
|
|
|
6195
4989
|
/* */
|
|
6196
4990
|
/* loop start */
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
ind_c = 1;
|
|
4991
|
+
nLoop = Min(word_c, word_r);
|
|
4992
|
+
ind_c = 0;
|
|
6200
4993
|
while (ind_c < nLoop) {
|
|
6201
4994
|
if (r->frac[ind_c] == 0) {
|
|
6202
4995
|
++ind_c;
|
|
6203
4996
|
continue;
|
|
6204
4997
|
}
|
|
6205
|
-
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
|
|
4998
|
+
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
|
|
6206
4999
|
if (r1r2 == b1b2) {
|
|
6207
5000
|
/* The first two word digits is the same */
|
|
6208
5001
|
ind_b = 2;
|
|
@@ -6215,26 +5008,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6215
5008
|
}
|
|
6216
5009
|
/* The first few word digits of r and b is the same and */
|
|
6217
5010
|
/* the first different word digit of w is greater than that */
|
|
6218
|
-
/* of b, so quotient is 1
|
|
6219
|
-
|
|
6220
|
-
ind_b = b->Prec - 1;
|
|
6221
|
-
ind_r = ind_c + ind_b;
|
|
6222
|
-
if (ind_r >= word_r) goto space_error;
|
|
6223
|
-
n = ind_b;
|
|
6224
|
-
for (i = 0; i <= n; ++i) {
|
|
6225
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
|
6226
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
|
6227
|
-
borrow = 1;
|
|
6228
|
-
}
|
|
6229
|
-
else {
|
|
6230
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
|
6231
|
-
borrow = 0;
|
|
6232
|
-
}
|
|
6233
|
-
--ind_r;
|
|
6234
|
-
--ind_b;
|
|
6235
|
-
}
|
|
5011
|
+
/* of b, so quotient is 1. */
|
|
5012
|
+
q = 1;
|
|
6236
5013
|
++c->frac[ind_c];
|
|
6237
|
-
|
|
5014
|
+
ind_r = b->Prec + ind_c - 1;
|
|
5015
|
+
goto sub_mult;
|
|
6238
5016
|
}
|
|
6239
5017
|
/* The first two word digits is not the same, */
|
|
6240
5018
|
/* then compare magnitude, and divide actually. */
|
|
@@ -6287,49 +5065,26 @@ sub_mult:
|
|
|
6287
5065
|
}
|
|
6288
5066
|
|
|
6289
5067
|
r->frac[ind_r] -= borrow2;
|
|
6290
|
-
carry:
|
|
6291
|
-
ind_r = ind_c;
|
|
6292
|
-
while (c->frac[ind_r] >= BASE) {
|
|
6293
|
-
c->frac[ind_r] -= BASE;
|
|
6294
|
-
--ind_r;
|
|
6295
|
-
++c->frac[ind_r];
|
|
6296
|
-
}
|
|
6297
5068
|
}
|
|
6298
5069
|
/* End of operation, now final arrangement */
|
|
6299
5070
|
out_side:
|
|
6300
5071
|
c->Prec = word_c;
|
|
6301
5072
|
c->exponent = a->exponent;
|
|
6302
|
-
|
|
5073
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
5074
|
+
if (!AddExponent(c, 1)) return 0;
|
|
6303
5075
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
|
6304
5076
|
|
|
6305
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
6306
5077
|
VpNmlz(c); /* normalize c */
|
|
6307
5078
|
r->Prec = word_r;
|
|
6308
5079
|
r->exponent = a->exponent;
|
|
6309
|
-
if (!AddExponent(r, 1)) return 0;
|
|
6310
5080
|
VpSetSign(r, VpGetSign(a));
|
|
6311
5081
|
VpNmlz(r); /* normalize r(remainder) */
|
|
6312
5082
|
goto Exit;
|
|
6313
5083
|
|
|
6314
5084
|
space_error:
|
|
6315
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6316
|
-
if (gfDebug) {
|
|
6317
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
|
6318
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
|
6319
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
|
6320
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
|
6321
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
|
6322
|
-
}
|
|
6323
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6324
5085
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
|
6325
5086
|
|
|
6326
5087
|
Exit:
|
|
6327
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6328
|
-
if (gfDebug) {
|
|
6329
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
|
6330
|
-
VPrint(stdout, " r=% \n", r);
|
|
6331
|
-
}
|
|
6332
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6333
5088
|
return c->Prec * BASE_FIG;
|
|
6334
5089
|
}
|
|
6335
5090
|
|
|
@@ -6452,13 +5207,6 @@ Exit:
|
|
|
6452
5207
|
if (val > 1) val = 1;
|
|
6453
5208
|
else if (val < -1) val = -1;
|
|
6454
5209
|
|
|
6455
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6456
|
-
if (gfDebug) {
|
|
6457
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
|
6458
|
-
VPrint(stdout, " b=%\n", b);
|
|
6459
|
-
printf(" ans=%d\n", val);
|
|
6460
|
-
}
|
|
6461
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6462
5210
|
return (int)val;
|
|
6463
5211
|
}
|
|
6464
5212
|
|
|
@@ -6576,25 +5324,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
|
6576
5324
|
static void
|
|
6577
5325
|
VpFormatSt(char *psz, size_t fFmt)
|
|
6578
5326
|
{
|
|
6579
|
-
size_t
|
|
6580
|
-
char
|
|
5327
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
|
5328
|
+
char *p;
|
|
6581
5329
|
|
|
6582
5330
|
if (fFmt == 0) return;
|
|
6583
5331
|
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
5332
|
+
iend = strlen(psz);
|
|
5333
|
+
|
|
5334
|
+
if ((p = strchr(psz, '.'))) {
|
|
5335
|
+
idig = (p - psz) + 1;
|
|
5336
|
+
}
|
|
5337
|
+
if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
|
|
5338
|
+
iexp = p - psz;
|
|
5339
|
+
}
|
|
5340
|
+
if (idig == 0 || idig > iexp) return;
|
|
5341
|
+
|
|
5342
|
+
nspaces = (iexp - idig - 1) / fFmt;
|
|
5343
|
+
p = psz + iend + 1;
|
|
5344
|
+
for (size_t i = nspaces; i > 0; i--) {
|
|
5345
|
+
char *src = psz + idig + i * fFmt;
|
|
5346
|
+
char *dst = psz + idig + i * (fFmt + 1);
|
|
5347
|
+
memmove(dst, src, p - src);
|
|
5348
|
+
dst[-1] = ' ';
|
|
5349
|
+
p = src;
|
|
6598
5350
|
}
|
|
6599
5351
|
}
|
|
6600
5352
|
|
|
@@ -6644,8 +5396,8 @@ VpSzMantissa(Real *a, char *buf, size_t buflen)
|
|
|
6644
5396
|
while (m) {
|
|
6645
5397
|
nn = e / m;
|
|
6646
5398
|
if (!ZeroSup || nn) {
|
|
6647
|
-
|
|
6648
|
-
buf
|
|
5399
|
+
*buf = (char)('0' + nn);
|
|
5400
|
+
buf++;
|
|
6649
5401
|
/* as 0.00xx will be ignored. */
|
|
6650
5402
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
6651
5403
|
}
|
|
@@ -6697,10 +5449,22 @@ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
|
|
|
6697
5449
|
return 0;
|
|
6698
5450
|
}
|
|
6699
5451
|
|
|
5452
|
+
#define ULLTOA_BUFFER_SIZE 20
|
|
5453
|
+
static size_t Vp_ulltoa(unsigned long long number, char *buf)
|
|
5454
|
+
{
|
|
5455
|
+
static const char digits[] = "0123456789";
|
|
5456
|
+
char* tmp = buf;
|
|
5457
|
+
|
|
5458
|
+
do *tmp-- = digits[number % 10]; while (number /= 10);
|
|
5459
|
+
return buf - tmp;
|
|
5460
|
+
}
|
|
5461
|
+
|
|
6700
5462
|
VP_EXPORT void
|
|
6701
5463
|
VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
6702
5464
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
6703
5465
|
{
|
|
5466
|
+
char ulltoa_buf[ULLTOA_BUFFER_SIZE];
|
|
5467
|
+
char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
|
|
6704
5468
|
size_t i, n, ZeroSup;
|
|
6705
5469
|
DECDIG shift, m, e, nn;
|
|
6706
5470
|
char *p = buf;
|
|
@@ -6740,10 +5504,9 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
6740
5504
|
while (m) {
|
|
6741
5505
|
nn = e / m;
|
|
6742
5506
|
if (!ZeroSup || nn) {
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
ADVANCE(n);
|
|
5507
|
+
*p = (char)('0' + nn);
|
|
5508
|
+
ADVANCE(1);
|
|
5509
|
+
|
|
6747
5510
|
/* as 0.00xx will be ignored. */
|
|
6748
5511
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
6749
5512
|
}
|
|
@@ -6762,7 +5525,22 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
6762
5525
|
*(--p) = '\0';
|
|
6763
5526
|
++plen;
|
|
6764
5527
|
}
|
|
6765
|
-
|
|
5528
|
+
*p = 'e';
|
|
5529
|
+
ADVANCE(1);
|
|
5530
|
+
|
|
5531
|
+
if (ex < 0) {
|
|
5532
|
+
*p = '-';
|
|
5533
|
+
ADVANCE(1);
|
|
5534
|
+
ex = -ex;
|
|
5535
|
+
}
|
|
5536
|
+
|
|
5537
|
+
size_t ex_n = Vp_ulltoa(ex, ulltoa_buf_end - 1);
|
|
5538
|
+
if (ex_n > plen) goto overflow;
|
|
5539
|
+
MEMCPY(p, ulltoa_buf_end - ex_n, char, ex_n);
|
|
5540
|
+
ADVANCE(ex_n);
|
|
5541
|
+
*p = '\0';
|
|
5542
|
+
ADVANCE(1);
|
|
5543
|
+
|
|
6766
5544
|
if (fFmt) VpFormatSt(buf, fFmt);
|
|
6767
5545
|
|
|
6768
5546
|
overflow:
|
|
@@ -6876,7 +5654,7 @@ VP_EXPORT int
|
|
|
6876
5654
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
|
6877
5655
|
{
|
|
6878
5656
|
size_t i, j, ind_a, ma, mi, me;
|
|
6879
|
-
SIGNED_VALUE e
|
|
5657
|
+
SIGNED_VALUE e;
|
|
6880
5658
|
int sign, signe, exponent_overflow;
|
|
6881
5659
|
|
|
6882
5660
|
/* get exponent part */
|
|
@@ -6899,23 +5677,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6899
5677
|
++me;
|
|
6900
5678
|
}
|
|
6901
5679
|
while (i < me) {
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
}
|
|
6906
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
|
6907
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
6908
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
|
6909
|
-
goto exp_overflow;
|
|
6910
|
-
e = e * 10 + exp_chr[i] - '0';
|
|
6911
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
6912
|
-
goto exp_overflow;
|
|
6913
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
|
6914
|
-
exp_overflow:
|
|
5680
|
+
int dig = exp_chr[i] - '0';
|
|
5681
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
5682
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
|
6915
5683
|
exponent_overflow = 1;
|
|
6916
|
-
e = es; /* keep sign */
|
|
6917
5684
|
break;
|
|
6918
5685
|
}
|
|
5686
|
+
e = e * 10 + signe * dig;
|
|
6919
5687
|
++i;
|
|
6920
5688
|
}
|
|
6921
5689
|
}
|
|
@@ -6934,34 +5702,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6934
5702
|
++mi;
|
|
6935
5703
|
}
|
|
6936
5704
|
}
|
|
5705
|
+
/* skip leading zeros in integer part */
|
|
5706
|
+
while (i < mi && int_chr[i] == '0') {
|
|
5707
|
+
++i;
|
|
5708
|
+
--ni;
|
|
5709
|
+
}
|
|
6937
5710
|
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
5711
|
+
/* set actual exponent size. */
|
|
5712
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
|
5713
|
+
exponent_overflow = 1;
|
|
5714
|
+
} else {
|
|
5715
|
+
e += ni;
|
|
5716
|
+
}
|
|
6943
5717
|
|
|
6944
5718
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
|
6945
|
-
j =
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
|
6951
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
|
6952
|
-
if (ef) {
|
|
6953
|
-
++j; /* Means to add one more preceding zero */
|
|
6954
|
-
++e;
|
|
6955
|
-
}
|
|
5719
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
|
5720
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
|
5721
|
+
exponent_overflow = 1;
|
|
5722
|
+
} else {
|
|
5723
|
+
e += j;
|
|
6956
5724
|
}
|
|
6957
5725
|
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
if (exponent_overflow) {
|
|
5726
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
|
6961
5727
|
int zero = 1;
|
|
6962
5728
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
|
6963
5729
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
|
6964
|
-
if (!zero &&
|
|
5730
|
+
if (!zero && e > 0) {
|
|
6965
5731
|
VpSetInf(a, sign);
|
|
6966
5732
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
|
6967
5733
|
}
|
|
@@ -7011,7 +5777,7 @@ Final:
|
|
|
7011
5777
|
++j;
|
|
7012
5778
|
}
|
|
7013
5779
|
a->Prec = ind_a + 1;
|
|
7014
|
-
a->exponent =
|
|
5780
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
|
7015
5781
|
VpSetSign(a, sign);
|
|
7016
5782
|
VpNmlz(a);
|
|
7017
5783
|
return 1;
|
|
@@ -7083,254 +5849,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
|
7083
5849
|
*d *= VpGetSign(m);
|
|
7084
5850
|
|
|
7085
5851
|
Exit:
|
|
7086
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7087
|
-
if (gfDebug) {
|
|
7088
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
|
7089
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
|
7090
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
7091
|
-
}
|
|
7092
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
7093
5852
|
return f;
|
|
7094
5853
|
}
|
|
7095
5854
|
|
|
7096
|
-
/*
|
|
7097
|
-
* m <- d
|
|
7098
|
-
*/
|
|
7099
|
-
VP_EXPORT void
|
|
7100
|
-
VpDtoV(Real *m, double d)
|
|
7101
|
-
{
|
|
7102
|
-
size_t ind_m, mm;
|
|
7103
|
-
SIGNED_VALUE ne;
|
|
7104
|
-
DECDIG i;
|
|
7105
|
-
double val, val2;
|
|
7106
|
-
|
|
7107
|
-
if (isnan(d)) {
|
|
7108
|
-
VpSetNaN(m);
|
|
7109
|
-
goto Exit;
|
|
7110
|
-
}
|
|
7111
|
-
if (isinf(d)) {
|
|
7112
|
-
if (d > 0.0) VpSetPosInf(m);
|
|
7113
|
-
else VpSetNegInf(m);
|
|
7114
|
-
goto Exit;
|
|
7115
|
-
}
|
|
7116
|
-
|
|
7117
|
-
if (d == 0.0) {
|
|
7118
|
-
VpSetZero(m, 1);
|
|
7119
|
-
goto Exit;
|
|
7120
|
-
}
|
|
7121
|
-
val = (d > 0.) ? d : -d;
|
|
7122
|
-
ne = 0;
|
|
7123
|
-
if (val >= 1.0) {
|
|
7124
|
-
while (val >= 1.0) {
|
|
7125
|
-
val /= (double)BASE;
|
|
7126
|
-
++ne;
|
|
7127
|
-
}
|
|
7128
|
-
}
|
|
7129
|
-
else {
|
|
7130
|
-
val2 = 1.0 / (double)BASE;
|
|
7131
|
-
while (val < val2) {
|
|
7132
|
-
val *= (double)BASE;
|
|
7133
|
-
--ne;
|
|
7134
|
-
}
|
|
7135
|
-
}
|
|
7136
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
|
7137
|
-
|
|
7138
|
-
mm = m->MaxPrec;
|
|
7139
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
|
7140
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
|
7141
|
-
val *= (double)BASE;
|
|
7142
|
-
i = (DECDIG)val;
|
|
7143
|
-
val -= (double)i;
|
|
7144
|
-
m->frac[ind_m] = i;
|
|
7145
|
-
}
|
|
7146
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
|
7147
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
|
7148
|
-
m->Prec = ind_m + 1;
|
|
7149
|
-
m->exponent = ne;
|
|
7150
|
-
|
|
7151
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
|
7152
|
-
(DECDIG)(val*(double)BASE));
|
|
7153
|
-
|
|
7154
|
-
Exit:
|
|
7155
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7156
|
-
if (gfDebug) {
|
|
7157
|
-
printf("VpDtoV d=%30.30e\n", d);
|
|
7158
|
-
VPrint(stdout, " m=%\n", m);
|
|
7159
|
-
}
|
|
7160
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7161
|
-
return;
|
|
7162
|
-
}
|
|
7163
|
-
|
|
7164
|
-
/*
|
|
7165
|
-
* m <- ival
|
|
7166
|
-
*/
|
|
7167
|
-
#if 0 /* unused */
|
|
7168
|
-
VP_EXPORT void
|
|
7169
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
|
7170
|
-
{
|
|
7171
|
-
size_t mm, ind_m;
|
|
7172
|
-
size_t val, v1, v2, v;
|
|
7173
|
-
int isign;
|
|
7174
|
-
SIGNED_VALUE ne;
|
|
7175
|
-
|
|
7176
|
-
if (ival == 0) {
|
|
7177
|
-
VpSetZero(m, 1);
|
|
7178
|
-
goto Exit;
|
|
7179
|
-
}
|
|
7180
|
-
isign = 1;
|
|
7181
|
-
val = ival;
|
|
7182
|
-
if (ival < 0) {
|
|
7183
|
-
isign = -1;
|
|
7184
|
-
val =(size_t)(-ival);
|
|
7185
|
-
}
|
|
7186
|
-
ne = 0;
|
|
7187
|
-
ind_m = 0;
|
|
7188
|
-
mm = m->MaxPrec;
|
|
7189
|
-
while (ind_m < mm) {
|
|
7190
|
-
m->frac[ind_m] = 0;
|
|
7191
|
-
++ind_m;
|
|
7192
|
-
}
|
|
7193
|
-
ind_m = 0;
|
|
7194
|
-
while (val > 0) {
|
|
7195
|
-
if (val) {
|
|
7196
|
-
v1 = val;
|
|
7197
|
-
v2 = 1;
|
|
7198
|
-
while (v1 >= BASE) {
|
|
7199
|
-
v1 /= BASE;
|
|
7200
|
-
v2 *= BASE;
|
|
7201
|
-
}
|
|
7202
|
-
val = val - v2 * v1;
|
|
7203
|
-
v = v1;
|
|
7204
|
-
}
|
|
7205
|
-
else {
|
|
7206
|
-
v = 0;
|
|
7207
|
-
}
|
|
7208
|
-
m->frac[ind_m] = v;
|
|
7209
|
-
++ind_m;
|
|
7210
|
-
++ne;
|
|
7211
|
-
}
|
|
7212
|
-
m->Prec = ind_m - 1;
|
|
7213
|
-
m->exponent = ne;
|
|
7214
|
-
VpSetSign(m, isign);
|
|
7215
|
-
VpNmlz(m);
|
|
7216
|
-
|
|
7217
|
-
Exit:
|
|
7218
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7219
|
-
if (gfDebug) {
|
|
7220
|
-
printf(" VpItoV i=%d\n", ival);
|
|
7221
|
-
VPrint(stdout, " m=%\n", m);
|
|
7222
|
-
}
|
|
7223
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7224
|
-
return;
|
|
7225
|
-
}
|
|
7226
|
-
#endif
|
|
7227
|
-
|
|
7228
|
-
/*
|
|
7229
|
-
* y = SQRT(x), y*y - x =>0
|
|
7230
|
-
*/
|
|
7231
|
-
VP_EXPORT int
|
|
7232
|
-
VpSqrt(Real *y, Real *x)
|
|
7233
|
-
{
|
|
7234
|
-
Real *f = NULL;
|
|
7235
|
-
Real *r = NULL;
|
|
7236
|
-
size_t y_prec;
|
|
7237
|
-
SIGNED_VALUE n, e;
|
|
7238
|
-
ssize_t nr;
|
|
7239
|
-
double val;
|
|
7240
|
-
|
|
7241
|
-
/* Zero or +Infinity ? */
|
|
7242
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
|
7243
|
-
VpAsgn(y,x,1);
|
|
7244
|
-
goto Exit;
|
|
7245
|
-
}
|
|
7246
|
-
|
|
7247
|
-
/* Negative ? */
|
|
7248
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
7249
|
-
VpSetNaN(y);
|
|
7250
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
|
7251
|
-
}
|
|
7252
|
-
|
|
7253
|
-
/* NaN ? */
|
|
7254
|
-
if (VpIsNaN(x)) {
|
|
7255
|
-
VpSetNaN(y);
|
|
7256
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
|
7257
|
-
}
|
|
7258
|
-
|
|
7259
|
-
/* One ? */
|
|
7260
|
-
if (VpIsOne(x)) {
|
|
7261
|
-
VpSetOne(y);
|
|
7262
|
-
goto Exit;
|
|
7263
|
-
}
|
|
7264
|
-
|
|
7265
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
|
7266
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
|
7267
|
-
|
|
7268
|
-
/* allocate temporally variables */
|
|
7269
|
-
/* TODO: reconsider MaxPrec of f and r */
|
|
7270
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
|
7271
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
|
7272
|
-
|
|
7273
|
-
nr = 0;
|
|
7274
|
-
y_prec = y->MaxPrec;
|
|
7275
|
-
|
|
7276
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
|
7277
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
|
7278
|
-
n = e / 2;
|
|
7279
|
-
if (e - n * 2 != 0) {
|
|
7280
|
-
val /= BASE;
|
|
7281
|
-
n = (e + 1) / 2;
|
|
7282
|
-
}
|
|
7283
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
|
7284
|
-
y->exponent += n;
|
|
7285
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
|
7286
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
|
7287
|
-
f->MaxPrec = y->MaxPrec + 1;
|
|
7288
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
|
7289
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
|
7290
|
-
|
|
7291
|
-
/*
|
|
7292
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
|
7293
|
-
*/
|
|
7294
|
-
do {
|
|
7295
|
-
y->MaxPrec *= 2;
|
|
7296
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
|
7297
|
-
f->MaxPrec = y->MaxPrec;
|
|
7298
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
|
7299
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
|
7300
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
|
7301
|
-
if (VpIsZero(f))
|
|
7302
|
-
goto converge;
|
|
7303
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
|
7304
|
-
VpAsgn(y, r, 1); /* y = r */
|
|
7305
|
-
} while (++nr < n);
|
|
7306
|
-
|
|
7307
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7308
|
-
if (gfDebug) {
|
|
7309
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
|
7310
|
-
}
|
|
7311
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7312
|
-
y->MaxPrec = y_prec;
|
|
7313
|
-
|
|
7314
|
-
converge:
|
|
7315
|
-
VpChangeSign(y, 1);
|
|
7316
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7317
|
-
if (gfDebug) {
|
|
7318
|
-
VpMult(r, y, y);
|
|
7319
|
-
VpAddSub(f, x, r, -1);
|
|
7320
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
|
7321
|
-
VPrint(stdout, " y =% \n", y);
|
|
7322
|
-
VPrint(stdout, " x =% \n", x);
|
|
7323
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
|
7324
|
-
}
|
|
7325
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7326
|
-
y->MaxPrec = y_prec;
|
|
7327
|
-
|
|
7328
|
-
Exit:
|
|
7329
|
-
rbd_free_struct(f);
|
|
7330
|
-
rbd_free_struct(r);
|
|
7331
|
-
return 1;
|
|
7332
|
-
}
|
|
7333
|
-
|
|
7334
5855
|
/*
|
|
7335
5856
|
* Round relatively from the decimal point.
|
|
7336
5857
|
* f: rounding mode
|
|
@@ -7507,7 +6028,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
7507
6028
|
DECDIG v;
|
|
7508
6029
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
|
7509
6030
|
v = y->frac[0];
|
|
7510
|
-
nf -=
|
|
6031
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
|
7511
6032
|
while ((v /= 10) != 0) nf--;
|
|
7512
6033
|
nf += (ssize_t)BASE_FIG-1;
|
|
7513
6034
|
return VpMidRound(y, f, nf);
|
|
@@ -7614,7 +6135,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7614
6135
|
size_t my, ind_y, ind_x;
|
|
7615
6136
|
|
|
7616
6137
|
if (!VpHasVal(x)) {
|
|
7617
|
-
VpAsgn(y, x,
|
|
6138
|
+
VpAsgn(y, x, 10);
|
|
7618
6139
|
goto Exit;
|
|
7619
6140
|
}
|
|
7620
6141
|
|
|
@@ -7623,7 +6144,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7623
6144
|
goto Exit;
|
|
7624
6145
|
}
|
|
7625
6146
|
else if (x->exponent <= 0) {
|
|
7626
|
-
VpAsgn(y, x,
|
|
6147
|
+
VpAsgn(y, x, 10);
|
|
7627
6148
|
goto Exit;
|
|
7628
6149
|
}
|
|
7629
6150
|
|
|
@@ -7644,117 +6165,9 @@ VpFrac(Real *y, Real *x)
|
|
|
7644
6165
|
VpNmlz(y);
|
|
7645
6166
|
|
|
7646
6167
|
Exit:
|
|
7647
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7648
|
-
if (gfDebug) {
|
|
7649
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
|
7650
|
-
VPrint(stdout, " x=%\n", x);
|
|
7651
|
-
}
|
|
7652
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7653
6168
|
return;
|
|
7654
6169
|
}
|
|
7655
6170
|
|
|
7656
|
-
/*
|
|
7657
|
-
* y = x ** n
|
|
7658
|
-
*/
|
|
7659
|
-
VP_EXPORT int
|
|
7660
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
|
7661
|
-
{
|
|
7662
|
-
size_t s, ss;
|
|
7663
|
-
ssize_t sign;
|
|
7664
|
-
Real *w1 = NULL;
|
|
7665
|
-
Real *w2 = NULL;
|
|
7666
|
-
|
|
7667
|
-
if (VpIsZero(x)) {
|
|
7668
|
-
if (n == 0) {
|
|
7669
|
-
VpSetOne(y);
|
|
7670
|
-
goto Exit;
|
|
7671
|
-
}
|
|
7672
|
-
sign = VpGetSign(x);
|
|
7673
|
-
if (n < 0) {
|
|
7674
|
-
n = -n;
|
|
7675
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7676
|
-
VpSetInf(y, sign);
|
|
7677
|
-
}
|
|
7678
|
-
else {
|
|
7679
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7680
|
-
VpSetZero(y,sign);
|
|
7681
|
-
}
|
|
7682
|
-
goto Exit;
|
|
7683
|
-
}
|
|
7684
|
-
if (VpIsNaN(x)) {
|
|
7685
|
-
VpSetNaN(y);
|
|
7686
|
-
goto Exit;
|
|
7687
|
-
}
|
|
7688
|
-
if (VpIsInf(x)) {
|
|
7689
|
-
if (n == 0) {
|
|
7690
|
-
VpSetOne(y);
|
|
7691
|
-
goto Exit;
|
|
7692
|
-
}
|
|
7693
|
-
if (n > 0) {
|
|
7694
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7695
|
-
goto Exit;
|
|
7696
|
-
}
|
|
7697
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7698
|
-
goto Exit;
|
|
7699
|
-
}
|
|
7700
|
-
|
|
7701
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
|
7702
|
-
/* abs(x) = 1 */
|
|
7703
|
-
VpSetOne(y);
|
|
7704
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
|
7705
|
-
if ((n % 2) == 0) goto Exit;
|
|
7706
|
-
VpSetSign(y, -1);
|
|
7707
|
-
goto Exit;
|
|
7708
|
-
}
|
|
7709
|
-
|
|
7710
|
-
if (n > 0) sign = 1;
|
|
7711
|
-
else if (n < 0) {
|
|
7712
|
-
sign = -1;
|
|
7713
|
-
n = -n;
|
|
7714
|
-
}
|
|
7715
|
-
else {
|
|
7716
|
-
VpSetOne(y);
|
|
7717
|
-
goto Exit;
|
|
7718
|
-
}
|
|
7719
|
-
|
|
7720
|
-
/* Allocate working variables */
|
|
7721
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
|
7722
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
|
7723
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
|
7724
|
-
|
|
7725
|
-
/* calculation start */
|
|
7726
|
-
|
|
7727
|
-
VpAsgn(y, x, 1);
|
|
7728
|
-
--n;
|
|
7729
|
-
while (n > 0) {
|
|
7730
|
-
VpAsgn(w1, x, 1);
|
|
7731
|
-
s = 1;
|
|
7732
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
|
7733
|
-
VpMult(w2, w1, w1);
|
|
7734
|
-
VpAsgn(w1, w2, 1);
|
|
7735
|
-
}
|
|
7736
|
-
n -= (SIGNED_VALUE)ss;
|
|
7737
|
-
VpMult(w2, y, w1);
|
|
7738
|
-
VpAsgn(y, w2, 1);
|
|
7739
|
-
}
|
|
7740
|
-
if (sign < 0) {
|
|
7741
|
-
VpDivd(w1, w2, VpConstOne, y);
|
|
7742
|
-
VpAsgn(y, w1, 1);
|
|
7743
|
-
}
|
|
7744
|
-
|
|
7745
|
-
Exit:
|
|
7746
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7747
|
-
if (gfDebug) {
|
|
7748
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
|
7749
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
|
7750
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
|
7751
|
-
}
|
|
7752
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7753
|
-
rbd_free_struct(w2);
|
|
7754
|
-
rbd_free_struct(w1);
|
|
7755
|
-
return 1;
|
|
7756
|
-
}
|
|
7757
|
-
|
|
7758
6171
|
#ifdef BIGDECIMAL_DEBUG
|
|
7759
6172
|
int
|
|
7760
6173
|
VpVarCheck(Real * v)
|