bigdecimal 3.2.2 → 4.1.1
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 +972 -2552
- 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 +7 -8
- 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 +828 -132
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +16 -15
- data/lib/bigdecimal.rb +391 -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 +8 -3
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.1"
|
|
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,37 +363,7 @@ 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
|
|
@@ -623,10 +477,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
|
623
477
|
static void
|
|
624
478
|
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
|
625
479
|
{
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
VpCountPrecisionAndScale(p, out_precision, out_scale);
|
|
480
|
+
BDVALUE v = GetBDValueMust(self);
|
|
481
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
|
482
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
630
483
|
}
|
|
631
484
|
|
|
632
485
|
/*
|
|
@@ -664,8 +517,8 @@ BigDecimal_precision(VALUE self)
|
|
|
664
517
|
* BigDecimal("1").scale # => 0
|
|
665
518
|
* BigDecimal("1.1").scale # => 1
|
|
666
519
|
* BigDecimal("3.1415").scale # => 4
|
|
667
|
-
* BigDecimal("-1e20").
|
|
668
|
-
* BigDecimal("1e-20").
|
|
520
|
+
* BigDecimal("-1e20").scale # => 0
|
|
521
|
+
* BigDecimal("1e-20").scale # => 20
|
|
669
522
|
* BigDecimal("Infinity").scale # => 0
|
|
670
523
|
* BigDecimal("-Infinity").scale # => 0
|
|
671
524
|
* BigDecimal("NaN").scale # => 0
|
|
@@ -715,25 +568,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
|
715
568
|
static VALUE
|
|
716
569
|
BigDecimal_n_significant_digits(VALUE self)
|
|
717
570
|
{
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
Real *p;
|
|
721
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
722
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
571
|
+
BDVALUE v = GetBDValueMust(self);
|
|
572
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
|
723
573
|
return INT2FIX(0);
|
|
724
574
|
}
|
|
725
575
|
|
|
726
|
-
ssize_t n =
|
|
727
|
-
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);
|
|
728
578
|
if (n == 0) return INT2FIX(0);
|
|
729
579
|
|
|
730
580
|
DECDIG x;
|
|
731
581
|
int nlz = BASE_FIG;
|
|
732
|
-
for (x =
|
|
582
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
|
733
583
|
|
|
734
584
|
int ntz = 0;
|
|
735
|
-
for (x =
|
|
585
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
|
736
586
|
|
|
587
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
737
588
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
|
738
589
|
return SSIZET2NUM(n_significant_digits);
|
|
739
590
|
}
|
|
@@ -755,17 +606,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
|
755
606
|
static VALUE
|
|
756
607
|
BigDecimal_hash(VALUE self)
|
|
757
608
|
{
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
st_index_t hash;
|
|
761
|
-
|
|
762
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
763
|
-
hash = (st_index_t)p->sign;
|
|
609
|
+
BDVALUE v = GetBDValueMust(self);
|
|
610
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
|
764
611
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
|
765
612
|
if(hash == 2 || hash == (st_index_t)-2) {
|
|
766
|
-
hash ^= rb_memhash(
|
|
767
|
-
hash +=
|
|
613
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
|
614
|
+
hash += v.real->exponent;
|
|
768
615
|
}
|
|
616
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
769
617
|
return ST2FIX(hash);
|
|
770
618
|
}
|
|
771
619
|
|
|
@@ -784,21 +632,22 @@ BigDecimal_hash(VALUE self)
|
|
|
784
632
|
static VALUE
|
|
785
633
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
786
634
|
{
|
|
787
|
-
|
|
788
|
-
Real *vp;
|
|
635
|
+
BDVALUE v;
|
|
789
636
|
char *psz;
|
|
790
637
|
VALUE dummy;
|
|
791
638
|
volatile VALUE dump;
|
|
792
639
|
size_t len;
|
|
793
640
|
|
|
794
641
|
rb_scan_args(argc, argv, "01", &dummy);
|
|
795
|
-
|
|
796
|
-
dump = rb_str_new(0, VpNumOfChars(
|
|
642
|
+
v = GetBDValueMust(self);
|
|
643
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
|
797
644
|
psz = RSTRING_PTR(dump);
|
|
798
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
|
645
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
|
799
646
|
len = strlen(psz);
|
|
800
|
-
VpToString(
|
|
647
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
|
801
648
|
rb_str_resize(dump, strlen(psz));
|
|
649
|
+
|
|
650
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
802
651
|
return dump;
|
|
803
652
|
}
|
|
804
653
|
|
|
@@ -808,27 +657,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
|
808
657
|
static VALUE
|
|
809
658
|
BigDecimal_load(VALUE self, VALUE str)
|
|
810
659
|
{
|
|
811
|
-
|
|
812
|
-
Real *pv;
|
|
660
|
+
BDVALUE v;
|
|
813
661
|
unsigned char *pch;
|
|
814
662
|
unsigned char ch;
|
|
815
|
-
unsigned long m=0;
|
|
816
663
|
|
|
817
664
|
pch = (unsigned char *)StringValueCStr(str);
|
|
818
|
-
/* First
|
|
665
|
+
/* First skip max prec. Don't trust the value. */
|
|
819
666
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
|
820
667
|
if(!ISDIGIT(ch)) {
|
|
821
668
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
|
822
669
|
}
|
|
823
|
-
m = m*10 + (unsigned long)(ch-'0');
|
|
824
|
-
}
|
|
825
|
-
if (m > VpBaseFig()) m -= VpBaseFig();
|
|
826
|
-
GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
|
|
827
|
-
m /= VpBaseFig();
|
|
828
|
-
if (m && pv->MaxPrec > m) {
|
|
829
|
-
pv->MaxPrec = m+1;
|
|
830
670
|
}
|
|
831
|
-
|
|
671
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
672
|
+
return CheckGetValue(v);
|
|
832
673
|
}
|
|
833
674
|
|
|
834
675
|
static unsigned short
|
|
@@ -1121,22 +962,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1121
962
|
static size_t
|
|
1122
963
|
GetAddSubPrec(Real *a, Real *b)
|
|
1123
964
|
{
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
|
1129
|
-
if (mx < b->Prec) mx = b->Prec;
|
|
1130
|
-
if (a->exponent != b->exponent) {
|
|
1131
|
-
mxs = mx;
|
|
1132
|
-
d = a->exponent - b->exponent;
|
|
1133
|
-
if (d < 0) d = -d;
|
|
1134
|
-
mx = mx + (size_t)d;
|
|
1135
|
-
if (mx < mxs) {
|
|
1136
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
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);
|
|
1140
969
|
}
|
|
1141
970
|
|
|
1142
971
|
static inline SIGNED_VALUE
|
|
@@ -1156,62 +985,28 @@ check_int_precision(VALUE v)
|
|
|
1156
985
|
return n;
|
|
1157
986
|
}
|
|
1158
987
|
|
|
1159
|
-
static
|
|
1160
|
-
|
|
1161
|
-
{
|
|
1162
|
-
assert(is_kind_of_BigDecimal(obj));
|
|
1163
|
-
assert(vp != NULL);
|
|
1164
|
-
|
|
1165
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
|
1166
|
-
return obj;
|
|
1167
|
-
|
|
1168
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
1169
|
-
assert(vp->obj == 0);
|
|
1170
|
-
|
|
1171
|
-
RTYPEDDATA_DATA(obj) = vp;
|
|
1172
|
-
vp->obj = obj;
|
|
1173
|
-
RB_OBJ_FREEZE(obj);
|
|
1174
|
-
return obj;
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
VP_EXPORT Real *
|
|
1178
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1179
|
-
{
|
|
1180
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
1181
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
|
1182
|
-
if (!pv)
|
|
1183
|
-
return NULL;
|
|
1184
|
-
BigDecimal_wrap_struct(obj, pv);
|
|
1185
|
-
return pv;
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
VP_EXPORT Real *
|
|
1189
|
-
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)
|
|
1190
990
|
{
|
|
1191
|
-
return
|
|
991
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1192
992
|
}
|
|
1193
993
|
|
|
1194
|
-
|
|
1195
|
-
|
|
994
|
+
void
|
|
995
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1196
996
|
{
|
|
1197
|
-
assert(x != NULL);
|
|
1198
|
-
|
|
1199
|
-
pv = rbd_reallocate_struct(pv, x->MaxPrec);
|
|
1200
997
|
pv->MaxPrec = x->MaxPrec;
|
|
1201
998
|
pv->Prec = x->Prec;
|
|
1202
999
|
pv->exponent = x->exponent;
|
|
1203
1000
|
pv->sign = x->sign;
|
|
1204
1001
|
pv->flag = x->flag;
|
|
1205
1002
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1206
|
-
|
|
1207
|
-
return pv;
|
|
1208
1003
|
}
|
|
1209
1004
|
|
|
1210
1005
|
/* Returns True if the value is Not a Number. */
|
|
1211
1006
|
static VALUE
|
|
1212
1007
|
BigDecimal_IsNaN(VALUE self)
|
|
1213
1008
|
{
|
|
1214
|
-
Real *p =
|
|
1009
|
+
Real *p = GetSelfVpValue(self);
|
|
1215
1010
|
if (VpIsNaN(p)) return Qtrue;
|
|
1216
1011
|
return Qfalse;
|
|
1217
1012
|
}
|
|
@@ -1222,7 +1017,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
|
1222
1017
|
static VALUE
|
|
1223
1018
|
BigDecimal_IsInfinite(VALUE self)
|
|
1224
1019
|
{
|
|
1225
|
-
Real *p =
|
|
1020
|
+
Real *p = GetSelfVpValue(self);
|
|
1226
1021
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
|
1227
1022
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
|
1228
1023
|
return Qnil;
|
|
@@ -1232,7 +1027,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
|
1232
1027
|
static VALUE
|
|
1233
1028
|
BigDecimal_IsFinite(VALUE self)
|
|
1234
1029
|
{
|
|
1235
|
-
Real *p =
|
|
1030
|
+
Real *p = GetSelfVpValue(self);
|
|
1236
1031
|
if (VpIsNaN(p)) return Qfalse;
|
|
1237
1032
|
if (VpIsInf(p)) return Qfalse;
|
|
1238
1033
|
return Qtrue;
|
|
@@ -1244,8 +1039,6 @@ BigDecimal_check_num(Real *p)
|
|
|
1244
1039
|
VpCheckException(p, true);
|
|
1245
1040
|
}
|
|
1246
1041
|
|
|
1247
|
-
static VALUE BigDecimal_split(VALUE self);
|
|
1248
|
-
|
|
1249
1042
|
/* Returns the value as an Integer.
|
|
1250
1043
|
*
|
|
1251
1044
|
* If the BigDecimal is infinity or NaN, raises FloatDomainError.
|
|
@@ -1253,44 +1046,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
|
1253
1046
|
static VALUE
|
|
1254
1047
|
BigDecimal_to_i(VALUE self)
|
|
1255
1048
|
{
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
Real *p;
|
|
1049
|
+
BDVALUE v;
|
|
1050
|
+
VALUE ret;
|
|
1259
1051
|
|
|
1260
|
-
|
|
1261
|
-
BigDecimal_check_num(
|
|
1052
|
+
v = GetBDValueMust(self);
|
|
1053
|
+
BigDecimal_check_num(v.real);
|
|
1262
1054
|
|
|
1263
|
-
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1266
|
-
if (e <= nf) {
|
|
1267
|
-
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]));
|
|
1268
1058
|
}
|
|
1269
1059
|
else {
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
ret = rb_funcall(numerator, '*', 1,
|
|
1286
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
|
1287
|
-
INT2FIX(dpower)));
|
|
1288
|
-
}
|
|
1289
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
|
1290
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1291
|
-
}
|
|
1292
|
-
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
|
+
}
|
|
1293
1075
|
}
|
|
1076
|
+
|
|
1077
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1078
|
+
return ret;
|
|
1294
1079
|
}
|
|
1295
1080
|
|
|
1296
1081
|
/* Returns a new Float object having approximately the same value as the
|
|
@@ -1300,24 +1085,26 @@ BigDecimal_to_i(VALUE self)
|
|
|
1300
1085
|
static VALUE
|
|
1301
1086
|
BigDecimal_to_f(VALUE self)
|
|
1302
1087
|
{
|
|
1303
|
-
ENTER(1);
|
|
1304
|
-
Real *p;
|
|
1305
1088
|
double d;
|
|
1306
1089
|
SIGNED_VALUE e;
|
|
1307
1090
|
char *buf;
|
|
1308
1091
|
volatile VALUE str;
|
|
1092
|
+
BDVALUE v = GetBDValueMust(self);
|
|
1093
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
|
1309
1094
|
|
|
1310
|
-
|
|
1311
|
-
if (VpVtoD(&d, &e, p) != 1)
|
|
1095
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
|
1312
1096
|
return rb_float_new(d);
|
|
1313
1097
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
|
1314
1098
|
goto overflow;
|
|
1315
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
|
1099
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
|
1316
1100
|
goto underflow;
|
|
1317
1101
|
|
|
1318
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
1102
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
1319
1103
|
buf = RSTRING_PTR(str);
|
|
1320
|
-
VpToString(
|
|
1104
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
|
1105
|
+
|
|
1106
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1107
|
+
|
|
1321
1108
|
errno = 0;
|
|
1322
1109
|
d = strtod(buf, 0);
|
|
1323
1110
|
if (errno == ERANGE) {
|
|
@@ -1328,14 +1115,14 @@ BigDecimal_to_f(VALUE self)
|
|
|
1328
1115
|
|
|
1329
1116
|
overflow:
|
|
1330
1117
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
|
1331
|
-
if (
|
|
1118
|
+
if (negative)
|
|
1332
1119
|
return rb_float_new(VpGetDoubleNegInf());
|
|
1333
1120
|
else
|
|
1334
1121
|
return rb_float_new(VpGetDoublePosInf());
|
|
1335
1122
|
|
|
1336
1123
|
underflow:
|
|
1337
1124
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
|
1338
|
-
if (
|
|
1125
|
+
if (negative)
|
|
1339
1126
|
return rb_float_new(-0.0);
|
|
1340
1127
|
else
|
|
1341
1128
|
return rb_float_new(0.0);
|
|
@@ -1347,15 +1134,16 @@ underflow:
|
|
|
1347
1134
|
static VALUE
|
|
1348
1135
|
BigDecimal_to_r(VALUE self)
|
|
1349
1136
|
{
|
|
1350
|
-
|
|
1137
|
+
BDVALUE v;
|
|
1351
1138
|
ssize_t sign, power, denomi_power;
|
|
1352
1139
|
VALUE a, digits, numerator;
|
|
1353
1140
|
|
|
1354
|
-
|
|
1355
|
-
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);
|
|
1356
1146
|
|
|
1357
|
-
sign = VpGetSign(p);
|
|
1358
|
-
power = VpExponent10(p);
|
|
1359
1147
|
a = BigDecimal_split(self);
|
|
1360
1148
|
digits = RARRAY_AREF(a, 1);
|
|
1361
1149
|
denomi_power = power - RSTRING_LEN(digits);
|
|
@@ -1376,6 +1164,14 @@ BigDecimal_to_r(VALUE self)
|
|
|
1376
1164
|
}
|
|
1377
1165
|
}
|
|
1378
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
|
+
|
|
1379
1175
|
/* The coerce method provides support for Ruby type coercion. It is not
|
|
1380
1176
|
* enabled by default.
|
|
1381
1177
|
*
|
|
@@ -1393,26 +1189,9 @@ BigDecimal_to_r(VALUE self)
|
|
|
1393
1189
|
static VALUE
|
|
1394
1190
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1395
1191
|
{
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
|
1401
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
|
1402
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
|
1403
|
-
}
|
|
1404
|
-
else {
|
|
1405
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
|
1406
|
-
Real* pv = DATA_PTR(self);
|
|
1407
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
|
1408
|
-
}
|
|
1409
|
-
else {
|
|
1410
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
|
1411
|
-
}
|
|
1412
|
-
obj = rb_assoc_new(b->obj, self);
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
return obj;
|
|
1192
|
+
Real* pv = VpPtr(self);
|
|
1193
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1194
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
|
1416
1195
|
}
|
|
1417
1196
|
|
|
1418
1197
|
/*
|
|
@@ -1432,6 +1211,15 @@ BigDecimal_uplus(VALUE self)
|
|
|
1432
1211
|
return self;
|
|
1433
1212
|
}
|
|
1434
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
|
+
|
|
1435
1223
|
/*
|
|
1436
1224
|
* call-seq:
|
|
1437
1225
|
* self + value -> bigdecimal
|
|
@@ -1451,42 +1239,59 @@ BigDecimal_uplus(VALUE self)
|
|
|
1451
1239
|
static VALUE
|
|
1452
1240
|
BigDecimal_add(VALUE self, VALUE r)
|
|
1453
1241
|
{
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1242
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
|
1243
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
|
1244
|
+
}
|
|
1457
1245
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1464
|
-
}
|
|
1465
|
-
else {
|
|
1466
|
-
b = GetVpValue(r, 0);
|
|
1467
|
-
}
|
|
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;
|
|
1468
1251
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1252
|
+
a = GetBDValueMust(self);
|
|
1253
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1471
1254
|
|
|
1472
|
-
if (VpIsNaN(
|
|
1473
|
-
if (VpIsNaN(
|
|
1255
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1256
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1474
1257
|
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
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);
|
|
1479
1261
|
}
|
|
1480
1262
|
else {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
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
|
+
}
|
|
1487
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);
|
|
1488
1290
|
}
|
|
1489
|
-
|
|
1291
|
+
|
|
1292
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1293
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1294
|
+
return CheckGetValue(c);
|
|
1490
1295
|
}
|
|
1491
1296
|
|
|
1492
1297
|
/*
|
|
@@ -1507,73 +1312,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
|
1507
1312
|
static VALUE
|
|
1508
1313
|
BigDecimal_sub(VALUE self, VALUE r)
|
|
1509
1314
|
{
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
size_t mx;
|
|
1513
|
-
|
|
1514
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
|
1515
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1516
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1517
|
-
}
|
|
1518
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1519
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1520
|
-
}
|
|
1521
|
-
else {
|
|
1522
|
-
b = GetVpValue(r,0);
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
if (!b) return DoSomeOne(self,r,'-');
|
|
1526
|
-
SAVE(b);
|
|
1527
|
-
|
|
1528
|
-
if (VpIsNaN(b)) return b->obj;
|
|
1529
|
-
if (VpIsNaN(a)) return a->obj;
|
|
1530
|
-
|
|
1531
|
-
mx = GetAddSubPrec(a,b);
|
|
1532
|
-
if (mx == (size_t)-1L) {
|
|
1533
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
|
1534
|
-
VpAddSub(c, a, b, -1);
|
|
1535
|
-
}
|
|
1536
|
-
else {
|
|
1537
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
|
|
1538
|
-
if (!mx) {
|
|
1539
|
-
VpSetInf(c,VpGetSign(a));
|
|
1540
|
-
}
|
|
1541
|
-
else {
|
|
1542
|
-
VpAddSub(c, a, b, -1);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
return VpCheckGetValue(c);
|
|
1315
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
|
1316
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
|
1546
1317
|
}
|
|
1547
1318
|
|
|
1548
1319
|
static VALUE
|
|
1549
1320
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1550
1321
|
{
|
|
1551
|
-
ENTER(5);
|
|
1552
1322
|
SIGNED_VALUE e;
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
switch (TYPE(r)) {
|
|
1556
|
-
case T_DATA:
|
|
1557
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
|
1558
|
-
/* fall through */
|
|
1559
|
-
case T_FIXNUM:
|
|
1560
|
-
/* fall through */
|
|
1561
|
-
case T_BIGNUM:
|
|
1562
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
|
1563
|
-
break;
|
|
1323
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1324
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1564
1325
|
|
|
1565
|
-
|
|
1566
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
|
1567
|
-
break;
|
|
1568
|
-
|
|
1569
|
-
case T_RATIONAL:
|
|
1570
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
|
1571
|
-
break;
|
|
1572
|
-
|
|
1573
|
-
default:
|
|
1574
|
-
break;
|
|
1575
|
-
}
|
|
1576
|
-
if (b == NULL) {
|
|
1326
|
+
if (b.real_or_null == NULL) {
|
|
1577
1327
|
ID f = 0;
|
|
1578
1328
|
|
|
1579
1329
|
switch (op) {
|
|
@@ -1602,8 +1352,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1602
1352
|
}
|
|
1603
1353
|
return rb_num_coerce_relop(self, r, f);
|
|
1604
1354
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
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
|
+
|
|
1607
1360
|
if (e == 999)
|
|
1608
1361
|
return (op == '*') ? Qnil : Qfalse;
|
|
1609
1362
|
switch (op) {
|
|
@@ -1643,7 +1396,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1643
1396
|
static VALUE
|
|
1644
1397
|
BigDecimal_zero(VALUE self)
|
|
1645
1398
|
{
|
|
1646
|
-
Real *a =
|
|
1399
|
+
Real *a = GetSelfVpValue(self);
|
|
1647
1400
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
|
1648
1401
|
}
|
|
1649
1402
|
|
|
@@ -1651,7 +1404,7 @@ BigDecimal_zero(VALUE self)
|
|
|
1651
1404
|
static VALUE
|
|
1652
1405
|
BigDecimal_nonzero(VALUE self)
|
|
1653
1406
|
{
|
|
1654
|
-
Real *a =
|
|
1407
|
+
Real *a = GetSelfVpValue(self);
|
|
1655
1408
|
return VpIsZero(a) ? Qnil : self;
|
|
1656
1409
|
}
|
|
1657
1410
|
|
|
@@ -1777,12 +1530,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
|
1777
1530
|
static VALUE
|
|
1778
1531
|
BigDecimal_neg(VALUE self)
|
|
1779
1532
|
{
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
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);
|
|
1786
1538
|
}
|
|
1787
1539
|
|
|
1788
1540
|
/*
|
|
@@ -1795,35 +1547,36 @@ BigDecimal_neg(VALUE self)
|
|
|
1795
1547
|
*
|
|
1796
1548
|
* See BigDecimal#mult.
|
|
1797
1549
|
*/
|
|
1798
|
-
|
|
1799
1550
|
static VALUE
|
|
1800
1551
|
BigDecimal_mult(VALUE self, VALUE r)
|
|
1801
1552
|
{
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1553
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
|
1554
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
|
1555
|
+
}
|
|
1805
1556
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1557
|
+
static VALUE
|
|
1558
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
|
1559
|
+
{
|
|
1560
|
+
BDVALUE a, b, c;
|
|
1561
|
+
|
|
1562
|
+
a = GetBDValueMust(self);
|
|
1563
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1564
|
+
|
|
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);
|
|
1812
1569
|
}
|
|
1813
1570
|
else {
|
|
1814
|
-
|
|
1571
|
+
VpLimitRound(c.real, 0);
|
|
1815
1572
|
}
|
|
1816
1573
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
mx = a->Prec + b->Prec;
|
|
1821
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
|
1822
|
-
VpMult(c, a, b);
|
|
1823
|
-
return VpCheckGetValue(c);
|
|
1574
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1575
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1576
|
+
return CheckGetValue(c);
|
|
1824
1577
|
}
|
|
1825
1578
|
|
|
1826
|
-
static
|
|
1579
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
|
1827
1580
|
|
|
1828
1581
|
/* call-seq:
|
|
1829
1582
|
* a / b -> bigdecimal
|
|
@@ -1840,14 +1593,7 @@ static VALUE
|
|
|
1840
1593
|
BigDecimal_div(VALUE self, VALUE r)
|
|
1841
1594
|
/* For c = self/r: with round operation */
|
|
1842
1595
|
{
|
|
1843
|
-
if (
|
|
1844
|
-
!is_kind_of_BigDecimal(r) &&
|
|
1845
|
-
!RB_INTEGER_TYPE_P(r) &&
|
|
1846
|
-
!RB_TYPE_P(r, T_FLOAT) &&
|
|
1847
|
-
!RB_TYPE_P(r, T_RATIONAL)
|
|
1848
|
-
) {
|
|
1849
|
-
return DoSomeOne(self, r, '/');
|
|
1850
|
-
}
|
|
1596
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
|
1851
1597
|
return BigDecimal_div2(self, r, INT2FIX(0));
|
|
1852
1598
|
}
|
|
1853
1599
|
|
|
@@ -1893,114 +1639,110 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
|
1893
1639
|
/*
|
|
1894
1640
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
|
1895
1641
|
* div = (a.to_f/b).floor
|
|
1642
|
+
* In truncate mode, use truncate instead of floor.
|
|
1896
1643
|
*/
|
|
1897
|
-
static
|
|
1898
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
|
1644
|
+
static bool
|
|
1645
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
|
1899
1646
|
{
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
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;
|
|
1905
1651
|
|
|
1906
|
-
|
|
1907
|
-
SAVE(a);
|
|
1652
|
+
a = GetBDValueMust(self);
|
|
1908
1653
|
|
|
1909
|
-
|
|
1910
|
-
if (
|
|
1911
|
-
|
|
1912
|
-
}
|
|
1913
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1914
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1915
|
-
}
|
|
1916
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1917
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1918
|
-
}
|
|
1919
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1920
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1921
|
-
}
|
|
1654
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1655
|
+
if (!b2.real_or_null) return false;
|
|
1656
|
+
b = bdvalue_nonnullable(b2);
|
|
1922
1657
|
|
|
1923
|
-
if (
|
|
1924
|
-
|
|
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;
|
|
1925
1662
|
}
|
|
1926
|
-
|
|
1927
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
|
1928
|
-
SAVE(b);
|
|
1929
|
-
|
|
1930
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
|
1931
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
|
1932
|
-
if (VpIsZero(b)) {
|
|
1663
|
+
if (VpIsZero(b.real)) {
|
|
1933
1664
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
|
1934
1665
|
}
|
|
1935
|
-
if (VpIsInf(a)) {
|
|
1936
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
|
1666
|
+
if (VpIsInf(a.real)) {
|
|
1667
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1937
1668
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1938
|
-
|
|
1669
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1939
1670
|
}
|
|
1940
1671
|
else {
|
|
1941
1672
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1942
|
-
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1943
1674
|
}
|
|
1944
1675
|
VALUE nan = BigDecimal_nan();
|
|
1945
|
-
|
|
1946
|
-
|
|
1676
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1677
|
+
goto Done;
|
|
1947
1678
|
}
|
|
1948
|
-
if (
|
|
1679
|
+
if (VpIsZero(a.real)) {
|
|
1949
1680
|
VALUE zero = BigDecimal_positive_zero();
|
|
1950
|
-
|
|
1951
|
-
*mod = a;
|
|
1952
|
-
|
|
1953
|
-
}
|
|
1954
|
-
if (
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
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);
|
|
1980
1720
|
|
|
1981
|
-
if (!VpIsZero(
|
|
1721
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
|
1982
1722
|
/* result adjustment for negative case */
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
VpAddSub(
|
|
1988
|
-
|
|
1989
|
-
*
|
|
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);
|
|
1990
1733
|
}
|
|
1991
1734
|
else {
|
|
1992
|
-
*div =
|
|
1993
|
-
*mod =
|
|
1735
|
+
*div = bdvalue_nullable(dv);
|
|
1736
|
+
*mod = bdvalue_nullable(md);
|
|
1994
1737
|
}
|
|
1995
|
-
return Qtrue;
|
|
1996
1738
|
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
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;
|
|
2004
1746
|
}
|
|
2005
1747
|
|
|
2006
1748
|
/* call-seq:
|
|
@@ -2014,69 +1756,14 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
|
2014
1756
|
static VALUE
|
|
2015
1757
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
|
2016
1758
|
{
|
|
2017
|
-
|
|
2018
|
-
Real *div = NULL, *mod = NULL;
|
|
1759
|
+
NULLABLE_BDVALUE div, mod;
|
|
2019
1760
|
|
|
2020
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2021
|
-
|
|
2022
|
-
return VpCheckGetValue(mod);
|
|
1761
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1762
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
2023
1763
|
}
|
|
2024
1764
|
return DoSomeOne(self, r, '%');
|
|
2025
1765
|
}
|
|
2026
1766
|
|
|
2027
|
-
static VALUE
|
|
2028
|
-
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
2029
|
-
{
|
|
2030
|
-
ENTER(10);
|
|
2031
|
-
size_t mx;
|
|
2032
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
|
2033
|
-
Real *f = NULL;
|
|
2034
|
-
|
|
2035
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2036
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
2037
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
2038
|
-
}
|
|
2039
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
2040
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
2041
|
-
}
|
|
2042
|
-
else {
|
|
2043
|
-
b = GetVpValue(r, 0);
|
|
2044
|
-
}
|
|
2045
|
-
|
|
2046
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2047
|
-
SAVE(b);
|
|
2048
|
-
|
|
2049
|
-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
|
|
2050
|
-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
|
|
2051
|
-
VpSetZero(*dv, 1);
|
|
2052
|
-
*rv = a;
|
|
2053
|
-
return Qnil;
|
|
2054
|
-
}
|
|
2055
|
-
|
|
2056
|
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
|
|
2057
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2058
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2059
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2060
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2061
|
-
|
|
2062
|
-
VpDivd(c, res, a, b);
|
|
2063
|
-
|
|
2064
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
|
2065
|
-
|
|
2066
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
|
2067
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
|
2068
|
-
|
|
2069
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2070
|
-
|
|
2071
|
-
VpFrac(f, c);
|
|
2072
|
-
VpMult(rr, f, b);
|
|
2073
|
-
VpAddSub(ff, res, rr, 1);
|
|
2074
|
-
|
|
2075
|
-
*dv = d;
|
|
2076
|
-
*rv = ff;
|
|
2077
|
-
return Qnil;
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
1767
|
/* call-seq:
|
|
2081
1768
|
* remainder(value)
|
|
2082
1769
|
*
|
|
@@ -2087,11 +1774,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
|
2087
1774
|
static VALUE
|
|
2088
1775
|
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2089
1776
|
{
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
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"));
|
|
2095
1783
|
}
|
|
2096
1784
|
|
|
2097
1785
|
/* call-seq:
|
|
@@ -2119,12 +1807,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
|
2119
1807
|
static VALUE
|
|
2120
1808
|
BigDecimal_divmod(VALUE self, VALUE r)
|
|
2121
1809
|
{
|
|
2122
|
-
|
|
2123
|
-
Real *div = NULL, *mod = NULL;
|
|
1810
|
+
NULLABLE_BDVALUE div, mod;
|
|
2124
1811
|
|
|
2125
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2126
|
-
|
|
2127
|
-
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)));
|
|
2128
1814
|
}
|
|
2129
1815
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
2130
1816
|
}
|
|
@@ -2136,17 +1822,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
2136
1822
|
static inline VALUE
|
|
2137
1823
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2138
1824
|
{
|
|
2139
|
-
ENTER(5);
|
|
2140
1825
|
SIGNED_VALUE ix;
|
|
2141
|
-
|
|
2142
|
-
Real *av = NULL, *bv = NULL, *cv = NULL;
|
|
2143
|
-
size_t mx, pl;
|
|
1826
|
+
BDVALUE av, bv, cv, res;
|
|
2144
1827
|
|
|
2145
1828
|
if (NIL_P(n)) { /* div in Float sense */
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
|
2149
|
-
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)));
|
|
2150
1833
|
}
|
|
2151
1834
|
return DoSomeOne(self, b, rb_intern("div"));
|
|
2152
1835
|
}
|
|
@@ -2154,48 +1837,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
|
2154
1837
|
/* div in BigDecimal sense */
|
|
2155
1838
|
ix = check_int_precision(n);
|
|
2156
1839
|
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
GUARD_OBJ(av, GetVpValue(self, 1));
|
|
2161
|
-
if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
2162
|
-
/* TODO: I want to refactor this precision control for a float value later
|
|
2163
|
-
* by introducing an implicit conversion function instead of
|
|
2164
|
-
* GetVpValueWithPrec. */
|
|
2165
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1));
|
|
2166
|
-
}
|
|
2167
|
-
else {
|
|
2168
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1));
|
|
2169
|
-
}
|
|
1840
|
+
av = GetBDValueMust(self);
|
|
1841
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
|
2170
1842
|
|
|
2171
1843
|
if (ix == 0) {
|
|
2172
|
-
ssize_t a_prec, b_prec;
|
|
2173
|
-
VpCountPrecisionAndScale(av, &a_prec, NULL);
|
|
2174
|
-
VpCountPrecisionAndScale(bv, &b_prec, NULL);
|
|
1844
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
|
1845
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
|
1846
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
|
2175
1847
|
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
|
2176
1848
|
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
|
2177
1849
|
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1850
|
+
if (limit && limit < ix) ix = limit;
|
|
2178
1851
|
}
|
|
2179
1852
|
|
|
2180
|
-
//
|
|
2181
|
-
|
|
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);
|
|
2182
1857
|
|
|
2183
|
-
|
|
2184
|
-
if (mx <= av->Prec) mx = av->Prec + 1;
|
|
2185
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig()));
|
|
2186
|
-
VpDivd(cv, res, av, bv);
|
|
2187
|
-
VpSetPrecLimit(pl);
|
|
2188
|
-
if (!VpIsZero(res)) {
|
|
1858
|
+
if (!VpIsZero(res.real)) {
|
|
2189
1859
|
// Remainder value affects rounding result.
|
|
2190
|
-
// ROUND_UP cv = 0.1e0 with
|
|
1860
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
|
2191
1861
|
// 0.1e0 if remainder == 0
|
|
2192
1862
|
// 0.1000000001e0 if remainder != 0
|
|
2193
1863
|
size_t idx = roomof(ix, BASE_FIG);
|
|
2194
|
-
while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0;
|
|
2195
|
-
if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++;
|
|
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]++;
|
|
2196
1866
|
}
|
|
2197
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
|
2198
|
-
|
|
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);
|
|
2199
1873
|
}
|
|
2200
1874
|
|
|
2201
1875
|
/*
|
|
@@ -2271,18 +1945,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
|
2271
1945
|
static VALUE
|
|
2272
1946
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2273
1947
|
{
|
|
2274
|
-
|
|
2275
|
-
Real *cv;
|
|
2276
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2277
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
|
2278
|
-
else {
|
|
2279
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2280
|
-
VALUE c = BigDecimal_add(self, b);
|
|
2281
|
-
VpSetPrecLimit(pl);
|
|
2282
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2283
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2284
|
-
return VpCheckGetValue(cv);
|
|
2285
|
-
}
|
|
1948
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
|
2286
1949
|
}
|
|
2287
1950
|
|
|
2288
1951
|
/* call-seq:
|
|
@@ -2301,18 +1964,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
|
2301
1964
|
static VALUE
|
|
2302
1965
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2303
1966
|
{
|
|
2304
|
-
|
|
2305
|
-
Real *cv;
|
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2307
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
|
2308
|
-
else {
|
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2310
|
-
VALUE c = BigDecimal_sub(self, b);
|
|
2311
|
-
VpSetPrecLimit(pl);
|
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2314
|
-
return VpCheckGetValue(cv);
|
|
2315
|
-
}
|
|
1967
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
|
2316
1968
|
}
|
|
2317
1969
|
|
|
2318
1970
|
/*
|
|
@@ -2344,18 +1996,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
|
2344
1996
|
static VALUE
|
|
2345
1997
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2346
1998
|
{
|
|
2347
|
-
|
|
2348
|
-
Real *cv;
|
|
2349
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2350
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
|
2351
|
-
else {
|
|
2352
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2353
|
-
VALUE c = BigDecimal_mult(self, b);
|
|
2354
|
-
VpSetPrecLimit(pl);
|
|
2355
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2356
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2357
|
-
return VpCheckGetValue(cv);
|
|
2358
|
-
}
|
|
1999
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
|
2359
2000
|
}
|
|
2360
2001
|
|
|
2361
2002
|
/*
|
|
@@ -2372,41 +2013,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
|
2372
2013
|
static VALUE
|
|
2373
2014
|
BigDecimal_abs(VALUE self)
|
|
2374
2015
|
{
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2382
|
-
VpAsgn(c, a, 1);
|
|
2383
|
-
VpChangeSign(c, 1);
|
|
2384
|
-
return VpCheckGetValue(c);
|
|
2385
|
-
}
|
|
2386
|
-
|
|
2387
|
-
/* call-seq:
|
|
2388
|
-
* sqrt(n)
|
|
2389
|
-
*
|
|
2390
|
-
* Returns the square root of the value.
|
|
2391
|
-
*
|
|
2392
|
-
* Result has at least n significant digits.
|
|
2393
|
-
*/
|
|
2394
|
-
static VALUE
|
|
2395
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2396
|
-
{
|
|
2397
|
-
ENTER(5);
|
|
2398
|
-
Real *c, *a;
|
|
2399
|
-
size_t mx, n;
|
|
2400
|
-
|
|
2401
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2402
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2403
|
-
|
|
2404
|
-
n = check_int_precision(nFig);
|
|
2405
|
-
n += VpDblFig() + VpBaseFig();
|
|
2406
|
-
if (mx <= n) mx = n;
|
|
2407
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2408
|
-
VpSqrt(c, a);
|
|
2409
|
-
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);
|
|
2410
2022
|
}
|
|
2411
2023
|
|
|
2412
2024
|
/* Return the integer part of the number, as a BigDecimal.
|
|
@@ -2414,15 +2026,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
|
2414
2026
|
static VALUE
|
|
2415
2027
|
BigDecimal_fix(VALUE self)
|
|
2416
2028
|
{
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
|
2423
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2424
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2425
|
-
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);
|
|
2426
2034
|
}
|
|
2427
2035
|
|
|
2428
2036
|
/* call-seq:
|
|
@@ -2454,13 +2062,12 @@ BigDecimal_fix(VALUE self)
|
|
|
2454
2062
|
static VALUE
|
|
2455
2063
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2456
2064
|
{
|
|
2457
|
-
|
|
2458
|
-
Real *c, *a;
|
|
2065
|
+
BDVALUE c, a;
|
|
2459
2066
|
int iLoc = 0;
|
|
2460
2067
|
VALUE vLoc;
|
|
2461
2068
|
VALUE vRound;
|
|
2462
2069
|
int round_to_int = 0;
|
|
2463
|
-
size_t mx
|
|
2070
|
+
size_t mx;
|
|
2464
2071
|
|
|
2465
2072
|
unsigned short sw = VpGetRoundMode();
|
|
2466
2073
|
|
|
@@ -2491,16 +2098,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2491
2098
|
break;
|
|
2492
2099
|
}
|
|
2493
2100
|
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
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
|
+
|
|
2500
2109
|
if (round_to_int) {
|
|
2501
|
-
return BigDecimal_to_i(
|
|
2110
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2111
|
+
}
|
|
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));
|
|
2502
2139
|
}
|
|
2503
|
-
return
|
|
2140
|
+
return CheckGetValue(c);
|
|
2504
2141
|
}
|
|
2505
2142
|
|
|
2506
2143
|
/* call-seq:
|
|
@@ -2525,28 +2162,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2525
2162
|
static VALUE
|
|
2526
2163
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2527
2164
|
{
|
|
2528
|
-
|
|
2529
|
-
Real *c, *a;
|
|
2530
|
-
int iLoc;
|
|
2531
|
-
VALUE vLoc;
|
|
2532
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2533
|
-
|
|
2534
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2535
|
-
iLoc = 0;
|
|
2536
|
-
}
|
|
2537
|
-
else {
|
|
2538
|
-
iLoc = NUM2INT(vLoc);
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2541
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2542
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2543
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2544
|
-
VpSetPrecLimit(pl);
|
|
2545
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
|
2546
|
-
if (argc == 0) {
|
|
2547
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2548
|
-
}
|
|
2549
|
-
return VpCheckGetValue(c);
|
|
2165
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
|
2550
2166
|
}
|
|
2551
2167
|
|
|
2552
2168
|
/* Return the fractional part of the number, as a BigDecimal.
|
|
@@ -2554,15 +2170,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
|
2554
2170
|
static VALUE
|
|
2555
2171
|
BigDecimal_frac(VALUE self)
|
|
2556
2172
|
{
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2563
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2564
|
-
VpFrac(c, a);
|
|
2565
|
-
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);
|
|
2566
2178
|
}
|
|
2567
2179
|
|
|
2568
2180
|
/* call-seq:
|
|
@@ -2585,31 +2197,7 @@ BigDecimal_frac(VALUE self)
|
|
|
2585
2197
|
static VALUE
|
|
2586
2198
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2587
2199
|
{
|
|
2588
|
-
|
|
2589
|
-
Real *c, *a;
|
|
2590
|
-
int iLoc;
|
|
2591
|
-
VALUE vLoc;
|
|
2592
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2593
|
-
|
|
2594
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
|
2595
|
-
iLoc = 0;
|
|
2596
|
-
}
|
|
2597
|
-
else {
|
|
2598
|
-
iLoc = NUM2INT(vLoc);
|
|
2599
|
-
}
|
|
2600
|
-
|
|
2601
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2602
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2603
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2604
|
-
VpSetPrecLimit(pl);
|
|
2605
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
|
2606
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
2607
|
-
VPrint(stderr, "floor: c=%\n", c);
|
|
2608
|
-
#endif
|
|
2609
|
-
if (argc == 0) {
|
|
2610
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2611
|
-
}
|
|
2612
|
-
return VpCheckGetValue(c);
|
|
2200
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
|
2613
2201
|
}
|
|
2614
2202
|
|
|
2615
2203
|
/* call-seq:
|
|
@@ -2632,27 +2220,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
|
2632
2220
|
static VALUE
|
|
2633
2221
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2634
2222
|
{
|
|
2635
|
-
|
|
2636
|
-
Real *c, *a;
|
|
2637
|
-
int iLoc;
|
|
2638
|
-
VALUE vLoc;
|
|
2639
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2640
|
-
|
|
2641
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2642
|
-
iLoc = 0;
|
|
2643
|
-
} else {
|
|
2644
|
-
iLoc = NUM2INT(vLoc);
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2648
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2649
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2650
|
-
VpSetPrecLimit(pl);
|
|
2651
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
|
2652
|
-
if (argc == 0) {
|
|
2653
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2654
|
-
}
|
|
2655
|
-
return VpCheckGetValue(c);
|
|
2223
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
|
2656
2224
|
}
|
|
2657
2225
|
|
|
2658
2226
|
/* call-seq:
|
|
@@ -2673,7 +2241,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2673
2241
|
* If s contains a number, a space is inserted after each group of that many
|
|
2674
2242
|
* digits, starting from '.' and counting outwards.
|
|
2675
2243
|
*
|
|
2676
|
-
* If s ends with an 'E',
|
|
2244
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
|
2677
2245
|
*
|
|
2678
2246
|
* If s ends with an 'F', conventional floating point notation is used.
|
|
2679
2247
|
*
|
|
@@ -2691,10 +2259,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2691
2259
|
static VALUE
|
|
2692
2260
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2693
2261
|
{
|
|
2694
|
-
ENTER(5);
|
|
2695
2262
|
int fmt = 0; /* 0: E format, 1: F format */
|
|
2696
2263
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
2697
|
-
|
|
2264
|
+
BDVALUE v;
|
|
2698
2265
|
volatile VALUE str;
|
|
2699
2266
|
char *psz;
|
|
2700
2267
|
char ch;
|
|
@@ -2702,7 +2269,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2702
2269
|
SIGNED_VALUE m;
|
|
2703
2270
|
VALUE f;
|
|
2704
2271
|
|
|
2705
|
-
|
|
2272
|
+
v = GetBDValueMust(self);
|
|
2706
2273
|
|
|
2707
2274
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
|
2708
2275
|
if (RB_TYPE_P(f, T_STRING)) {
|
|
@@ -2737,10 +2304,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2737
2304
|
}
|
|
2738
2305
|
}
|
|
2739
2306
|
if (fmt) {
|
|
2740
|
-
nc = VpNumOfChars(
|
|
2307
|
+
nc = VpNumOfChars(v.real, "F");
|
|
2741
2308
|
}
|
|
2742
2309
|
else {
|
|
2743
|
-
nc = VpNumOfChars(
|
|
2310
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2744
2311
|
}
|
|
2745
2312
|
if (mc > 0) {
|
|
2746
2313
|
nc += (nc + mc - 1) / mc + 1;
|
|
@@ -2749,494 +2316,188 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2749
2316
|
str = rb_usascii_str_new(0, nc);
|
|
2750
2317
|
psz = RSTRING_PTR(str);
|
|
2751
2318
|
|
|
2752
|
-
if (fmt) {
|
|
2753
|
-
VpToFString(
|
|
2754
|
-
}
|
|
2755
|
-
else {
|
|
2756
|
-
VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2757
|
-
}
|
|
2758
|
-
rb_str_resize(str, strlen(psz));
|
|
2759
|
-
return str;
|
|
2760
|
-
}
|
|
2761
|
-
|
|
2762
|
-
/* Splits a BigDecimal number into four parts, returned as an array of values.
|
|
2763
|
-
*
|
|
2764
|
-
* The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
|
|
2765
|
-
* if the BigDecimal is Not a Number.
|
|
2766
|
-
*
|
|
2767
|
-
* The second value is a string representing the significant digits of the
|
|
2768
|
-
* BigDecimal, with no leading zeros.
|
|
2769
|
-
*
|
|
2770
|
-
* The third value is the base used for arithmetic (currently always 10) as an
|
|
2771
|
-
* Integer.
|
|
2772
|
-
*
|
|
2773
|
-
* The fourth value is an Integer exponent.
|
|
2774
|
-
*
|
|
2775
|
-
* If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
|
|
2776
|
-
* string of significant digits with no leading zeros, and n is the exponent.
|
|
2777
|
-
*
|
|
2778
|
-
* From these values, you can translate a BigDecimal to a float as follows:
|
|
2779
|
-
*
|
|
2780
|
-
* sign, significant_digits, base, exponent = a.split
|
|
2781
|
-
* f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
|
|
2782
|
-
*
|
|
2783
|
-
* (Note that the to_f method is provided as a more convenient way to translate
|
|
2784
|
-
* a BigDecimal to a Float.)
|
|
2785
|
-
*/
|
|
2786
|
-
static VALUE
|
|
2787
|
-
BigDecimal_split(VALUE self)
|
|
2788
|
-
{
|
|
2789
|
-
ENTER(5);
|
|
2790
|
-
Real *vp;
|
|
2791
|
-
VALUE obj,str;
|
|
2792
|
-
ssize_t e, s;
|
|
2793
|
-
char *psz1;
|
|
2794
|
-
|
|
2795
|
-
GUARD_OBJ(vp, GetVpValue(self, 1));
|
|
2796
|
-
str = rb_str_new(0, VpNumOfChars(vp, "E"));
|
|
2797
|
-
psz1 = RSTRING_PTR(str);
|
|
2798
|
-
VpSzMantissa(vp, psz1, RSTRING_LEN(str));
|
|
2799
|
-
s = 1;
|
|
2800
|
-
if(psz1[0] == '-') {
|
|
2801
|
-
size_t len = strlen(psz1 + 1);
|
|
2802
|
-
|
|
2803
|
-
memmove(psz1, psz1 + 1, len);
|
|
2804
|
-
psz1[len] = '\0';
|
|
2805
|
-
s = -1;
|
|
2806
|
-
}
|
|
2807
|
-
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2808
|
-
e = VpExponent10(vp);
|
|
2809
|
-
obj = rb_ary_new2(4);
|
|
2810
|
-
rb_ary_push(obj, INT2FIX(s));
|
|
2811
|
-
rb_ary_push(obj, str);
|
|
2812
|
-
rb_str_resize(str, strlen(psz1));
|
|
2813
|
-
rb_ary_push(obj, INT2FIX(10));
|
|
2814
|
-
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2815
|
-
return obj;
|
|
2816
|
-
}
|
|
2817
|
-
|
|
2818
|
-
/* Returns the exponent of the BigDecimal number, as an Integer.
|
|
2819
|
-
*
|
|
2820
|
-
* If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
|
|
2821
|
-
* of digits with no leading zeros, then n is the exponent.
|
|
2822
|
-
*/
|
|
2823
|
-
static VALUE
|
|
2824
|
-
BigDecimal_exponent(VALUE self)
|
|
2825
|
-
{
|
|
2826
|
-
ssize_t e = VpExponent10(GetVpValue(self, 1));
|
|
2827
|
-
return SSIZET2NUM(e);
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
/* Returns a string representation of self.
|
|
2831
|
-
*
|
|
2832
|
-
* BigDecimal("1234.5678").inspect
|
|
2833
|
-
* #=> "0.12345678e4"
|
|
2834
|
-
*/
|
|
2835
|
-
static VALUE
|
|
2836
|
-
BigDecimal_inspect(VALUE self)
|
|
2837
|
-
{
|
|
2838
|
-
ENTER(5);
|
|
2839
|
-
Real *vp;
|
|
2840
|
-
volatile VALUE str;
|
|
2841
|
-
size_t nc;
|
|
2842
|
-
|
|
2843
|
-
GUARD_OBJ(vp, GetVpValue(self, 1));
|
|
2844
|
-
nc = VpNumOfChars(vp, "E");
|
|
2845
|
-
|
|
2846
|
-
str = rb_str_new(0, nc);
|
|
2847
|
-
VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2848
|
-
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
|
2849
|
-
return str;
|
|
2850
|
-
}
|
|
2851
|
-
|
|
2852
|
-
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
|
2853
|
-
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
|
2854
|
-
|
|
2855
|
-
#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
|
|
2856
|
-
#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
|
|
2857
|
-
|
|
2858
|
-
inline static int
|
|
2859
|
-
is_integer(VALUE x)
|
|
2860
|
-
{
|
|
2861
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
inline static int
|
|
2865
|
-
is_negative(VALUE x)
|
|
2866
|
-
{
|
|
2867
|
-
if (FIXNUM_P(x)) {
|
|
2868
|
-
return FIX2LONG(x) < 0;
|
|
2869
|
-
}
|
|
2870
|
-
else if (RB_TYPE_P(x, T_BIGNUM)) {
|
|
2871
|
-
return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
|
|
2872
|
-
}
|
|
2873
|
-
else if (RB_TYPE_P(x, T_FLOAT)) {
|
|
2874
|
-
return RFLOAT_VALUE(x) < 0.0;
|
|
2875
|
-
}
|
|
2876
|
-
return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
|
|
2877
|
-
}
|
|
2878
|
-
|
|
2879
|
-
#define is_positive(x) (!is_negative(x))
|
|
2880
|
-
|
|
2881
|
-
inline static int
|
|
2882
|
-
is_zero(VALUE x)
|
|
2883
|
-
{
|
|
2884
|
-
VALUE num;
|
|
2885
|
-
|
|
2886
|
-
switch (TYPE(x)) {
|
|
2887
|
-
case T_FIXNUM:
|
|
2888
|
-
return FIX2LONG(x) == 0;
|
|
2889
|
-
|
|
2890
|
-
case T_BIGNUM:
|
|
2891
|
-
return Qfalse;
|
|
2892
|
-
|
|
2893
|
-
case T_RATIONAL:
|
|
2894
|
-
num = rb_rational_num(x);
|
|
2895
|
-
return FIXNUM_P(num) && FIX2LONG(num) == 0;
|
|
2896
|
-
|
|
2897
|
-
default:
|
|
2898
|
-
break;
|
|
2899
|
-
}
|
|
2900
|
-
|
|
2901
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
2902
|
-
}
|
|
2903
|
-
|
|
2904
|
-
inline static int
|
|
2905
|
-
is_one(VALUE x)
|
|
2906
|
-
{
|
|
2907
|
-
VALUE num, den;
|
|
2908
|
-
|
|
2909
|
-
switch (TYPE(x)) {
|
|
2910
|
-
case T_FIXNUM:
|
|
2911
|
-
return FIX2LONG(x) == 1;
|
|
2912
|
-
|
|
2913
|
-
case T_BIGNUM:
|
|
2914
|
-
return Qfalse;
|
|
2915
|
-
|
|
2916
|
-
case T_RATIONAL:
|
|
2917
|
-
num = rb_rational_num(x);
|
|
2918
|
-
den = rb_rational_den(x);
|
|
2919
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
|
2920
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
|
2921
|
-
|
|
2922
|
-
default:
|
|
2923
|
-
break;
|
|
2924
|
-
}
|
|
2925
|
-
|
|
2926
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
|
2927
|
-
}
|
|
2928
|
-
|
|
2929
|
-
inline static int
|
|
2930
|
-
is_even(VALUE x)
|
|
2931
|
-
{
|
|
2932
|
-
switch (TYPE(x)) {
|
|
2933
|
-
case T_FIXNUM:
|
|
2934
|
-
return (FIX2LONG(x) % 2) == 0;
|
|
2935
|
-
|
|
2936
|
-
case T_BIGNUM:
|
|
2937
|
-
{
|
|
2938
|
-
unsigned long l;
|
|
2939
|
-
rb_big_pack(x, &l, 1);
|
|
2940
|
-
return l % 2 == 0;
|
|
2941
|
-
}
|
|
2942
|
-
|
|
2943
|
-
default:
|
|
2944
|
-
break;
|
|
2945
|
-
}
|
|
2946
|
-
|
|
2947
|
-
return 0;
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
|
-
static VALUE
|
|
2951
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
|
2952
|
-
{
|
|
2953
|
-
VALUE log_x, multiplied, y;
|
|
2954
|
-
volatile VALUE obj = exp->obj;
|
|
2955
|
-
|
|
2956
|
-
if (VpIsZero(exp)) {
|
|
2957
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
2958
|
-
}
|
|
2959
|
-
|
|
2960
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
|
2961
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
|
2962
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
|
2963
|
-
RB_GC_GUARD(obj);
|
|
2964
|
-
|
|
2965
|
-
return y;
|
|
2966
|
-
}
|
|
2967
|
-
|
|
2968
|
-
/* call-seq:
|
|
2969
|
-
* power(n)
|
|
2970
|
-
* power(n, prec)
|
|
2971
|
-
*
|
|
2972
|
-
* Returns the value raised to the power of n.
|
|
2973
|
-
*
|
|
2974
|
-
* Note that n must be an Integer.
|
|
2975
|
-
*
|
|
2976
|
-
* Also available as the operator **.
|
|
2977
|
-
*/
|
|
2978
|
-
static VALUE
|
|
2979
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
|
2980
|
-
{
|
|
2981
|
-
ENTER(5);
|
|
2982
|
-
VALUE vexp, prec;
|
|
2983
|
-
Real* exp = NULL;
|
|
2984
|
-
Real *x, *y;
|
|
2985
|
-
ssize_t mp, ma, n;
|
|
2986
|
-
SIGNED_VALUE int_exp;
|
|
2987
|
-
double d;
|
|
2988
|
-
|
|
2989
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
|
2990
|
-
|
|
2991
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
|
2992
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
|
2993
|
-
|
|
2994
|
-
if (VpIsNaN(x)) {
|
|
2995
|
-
y = NewZeroWrapLimited(1, n);
|
|
2996
|
-
VpSetNaN(y);
|
|
2997
|
-
RB_GC_GUARD(y->obj);
|
|
2998
|
-
return VpCheckGetValue(y);
|
|
2999
|
-
}
|
|
3000
|
-
|
|
3001
|
-
retry:
|
|
3002
|
-
switch (TYPE(vexp)) {
|
|
3003
|
-
case T_FIXNUM:
|
|
3004
|
-
break;
|
|
3005
|
-
|
|
3006
|
-
case T_BIGNUM:
|
|
3007
|
-
break;
|
|
3008
|
-
|
|
3009
|
-
case T_FLOAT:
|
|
3010
|
-
d = RFLOAT_VALUE(vexp);
|
|
3011
|
-
if (d == round(d)) {
|
|
3012
|
-
if (FIXABLE(d)) {
|
|
3013
|
-
vexp = LONG2FIX((long)d);
|
|
3014
|
-
}
|
|
3015
|
-
else {
|
|
3016
|
-
vexp = rb_dbl2big(d);
|
|
3017
|
-
}
|
|
3018
|
-
goto retry;
|
|
3019
|
-
}
|
|
3020
|
-
if (NIL_P(prec)) {
|
|
3021
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
|
3022
|
-
}
|
|
3023
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
|
3024
|
-
break;
|
|
3025
|
-
|
|
3026
|
-
case T_RATIONAL:
|
|
3027
|
-
if (is_zero(rb_rational_num(vexp))) {
|
|
3028
|
-
if (is_positive(vexp)) {
|
|
3029
|
-
vexp = INT2FIX(0);
|
|
3030
|
-
goto retry;
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
else if (is_one(rb_rational_den(vexp))) {
|
|
3034
|
-
vexp = rb_rational_num(vexp);
|
|
3035
|
-
goto retry;
|
|
3036
|
-
}
|
|
3037
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
|
3038
|
-
if (NIL_P(prec)) {
|
|
3039
|
-
n += n;
|
|
3040
|
-
}
|
|
3041
|
-
break;
|
|
3042
|
-
|
|
3043
|
-
case T_DATA:
|
|
3044
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
|
3045
|
-
VALUE zero = INT2FIX(0);
|
|
3046
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
|
3047
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
|
3048
|
-
vexp = BigDecimal_to_i(vexp);
|
|
3049
|
-
goto retry;
|
|
3050
|
-
}
|
|
3051
|
-
if (NIL_P(prec)) {
|
|
3052
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
|
3053
|
-
n += y->Prec*VpBaseFig();
|
|
3054
|
-
}
|
|
3055
|
-
exp = DATA_PTR(vexp);
|
|
3056
|
-
break;
|
|
3057
|
-
}
|
|
3058
|
-
/* fall through */
|
|
3059
|
-
default:
|
|
3060
|
-
rb_raise(rb_eTypeError,
|
|
3061
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
|
3062
|
-
RB_OBJ_CLASSNAME(vexp));
|
|
3063
|
-
}
|
|
3064
|
-
|
|
3065
|
-
if (VpIsZero(x)) {
|
|
3066
|
-
if (is_negative(vexp)) {
|
|
3067
|
-
y = NewZeroWrapNolimit(1, n);
|
|
3068
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3069
|
-
if (is_integer(vexp)) {
|
|
3070
|
-
if (is_even(vexp)) {
|
|
3071
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
|
3072
|
-
VpSetPosInf(y);
|
|
3073
|
-
}
|
|
3074
|
-
else {
|
|
3075
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
|
3076
|
-
VpSetNegInf(y);
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
else {
|
|
3080
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
|
3081
|
-
VpSetPosInf(y);
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
else {
|
|
3085
|
-
/* (+0) ** (-num) -> Infinity */
|
|
3086
|
-
VpSetPosInf(y);
|
|
3087
|
-
}
|
|
3088
|
-
RB_GC_GUARD(y->obj);
|
|
3089
|
-
return VpCheckGetValue(y);
|
|
3090
|
-
}
|
|
3091
|
-
else if (is_zero(vexp)) {
|
|
3092
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3093
|
-
}
|
|
3094
|
-
else {
|
|
3095
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3096
|
-
}
|
|
3097
|
-
}
|
|
3098
|
-
|
|
3099
|
-
if (is_zero(vexp)) {
|
|
3100
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3101
|
-
}
|
|
3102
|
-
else if (is_one(vexp)) {
|
|
3103
|
-
return self;
|
|
3104
|
-
}
|
|
3105
|
-
|
|
3106
|
-
if (VpIsInf(x)) {
|
|
3107
|
-
if (is_negative(vexp)) {
|
|
3108
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3109
|
-
if (is_integer(vexp)) {
|
|
3110
|
-
if (is_even(vexp)) {
|
|
3111
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
|
3112
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3113
|
-
}
|
|
3114
|
-
else {
|
|
3115
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
|
3116
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3117
|
-
}
|
|
3118
|
-
}
|
|
3119
|
-
else {
|
|
3120
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
|
3121
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
|
-
else {
|
|
3125
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3126
|
-
}
|
|
3127
|
-
}
|
|
3128
|
-
else {
|
|
3129
|
-
y = NewZeroWrapLimited(1, n);
|
|
3130
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3131
|
-
if (is_integer(vexp)) {
|
|
3132
|
-
if (is_even(vexp)) {
|
|
3133
|
-
VpSetPosInf(y);
|
|
3134
|
-
}
|
|
3135
|
-
else {
|
|
3136
|
-
VpSetNegInf(y);
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
else {
|
|
3140
|
-
/* TODO: support complex */
|
|
3141
|
-
rb_raise(rb_eMathDomainError,
|
|
3142
|
-
"a non-integral exponent for a negative base");
|
|
3143
|
-
}
|
|
3144
|
-
}
|
|
3145
|
-
else {
|
|
3146
|
-
VpSetPosInf(y);
|
|
3147
|
-
}
|
|
3148
|
-
return VpCheckGetValue(y);
|
|
3149
|
-
}
|
|
3150
|
-
}
|
|
3151
|
-
|
|
3152
|
-
if (exp != NULL) {
|
|
3153
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
|
3154
|
-
}
|
|
3155
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
|
3156
|
-
VALUE abs_value = BigDecimal_abs(self);
|
|
3157
|
-
if (is_one(abs_value)) {
|
|
3158
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3159
|
-
}
|
|
3160
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
|
3161
|
-
if (is_negative(vexp)) {
|
|
3162
|
-
y = NewZeroWrapLimited(1, n);
|
|
3163
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3164
|
-
return VpCheckGetValue(y);
|
|
3165
|
-
}
|
|
3166
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3167
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3168
|
-
}
|
|
3169
|
-
else {
|
|
3170
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
else {
|
|
3174
|
-
if (is_positive(vexp)) {
|
|
3175
|
-
y = NewZeroWrapLimited(1, n);
|
|
3176
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3177
|
-
return VpCheckGetValue(y);
|
|
3178
|
-
}
|
|
3179
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3180
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3181
|
-
}
|
|
3182
|
-
else {
|
|
3183
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3184
|
-
}
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
|
|
3188
|
-
int_exp = FIX2LONG(vexp);
|
|
3189
|
-
ma = int_exp;
|
|
3190
|
-
if (ma < 0) ma = -ma;
|
|
3191
|
-
if (ma == 0) ma = 1;
|
|
3192
|
-
|
|
3193
|
-
if (VpIsDef(x)) {
|
|
3194
|
-
mp = x->Prec * (VpBaseFig() + 1);
|
|
3195
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
|
2319
|
+
if (fmt) {
|
|
2320
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
3196
2321
|
}
|
|
3197
2322
|
else {
|
|
3198
|
-
|
|
3199
|
-
}
|
|
3200
|
-
VpPowerByInt(y, x, int_exp);
|
|
3201
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
|
3202
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
|
2323
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
3203
2324
|
}
|
|
3204
|
-
|
|
2325
|
+
rb_str_resize(str, strlen(psz));
|
|
2326
|
+
|
|
2327
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2328
|
+
return str;
|
|
3205
2329
|
}
|
|
3206
2330
|
|
|
3207
|
-
/*
|
|
3208
|
-
*
|
|
2331
|
+
/* Splits a BigDecimal number into four parts, returned as an array of values.
|
|
2332
|
+
*
|
|
2333
|
+
* The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
|
|
2334
|
+
* if the BigDecimal is Not a Number.
|
|
2335
|
+
*
|
|
2336
|
+
* The second value is a string representing the significant digits of the
|
|
2337
|
+
* BigDecimal, with no leading zeros.
|
|
2338
|
+
*
|
|
2339
|
+
* The third value is the base used for arithmetic (currently always 10) as an
|
|
2340
|
+
* Integer.
|
|
3209
2341
|
*
|
|
3210
|
-
*
|
|
2342
|
+
* The fourth value is an Integer exponent.
|
|
2343
|
+
*
|
|
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)
|
|
3211
2351
|
*
|
|
3212
|
-
*
|
|
3213
|
-
*
|
|
3214
|
-
|
|
3215
|
-
|
|
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;
|
|
2362
|
+
|
|
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);
|
|
2370
|
+
|
|
2371
|
+
memmove(psz1, psz1 + 1, len);
|
|
2372
|
+
psz1[len] = '\0';
|
|
2373
|
+
s = -1;
|
|
2374
|
+
}
|
|
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;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
/* Returns the exponent of the BigDecimal number, as an Integer.
|
|
3216
2389
|
*
|
|
3217
|
-
*
|
|
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.
|
|
3218
2401
|
*
|
|
2402
|
+
* BigDecimal("1234.5678").inspect
|
|
2403
|
+
* #=> "0.12345678e4"
|
|
3219
2404
|
*/
|
|
3220
2405
|
static VALUE
|
|
3221
|
-
|
|
2406
|
+
BigDecimal_inspect(VALUE self)
|
|
3222
2407
|
{
|
|
3223
|
-
|
|
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;
|
|
3224
2421
|
}
|
|
3225
2422
|
|
|
3226
|
-
/*
|
|
2423
|
+
/* Returns self * 10**v without changing the precision.
|
|
2424
|
+
* This method is currently for internal use.
|
|
3227
2425
|
*
|
|
3228
|
-
*
|
|
2426
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
|
2427
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
|
3229
2428
|
*/
|
|
3230
2429
|
static VALUE
|
|
3231
|
-
|
|
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)
|
|
3232
2482
|
{
|
|
3233
|
-
|
|
3234
|
-
|
|
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;
|
|
3235
2495
|
|
|
3236
|
-
|
|
3237
|
-
|
|
2496
|
+
default:
|
|
2497
|
+
break;
|
|
3238
2498
|
}
|
|
3239
|
-
|
|
2499
|
+
|
|
2500
|
+
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
3240
2501
|
}
|
|
3241
2502
|
|
|
3242
2503
|
/* :nodoc: */
|
|
@@ -3275,30 +2536,27 @@ check_exception(VALUE bd)
|
|
|
3275
2536
|
{
|
|
3276
2537
|
assert(is_kind_of_BigDecimal(bd));
|
|
3277
2538
|
|
|
3278
|
-
|
|
3279
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3280
|
-
VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
|
|
2539
|
+
VpCheckException(VpPtr(bd), false);
|
|
3281
2540
|
|
|
3282
2541
|
return bd;
|
|
3283
2542
|
}
|
|
3284
2543
|
|
|
3285
2544
|
static VALUE
|
|
3286
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
|
2545
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
3287
2546
|
{
|
|
3288
|
-
VALUE
|
|
3289
|
-
|
|
2547
|
+
VALUE bd;
|
|
3290
2548
|
Real *vp;
|
|
3291
2549
|
if (uval == 0) {
|
|
3292
|
-
|
|
3293
|
-
vp
|
|
2550
|
+
bd = BigDecimal_allocate(1);
|
|
2551
|
+
vp = VpPtr(bd);
|
|
3294
2552
|
vp->Prec = 1;
|
|
3295
2553
|
vp->exponent = 1;
|
|
3296
2554
|
VpSetZero(vp, 1);
|
|
3297
2555
|
vp->frac[0] = 0;
|
|
3298
2556
|
}
|
|
3299
2557
|
else if (uval < BASE) {
|
|
3300
|
-
|
|
3301
|
-
vp
|
|
2558
|
+
bd = BigDecimal_allocate(1);
|
|
2559
|
+
vp = VpPtr(bd);
|
|
3302
2560
|
vp->Prec = 1;
|
|
3303
2561
|
vp->exponent = 1;
|
|
3304
2562
|
VpSetSign(vp, 1);
|
|
@@ -3323,32 +2581,31 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3323
2581
|
}
|
|
3324
2582
|
|
|
3325
2583
|
const size_t exp = len + ntz;
|
|
3326
|
-
|
|
3327
|
-
vp
|
|
2584
|
+
bd = BigDecimal_allocate(len);
|
|
2585
|
+
vp = VpPtr(bd);
|
|
3328
2586
|
vp->Prec = len;
|
|
3329
2587
|
vp->exponent = exp;
|
|
3330
2588
|
VpSetSign(vp, 1);
|
|
3331
2589
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
3332
2590
|
}
|
|
3333
2591
|
|
|
3334
|
-
return
|
|
2592
|
+
return bd;
|
|
3335
2593
|
}
|
|
3336
2594
|
|
|
3337
2595
|
static VALUE
|
|
3338
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
|
2596
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
3339
2597
|
{
|
|
3340
2598
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
3341
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
|
2599
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
3342
2600
|
if (ival < 0) {
|
|
3343
|
-
Real *vp;
|
|
3344
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2601
|
+
Real *vp = VpPtr(bd);
|
|
3345
2602
|
VpSetSign(vp, -1);
|
|
3346
2603
|
}
|
|
3347
2604
|
return bd;
|
|
3348
2605
|
}
|
|
3349
2606
|
|
|
3350
2607
|
static VALUE
|
|
3351
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
|
2608
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
|
3352
2609
|
{
|
|
3353
2610
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
|
3354
2611
|
|
|
@@ -3360,40 +2617,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
|
3360
2617
|
}
|
|
3361
2618
|
if (size <= sizeof(long)) {
|
|
3362
2619
|
if (sign < 0) {
|
|
3363
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
|
2620
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
|
3364
2621
|
}
|
|
3365
2622
|
else {
|
|
3366
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
|
2623
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
|
3367
2624
|
}
|
|
3368
2625
|
}
|
|
3369
2626
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
|
3370
2627
|
else if (size <= sizeof(LONG_LONG)) {
|
|
3371
2628
|
if (sign < 0) {
|
|
3372
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
|
2629
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
|
3373
2630
|
}
|
|
3374
2631
|
else {
|
|
3375
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
|
2632
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
|
3376
2633
|
}
|
|
3377
2634
|
}
|
|
3378
2635
|
#endif
|
|
3379
2636
|
else {
|
|
3380
2637
|
VALUE str = rb_big2str(val, 10);
|
|
3381
|
-
|
|
3382
|
-
|
|
2638
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
|
2639
|
+
RSTRING_PTR(str),
|
|
2640
|
+
rb_cBigDecimal,
|
|
2641
|
+
true,
|
|
2642
|
+
true
|
|
2643
|
+
));
|
|
3383
2644
|
RB_GC_GUARD(str);
|
|
3384
|
-
return
|
|
2645
|
+
return CheckGetValue(v);
|
|
3385
2646
|
}
|
|
3386
2647
|
}
|
|
3387
2648
|
|
|
3388
2649
|
static VALUE
|
|
3389
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
|
2650
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
|
3390
2651
|
{
|
|
3391
2652
|
assert(RB_INTEGER_TYPE_P(val));
|
|
3392
2653
|
if (FIXNUM_P(val)) {
|
|
3393
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
|
2654
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
|
3394
2655
|
}
|
|
3395
2656
|
else {
|
|
3396
|
-
return rb_big_convert_to_BigDecimal(val
|
|
2657
|
+
return rb_big_convert_to_BigDecimal(val);
|
|
3397
2658
|
}
|
|
3398
2659
|
}
|
|
3399
2660
|
|
|
@@ -3428,11 +2689,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3428
2689
|
}
|
|
3429
2690
|
|
|
3430
2691
|
if (digs == SIZE_MAX) {
|
|
3431
|
-
|
|
3432
|
-
return Qnil;
|
|
3433
|
-
rb_raise(rb_eArgError,
|
|
3434
|
-
"can't omit precision for a %"PRIsVALUE".",
|
|
3435
|
-
CLASS_OF(val));
|
|
2692
|
+
digs = 0;
|
|
3436
2693
|
}
|
|
3437
2694
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
3438
2695
|
if (!raise_exception)
|
|
@@ -3547,9 +2804,8 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3547
2804
|
exp = -exp;
|
|
3548
2805
|
}
|
|
3549
2806
|
|
|
3550
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
|
3551
|
-
Real *vp;
|
|
3552
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2807
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2808
|
+
Real *vp = VpPtr(bd);
|
|
3553
2809
|
assert(vp->Prec == prec);
|
|
3554
2810
|
vp->exponent = exp;
|
|
3555
2811
|
|
|
@@ -3570,28 +2826,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3570
2826
|
CLASS_OF(val));
|
|
3571
2827
|
}
|
|
3572
2828
|
|
|
3573
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
|
2829
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
|
3574
2830
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
|
3575
2831
|
return d;
|
|
3576
2832
|
}
|
|
3577
2833
|
|
|
3578
2834
|
static VALUE
|
|
3579
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
2835
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
3580
2836
|
{
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
|
3585
|
-
if (!vp)
|
|
3586
|
-
return Qnil;
|
|
3587
|
-
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));
|
|
3588
2840
|
}
|
|
3589
2841
|
|
|
3590
2842
|
static inline VALUE
|
|
3591
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
|
2843
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
3592
2844
|
{
|
|
3593
2845
|
const char *c_str = StringValueCStr(val);
|
|
3594
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
|
2846
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
3595
2847
|
}
|
|
3596
2848
|
|
|
3597
2849
|
static VALUE
|
|
@@ -3619,17 +2871,20 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3619
2871
|
if (digs == SIZE_MAX)
|
|
3620
2872
|
return check_exception(val);
|
|
3621
2873
|
|
|
3622
|
-
Real *vp;
|
|
3623
|
-
|
|
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);
|
|
3624
2882
|
|
|
3625
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
|
3626
|
-
vp = VpCopy(NULL, vp);
|
|
3627
2883
|
/* TODO: rounding */
|
|
3628
|
-
|
|
3629
|
-
return VpCheckGetValue(vp);
|
|
2884
|
+
return check_exception(copy);
|
|
3630
2885
|
}
|
|
3631
2886
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
3632
|
-
return rb_inum_convert_to_BigDecimal(val
|
|
2887
|
+
return rb_inum_convert_to_BigDecimal(val);
|
|
3633
2888
|
}
|
|
3634
2889
|
else if (RB_FLOAT_TYPE_P(val)) {
|
|
3635
2890
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
|
@@ -3647,7 +2902,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3647
2902
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
|
3648
2903
|
}
|
|
3649
2904
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
3650
|
-
return rb_str_convert_to_BigDecimal(val,
|
|
2905
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
|
3651
2906
|
}
|
|
3652
2907
|
|
|
3653
2908
|
/* TODO: chheck to_d */
|
|
@@ -3661,7 +2916,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3661
2916
|
}
|
|
3662
2917
|
return Qnil;
|
|
3663
2918
|
}
|
|
3664
|
-
return rb_str_convert_to_BigDecimal(str,
|
|
2919
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
|
3665
2920
|
}
|
|
3666
2921
|
|
|
3667
2922
|
/* call-seq:
|
|
@@ -3682,12 +2937,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3682
2937
|
*
|
|
3683
2938
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
|
3684
2939
|
*
|
|
3685
|
-
* # 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.
|
|
3686
2941
|
* BigDecimal(2) # => 0.2e1
|
|
3687
2942
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
|
3688
2943
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
|
3689
|
-
* #
|
|
3690
|
-
*
|
|
2944
|
+
* BigDecimal(2.0) # => 0.2e1
|
|
2945
|
+
* # Rational value requires ndigits.
|
|
3691
2946
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
|
3692
2947
|
*
|
|
3693
2948
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
|
@@ -3751,11 +3006,11 @@ static VALUE
|
|
|
3751
3006
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3752
3007
|
{
|
|
3753
3008
|
char const *c_str = StringValueCStr(str);
|
|
3754
|
-
|
|
3755
|
-
if (
|
|
3009
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3010
|
+
if (v.bigdecimal_or_nil == Qnil)
|
|
3756
3011
|
return Qnil;
|
|
3757
3012
|
else
|
|
3758
|
-
return
|
|
3013
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3759
3014
|
}
|
|
3760
3015
|
|
|
3761
3016
|
/*
|
|
@@ -3810,7 +3065,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
|
3810
3065
|
static VALUE
|
|
3811
3066
|
BigDecimal_sign(VALUE self)
|
|
3812
3067
|
{ /* sign */
|
|
3813
|
-
int s =
|
|
3068
|
+
int s = GetSelfVpValue(self)->sign;
|
|
3814
3069
|
return INT2FIX(s);
|
|
3815
3070
|
}
|
|
3816
3071
|
|
|
@@ -3893,301 +3148,6 @@ BigDecimal_save_limit(VALUE self)
|
|
|
3893
3148
|
return ret;
|
|
3894
3149
|
}
|
|
3895
3150
|
|
|
3896
|
-
/* call-seq:
|
|
3897
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
|
3898
|
-
*
|
|
3899
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
|
3900
|
-
* power of +decimal+, to the specified number of digits of precision.
|
|
3901
|
-
*
|
|
3902
|
-
* If +decimal+ is infinity, returns Infinity.
|
|
3903
|
-
*
|
|
3904
|
-
* If +decimal+ is NaN, returns NaN.
|
|
3905
|
-
*/
|
|
3906
|
-
static VALUE
|
|
3907
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
|
3908
|
-
{
|
|
3909
|
-
ssize_t prec, n, i;
|
|
3910
|
-
Real* vx = NULL;
|
|
3911
|
-
VALUE one, d, y;
|
|
3912
|
-
int negative = 0;
|
|
3913
|
-
int infinite = 0;
|
|
3914
|
-
int nan = 0;
|
|
3915
|
-
double flo;
|
|
3916
|
-
|
|
3917
|
-
prec = NUM2SSIZET(vprec);
|
|
3918
|
-
if (prec <= 0) {
|
|
3919
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
3920
|
-
}
|
|
3921
|
-
|
|
3922
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
3923
|
-
* BigDecimalCmp function. */
|
|
3924
|
-
switch (TYPE(x)) {
|
|
3925
|
-
case T_DATA:
|
|
3926
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
3927
|
-
vx = DATA_PTR(x);
|
|
3928
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
3929
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
3930
|
-
nan = VpIsNaN(vx);
|
|
3931
|
-
break;
|
|
3932
|
-
|
|
3933
|
-
case T_FIXNUM:
|
|
3934
|
-
/* fall through */
|
|
3935
|
-
case T_BIGNUM:
|
|
3936
|
-
vx = GetVpValue(x, 0);
|
|
3937
|
-
break;
|
|
3938
|
-
|
|
3939
|
-
case T_FLOAT:
|
|
3940
|
-
flo = RFLOAT_VALUE(x);
|
|
3941
|
-
negative = flo < 0;
|
|
3942
|
-
infinite = isinf(flo);
|
|
3943
|
-
nan = isnan(flo);
|
|
3944
|
-
if (!infinite && !nan) {
|
|
3945
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
|
3946
|
-
}
|
|
3947
|
-
break;
|
|
3948
|
-
|
|
3949
|
-
case T_RATIONAL:
|
|
3950
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
|
3951
|
-
break;
|
|
3952
|
-
|
|
3953
|
-
default:
|
|
3954
|
-
break;
|
|
3955
|
-
}
|
|
3956
|
-
if (infinite) {
|
|
3957
|
-
if (negative) {
|
|
3958
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
|
3959
|
-
}
|
|
3960
|
-
else {
|
|
3961
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3962
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
3963
|
-
RB_GC_GUARD(vy->obj);
|
|
3964
|
-
return VpCheckGetValue(vy);
|
|
3965
|
-
}
|
|
3966
|
-
}
|
|
3967
|
-
else if (nan) {
|
|
3968
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3969
|
-
VpSetNaN(vy);
|
|
3970
|
-
RB_GC_GUARD(vy->obj);
|
|
3971
|
-
return VpCheckGetValue(vy);
|
|
3972
|
-
}
|
|
3973
|
-
else if (vx == NULL) {
|
|
3974
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
3975
|
-
}
|
|
3976
|
-
x = vx->obj;
|
|
3977
|
-
|
|
3978
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
3979
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
3980
|
-
if (negative) {
|
|
3981
|
-
VALUE x_zero = INT2NUM(1);
|
|
3982
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
|
3983
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
|
3984
|
-
vx = DATA_PTR(x);
|
|
3985
|
-
VpSetSign(vx, 1);
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
3989
|
-
y = one;
|
|
3990
|
-
d = y;
|
|
3991
|
-
i = 1;
|
|
3992
|
-
|
|
3993
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
3994
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
3995
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
3996
|
-
ssize_t m = n - vabs(ey - ed);
|
|
3997
|
-
|
|
3998
|
-
rb_thread_check_ints();
|
|
3999
|
-
|
|
4000
|
-
if (m <= 0) {
|
|
4001
|
-
break;
|
|
4002
|
-
}
|
|
4003
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4004
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4005
|
-
}
|
|
4006
|
-
|
|
4007
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
|
4008
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
|
4009
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
|
4010
|
-
++i; /* i <- i + 1 */
|
|
4011
|
-
}
|
|
4012
|
-
|
|
4013
|
-
if (negative) {
|
|
4014
|
-
return BigDecimal_div2(one, y, vprec);
|
|
4015
|
-
}
|
|
4016
|
-
else {
|
|
4017
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
|
4018
|
-
return BigDecimal_round(1, &vprec, y);
|
|
4019
|
-
}
|
|
4020
|
-
|
|
4021
|
-
RB_GC_GUARD(one);
|
|
4022
|
-
RB_GC_GUARD(x);
|
|
4023
|
-
RB_GC_GUARD(y);
|
|
4024
|
-
RB_GC_GUARD(d);
|
|
4025
|
-
}
|
|
4026
|
-
|
|
4027
|
-
/* call-seq:
|
|
4028
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
|
4029
|
-
*
|
|
4030
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
|
4031
|
-
* digits of precision, +numeric+.
|
|
4032
|
-
*
|
|
4033
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
|
4034
|
-
*
|
|
4035
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
|
4036
|
-
*
|
|
4037
|
-
* If +decimal+ is NaN, returns NaN.
|
|
4038
|
-
*/
|
|
4039
|
-
static VALUE
|
|
4040
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
|
4041
|
-
{
|
|
4042
|
-
ssize_t prec, n, i;
|
|
4043
|
-
SIGNED_VALUE expo;
|
|
4044
|
-
Real* vx = NULL;
|
|
4045
|
-
VALUE vn, one, two, w, x2, y, d;
|
|
4046
|
-
int zero = 0;
|
|
4047
|
-
int negative = 0;
|
|
4048
|
-
int infinite = 0;
|
|
4049
|
-
int nan = 0;
|
|
4050
|
-
double flo;
|
|
4051
|
-
long fix;
|
|
4052
|
-
|
|
4053
|
-
if (!is_integer(vprec)) {
|
|
4054
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
|
4055
|
-
}
|
|
4056
|
-
|
|
4057
|
-
prec = NUM2SSIZET(vprec);
|
|
4058
|
-
if (prec <= 0) {
|
|
4059
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
4060
|
-
}
|
|
4061
|
-
|
|
4062
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
4063
|
-
* BigDecimalCmp function. */
|
|
4064
|
-
switch (TYPE(x)) {
|
|
4065
|
-
case T_DATA:
|
|
4066
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
4067
|
-
vx = DATA_PTR(x);
|
|
4068
|
-
zero = VpIsZero(vx);
|
|
4069
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4070
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
4071
|
-
nan = VpIsNaN(vx);
|
|
4072
|
-
break;
|
|
4073
|
-
|
|
4074
|
-
case T_FIXNUM:
|
|
4075
|
-
fix = FIX2LONG(x);
|
|
4076
|
-
zero = fix == 0;
|
|
4077
|
-
negative = fix < 0;
|
|
4078
|
-
goto get_vp_value;
|
|
4079
|
-
|
|
4080
|
-
case T_BIGNUM:
|
|
4081
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
|
4082
|
-
zero = i == 0;
|
|
4083
|
-
negative = i < 0;
|
|
4084
|
-
get_vp_value:
|
|
4085
|
-
if (zero || negative) break;
|
|
4086
|
-
vx = GetVpValue(x, 0);
|
|
4087
|
-
break;
|
|
4088
|
-
|
|
4089
|
-
case T_FLOAT:
|
|
4090
|
-
flo = RFLOAT_VALUE(x);
|
|
4091
|
-
zero = flo == 0;
|
|
4092
|
-
negative = flo < 0;
|
|
4093
|
-
infinite = isinf(flo);
|
|
4094
|
-
nan = isnan(flo);
|
|
4095
|
-
if (!zero && !negative && !infinite && !nan) {
|
|
4096
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
|
4097
|
-
}
|
|
4098
|
-
break;
|
|
4099
|
-
|
|
4100
|
-
case T_RATIONAL:
|
|
4101
|
-
zero = RRATIONAL_ZERO_P(x);
|
|
4102
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
|
4103
|
-
if (zero || negative) break;
|
|
4104
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
|
4105
|
-
break;
|
|
4106
|
-
|
|
4107
|
-
case T_COMPLEX:
|
|
4108
|
-
rb_raise(rb_eMathDomainError,
|
|
4109
|
-
"Complex argument for BigMath.log");
|
|
4110
|
-
|
|
4111
|
-
default:
|
|
4112
|
-
break;
|
|
4113
|
-
}
|
|
4114
|
-
if (infinite && !negative) {
|
|
4115
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
|
4116
|
-
RB_GC_GUARD(vy->obj);
|
|
4117
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
4118
|
-
return VpCheckGetValue(vy);
|
|
4119
|
-
}
|
|
4120
|
-
else if (nan) {
|
|
4121
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
4122
|
-
RB_GC_GUARD(vy->obj);
|
|
4123
|
-
VpSetNaN(vy);
|
|
4124
|
-
return VpCheckGetValue(vy);
|
|
4125
|
-
}
|
|
4126
|
-
else if (zero || negative) {
|
|
4127
|
-
rb_raise(rb_eMathDomainError,
|
|
4128
|
-
"Zero or negative argument for log");
|
|
4129
|
-
}
|
|
4130
|
-
else if (vx == NULL) {
|
|
4131
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4132
|
-
}
|
|
4133
|
-
x = VpCheckGetValue(vx);
|
|
4134
|
-
|
|
4135
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4136
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
|
4137
|
-
|
|
4138
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4139
|
-
vn = SSIZET2NUM(n);
|
|
4140
|
-
expo = VpExponent10(vx);
|
|
4141
|
-
if (expo < 0 || expo >= 3) {
|
|
4142
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
|
4143
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
|
4144
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
|
4145
|
-
}
|
|
4146
|
-
else {
|
|
4147
|
-
expo = 0;
|
|
4148
|
-
}
|
|
4149
|
-
w = BigDecimal_sub(x, one);
|
|
4150
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
|
4151
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
|
4152
|
-
y = x;
|
|
4153
|
-
d = y;
|
|
4154
|
-
i = 1;
|
|
4155
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4156
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4157
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4158
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4159
|
-
if (m <= 0) {
|
|
4160
|
-
break;
|
|
4161
|
-
}
|
|
4162
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4163
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4164
|
-
}
|
|
4165
|
-
|
|
4166
|
-
x = BigDecimal_mult2(x2, x, vn);
|
|
4167
|
-
i += 2;
|
|
4168
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
|
4169
|
-
y = BigDecimal_add(y, d);
|
|
4170
|
-
}
|
|
4171
|
-
|
|
4172
|
-
y = BigDecimal_mult(y, two);
|
|
4173
|
-
if (expo != 0) {
|
|
4174
|
-
VALUE log10, vexpo, dy;
|
|
4175
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
|
4176
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
|
4177
|
-
dy = BigDecimal_mult(log10, vexpo);
|
|
4178
|
-
y = BigDecimal_add(y, dy);
|
|
4179
|
-
}
|
|
4180
|
-
|
|
4181
|
-
RB_GC_GUARD(one);
|
|
4182
|
-
RB_GC_GUARD(two);
|
|
4183
|
-
RB_GC_GUARD(vn);
|
|
4184
|
-
RB_GC_GUARD(x2);
|
|
4185
|
-
RB_GC_GUARD(y);
|
|
4186
|
-
RB_GC_GUARD(d);
|
|
4187
|
-
|
|
4188
|
-
return y;
|
|
4189
|
-
}
|
|
4190
|
-
|
|
4191
3151
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
|
4192
3152
|
|
|
4193
3153
|
static VALUE
|
|
@@ -4239,6 +3199,71 @@ BigDecimal_literal(const char *str)
|
|
|
4239
3199
|
|
|
4240
3200
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
|
4241
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
|
+
|
|
4242
3267
|
/* Document-class: BigDecimal
|
|
4243
3268
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
|
4244
3269
|
*
|
|
@@ -4355,14 +3380,16 @@ BigDecimal_literal(const char *str)
|
|
|
4355
3380
|
*
|
|
4356
3381
|
* When you require +bigdecimal/util+, the #to_d method will be
|
|
4357
3382
|
* available on BigDecimal and the native Integer, Float, Rational,
|
|
4358
|
-
* and
|
|
3383
|
+
* String, Complex, and NilClass classes:
|
|
4359
3384
|
*
|
|
4360
3385
|
* require 'bigdecimal/util'
|
|
4361
3386
|
*
|
|
4362
|
-
* 42.to_d
|
|
4363
|
-
* 0.5.to_d
|
|
4364
|
-
* (2/3r).to_d(3)
|
|
4365
|
-
* "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
|
|
4366
3393
|
*
|
|
4367
3394
|
* == Methods for Working with \JSON
|
|
4368
3395
|
*
|
|
@@ -4436,7 +3463,7 @@ Init_bigdecimal(void)
|
|
|
4436
3463
|
* guarantee that two groups could always be multiplied together without
|
|
4437
3464
|
* overflow.)
|
|
4438
3465
|
*/
|
|
4439
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
|
3466
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
|
4440
3467
|
|
|
4441
3468
|
/* Exceptions */
|
|
4442
3469
|
|
|
@@ -4547,7 +3574,6 @@ Init_bigdecimal(void)
|
|
|
4547
3574
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
4548
3575
|
|
|
4549
3576
|
/* instance methods */
|
|
4550
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
4551
3577
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
4552
3578
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
4553
3579
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -4578,14 +3604,11 @@ Init_bigdecimal(void)
|
|
|
4578
3604
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
|
4579
3605
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
|
4580
3606
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
|
4581
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
|
4582
3607
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
|
4583
3608
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
|
4584
3609
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
|
4585
3610
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
|
4586
3611
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
|
4587
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
|
4588
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
|
4589
3612
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
|
4590
3613
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
|
4591
3614
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
|
@@ -4604,11 +3627,16 @@ Init_bigdecimal(void)
|
|
|
4604
3627
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
|
4605
3628
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
|
4606
3629
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
|
3630
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
|
4607
3631
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
|
4608
3632
|
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
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 */
|
|
4612
3640
|
|
|
4613
3641
|
#define ROUNDING_MODE(i, name, value) \
|
|
4614
3642
|
id_##name = rb_intern_const(#name); \
|
|
@@ -4648,19 +3676,9 @@ Init_bigdecimal(void)
|
|
|
4648
3676
|
*/
|
|
4649
3677
|
#ifdef BIGDECIMAL_DEBUG
|
|
4650
3678
|
static int gfDebug = 1; /* Debug switch */
|
|
4651
|
-
#if 0
|
|
4652
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
|
4653
|
-
#endif
|
|
4654
3679
|
#endif /* BIGDECIMAL_DEBUG */
|
|
4655
3680
|
|
|
4656
|
-
static
|
|
4657
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
|
4658
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
|
4659
|
-
/* used in VpSqrt() */
|
|
4660
|
-
|
|
4661
|
-
/* ETC */
|
|
4662
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
|
4663
|
-
#define StrCmp(x,y) strcmp(x,y)
|
|
3681
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
4664
3682
|
|
|
4665
3683
|
enum op_sw {
|
|
4666
3684
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4670,11 +3688,9 @@ enum op_sw {
|
|
|
4670
3688
|
};
|
|
4671
3689
|
|
|
4672
3690
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
|
4673
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
4674
3691
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
|
4675
3692
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
|
4676
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);
|
|
4677
|
-
static int VpNmlz(Real *a);
|
|
4678
3694
|
static void VpFormatSt(char *psz, size_t fFmt);
|
|
4679
3695
|
static int VpRdup(Real *m, size_t ind_m);
|
|
4680
3696
|
|
|
@@ -4733,10 +3749,10 @@ VpCheckException(Real *p, bool always)
|
|
|
4733
3749
|
}
|
|
4734
3750
|
|
|
4735
3751
|
static VALUE
|
|
4736
|
-
|
|
3752
|
+
CheckGetValue(BDVALUE v)
|
|
4737
3753
|
{
|
|
4738
|
-
VpCheckException(
|
|
4739
|
-
return
|
|
3754
|
+
VpCheckException(v.real, false);
|
|
3755
|
+
return v.bigdecimal;
|
|
4740
3756
|
}
|
|
4741
3757
|
|
|
4742
3758
|
/*
|
|
@@ -4768,12 +3784,10 @@ VpGetPrecLimit(void)
|
|
|
4768
3784
|
return NUM2SIZET(vlimit);
|
|
4769
3785
|
}
|
|
4770
3786
|
|
|
4771
|
-
VP_EXPORT
|
|
3787
|
+
VP_EXPORT void
|
|
4772
3788
|
VpSetPrecLimit(size_t n)
|
|
4773
3789
|
{
|
|
4774
|
-
size_t const s = VpGetPrecLimit();
|
|
4775
3790
|
bigdecimal_set_thread_local_precision_limit(n);
|
|
4776
|
-
return s;
|
|
4777
3791
|
}
|
|
4778
3792
|
|
|
4779
3793
|
/*
|
|
@@ -4888,15 +3902,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
|
4888
3902
|
return nzero;
|
|
4889
3903
|
}
|
|
4890
3904
|
|
|
4891
|
-
#if 0 /* unused */
|
|
4892
|
-
VP_EXPORT int
|
|
4893
|
-
VpIsNegDoubleZero(double v)
|
|
4894
|
-
{
|
|
4895
|
-
double z = VpGetDoubleNegZero();
|
|
4896
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
|
4897
|
-
}
|
|
4898
|
-
#endif
|
|
4899
|
-
|
|
4900
3905
|
VP_EXPORT int
|
|
4901
3906
|
VpException(unsigned short f, const char *str,int always)
|
|
4902
3907
|
{
|
|
@@ -5048,7 +4053,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
|
5048
4053
|
case 'E':
|
|
5049
4054
|
/* fall through */
|
|
5050
4055
|
default:
|
|
5051
|
-
nc = BASE_FIG*
|
|
4056
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
|
5052
4057
|
}
|
|
5053
4058
|
return nc;
|
|
5054
4059
|
}
|
|
@@ -5074,35 +4079,21 @@ VpInit(DECDIG BaseVal)
|
|
|
5074
4079
|
VpGetDoubleNegZero();
|
|
5075
4080
|
|
|
5076
4081
|
/* Const 1.0 */
|
|
5077
|
-
VpConstOne
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
|
5081
|
-
VpConstPt5->exponent = 0;
|
|
5082
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
|
4082
|
+
rb_global_variable(&VpConstOne);
|
|
4083
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4084
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
5083
4085
|
|
|
5084
4086
|
#ifdef BIGDECIMAL_DEBUG
|
|
5085
4087
|
gnAlloc = 0;
|
|
5086
4088
|
#endif /* BIGDECIMAL_DEBUG */
|
|
5087
4089
|
|
|
5088
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5089
|
-
if (gfDebug) {
|
|
5090
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
|
5091
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
|
5092
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
|
5093
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
|
5094
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
|
5095
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
5096
|
-
}
|
|
5097
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5098
|
-
|
|
5099
4090
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
|
5100
4091
|
}
|
|
5101
4092
|
|
|
5102
4093
|
VP_EXPORT Real *
|
|
5103
4094
|
VpOne(void)
|
|
5104
4095
|
{
|
|
5105
|
-
return VpConstOne;
|
|
4096
|
+
return VpPtr(VpConstOne);
|
|
5106
4097
|
}
|
|
5107
4098
|
|
|
5108
4099
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -5111,24 +4102,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
|
5111
4102
|
{
|
|
5112
4103
|
SIGNED_VALUE e = a->exponent;
|
|
5113
4104
|
SIGNED_VALUE m = e+n;
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
if (eb - mb > 0) goto overflow;
|
|
5123
|
-
}
|
|
5124
|
-
}
|
|
5125
|
-
else if (n < 0) {
|
|
5126
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
|
5127
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
5128
|
-
goto underflow;
|
|
5129
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
|
5130
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
|
5131
|
-
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;
|
|
5132
4113
|
}
|
|
5133
4114
|
a->exponent = m;
|
|
5134
4115
|
return 1;
|
|
@@ -5143,7 +4124,7 @@ overflow:
|
|
|
5143
4124
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
5144
4125
|
}
|
|
5145
4126
|
|
|
5146
|
-
|
|
4127
|
+
NULLABLE_BDVALUE
|
|
5147
4128
|
bigdecimal_parse_special_string(const char *str)
|
|
5148
4129
|
{
|
|
5149
4130
|
static const struct {
|
|
@@ -5168,120 +4149,61 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
5168
4149
|
p = str + table[i].len;
|
|
5169
4150
|
while (*p && ISSPACE(*p)) ++p;
|
|
5170
4151
|
if (*p == '\0') {
|
|
5171
|
-
|
|
5172
|
-
vp
|
|
4152
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4153
|
+
Real *vp = VpPtr(obj);
|
|
5173
4154
|
switch (table[i].sign) {
|
|
5174
4155
|
default:
|
|
5175
|
-
UNREACHABLE;
|
|
4156
|
+
UNREACHABLE;
|
|
4157
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5176
4158
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
5177
4159
|
VpSetPosInf(vp);
|
|
5178
|
-
|
|
4160
|
+
break;
|
|
5179
4161
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
5180
4162
|
VpSetNegInf(vp);
|
|
5181
|
-
|
|
4163
|
+
break;
|
|
5182
4164
|
case VP_SIGN_NaN:
|
|
5183
4165
|
VpSetNaN(vp);
|
|
5184
|
-
|
|
4166
|
+
break;
|
|
5185
4167
|
}
|
|
4168
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
5186
4169
|
}
|
|
5187
4170
|
}
|
|
5188
4171
|
|
|
5189
|
-
return NULL;
|
|
5190
|
-
}
|
|
5191
|
-
|
|
5192
|
-
struct VpCtoV_args {
|
|
5193
|
-
Real *a;
|
|
5194
|
-
const char *int_chr;
|
|
5195
|
-
size_t ni;
|
|
5196
|
-
const char *frac;
|
|
5197
|
-
size_t nf;
|
|
5198
|
-
const char *exp_chr;
|
|
5199
|
-
size_t ne;
|
|
5200
|
-
};
|
|
5201
|
-
|
|
5202
|
-
static VALUE
|
|
5203
|
-
call_VpCtoV(VALUE arg)
|
|
5204
|
-
{
|
|
5205
|
-
struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
|
|
5206
|
-
return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
|
|
5207
|
-
}
|
|
5208
|
-
|
|
5209
|
-
static int
|
|
5210
|
-
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)
|
|
5211
|
-
{
|
|
5212
|
-
struct VpCtoV_args args;
|
|
5213
|
-
int state = 0;
|
|
5214
|
-
|
|
5215
|
-
args.a = a;
|
|
5216
|
-
args.int_chr = int_chr;
|
|
5217
|
-
args.ni = ni;
|
|
5218
|
-
args.frac = frac;
|
|
5219
|
-
args.nf = nf;
|
|
5220
|
-
args.exp_chr = exp_chr;
|
|
5221
|
-
args.ne = ne;
|
|
5222
|
-
|
|
5223
|
-
VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
|
|
5224
|
-
if (state) {
|
|
5225
|
-
if (free_on_error) {
|
|
5226
|
-
rbd_free_struct(a);
|
|
5227
|
-
}
|
|
5228
|
-
rb_jump_tag(state);
|
|
5229
|
-
}
|
|
5230
|
-
|
|
5231
|
-
return (int)result;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5232
4173
|
}
|
|
5233
4174
|
|
|
5234
4175
|
/*
|
|
5235
4176
|
* Allocates variable.
|
|
5236
4177
|
* [Input]
|
|
5237
|
-
*
|
|
5238
|
-
* The mx will be the number of significant digits can to be stored.
|
|
5239
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
|
5240
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
|
5241
|
-
* so that the full precision specified by szVal is allocated.
|
|
4178
|
+
* szVal ... The value assigned(char).
|
|
5242
4179
|
*
|
|
5243
4180
|
* [Returns]
|
|
5244
|
-
*
|
|
5245
|
-
*
|
|
4181
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4182
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
5246
4183
|
*/
|
|
5247
|
-
VP_EXPORT
|
|
5248
|
-
VpAlloc(
|
|
4184
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4185
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
5249
4186
|
{
|
|
5250
4187
|
const char *orig_szVal = szVal;
|
|
5251
4188
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
5252
|
-
size_t len;
|
|
5253
4189
|
char v, *psz;
|
|
5254
4190
|
int sign=1;
|
|
5255
|
-
Real *vp = NULL;
|
|
5256
4191
|
VALUE buf;
|
|
5257
4192
|
|
|
5258
|
-
if (szVal == NULL) {
|
|
5259
|
-
return_zero:
|
|
5260
|
-
/* necessary to be able to store */
|
|
5261
|
-
/* at least mx digits. */
|
|
5262
|
-
/* szVal==NULL ==> allocate zero value. */
|
|
5263
|
-
vp = rbd_allocate_struct(mx);
|
|
5264
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
|
5265
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
|
5266
|
-
return vp;
|
|
5267
|
-
}
|
|
5268
|
-
|
|
5269
4193
|
/* Skipping leading spaces */
|
|
5270
4194
|
while (ISSPACE(*szVal)) szVal++;
|
|
5271
4195
|
|
|
5272
4196
|
/* Check on Inf & NaN */
|
|
5273
|
-
|
|
5274
|
-
|
|
4197
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4198
|
+
if (special_bd.real_or_null != NULL) {
|
|
4199
|
+
return special_bd;
|
|
5275
4200
|
}
|
|
5276
4201
|
|
|
5277
|
-
/*
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
len = rbd_calculate_internal_digits(mx, false);
|
|
5283
|
-
++szVal;
|
|
5284
|
-
}
|
|
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;
|
|
5285
4207
|
|
|
5286
4208
|
/* Scanning digits */
|
|
5287
4209
|
|
|
@@ -5428,10 +4350,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5428
4350
|
VALUE str;
|
|
5429
4351
|
invalid_value:
|
|
5430
4352
|
if (!strict_p) {
|
|
5431
|
-
|
|
4353
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4354
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
5432
4355
|
}
|
|
5433
4356
|
if (!exc) {
|
|
5434
|
-
return NULL;
|
|
4357
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
5435
4358
|
}
|
|
5436
4359
|
str = rb_str_new2(orig_szVal);
|
|
5437
4360
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -5439,15 +4362,12 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5439
4362
|
|
|
5440
4363
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
5441
4364
|
/* units for szVal[] */
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
len = nalloc;
|
|
5445
|
-
vp = rbd_allocate_struct(len);
|
|
5446
|
-
vp->MaxPrec = len; /* set max precision */
|
|
4365
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4366
|
+
Real *vp = VpPtr(obj);
|
|
5447
4367
|
VpSetZero(vp, sign);
|
|
5448
|
-
|
|
4368
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
5449
4369
|
rb_str_resize(buf, 0);
|
|
5450
|
-
return vp;
|
|
4370
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
5451
4371
|
}
|
|
5452
4372
|
|
|
5453
4373
|
/*
|
|
@@ -5483,7 +4403,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5483
4403
|
c->Prec = n;
|
|
5484
4404
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
|
5485
4405
|
/* Needs round ? */
|
|
5486
|
-
if (isw != 10) {
|
|
4406
|
+
if (isw != 10 && isw != -10) {
|
|
5487
4407
|
/* Not in ActiveRound */
|
|
5488
4408
|
if(c->Prec < a->Prec) {
|
|
5489
4409
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
|
@@ -5509,19 +4429,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5509
4429
|
VP_EXPORT size_t
|
|
5510
4430
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
|
5511
4431
|
{
|
|
5512
|
-
short sw, isw;
|
|
4432
|
+
short sw, isw, sign;
|
|
5513
4433
|
Real *a_ptr, *b_ptr;
|
|
5514
4434
|
size_t n, na, nb, i;
|
|
5515
4435
|
DECDIG mrv;
|
|
5516
4436
|
|
|
5517
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5518
|
-
if (gfDebug) {
|
|
5519
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
|
5520
|
-
VPrint(stdout, " b=% \n", b);
|
|
5521
|
-
printf(" operation=%d\n", operation);
|
|
5522
|
-
}
|
|
5523
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5524
|
-
|
|
5525
4437
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
|
5526
4438
|
|
|
5527
4439
|
/* check if a or b is zero */
|
|
@@ -5610,28 +4522,21 @@ end_if:
|
|
|
5610
4522
|
if (isw) { /* addition */
|
|
5611
4523
|
VpSetSign(c, 1);
|
|
5612
4524
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
|
5613
|
-
|
|
4525
|
+
sign = isw / 2;
|
|
5614
4526
|
}
|
|
5615
4527
|
else { /* subtraction */
|
|
5616
4528
|
VpSetSign(c, 1);
|
|
5617
4529
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
|
5618
|
-
|
|
5619
|
-
VpSetSign(c,VpGetSign(a));
|
|
5620
|
-
}
|
|
5621
|
-
else {
|
|
5622
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
|
5623
|
-
}
|
|
4530
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
|
5624
4531
|
}
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5628
|
-
if (gfDebug) {
|
|
5629
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
|
5630
|
-
VPrint(stdout, " a=% \n", a);
|
|
5631
|
-
VPrint(stdout, " b=% \n", b);
|
|
5632
|
-
printf(" operation=%d\n", operation);
|
|
4532
|
+
if (VpIsInf(c)) {
|
|
4533
|
+
VpSetInf(c, sign);
|
|
5633
4534
|
}
|
|
5634
|
-
|
|
4535
|
+
else {
|
|
4536
|
+
VpSetSign(c, sign);
|
|
4537
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
|
4538
|
+
}
|
|
4539
|
+
|
|
5635
4540
|
return c->Prec * BASE_FIG;
|
|
5636
4541
|
}
|
|
5637
4542
|
|
|
@@ -5652,13 +4557,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
|
5652
4557
|
size_t c_pos;
|
|
5653
4558
|
DECDIG av, bv, carry, mrv;
|
|
5654
4559
|
|
|
5655
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5656
|
-
if (gfDebug) {
|
|
5657
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
|
5658
|
-
VPrint(stdout, " b = %\n", b);
|
|
5659
|
-
}
|
|
5660
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5661
|
-
|
|
5662
4560
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5663
4561
|
a_pos = ap;
|
|
5664
4562
|
b_pos = bp;
|
|
@@ -5724,11 +4622,6 @@ Assign_a:
|
|
|
5724
4622
|
|
|
5725
4623
|
Exit:
|
|
5726
4624
|
|
|
5727
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5728
|
-
if (gfDebug) {
|
|
5729
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
|
5730
|
-
}
|
|
5731
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5732
4625
|
return mrv;
|
|
5733
4626
|
}
|
|
5734
4627
|
|
|
@@ -5747,13 +4640,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
|
5747
4640
|
size_t c_pos;
|
|
5748
4641
|
DECDIG av, bv, borrow, mrv;
|
|
5749
4642
|
|
|
5750
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5751
|
-
if (gfDebug) {
|
|
5752
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
|
5753
|
-
VPrint(stdout, " b = %\n", b);
|
|
5754
|
-
}
|
|
5755
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5756
|
-
|
|
5757
4643
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5758
4644
|
a_pos = ap;
|
|
5759
4645
|
b_pos = bp;
|
|
@@ -5829,11 +4715,6 @@ Assign_a:
|
|
|
5829
4715
|
mrv = 0;
|
|
5830
4716
|
|
|
5831
4717
|
Exit:
|
|
5832
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5833
|
-
if (gfDebug) {
|
|
5834
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
|
5835
|
-
}
|
|
5836
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5837
4718
|
return mrv;
|
|
5838
4719
|
}
|
|
5839
4720
|
|
|
@@ -5958,25 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
5958
4839
|
* a0 a1 .... an * b0
|
|
5959
4840
|
* +_____________________________
|
|
5960
4841
|
* c0 c1 c2 ...... cl
|
|
5961
|
-
* nc <---|
|
|
5962
|
-
* MaxAB |--------------------|
|
|
5963
4842
|
*/
|
|
5964
4843
|
VP_EXPORT size_t
|
|
5965
4844
|
VpMult(Real *c, Real *a, Real *b)
|
|
5966
4845
|
{
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
5970
|
-
DECDIG carry;
|
|
5971
|
-
DECDIG_DBL s;
|
|
5972
|
-
Real *w;
|
|
5973
|
-
|
|
5974
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5975
|
-
if (gfDebug) {
|
|
5976
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
|
5977
|
-
VPrint(stdout, " b=% \n", b);
|
|
5978
|
-
}
|
|
5979
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
4846
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4847
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
5980
4848
|
|
|
5981
4849
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
5982
4850
|
|
|
@@ -5987,108 +4855,82 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
5987
4855
|
}
|
|
5988
4856
|
|
|
5989
4857
|
if (VpIsOne(a)) {
|
|
5990
|
-
VpAsgn(c, b, VpGetSign(a));
|
|
4858
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
|
5991
4859
|
goto Exit;
|
|
5992
4860
|
}
|
|
5993
4861
|
if (VpIsOne(b)) {
|
|
5994
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
4862
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
|
5995
4863
|
goto Exit;
|
|
5996
4864
|
}
|
|
5997
4865
|
if (b->Prec > a->Prec) {
|
|
5998
4866
|
/* Adjust so that digits(a)>digits(b) */
|
|
5999
|
-
w = a;
|
|
4867
|
+
Real *w = a;
|
|
6000
4868
|
a = b;
|
|
6001
4869
|
b = w;
|
|
6002
4870
|
}
|
|
6003
|
-
w = NULL;
|
|
6004
|
-
MxIndA = a->Prec - 1;
|
|
6005
|
-
MxIndB = b->Prec - 1;
|
|
6006
|
-
MxIndC = c->MaxPrec - 1;
|
|
6007
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
6008
|
-
|
|
6009
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
|
6010
|
-
w = c;
|
|
6011
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
|
6012
|
-
MxIndC = MxIndAB;
|
|
6013
|
-
}
|
|
6014
4871
|
|
|
6015
4872
|
/* set LHSV c info */
|
|
6016
4873
|
|
|
6017
4874
|
c->exponent = a->exponent; /* set exponent */
|
|
6018
|
-
if (!AddExponent(c, b->exponent)) {
|
|
6019
|
-
if (w) rbd_free_struct(c);
|
|
6020
|
-
return 0;
|
|
6021
|
-
}
|
|
6022
4875
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
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
|
+
}
|
|
6043
4904
|
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
carry += (DECDIG)s;
|
|
6052
|
-
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);
|
|
6053
4912
|
}
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
c->frac[ii] -= (carry * BASE);
|
|
6061
|
-
}
|
|
6062
|
-
else {
|
|
6063
|
-
break;
|
|
6064
|
-
}
|
|
6065
|
-
}
|
|
6066
|
-
}
|
|
6067
|
-
}
|
|
6068
|
-
}
|
|
6069
|
-
if (w != NULL) { /* free work variable */
|
|
6070
|
-
VpNmlz(c);
|
|
6071
|
-
VpAsgn(w, c, 1);
|
|
6072
|
-
rbd_free_struct(c);
|
|
6073
|
-
c = w;
|
|
6074
|
-
}
|
|
6075
|
-
else {
|
|
6076
|
-
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
|
+
}
|
|
6077
4919
|
}
|
|
6078
4920
|
|
|
4921
|
+
Cleanup:
|
|
4922
|
+
VpNmlz(c);
|
|
4923
|
+
|
|
6079
4924
|
Exit:
|
|
6080
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6081
|
-
if (gfDebug) {
|
|
6082
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
|
6083
|
-
VPrint(stdout, " a=% \n", a);
|
|
6084
|
-
VPrint(stdout, " b=% \n", b);
|
|
6085
|
-
}
|
|
6086
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6087
4925
|
return c->Prec*BASE_FIG;
|
|
6088
4926
|
}
|
|
6089
4927
|
|
|
6090
4928
|
/*
|
|
6091
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
|
|
6092
4934
|
*/
|
|
6093
4935
|
VP_EXPORT size_t
|
|
6094
4936
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
@@ -6097,16 +4939,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6097
4939
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
|
6098
4940
|
size_t nLoop;
|
|
6099
4941
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
|
6100
|
-
DECDIG
|
|
4942
|
+
DECDIG borrow1, borrow2;
|
|
6101
4943
|
DECDIG_DBL qb;
|
|
6102
4944
|
|
|
6103
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6104
|
-
if (gfDebug) {
|
|
6105
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
|
6106
|
-
VPrint(stdout, " b=% \n", b);
|
|
6107
|
-
}
|
|
6108
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6109
|
-
|
|
6110
4945
|
VpSetNaN(r);
|
|
6111
4946
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
|
6112
4947
|
if (VpIsZero(a) && VpIsZero(b)) {
|
|
@@ -6123,30 +4958,22 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6123
4958
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
|
6124
4959
|
goto Exit;
|
|
6125
4960
|
}
|
|
6126
|
-
if (VpIsOne(b)) {
|
|
6127
|
-
/* divide by one */
|
|
6128
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
6129
|
-
VpSetZero(r, VpGetSign(a));
|
|
6130
|
-
goto Exit;
|
|
6131
|
-
}
|
|
6132
4961
|
|
|
6133
4962
|
word_a = a->Prec;
|
|
6134
4963
|
word_b = b->Prec;
|
|
6135
4964
|
word_c = c->MaxPrec;
|
|
6136
4965
|
word_r = r->MaxPrec;
|
|
6137
4966
|
|
|
6138
|
-
if (word_a
|
|
4967
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
6139
4968
|
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
|
6144
|
-
++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;
|
|
6145
4972
|
}
|
|
6146
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
|
6147
4973
|
|
|
6148
|
-
|
|
6149
|
-
|
|
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;
|
|
6150
4977
|
|
|
6151
4978
|
/* initial procedure */
|
|
6152
4979
|
b1 = b1p1 = b->frac[0];
|
|
@@ -6161,15 +4988,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6161
4988
|
|
|
6162
4989
|
/* */
|
|
6163
4990
|
/* loop start */
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
ind_c = 1;
|
|
4991
|
+
nLoop = Min(word_c, word_r);
|
|
4992
|
+
ind_c = 0;
|
|
6167
4993
|
while (ind_c < nLoop) {
|
|
6168
4994
|
if (r->frac[ind_c] == 0) {
|
|
6169
4995
|
++ind_c;
|
|
6170
4996
|
continue;
|
|
6171
4997
|
}
|
|
6172
|
-
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);
|
|
6173
4999
|
if (r1r2 == b1b2) {
|
|
6174
5000
|
/* The first two word digits is the same */
|
|
6175
5001
|
ind_b = 2;
|
|
@@ -6182,26 +5008,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6182
5008
|
}
|
|
6183
5009
|
/* The first few word digits of r and b is the same and */
|
|
6184
5010
|
/* the first different word digit of w is greater than that */
|
|
6185
|
-
/* of b, so quotient is 1
|
|
6186
|
-
|
|
6187
|
-
ind_b = b->Prec - 1;
|
|
6188
|
-
ind_r = ind_c + ind_b;
|
|
6189
|
-
if (ind_r >= word_r) goto space_error;
|
|
6190
|
-
n = ind_b;
|
|
6191
|
-
for (i = 0; i <= n; ++i) {
|
|
6192
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
|
6193
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
|
6194
|
-
borrow = 1;
|
|
6195
|
-
}
|
|
6196
|
-
else {
|
|
6197
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
|
6198
|
-
borrow = 0;
|
|
6199
|
-
}
|
|
6200
|
-
--ind_r;
|
|
6201
|
-
--ind_b;
|
|
6202
|
-
}
|
|
5011
|
+
/* of b, so quotient is 1. */
|
|
5012
|
+
q = 1;
|
|
6203
5013
|
++c->frac[ind_c];
|
|
6204
|
-
|
|
5014
|
+
ind_r = b->Prec + ind_c - 1;
|
|
5015
|
+
goto sub_mult;
|
|
6205
5016
|
}
|
|
6206
5017
|
/* The first two word digits is not the same, */
|
|
6207
5018
|
/* then compare magnitude, and divide actually. */
|
|
@@ -6254,49 +5065,26 @@ sub_mult:
|
|
|
6254
5065
|
}
|
|
6255
5066
|
|
|
6256
5067
|
r->frac[ind_r] -= borrow2;
|
|
6257
|
-
carry:
|
|
6258
|
-
ind_r = ind_c;
|
|
6259
|
-
while (c->frac[ind_r] >= BASE) {
|
|
6260
|
-
c->frac[ind_r] -= BASE;
|
|
6261
|
-
--ind_r;
|
|
6262
|
-
++c->frac[ind_r];
|
|
6263
|
-
}
|
|
6264
5068
|
}
|
|
6265
5069
|
/* End of operation, now final arrangement */
|
|
6266
5070
|
out_side:
|
|
6267
5071
|
c->Prec = word_c;
|
|
6268
5072
|
c->exponent = a->exponent;
|
|
6269
|
-
|
|
5073
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
5074
|
+
if (!AddExponent(c, 1)) return 0;
|
|
6270
5075
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
|
6271
5076
|
|
|
6272
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
6273
5077
|
VpNmlz(c); /* normalize c */
|
|
6274
5078
|
r->Prec = word_r;
|
|
6275
5079
|
r->exponent = a->exponent;
|
|
6276
|
-
if (!AddExponent(r, 1)) return 0;
|
|
6277
5080
|
VpSetSign(r, VpGetSign(a));
|
|
6278
5081
|
VpNmlz(r); /* normalize r(remainder) */
|
|
6279
5082
|
goto Exit;
|
|
6280
5083
|
|
|
6281
5084
|
space_error:
|
|
6282
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6283
|
-
if (gfDebug) {
|
|
6284
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
|
6285
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
|
6286
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
|
6287
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
|
6288
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
|
6289
|
-
}
|
|
6290
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6291
5085
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
|
6292
5086
|
|
|
6293
5087
|
Exit:
|
|
6294
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6295
|
-
if (gfDebug) {
|
|
6296
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
|
6297
|
-
VPrint(stdout, " r=% \n", r);
|
|
6298
|
-
}
|
|
6299
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6300
5088
|
return c->Prec * BASE_FIG;
|
|
6301
5089
|
}
|
|
6302
5090
|
|
|
@@ -6419,13 +5207,6 @@ Exit:
|
|
|
6419
5207
|
if (val > 1) val = 1;
|
|
6420
5208
|
else if (val < -1) val = -1;
|
|
6421
5209
|
|
|
6422
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6423
|
-
if (gfDebug) {
|
|
6424
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
|
6425
|
-
VPrint(stdout, " b=%\n", b);
|
|
6426
|
-
printf(" ans=%d\n", val);
|
|
6427
|
-
}
|
|
6428
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6429
5210
|
return (int)val;
|
|
6430
5211
|
}
|
|
6431
5212
|
|
|
@@ -6543,25 +5324,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
|
6543
5324
|
static void
|
|
6544
5325
|
VpFormatSt(char *psz, size_t fFmt)
|
|
6545
5326
|
{
|
|
6546
|
-
size_t
|
|
6547
|
-
char
|
|
5327
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
|
5328
|
+
char *p;
|
|
6548
5329
|
|
|
6549
5330
|
if (fFmt == 0) return;
|
|
6550
5331
|
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
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;
|
|
6565
5350
|
}
|
|
6566
5351
|
}
|
|
6567
5352
|
|
|
@@ -6843,7 +5628,7 @@ VP_EXPORT int
|
|
|
6843
5628
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
|
6844
5629
|
{
|
|
6845
5630
|
size_t i, j, ind_a, ma, mi, me;
|
|
6846
|
-
SIGNED_VALUE e
|
|
5631
|
+
SIGNED_VALUE e;
|
|
6847
5632
|
int sign, signe, exponent_overflow;
|
|
6848
5633
|
|
|
6849
5634
|
/* get exponent part */
|
|
@@ -6866,23 +5651,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6866
5651
|
++me;
|
|
6867
5652
|
}
|
|
6868
5653
|
while (i < me) {
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
}
|
|
6873
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
|
6874
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
6875
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
|
6876
|
-
goto exp_overflow;
|
|
6877
|
-
e = e * 10 + exp_chr[i] - '0';
|
|
6878
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
6879
|
-
goto exp_overflow;
|
|
6880
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
|
6881
|
-
exp_overflow:
|
|
5654
|
+
int dig = exp_chr[i] - '0';
|
|
5655
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
5656
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
|
6882
5657
|
exponent_overflow = 1;
|
|
6883
|
-
e = es; /* keep sign */
|
|
6884
5658
|
break;
|
|
6885
5659
|
}
|
|
5660
|
+
e = e * 10 + signe * dig;
|
|
6886
5661
|
++i;
|
|
6887
5662
|
}
|
|
6888
5663
|
}
|
|
@@ -6901,34 +5676,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6901
5676
|
++mi;
|
|
6902
5677
|
}
|
|
6903
5678
|
}
|
|
5679
|
+
/* skip leading zeros in integer part */
|
|
5680
|
+
while (i < mi && int_chr[i] == '0') {
|
|
5681
|
+
++i;
|
|
5682
|
+
--ni;
|
|
5683
|
+
}
|
|
6904
5684
|
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
5685
|
+
/* set actual exponent size. */
|
|
5686
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
|
5687
|
+
exponent_overflow = 1;
|
|
5688
|
+
} else {
|
|
5689
|
+
e += ni;
|
|
5690
|
+
}
|
|
6910
5691
|
|
|
6911
5692
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
|
6912
|
-
j =
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
|
6918
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
|
6919
|
-
if (ef) {
|
|
6920
|
-
++j; /* Means to add one more preceding zero */
|
|
6921
|
-
++e;
|
|
6922
|
-
}
|
|
5693
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
|
5694
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
|
5695
|
+
exponent_overflow = 1;
|
|
5696
|
+
} else {
|
|
5697
|
+
e += j;
|
|
6923
5698
|
}
|
|
6924
5699
|
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
if (exponent_overflow) {
|
|
5700
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
|
6928
5701
|
int zero = 1;
|
|
6929
5702
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
|
6930
5703
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
|
6931
|
-
if (!zero &&
|
|
5704
|
+
if (!zero && e > 0) {
|
|
6932
5705
|
VpSetInf(a, sign);
|
|
6933
5706
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
|
6934
5707
|
}
|
|
@@ -6978,7 +5751,7 @@ Final:
|
|
|
6978
5751
|
++j;
|
|
6979
5752
|
}
|
|
6980
5753
|
a->Prec = ind_a + 1;
|
|
6981
|
-
a->exponent =
|
|
5754
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
|
6982
5755
|
VpSetSign(a, sign);
|
|
6983
5756
|
VpNmlz(a);
|
|
6984
5757
|
return 1;
|
|
@@ -7050,254 +5823,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
|
7050
5823
|
*d *= VpGetSign(m);
|
|
7051
5824
|
|
|
7052
5825
|
Exit:
|
|
7053
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7054
|
-
if (gfDebug) {
|
|
7055
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
|
7056
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
|
7057
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
7058
|
-
}
|
|
7059
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
7060
5826
|
return f;
|
|
7061
5827
|
}
|
|
7062
5828
|
|
|
7063
|
-
/*
|
|
7064
|
-
* m <- d
|
|
7065
|
-
*/
|
|
7066
|
-
VP_EXPORT void
|
|
7067
|
-
VpDtoV(Real *m, double d)
|
|
7068
|
-
{
|
|
7069
|
-
size_t ind_m, mm;
|
|
7070
|
-
SIGNED_VALUE ne;
|
|
7071
|
-
DECDIG i;
|
|
7072
|
-
double val, val2;
|
|
7073
|
-
|
|
7074
|
-
if (isnan(d)) {
|
|
7075
|
-
VpSetNaN(m);
|
|
7076
|
-
goto Exit;
|
|
7077
|
-
}
|
|
7078
|
-
if (isinf(d)) {
|
|
7079
|
-
if (d > 0.0) VpSetPosInf(m);
|
|
7080
|
-
else VpSetNegInf(m);
|
|
7081
|
-
goto Exit;
|
|
7082
|
-
}
|
|
7083
|
-
|
|
7084
|
-
if (d == 0.0) {
|
|
7085
|
-
VpSetZero(m, 1);
|
|
7086
|
-
goto Exit;
|
|
7087
|
-
}
|
|
7088
|
-
val = (d > 0.) ? d : -d;
|
|
7089
|
-
ne = 0;
|
|
7090
|
-
if (val >= 1.0) {
|
|
7091
|
-
while (val >= 1.0) {
|
|
7092
|
-
val /= (double)BASE;
|
|
7093
|
-
++ne;
|
|
7094
|
-
}
|
|
7095
|
-
}
|
|
7096
|
-
else {
|
|
7097
|
-
val2 = 1.0 / (double)BASE;
|
|
7098
|
-
while (val < val2) {
|
|
7099
|
-
val *= (double)BASE;
|
|
7100
|
-
--ne;
|
|
7101
|
-
}
|
|
7102
|
-
}
|
|
7103
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
|
7104
|
-
|
|
7105
|
-
mm = m->MaxPrec;
|
|
7106
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
|
7107
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
|
7108
|
-
val *= (double)BASE;
|
|
7109
|
-
i = (DECDIG)val;
|
|
7110
|
-
val -= (double)i;
|
|
7111
|
-
m->frac[ind_m] = i;
|
|
7112
|
-
}
|
|
7113
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
|
7114
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
|
7115
|
-
m->Prec = ind_m + 1;
|
|
7116
|
-
m->exponent = ne;
|
|
7117
|
-
|
|
7118
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
|
7119
|
-
(DECDIG)(val*(double)BASE));
|
|
7120
|
-
|
|
7121
|
-
Exit:
|
|
7122
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7123
|
-
if (gfDebug) {
|
|
7124
|
-
printf("VpDtoV d=%30.30e\n", d);
|
|
7125
|
-
VPrint(stdout, " m=%\n", m);
|
|
7126
|
-
}
|
|
7127
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7128
|
-
return;
|
|
7129
|
-
}
|
|
7130
|
-
|
|
7131
|
-
/*
|
|
7132
|
-
* m <- ival
|
|
7133
|
-
*/
|
|
7134
|
-
#if 0 /* unused */
|
|
7135
|
-
VP_EXPORT void
|
|
7136
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
|
7137
|
-
{
|
|
7138
|
-
size_t mm, ind_m;
|
|
7139
|
-
size_t val, v1, v2, v;
|
|
7140
|
-
int isign;
|
|
7141
|
-
SIGNED_VALUE ne;
|
|
7142
|
-
|
|
7143
|
-
if (ival == 0) {
|
|
7144
|
-
VpSetZero(m, 1);
|
|
7145
|
-
goto Exit;
|
|
7146
|
-
}
|
|
7147
|
-
isign = 1;
|
|
7148
|
-
val = ival;
|
|
7149
|
-
if (ival < 0) {
|
|
7150
|
-
isign = -1;
|
|
7151
|
-
val =(size_t)(-ival);
|
|
7152
|
-
}
|
|
7153
|
-
ne = 0;
|
|
7154
|
-
ind_m = 0;
|
|
7155
|
-
mm = m->MaxPrec;
|
|
7156
|
-
while (ind_m < mm) {
|
|
7157
|
-
m->frac[ind_m] = 0;
|
|
7158
|
-
++ind_m;
|
|
7159
|
-
}
|
|
7160
|
-
ind_m = 0;
|
|
7161
|
-
while (val > 0) {
|
|
7162
|
-
if (val) {
|
|
7163
|
-
v1 = val;
|
|
7164
|
-
v2 = 1;
|
|
7165
|
-
while (v1 >= BASE) {
|
|
7166
|
-
v1 /= BASE;
|
|
7167
|
-
v2 *= BASE;
|
|
7168
|
-
}
|
|
7169
|
-
val = val - v2 * v1;
|
|
7170
|
-
v = v1;
|
|
7171
|
-
}
|
|
7172
|
-
else {
|
|
7173
|
-
v = 0;
|
|
7174
|
-
}
|
|
7175
|
-
m->frac[ind_m] = v;
|
|
7176
|
-
++ind_m;
|
|
7177
|
-
++ne;
|
|
7178
|
-
}
|
|
7179
|
-
m->Prec = ind_m - 1;
|
|
7180
|
-
m->exponent = ne;
|
|
7181
|
-
VpSetSign(m, isign);
|
|
7182
|
-
VpNmlz(m);
|
|
7183
|
-
|
|
7184
|
-
Exit:
|
|
7185
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7186
|
-
if (gfDebug) {
|
|
7187
|
-
printf(" VpItoV i=%d\n", ival);
|
|
7188
|
-
VPrint(stdout, " m=%\n", m);
|
|
7189
|
-
}
|
|
7190
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7191
|
-
return;
|
|
7192
|
-
}
|
|
7193
|
-
#endif
|
|
7194
|
-
|
|
7195
|
-
/*
|
|
7196
|
-
* y = SQRT(x), y*y - x =>0
|
|
7197
|
-
*/
|
|
7198
|
-
VP_EXPORT int
|
|
7199
|
-
VpSqrt(Real *y, Real *x)
|
|
7200
|
-
{
|
|
7201
|
-
Real *f = NULL;
|
|
7202
|
-
Real *r = NULL;
|
|
7203
|
-
size_t y_prec;
|
|
7204
|
-
SIGNED_VALUE n, e;
|
|
7205
|
-
ssize_t nr;
|
|
7206
|
-
double val;
|
|
7207
|
-
|
|
7208
|
-
/* Zero or +Infinity ? */
|
|
7209
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
|
7210
|
-
VpAsgn(y,x,1);
|
|
7211
|
-
goto Exit;
|
|
7212
|
-
}
|
|
7213
|
-
|
|
7214
|
-
/* Negative ? */
|
|
7215
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
7216
|
-
VpSetNaN(y);
|
|
7217
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
|
7218
|
-
}
|
|
7219
|
-
|
|
7220
|
-
/* NaN ? */
|
|
7221
|
-
if (VpIsNaN(x)) {
|
|
7222
|
-
VpSetNaN(y);
|
|
7223
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
|
7224
|
-
}
|
|
7225
|
-
|
|
7226
|
-
/* One ? */
|
|
7227
|
-
if (VpIsOne(x)) {
|
|
7228
|
-
VpSetOne(y);
|
|
7229
|
-
goto Exit;
|
|
7230
|
-
}
|
|
7231
|
-
|
|
7232
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
|
7233
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
|
7234
|
-
|
|
7235
|
-
/* allocate temporally variables */
|
|
7236
|
-
/* TODO: reconsider MaxPrec of f and r */
|
|
7237
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
|
7238
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
|
7239
|
-
|
|
7240
|
-
nr = 0;
|
|
7241
|
-
y_prec = y->MaxPrec;
|
|
7242
|
-
|
|
7243
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
|
7244
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
|
7245
|
-
n = e / 2;
|
|
7246
|
-
if (e - n * 2 != 0) {
|
|
7247
|
-
val /= BASE;
|
|
7248
|
-
n = (e + 1) / 2;
|
|
7249
|
-
}
|
|
7250
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
|
7251
|
-
y->exponent += n;
|
|
7252
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
|
7253
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
|
7254
|
-
f->MaxPrec = y->MaxPrec + 1;
|
|
7255
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
|
7256
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
|
7257
|
-
|
|
7258
|
-
/*
|
|
7259
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
|
7260
|
-
*/
|
|
7261
|
-
do {
|
|
7262
|
-
y->MaxPrec *= 2;
|
|
7263
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
|
7264
|
-
f->MaxPrec = y->MaxPrec;
|
|
7265
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
|
7266
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
|
7267
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
|
7268
|
-
if (VpIsZero(f))
|
|
7269
|
-
goto converge;
|
|
7270
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
|
7271
|
-
VpAsgn(y, r, 1); /* y = r */
|
|
7272
|
-
} while (++nr < n);
|
|
7273
|
-
|
|
7274
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7275
|
-
if (gfDebug) {
|
|
7276
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
|
7277
|
-
}
|
|
7278
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7279
|
-
y->MaxPrec = y_prec;
|
|
7280
|
-
|
|
7281
|
-
converge:
|
|
7282
|
-
VpChangeSign(y, 1);
|
|
7283
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7284
|
-
if (gfDebug) {
|
|
7285
|
-
VpMult(r, y, y);
|
|
7286
|
-
VpAddSub(f, x, r, -1);
|
|
7287
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
|
7288
|
-
VPrint(stdout, " y =% \n", y);
|
|
7289
|
-
VPrint(stdout, " x =% \n", x);
|
|
7290
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
|
7291
|
-
}
|
|
7292
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7293
|
-
y->MaxPrec = y_prec;
|
|
7294
|
-
|
|
7295
|
-
Exit:
|
|
7296
|
-
rbd_free_struct(f);
|
|
7297
|
-
rbd_free_struct(r);
|
|
7298
|
-
return 1;
|
|
7299
|
-
}
|
|
7300
|
-
|
|
7301
5829
|
/*
|
|
7302
5830
|
* Round relatively from the decimal point.
|
|
7303
5831
|
* f: rounding mode
|
|
@@ -7474,7 +6002,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
7474
6002
|
DECDIG v;
|
|
7475
6003
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
|
7476
6004
|
v = y->frac[0];
|
|
7477
|
-
nf -=
|
|
6005
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
|
7478
6006
|
while ((v /= 10) != 0) nf--;
|
|
7479
6007
|
nf += (ssize_t)BASE_FIG-1;
|
|
7480
6008
|
return VpMidRound(y, f, nf);
|
|
@@ -7581,7 +6109,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7581
6109
|
size_t my, ind_y, ind_x;
|
|
7582
6110
|
|
|
7583
6111
|
if (!VpHasVal(x)) {
|
|
7584
|
-
VpAsgn(y, x,
|
|
6112
|
+
VpAsgn(y, x, 10);
|
|
7585
6113
|
goto Exit;
|
|
7586
6114
|
}
|
|
7587
6115
|
|
|
@@ -7590,7 +6118,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7590
6118
|
goto Exit;
|
|
7591
6119
|
}
|
|
7592
6120
|
else if (x->exponent <= 0) {
|
|
7593
|
-
VpAsgn(y, x,
|
|
6121
|
+
VpAsgn(y, x, 10);
|
|
7594
6122
|
goto Exit;
|
|
7595
6123
|
}
|
|
7596
6124
|
|
|
@@ -7611,117 +6139,9 @@ VpFrac(Real *y, Real *x)
|
|
|
7611
6139
|
VpNmlz(y);
|
|
7612
6140
|
|
|
7613
6141
|
Exit:
|
|
7614
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7615
|
-
if (gfDebug) {
|
|
7616
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
|
7617
|
-
VPrint(stdout, " x=%\n", x);
|
|
7618
|
-
}
|
|
7619
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7620
6142
|
return;
|
|
7621
6143
|
}
|
|
7622
6144
|
|
|
7623
|
-
/*
|
|
7624
|
-
* y = x ** n
|
|
7625
|
-
*/
|
|
7626
|
-
VP_EXPORT int
|
|
7627
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
|
7628
|
-
{
|
|
7629
|
-
size_t s, ss;
|
|
7630
|
-
ssize_t sign;
|
|
7631
|
-
Real *w1 = NULL;
|
|
7632
|
-
Real *w2 = NULL;
|
|
7633
|
-
|
|
7634
|
-
if (VpIsZero(x)) {
|
|
7635
|
-
if (n == 0) {
|
|
7636
|
-
VpSetOne(y);
|
|
7637
|
-
goto Exit;
|
|
7638
|
-
}
|
|
7639
|
-
sign = VpGetSign(x);
|
|
7640
|
-
if (n < 0) {
|
|
7641
|
-
n = -n;
|
|
7642
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7643
|
-
VpSetInf(y, sign);
|
|
7644
|
-
}
|
|
7645
|
-
else {
|
|
7646
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7647
|
-
VpSetZero(y,sign);
|
|
7648
|
-
}
|
|
7649
|
-
goto Exit;
|
|
7650
|
-
}
|
|
7651
|
-
if (VpIsNaN(x)) {
|
|
7652
|
-
VpSetNaN(y);
|
|
7653
|
-
goto Exit;
|
|
7654
|
-
}
|
|
7655
|
-
if (VpIsInf(x)) {
|
|
7656
|
-
if (n == 0) {
|
|
7657
|
-
VpSetOne(y);
|
|
7658
|
-
goto Exit;
|
|
7659
|
-
}
|
|
7660
|
-
if (n > 0) {
|
|
7661
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7662
|
-
goto Exit;
|
|
7663
|
-
}
|
|
7664
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7665
|
-
goto Exit;
|
|
7666
|
-
}
|
|
7667
|
-
|
|
7668
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
|
7669
|
-
/* abs(x) = 1 */
|
|
7670
|
-
VpSetOne(y);
|
|
7671
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
|
7672
|
-
if ((n % 2) == 0) goto Exit;
|
|
7673
|
-
VpSetSign(y, -1);
|
|
7674
|
-
goto Exit;
|
|
7675
|
-
}
|
|
7676
|
-
|
|
7677
|
-
if (n > 0) sign = 1;
|
|
7678
|
-
else if (n < 0) {
|
|
7679
|
-
sign = -1;
|
|
7680
|
-
n = -n;
|
|
7681
|
-
}
|
|
7682
|
-
else {
|
|
7683
|
-
VpSetOne(y);
|
|
7684
|
-
goto Exit;
|
|
7685
|
-
}
|
|
7686
|
-
|
|
7687
|
-
/* Allocate working variables */
|
|
7688
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
|
7689
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
|
7690
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
|
7691
|
-
|
|
7692
|
-
/* calculation start */
|
|
7693
|
-
|
|
7694
|
-
VpAsgn(y, x, 1);
|
|
7695
|
-
--n;
|
|
7696
|
-
while (n > 0) {
|
|
7697
|
-
VpAsgn(w1, x, 1);
|
|
7698
|
-
s = 1;
|
|
7699
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
|
7700
|
-
VpMult(w2, w1, w1);
|
|
7701
|
-
VpAsgn(w1, w2, 1);
|
|
7702
|
-
}
|
|
7703
|
-
n -= (SIGNED_VALUE)ss;
|
|
7704
|
-
VpMult(w2, y, w1);
|
|
7705
|
-
VpAsgn(y, w2, 1);
|
|
7706
|
-
}
|
|
7707
|
-
if (sign < 0) {
|
|
7708
|
-
VpDivd(w1, w2, VpConstOne, y);
|
|
7709
|
-
VpAsgn(y, w1, 1);
|
|
7710
|
-
}
|
|
7711
|
-
|
|
7712
|
-
Exit:
|
|
7713
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7714
|
-
if (gfDebug) {
|
|
7715
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
|
7716
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
|
7717
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
|
7718
|
-
}
|
|
7719
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7720
|
-
rbd_free_struct(w2);
|
|
7721
|
-
rbd_free_struct(w1);
|
|
7722
|
-
return 1;
|
|
7723
|
-
}
|
|
7724
|
-
|
|
7725
6145
|
#ifdef BIGDECIMAL_DEBUG
|
|
7726
6146
|
int
|
|
7727
6147
|
VpVarCheck(Real * v)
|