bigdecimal 3.2.2 → 4.0.0
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/ext/bigdecimal/bigdecimal.c +734 -2289
- data/ext/bigdecimal/bigdecimal.h +4 -25
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/extconf.rb +3 -7
- data/ext/bigdecimal/missing.h +1 -93
- data/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math.rb +789 -71
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +15 -14
- data/lib/bigdecimal.rb +355 -0
- metadata +2 -2
data/ext/bigdecimal/bigdecimal.c
CHANGED
|
@@ -31,16 +31,23 @@
|
|
|
31
31
|
#include "bits.h"
|
|
32
32
|
#include "static_assert.h"
|
|
33
33
|
|
|
34
|
-
#define BIGDECIMAL_VERSION "
|
|
34
|
+
#define BIGDECIMAL_VERSION "4.0.0"
|
|
35
35
|
|
|
36
36
|
/* #define ENABLE_NUMERIC_STRING */
|
|
37
37
|
|
|
38
38
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
|
39
39
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
|
40
40
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
41
|
+
#define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
42
|
+
|
|
43
|
+
/* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
|
|
44
|
+
#define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
|
|
45
|
+
/* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
|
|
46
|
+
#define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
|
|
47
|
+
#define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
|
|
48
|
+
#define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
|
|
41
49
|
|
|
42
50
|
VALUE rb_cBigDecimal;
|
|
43
|
-
VALUE rb_mBigMath;
|
|
44
51
|
|
|
45
52
|
static ID id_BigDecimal_exception_mode;
|
|
46
53
|
static ID id_BigDecimal_rounding_mode;
|
|
@@ -68,15 +75,28 @@ static struct {
|
|
|
68
75
|
uint8_t mode;
|
|
69
76
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
typedef struct {
|
|
79
|
+
VALUE bigdecimal;
|
|
80
|
+
Real *real;
|
|
81
|
+
} BDVALUE;
|
|
82
|
+
|
|
83
|
+
typedef struct {
|
|
84
|
+
VALUE bigdecimal_or_nil;
|
|
85
|
+
Real *real_or_null;
|
|
86
|
+
} NULLABLE_BDVALUE;
|
|
87
|
+
|
|
88
|
+
static inline BDVALUE
|
|
89
|
+
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
90
|
+
{
|
|
91
|
+
assert(v.real_or_null != NULL);
|
|
92
|
+
return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static inline NULLABLE_BDVALUE
|
|
96
|
+
bdvalue_nullable(BDVALUE v)
|
|
97
|
+
{
|
|
98
|
+
return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
|
|
99
|
+
}
|
|
80
100
|
|
|
81
101
|
#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
|
|
82
102
|
#define BASE BIGDECIMAL_BASE
|
|
@@ -84,31 +104,6 @@ static struct {
|
|
|
84
104
|
#define HALF_BASE (BASE/2)
|
|
85
105
|
#define BASE1 (BASE/10)
|
|
86
106
|
|
|
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
107
|
#ifndef MAYBE_UNUSED
|
|
113
108
|
# define MAYBE_UNUSED(x) x
|
|
114
109
|
#endif
|
|
@@ -145,6 +140,17 @@ check_allocation_count_nonzero(void)
|
|
|
145
140
|
# define check_allocation_count_nonzero() /* nothing */
|
|
146
141
|
#endif /* BIGDECIMAL_DEBUG */
|
|
147
142
|
|
|
143
|
+
/* VpMult VpDivd helpers */
|
|
144
|
+
#define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
|
|
145
|
+
/* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
|
|
146
|
+
/* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
|
|
147
|
+
#define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
|
|
148
|
+
/* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
|
|
149
|
+
#define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
|
|
150
|
+
|
|
151
|
+
static NULLABLE_BDVALUE
|
|
152
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
|
|
153
|
+
|
|
148
154
|
PUREFUNC(static inline size_t rbd_struct_size(size_t const));
|
|
149
155
|
|
|
150
156
|
static inline size_t
|
|
@@ -164,44 +170,10 @@ rbd_allocate_struct(size_t const internal_digits)
|
|
|
164
170
|
return real;
|
|
165
171
|
}
|
|
166
172
|
|
|
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
173
|
static inline Real *
|
|
185
|
-
rbd_allocate_struct_decimal_digits(size_t const decimal_digits
|
|
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)
|
|
174
|
+
rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
|
|
195
175
|
{
|
|
196
|
-
|
|
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;
|
|
176
|
+
return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
|
|
205
177
|
}
|
|
206
178
|
|
|
207
179
|
static void
|
|
@@ -214,58 +186,16 @@ rbd_free_struct(Real *real)
|
|
|
214
186
|
}
|
|
215
187
|
}
|
|
216
188
|
|
|
189
|
+
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
|
|
217
190
|
#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
191
|
static inline Real *
|
|
237
|
-
|
|
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)
|
|
192
|
+
rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
245
193
|
{
|
|
246
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits
|
|
247
|
-
|
|
248
|
-
if (sign < 0)
|
|
249
|
-
VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
|
|
194
|
+
Real *real = rbd_allocate_struct_decimal_digits(digits);
|
|
195
|
+
VpSetZero(real, sign);
|
|
250
196
|
return real;
|
|
251
197
|
}
|
|
252
198
|
|
|
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
199
|
/*
|
|
270
200
|
* ================== Ruby Interface part ==========================
|
|
271
201
|
*/
|
|
@@ -277,7 +207,8 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
|
|
277
207
|
static unsigned short VpGetException(void);
|
|
278
208
|
static void VpSetException(unsigned short f);
|
|
279
209
|
static void VpCheckException(Real *p, bool always);
|
|
280
|
-
static
|
|
210
|
+
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
211
|
+
static VALUE CheckGetValue(BDVALUE v);
|
|
281
212
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
282
213
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
283
214
|
static Real *VpCopy(Real *pv, Real const* const x);
|
|
@@ -292,6 +223,8 @@ static VALUE BigDecimal_positive_infinity(void);
|
|
|
292
223
|
static VALUE BigDecimal_negative_infinity(void);
|
|
293
224
|
static VALUE BigDecimal_positive_zero(void);
|
|
294
225
|
static VALUE BigDecimal_negative_zero(void);
|
|
226
|
+
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
227
|
+
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
295
228
|
|
|
296
229
|
static void
|
|
297
230
|
BigDecimal_delete(void *pv)
|
|
@@ -319,58 +252,33 @@ static const rb_data_type_t BigDecimal_data_type = {
|
|
|
319
252
|
#endif
|
|
320
253
|
};
|
|
321
254
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
{
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
328
|
-
BigDecimal_wrap_struct(obj, real);
|
|
329
|
-
}
|
|
330
|
-
return real;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
|
|
334
|
-
#define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
|
|
335
|
-
static inline Real *
|
|
336
|
-
rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
|
|
337
|
-
{
|
|
338
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
|
|
342
|
-
#define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
|
|
343
|
-
static inline Real *
|
|
344
|
-
rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
|
|
345
|
-
{
|
|
346
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
static Real *
|
|
350
|
-
rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
|
|
255
|
+
// TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
|
|
256
|
+
// We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
|
|
257
|
+
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
|
258
|
+
static NULL_WRAPPED_VALUE
|
|
259
|
+
BigDecimal_alloc_empty_struct(VALUE klass)
|
|
351
260
|
{
|
|
352
|
-
|
|
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;
|
|
261
|
+
return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
|
|
358
262
|
}
|
|
359
263
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
static inline Real *
|
|
363
|
-
rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
|
|
264
|
+
static VALUE
|
|
265
|
+
BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
|
|
364
266
|
{
|
|
365
|
-
|
|
267
|
+
VALUE obj = v._obj;
|
|
268
|
+
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
269
|
+
RTYPEDDATA_DATA(obj) = real;
|
|
270
|
+
RB_OBJ_FREEZE(obj);
|
|
271
|
+
return obj;
|
|
366
272
|
}
|
|
367
273
|
|
|
368
|
-
MAYBE_UNUSED(static inline
|
|
369
|
-
#define
|
|
370
|
-
static
|
|
371
|
-
|
|
274
|
+
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
275
|
+
#define NewZeroWrap rbd_allocate_struct_zero_wrap
|
|
276
|
+
static BDVALUE
|
|
277
|
+
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
372
278
|
{
|
|
373
|
-
|
|
279
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
280
|
+
Real *real = rbd_allocate_struct_zero(sign, digits);
|
|
281
|
+
return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
|
|
374
282
|
}
|
|
375
283
|
|
|
376
284
|
static inline int
|
|
@@ -398,24 +306,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
|
|
|
398
306
|
}
|
|
399
307
|
|
|
400
308
|
static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
|
|
401
|
-
static VALUE rb_inum_convert_to_BigDecimal(VALUE val
|
|
309
|
+
static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
|
|
402
310
|
static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
403
311
|
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,
|
|
312
|
+
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
|
|
405
313
|
static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
406
314
|
|
|
407
|
-
static
|
|
408
|
-
|
|
315
|
+
static NULLABLE_BDVALUE
|
|
316
|
+
GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
409
317
|
{
|
|
410
|
-
const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
|
|
411
|
-
|
|
412
318
|
switch(TYPE(v)) {
|
|
413
319
|
case T_FLOAT:
|
|
414
|
-
v = rb_float_convert_to_BigDecimal(v,
|
|
320
|
+
v = rb_float_convert_to_BigDecimal(v, 0, true);
|
|
415
321
|
break;
|
|
416
322
|
|
|
417
323
|
case T_RATIONAL:
|
|
418
|
-
v = rb_rational_convert_to_BigDecimal(v,
|
|
324
|
+
v = rb_rational_convert_to_BigDecimal(v, prec, true);
|
|
419
325
|
break;
|
|
420
326
|
|
|
421
327
|
case T_DATA:
|
|
@@ -424,47 +330,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
|
|
|
424
330
|
}
|
|
425
331
|
break;
|
|
426
332
|
|
|
427
|
-
case T_FIXNUM:
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
|
|
333
|
+
case T_FIXNUM:
|
|
334
|
+
case T_BIGNUM: {
|
|
335
|
+
v = rb_inum_convert_to_BigDecimal(v);
|
|
431
336
|
break;
|
|
432
337
|
}
|
|
433
338
|
|
|
434
339
|
#ifdef ENABLE_NUMERIC_STRING
|
|
435
340
|
case T_STRING: {
|
|
436
341
|
const char *c_str = StringValueCStr(v);
|
|
437
|
-
v = rb_cstr_convert_to_BigDecimal(c_str,
|
|
342
|
+
v = rb_cstr_convert_to_BigDecimal(c_str, must);
|
|
438
343
|
break;
|
|
439
344
|
}
|
|
440
345
|
#endif /* ENABLE_NUMERIC_STRING */
|
|
441
346
|
|
|
442
|
-
case T_BIGNUM: {
|
|
443
|
-
VALUE bg = rb_big2str(v, 10);
|
|
444
|
-
v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
|
|
445
|
-
RB_GC_GUARD(bg);
|
|
446
|
-
break;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
347
|
default:
|
|
450
348
|
goto SomeOneMayDoIt;
|
|
451
349
|
}
|
|
452
350
|
|
|
453
351
|
Real *vp;
|
|
454
352
|
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
|
455
|
-
return vp;
|
|
353
|
+
return (NULLABLE_BDVALUE) { v, vp };
|
|
456
354
|
|
|
457
355
|
SomeOneMayDoIt:
|
|
458
356
|
if (must) {
|
|
459
357
|
cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
|
|
460
358
|
}
|
|
461
|
-
return NULL; /* NULL means to coerce */
|
|
359
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
static inline NULLABLE_BDVALUE
|
|
363
|
+
GetBDValueWithPrec(VALUE v, size_t prec)
|
|
364
|
+
{
|
|
365
|
+
return GetBDValueWithPrecInternal(v, prec, 0);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
static inline BDVALUE
|
|
370
|
+
GetBDValueWithPrecMust(VALUE v, size_t prec)
|
|
371
|
+
{
|
|
372
|
+
return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
|
|
462
373
|
}
|
|
463
374
|
|
|
375
|
+
// self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
|
|
464
376
|
static inline Real*
|
|
465
|
-
|
|
377
|
+
GetSelfVpValue(VALUE self)
|
|
378
|
+
{
|
|
379
|
+
return GetBDValueWithPrecMust(self, 0).real;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
static inline BDVALUE
|
|
383
|
+
GetBDValueMust(VALUE v)
|
|
466
384
|
{
|
|
467
|
-
return
|
|
385
|
+
return GetBDValueWithPrecMust(v, 0);
|
|
468
386
|
}
|
|
469
387
|
|
|
470
388
|
/* call-seq:
|
|
@@ -479,37 +397,7 @@ GetVpValue(VALUE v, int must)
|
|
|
479
397
|
static inline VALUE
|
|
480
398
|
BigDecimal_double_fig(VALUE self)
|
|
481
399
|
{
|
|
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;
|
|
400
|
+
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
513
401
|
}
|
|
514
402
|
|
|
515
403
|
static void
|
|
@@ -623,10 +511,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
|
623
511
|
static void
|
|
624
512
|
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
|
625
513
|
{
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
VpCountPrecisionAndScale(p, out_precision, out_scale);
|
|
514
|
+
BDVALUE v = GetBDValueMust(self);
|
|
515
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
|
516
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
630
517
|
}
|
|
631
518
|
|
|
632
519
|
/*
|
|
@@ -664,8 +551,8 @@ BigDecimal_precision(VALUE self)
|
|
|
664
551
|
* BigDecimal("1").scale # => 0
|
|
665
552
|
* BigDecimal("1.1").scale # => 1
|
|
666
553
|
* BigDecimal("3.1415").scale # => 4
|
|
667
|
-
* BigDecimal("-1e20").
|
|
668
|
-
* BigDecimal("1e-20").
|
|
554
|
+
* BigDecimal("-1e20").scale # => 0
|
|
555
|
+
* BigDecimal("1e-20").scale # => 20
|
|
669
556
|
* BigDecimal("Infinity").scale # => 0
|
|
670
557
|
* BigDecimal("-Infinity").scale # => 0
|
|
671
558
|
* BigDecimal("NaN").scale # => 0
|
|
@@ -715,25 +602,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
|
715
602
|
static VALUE
|
|
716
603
|
BigDecimal_n_significant_digits(VALUE self)
|
|
717
604
|
{
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
Real *p;
|
|
721
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
722
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
605
|
+
BDVALUE v = GetBDValueMust(self);
|
|
606
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
|
723
607
|
return INT2FIX(0);
|
|
724
608
|
}
|
|
725
609
|
|
|
726
|
-
ssize_t n =
|
|
727
|
-
for (n =
|
|
610
|
+
ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
|
|
611
|
+
for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
|
|
728
612
|
if (n == 0) return INT2FIX(0);
|
|
729
613
|
|
|
730
614
|
DECDIG x;
|
|
731
615
|
int nlz = BASE_FIG;
|
|
732
|
-
for (x =
|
|
616
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
|
733
617
|
|
|
734
618
|
int ntz = 0;
|
|
735
|
-
for (x =
|
|
619
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
|
736
620
|
|
|
621
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
737
622
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
|
738
623
|
return SSIZET2NUM(n_significant_digits);
|
|
739
624
|
}
|
|
@@ -755,17 +640,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
|
755
640
|
static VALUE
|
|
756
641
|
BigDecimal_hash(VALUE self)
|
|
757
642
|
{
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
st_index_t hash;
|
|
761
|
-
|
|
762
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
763
|
-
hash = (st_index_t)p->sign;
|
|
643
|
+
BDVALUE v = GetBDValueMust(self);
|
|
644
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
|
764
645
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
|
765
646
|
if(hash == 2 || hash == (st_index_t)-2) {
|
|
766
|
-
hash ^= rb_memhash(
|
|
767
|
-
hash +=
|
|
647
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
|
648
|
+
hash += v.real->exponent;
|
|
768
649
|
}
|
|
650
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
769
651
|
return ST2FIX(hash);
|
|
770
652
|
}
|
|
771
653
|
|
|
@@ -784,21 +666,22 @@ BigDecimal_hash(VALUE self)
|
|
|
784
666
|
static VALUE
|
|
785
667
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
786
668
|
{
|
|
787
|
-
|
|
788
|
-
Real *vp;
|
|
669
|
+
BDVALUE v;
|
|
789
670
|
char *psz;
|
|
790
671
|
VALUE dummy;
|
|
791
672
|
volatile VALUE dump;
|
|
792
673
|
size_t len;
|
|
793
674
|
|
|
794
675
|
rb_scan_args(argc, argv, "01", &dummy);
|
|
795
|
-
|
|
796
|
-
dump = rb_str_new(0, VpNumOfChars(
|
|
676
|
+
v = GetBDValueMust(self);
|
|
677
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
|
797
678
|
psz = RSTRING_PTR(dump);
|
|
798
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
|
679
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
|
799
680
|
len = strlen(psz);
|
|
800
|
-
VpToString(
|
|
681
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
|
801
682
|
rb_str_resize(dump, strlen(psz));
|
|
683
|
+
|
|
684
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
802
685
|
return dump;
|
|
803
686
|
}
|
|
804
687
|
|
|
@@ -808,27 +691,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
|
808
691
|
static VALUE
|
|
809
692
|
BigDecimal_load(VALUE self, VALUE str)
|
|
810
693
|
{
|
|
811
|
-
|
|
812
|
-
Real *pv;
|
|
694
|
+
BDVALUE v;
|
|
813
695
|
unsigned char *pch;
|
|
814
696
|
unsigned char ch;
|
|
815
|
-
unsigned long m=0;
|
|
816
697
|
|
|
817
698
|
pch = (unsigned char *)StringValueCStr(str);
|
|
818
|
-
/* First
|
|
699
|
+
/* First skip max prec. Don't trust the value. */
|
|
819
700
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
|
820
701
|
if(!ISDIGIT(ch)) {
|
|
821
702
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
|
822
703
|
}
|
|
823
|
-
m = m*10 + (unsigned long)(ch-'0');
|
|
824
704
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
m /= VpBaseFig();
|
|
828
|
-
if (m && pv->MaxPrec > m) {
|
|
829
|
-
pv->MaxPrec = m+1;
|
|
830
|
-
}
|
|
831
|
-
return VpCheckGetValue(pv);
|
|
705
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
706
|
+
return CheckGetValue(v);
|
|
832
707
|
}
|
|
833
708
|
|
|
834
709
|
static unsigned short
|
|
@@ -1121,22 +996,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1121
996
|
static size_t
|
|
1122
997
|
GetAddSubPrec(Real *a, Real *b)
|
|
1123
998
|
{
|
|
1124
|
-
size_t mxs;
|
|
1125
|
-
size_t mx = a->Prec;
|
|
1126
|
-
SIGNED_VALUE d;
|
|
1127
|
-
|
|
1128
999
|
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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;
|
|
1000
|
+
ssize_t min_a = a->exponent - a->Prec;
|
|
1001
|
+
ssize_t min_b = b->exponent - b->Prec;
|
|
1002
|
+
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
1140
1003
|
}
|
|
1141
1004
|
|
|
1142
1005
|
static inline SIGNED_VALUE
|
|
@@ -1156,39 +1019,13 @@ check_int_precision(VALUE v)
|
|
|
1156
1019
|
return n;
|
|
1157
1020
|
}
|
|
1158
1021
|
|
|
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)
|
|
1022
|
+
static NULLABLE_BDVALUE
|
|
1023
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1190
1024
|
{
|
|
1191
|
-
|
|
1025
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
|
|
1026
|
+
Real *pv = VpAlloc(str, strict_p, raise_exception);
|
|
1027
|
+
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1028
|
+
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
|
|
1192
1029
|
}
|
|
1193
1030
|
|
|
1194
1031
|
static Real *
|
|
@@ -1196,7 +1033,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1196
1033
|
{
|
|
1197
1034
|
assert(x != NULL);
|
|
1198
1035
|
|
|
1199
|
-
pv =
|
|
1036
|
+
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1200
1037
|
pv->MaxPrec = x->MaxPrec;
|
|
1201
1038
|
pv->Prec = x->Prec;
|
|
1202
1039
|
pv->exponent = x->exponent;
|
|
@@ -1211,7 +1048,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1211
1048
|
static VALUE
|
|
1212
1049
|
BigDecimal_IsNaN(VALUE self)
|
|
1213
1050
|
{
|
|
1214
|
-
Real *p =
|
|
1051
|
+
Real *p = GetSelfVpValue(self);
|
|
1215
1052
|
if (VpIsNaN(p)) return Qtrue;
|
|
1216
1053
|
return Qfalse;
|
|
1217
1054
|
}
|
|
@@ -1222,7 +1059,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
|
1222
1059
|
static VALUE
|
|
1223
1060
|
BigDecimal_IsInfinite(VALUE self)
|
|
1224
1061
|
{
|
|
1225
|
-
Real *p =
|
|
1062
|
+
Real *p = GetSelfVpValue(self);
|
|
1226
1063
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
|
1227
1064
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
|
1228
1065
|
return Qnil;
|
|
@@ -1232,7 +1069,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
|
1232
1069
|
static VALUE
|
|
1233
1070
|
BigDecimal_IsFinite(VALUE self)
|
|
1234
1071
|
{
|
|
1235
|
-
Real *p =
|
|
1072
|
+
Real *p = GetSelfVpValue(self);
|
|
1236
1073
|
if (VpIsNaN(p)) return Qfalse;
|
|
1237
1074
|
if (VpIsInf(p)) return Qfalse;
|
|
1238
1075
|
return Qtrue;
|
|
@@ -1244,6 +1081,7 @@ BigDecimal_check_num(Real *p)
|
|
|
1244
1081
|
VpCheckException(p, true);
|
|
1245
1082
|
}
|
|
1246
1083
|
|
|
1084
|
+
static VALUE BigDecimal_fix(VALUE self);
|
|
1247
1085
|
static VALUE BigDecimal_split(VALUE self);
|
|
1248
1086
|
|
|
1249
1087
|
/* Returns the value as an Integer.
|
|
@@ -1253,44 +1091,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
|
1253
1091
|
static VALUE
|
|
1254
1092
|
BigDecimal_to_i(VALUE self)
|
|
1255
1093
|
{
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
Real *p;
|
|
1094
|
+
BDVALUE v;
|
|
1095
|
+
VALUE ret;
|
|
1259
1096
|
|
|
1260
|
-
|
|
1261
|
-
BigDecimal_check_num(
|
|
1097
|
+
v = GetBDValueMust(self);
|
|
1098
|
+
BigDecimal_check_num(v.real);
|
|
1262
1099
|
|
|
1263
|
-
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1266
|
-
if (e <= nf) {
|
|
1267
|
-
return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
|
|
1100
|
+
if (v.real->exponent <= 0) return INT2FIX(0);
|
|
1101
|
+
if (v.real->exponent == 1) {
|
|
1102
|
+
ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
|
|
1268
1103
|
}
|
|
1269
1104
|
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;
|
|
1105
|
+
VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
|
|
1106
|
+
VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
|
|
1107
|
+
ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
|
|
1108
|
+
ret = rb_funcall(digits, rb_intern("to_i"), 0);
|
|
1109
|
+
|
|
1110
|
+
if (BIGDECIMAL_NEGATIVE_P(v.real)) {
|
|
1111
|
+
ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
|
|
1112
|
+
}
|
|
1113
|
+
if (dpower) {
|
|
1114
|
+
VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
|
|
1115
|
+
// In Ruby < 3.4, int**int may return Float::INFINITY
|
|
1116
|
+
if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1117
|
+
|
|
1118
|
+
ret = rb_funcall(ret, '*', 1, pow10);
|
|
1119
|
+
}
|
|
1293
1120
|
}
|
|
1121
|
+
|
|
1122
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1123
|
+
return ret;
|
|
1294
1124
|
}
|
|
1295
1125
|
|
|
1296
1126
|
/* Returns a new Float object having approximately the same value as the
|
|
@@ -1300,24 +1130,26 @@ BigDecimal_to_i(VALUE self)
|
|
|
1300
1130
|
static VALUE
|
|
1301
1131
|
BigDecimal_to_f(VALUE self)
|
|
1302
1132
|
{
|
|
1303
|
-
ENTER(1);
|
|
1304
|
-
Real *p;
|
|
1305
1133
|
double d;
|
|
1306
1134
|
SIGNED_VALUE e;
|
|
1307
1135
|
char *buf;
|
|
1308
1136
|
volatile VALUE str;
|
|
1137
|
+
BDVALUE v = GetBDValueMust(self);
|
|
1138
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
|
1309
1139
|
|
|
1310
|
-
|
|
1311
|
-
if (VpVtoD(&d, &e, p) != 1)
|
|
1140
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
|
1312
1141
|
return rb_float_new(d);
|
|
1313
1142
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
|
1314
1143
|
goto overflow;
|
|
1315
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
|
1144
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
|
1316
1145
|
goto underflow;
|
|
1317
1146
|
|
|
1318
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
1147
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
1319
1148
|
buf = RSTRING_PTR(str);
|
|
1320
|
-
VpToString(
|
|
1149
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
|
1150
|
+
|
|
1151
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1152
|
+
|
|
1321
1153
|
errno = 0;
|
|
1322
1154
|
d = strtod(buf, 0);
|
|
1323
1155
|
if (errno == ERANGE) {
|
|
@@ -1328,14 +1160,14 @@ BigDecimal_to_f(VALUE self)
|
|
|
1328
1160
|
|
|
1329
1161
|
overflow:
|
|
1330
1162
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
|
1331
|
-
if (
|
|
1163
|
+
if (negative)
|
|
1332
1164
|
return rb_float_new(VpGetDoubleNegInf());
|
|
1333
1165
|
else
|
|
1334
1166
|
return rb_float_new(VpGetDoublePosInf());
|
|
1335
1167
|
|
|
1336
1168
|
underflow:
|
|
1337
1169
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
|
1338
|
-
if (
|
|
1170
|
+
if (negative)
|
|
1339
1171
|
return rb_float_new(-0.0);
|
|
1340
1172
|
else
|
|
1341
1173
|
return rb_float_new(0.0);
|
|
@@ -1347,15 +1179,16 @@ underflow:
|
|
|
1347
1179
|
static VALUE
|
|
1348
1180
|
BigDecimal_to_r(VALUE self)
|
|
1349
1181
|
{
|
|
1350
|
-
|
|
1182
|
+
BDVALUE v;
|
|
1351
1183
|
ssize_t sign, power, denomi_power;
|
|
1352
1184
|
VALUE a, digits, numerator;
|
|
1353
1185
|
|
|
1354
|
-
|
|
1355
|
-
BigDecimal_check_num(
|
|
1186
|
+
v = GetBDValueMust(self);
|
|
1187
|
+
BigDecimal_check_num(v.real);
|
|
1188
|
+
sign = VpGetSign(v.real);
|
|
1189
|
+
power = VpExponent10(v.real);
|
|
1190
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1356
1191
|
|
|
1357
|
-
sign = VpGetSign(p);
|
|
1358
|
-
power = VpExponent10(p);
|
|
1359
1192
|
a = BigDecimal_split(self);
|
|
1360
1193
|
digits = RARRAY_AREF(a, 1);
|
|
1361
1194
|
denomi_power = power - RSTRING_LEN(digits);
|
|
@@ -1376,6 +1209,14 @@ BigDecimal_to_r(VALUE self)
|
|
|
1376
1209
|
}
|
|
1377
1210
|
}
|
|
1378
1211
|
|
|
1212
|
+
static size_t
|
|
1213
|
+
GetCoercePrec(Real *a, size_t prec)
|
|
1214
|
+
{
|
|
1215
|
+
if (prec == 0) prec = a->Prec * BASE_FIG;
|
|
1216
|
+
if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1217
|
+
return prec;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1379
1220
|
/* The coerce method provides support for Ruby type coercion. It is not
|
|
1380
1221
|
* enabled by default.
|
|
1381
1222
|
*
|
|
@@ -1393,26 +1234,9 @@ BigDecimal_to_r(VALUE self)
|
|
|
1393
1234
|
static VALUE
|
|
1394
1235
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1395
1236
|
{
|
|
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;
|
|
1237
|
+
Real* pv = DATA_PTR(self);
|
|
1238
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1239
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
|
1416
1240
|
}
|
|
1417
1241
|
|
|
1418
1242
|
/*
|
|
@@ -1432,6 +1256,15 @@ BigDecimal_uplus(VALUE self)
|
|
|
1432
1256
|
return self;
|
|
1433
1257
|
}
|
|
1434
1258
|
|
|
1259
|
+
static bool
|
|
1260
|
+
is_coerceable_to_BigDecimal(VALUE r)
|
|
1261
|
+
{
|
|
1262
|
+
return is_kind_of_BigDecimal(r) ||
|
|
1263
|
+
RB_INTEGER_TYPE_P(r) ||
|
|
1264
|
+
RB_TYPE_P(r, T_FLOAT) ||
|
|
1265
|
+
RB_TYPE_P(r, T_RATIONAL);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1435
1268
|
/*
|
|
1436
1269
|
* call-seq:
|
|
1437
1270
|
* self + value -> bigdecimal
|
|
@@ -1451,42 +1284,40 @@ BigDecimal_uplus(VALUE self)
|
|
|
1451
1284
|
static VALUE
|
|
1452
1285
|
BigDecimal_add(VALUE self, VALUE r)
|
|
1453
1286
|
{
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1287
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
|
1288
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
|
1289
|
+
}
|
|
1457
1290
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1464
|
-
}
|
|
1465
|
-
else {
|
|
1466
|
-
b = GetVpValue(r, 0);
|
|
1467
|
-
}
|
|
1291
|
+
static VALUE
|
|
1292
|
+
BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
1293
|
+
{
|
|
1294
|
+
BDVALUE a, b, c;
|
|
1295
|
+
size_t mx;
|
|
1468
1296
|
|
|
1469
|
-
|
|
1470
|
-
|
|
1297
|
+
a = GetBDValueMust(self);
|
|
1298
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1471
1299
|
|
|
1472
|
-
if (VpIsNaN(
|
|
1473
|
-
if (VpIsNaN(
|
|
1300
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1301
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1474
1302
|
|
|
1475
|
-
mx = GetAddSubPrec(a, b);
|
|
1303
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1476
1304
|
if (mx == (size_t)-1L) {
|
|
1477
|
-
|
|
1478
|
-
|
|
1305
|
+
/* a or b is inf */
|
|
1306
|
+
c = NewZeroWrap(1, BASE_FIG);
|
|
1307
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1479
1308
|
}
|
|
1480
1309
|
else {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
}
|
|
1310
|
+
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1311
|
+
size_t pl = VpGetPrecLimit();
|
|
1312
|
+
if (prec) VpSetPrecLimit(prec);
|
|
1313
|
+
// Let VpAddSub round the result
|
|
1314
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1315
|
+
if (prec) VpSetPrecLimit(pl);
|
|
1488
1316
|
}
|
|
1489
|
-
|
|
1317
|
+
|
|
1318
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1319
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1320
|
+
return CheckGetValue(c);
|
|
1490
1321
|
}
|
|
1491
1322
|
|
|
1492
1323
|
/*
|
|
@@ -1507,73 +1338,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
|
1507
1338
|
static VALUE
|
|
1508
1339
|
BigDecimal_sub(VALUE self, VALUE r)
|
|
1509
1340
|
{
|
|
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);
|
|
1341
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
|
1342
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
|
1546
1343
|
}
|
|
1547
1344
|
|
|
1548
1345
|
static VALUE
|
|
1549
1346
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1550
1347
|
{
|
|
1551
|
-
ENTER(5);
|
|
1552
1348
|
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;
|
|
1564
|
-
|
|
1565
|
-
case T_FLOAT:
|
|
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;
|
|
1349
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1350
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1572
1351
|
|
|
1573
|
-
|
|
1574
|
-
break;
|
|
1575
|
-
}
|
|
1576
|
-
if (b == NULL) {
|
|
1352
|
+
if (b.real_or_null == NULL) {
|
|
1577
1353
|
ID f = 0;
|
|
1578
1354
|
|
|
1579
1355
|
switch (op) {
|
|
@@ -1602,8 +1378,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1602
1378
|
}
|
|
1603
1379
|
return rb_num_coerce_relop(self, r, f);
|
|
1604
1380
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1381
|
+
e = VpComp(a.real, b.real_or_null);
|
|
1382
|
+
|
|
1383
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1384
|
+
RB_GC_GUARD(b.bigdecimal_or_nil);
|
|
1385
|
+
|
|
1607
1386
|
if (e == 999)
|
|
1608
1387
|
return (op == '*') ? Qnil : Qfalse;
|
|
1609
1388
|
switch (op) {
|
|
@@ -1643,7 +1422,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1643
1422
|
static VALUE
|
|
1644
1423
|
BigDecimal_zero(VALUE self)
|
|
1645
1424
|
{
|
|
1646
|
-
Real *a =
|
|
1425
|
+
Real *a = GetSelfVpValue(self);
|
|
1647
1426
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
|
1648
1427
|
}
|
|
1649
1428
|
|
|
@@ -1651,7 +1430,7 @@ BigDecimal_zero(VALUE self)
|
|
|
1651
1430
|
static VALUE
|
|
1652
1431
|
BigDecimal_nonzero(VALUE self)
|
|
1653
1432
|
{
|
|
1654
|
-
Real *a =
|
|
1433
|
+
Real *a = GetSelfVpValue(self);
|
|
1655
1434
|
return VpIsZero(a) ? Qnil : self;
|
|
1656
1435
|
}
|
|
1657
1436
|
|
|
@@ -1777,12 +1556,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
|
1777
1556
|
static VALUE
|
|
1778
1557
|
BigDecimal_neg(VALUE self)
|
|
1779
1558
|
{
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
return VpCheckGetValue(c);
|
|
1559
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1560
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
1561
|
+
VpAsgn(c.real, a.real, -10);
|
|
1562
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1563
|
+
return CheckGetValue(c);
|
|
1786
1564
|
}
|
|
1787
1565
|
|
|
1788
1566
|
/*
|
|
@@ -1795,35 +1573,36 @@ BigDecimal_neg(VALUE self)
|
|
|
1795
1573
|
*
|
|
1796
1574
|
* See BigDecimal#mult.
|
|
1797
1575
|
*/
|
|
1798
|
-
|
|
1799
1576
|
static VALUE
|
|
1800
1577
|
BigDecimal_mult(VALUE self, VALUE r)
|
|
1801
1578
|
{
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1579
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
|
1580
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
|
1581
|
+
}
|
|
1805
1582
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1583
|
+
static VALUE
|
|
1584
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
|
1585
|
+
{
|
|
1586
|
+
BDVALUE a, b, c;
|
|
1587
|
+
|
|
1588
|
+
a = GetBDValueMust(self);
|
|
1589
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1590
|
+
|
|
1591
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
1592
|
+
VpMult(c.real, a.real, b.real);
|
|
1593
|
+
if (prec) {
|
|
1594
|
+
VpLeftRound(c.real, VpGetRoundMode(), prec);
|
|
1812
1595
|
}
|
|
1813
1596
|
else {
|
|
1814
|
-
|
|
1597
|
+
VpLimitRound(c.real, 0);
|
|
1815
1598
|
}
|
|
1816
1599
|
|
|
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);
|
|
1600
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1601
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1602
|
+
return CheckGetValue(c);
|
|
1824
1603
|
}
|
|
1825
1604
|
|
|
1826
|
-
static
|
|
1605
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
|
1827
1606
|
|
|
1828
1607
|
/* call-seq:
|
|
1829
1608
|
* a / b -> bigdecimal
|
|
@@ -1840,14 +1619,7 @@ static VALUE
|
|
|
1840
1619
|
BigDecimal_div(VALUE self, VALUE r)
|
|
1841
1620
|
/* For c = self/r: with round operation */
|
|
1842
1621
|
{
|
|
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
|
-
}
|
|
1622
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
|
1851
1623
|
return BigDecimal_div2(self, r, INT2FIX(0));
|
|
1852
1624
|
}
|
|
1853
1625
|
|
|
@@ -1893,114 +1665,110 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
|
1893
1665
|
/*
|
|
1894
1666
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
|
1895
1667
|
* div = (a.to_f/b).floor
|
|
1668
|
+
* In truncate mode, use truncate instead of floor.
|
|
1896
1669
|
*/
|
|
1897
|
-
static
|
|
1898
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
|
1670
|
+
static bool
|
|
1671
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
|
1899
1672
|
{
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
size_t mx;
|
|
1673
|
+
BDVALUE a, b, dv, md, res;
|
|
1674
|
+
NULLABLE_BDVALUE b2;
|
|
1675
|
+
ssize_t a_exponent, b_exponent;
|
|
1676
|
+
size_t mx, rx, pl;
|
|
1905
1677
|
|
|
1906
|
-
|
|
1907
|
-
SAVE(a);
|
|
1678
|
+
a = GetBDValueMust(self);
|
|
1908
1679
|
|
|
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
|
-
}
|
|
1680
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1681
|
+
if (!b2.real_or_null) return false;
|
|
1682
|
+
b = bdvalue_nonnullable(b2);
|
|
1922
1683
|
|
|
1923
|
-
if (
|
|
1924
|
-
|
|
1684
|
+
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1685
|
+
VALUE nan = BigDecimal_nan();
|
|
1686
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1687
|
+
goto Done;
|
|
1925
1688
|
}
|
|
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)) {
|
|
1689
|
+
if (VpIsZero(b.real)) {
|
|
1933
1690
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
|
1934
1691
|
}
|
|
1935
|
-
if (VpIsInf(a)) {
|
|
1936
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
|
1692
|
+
if (VpIsInf(a.real)) {
|
|
1693
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1937
1694
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1938
|
-
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1939
1696
|
}
|
|
1940
1697
|
else {
|
|
1941
1698
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1942
|
-
|
|
1699
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1943
1700
|
}
|
|
1944
1701
|
VALUE nan = BigDecimal_nan();
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
}
|
|
1948
|
-
if (VpIsInf(b)) {
|
|
1949
|
-
VALUE zero = BigDecimal_positive_zero();
|
|
1950
|
-
TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
|
|
1951
|
-
*mod = a;
|
|
1952
|
-
return Qtrue;
|
|
1702
|
+
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1703
|
+
goto Done;
|
|
1953
1704
|
}
|
|
1954
|
-
if (VpIsZero(a)) {
|
|
1705
|
+
if (VpIsZero(a.real)) {
|
|
1955
1706
|
VALUE zero = BigDecimal_positive_zero();
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1707
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1708
|
+
*mod = bdvalue_nullable(a);
|
|
1709
|
+
goto Done;
|
|
1710
|
+
}
|
|
1711
|
+
if (VpIsInf(b.real)) {
|
|
1712
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
|
1713
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
|
1714
|
+
VpSetOne(minus_one.real);
|
|
1715
|
+
VpSetSign(minus_one.real, -1);
|
|
1716
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
|
1717
|
+
*div = bdvalue_nullable(minus_one);
|
|
1718
|
+
*mod = bdvalue_nullable(b);
|
|
1719
|
+
} else {
|
|
1720
|
+
VALUE zero = BigDecimal_positive_zero();
|
|
1721
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1722
|
+
*mod = bdvalue_nullable(a);
|
|
1723
|
+
}
|
|
1724
|
+
goto Done;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
a_exponent = VpExponent10(a.real);
|
|
1728
|
+
b_exponent = VpExponent10(b.real);
|
|
1729
|
+
mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
|
|
1730
|
+
dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
|
|
1731
|
+
|
|
1732
|
+
/* res is reused for VpDivd remainder and VpMult result */
|
|
1733
|
+
rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
|
|
1734
|
+
mx = VPMULT_RESULT_PREC(dv.real, b.real);
|
|
1735
|
+
res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
|
|
1736
|
+
/* AddSub needs one more prec */
|
|
1737
|
+
md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
|
|
1738
|
+
|
|
1739
|
+
VpDivd(dv.real, res.real, a.real, b.real);
|
|
1740
|
+
VpMidRound(dv.real, VP_ROUND_DOWN, 0);
|
|
1741
|
+
VpMult(res.real, dv.real, b.real);
|
|
1742
|
+
pl = VpGetPrecLimit();
|
|
1743
|
+
VpSetPrecLimit(0);
|
|
1744
|
+
VpAddSub(md.real, a.real, res.real, -1);
|
|
1745
|
+
VpSetPrecLimit(pl);
|
|
1980
1746
|
|
|
1981
|
-
if (!VpIsZero(
|
|
1747
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
|
1982
1748
|
/* result adjustment for negative case */
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
VpAddSub(
|
|
1988
|
-
|
|
1989
|
-
*
|
|
1749
|
+
BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
|
|
1750
|
+
BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
|
|
1751
|
+
VpSetPrecLimit(0);
|
|
1752
|
+
VpAddSub(dv2.real, dv.real, VpOne(), -1);
|
|
1753
|
+
VpAddSub(md2.real, md.real, b.real, 1);
|
|
1754
|
+
VpSetPrecLimit(pl);
|
|
1755
|
+
*div = bdvalue_nullable(dv2);
|
|
1756
|
+
*mod = bdvalue_nullable(md2);
|
|
1757
|
+
RB_GC_GUARD(dv2.bigdecimal);
|
|
1758
|
+
RB_GC_GUARD(md2.bigdecimal);
|
|
1990
1759
|
}
|
|
1991
1760
|
else {
|
|
1992
|
-
*div =
|
|
1993
|
-
*mod =
|
|
1761
|
+
*div = bdvalue_nullable(dv);
|
|
1762
|
+
*mod = bdvalue_nullable(md);
|
|
1994
1763
|
}
|
|
1995
|
-
return Qtrue;
|
|
1996
1764
|
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
return
|
|
1765
|
+
Done:
|
|
1766
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1767
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1768
|
+
RB_GC_GUARD(dv.bigdecimal);
|
|
1769
|
+
RB_GC_GUARD(md.bigdecimal);
|
|
1770
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1771
|
+
return true;
|
|
2004
1772
|
}
|
|
2005
1773
|
|
|
2006
1774
|
/* call-seq:
|
|
@@ -2014,69 +1782,14 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
|
2014
1782
|
static VALUE
|
|
2015
1783
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
|
2016
1784
|
{
|
|
2017
|
-
|
|
2018
|
-
Real *div = NULL, *mod = NULL;
|
|
1785
|
+
NULLABLE_BDVALUE div, mod;
|
|
2019
1786
|
|
|
2020
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2021
|
-
|
|
2022
|
-
return VpCheckGetValue(mod);
|
|
1787
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1788
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
2023
1789
|
}
|
|
2024
1790
|
return DoSomeOne(self, r, '%');
|
|
2025
1791
|
}
|
|
2026
1792
|
|
|
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
1793
|
/* call-seq:
|
|
2081
1794
|
* remainder(value)
|
|
2082
1795
|
*
|
|
@@ -2087,11 +1800,12 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
|
2087
1800
|
static VALUE
|
|
2088
1801
|
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2089
1802
|
{
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
1803
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
|
1804
|
+
|
|
1805
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
|
1806
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
1807
|
+
}
|
|
1808
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2095
1809
|
}
|
|
2096
1810
|
|
|
2097
1811
|
/* call-seq:
|
|
@@ -2119,12 +1833,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
|
2119
1833
|
static VALUE
|
|
2120
1834
|
BigDecimal_divmod(VALUE self, VALUE r)
|
|
2121
1835
|
{
|
|
2122
|
-
|
|
2123
|
-
Real *div = NULL, *mod = NULL;
|
|
1836
|
+
NULLABLE_BDVALUE div, mod;
|
|
2124
1837
|
|
|
2125
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2126
|
-
|
|
2127
|
-
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
|
|
1838
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1839
|
+
return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
2128
1840
|
}
|
|
2129
1841
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
2130
1842
|
}
|
|
@@ -2136,17 +1848,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
2136
1848
|
static inline VALUE
|
|
2137
1849
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2138
1850
|
{
|
|
2139
|
-
ENTER(5);
|
|
2140
1851
|
SIGNED_VALUE ix;
|
|
2141
|
-
|
|
2142
|
-
Real *av = NULL, *bv = NULL, *cv = NULL;
|
|
2143
|
-
size_t mx, pl;
|
|
1852
|
+
BDVALUE av, bv, cv, res;
|
|
2144
1853
|
|
|
2145
1854
|
if (NIL_P(n)) { /* div in Float sense */
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
|
2149
|
-
return BigDecimal_to_i(
|
|
1855
|
+
NULLABLE_BDVALUE div;
|
|
1856
|
+
NULLABLE_BDVALUE mod;
|
|
1857
|
+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
|
|
1858
|
+
return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
|
|
2150
1859
|
}
|
|
2151
1860
|
return DoSomeOne(self, b, rb_intern("div"));
|
|
2152
1861
|
}
|
|
@@ -2154,48 +1863,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
|
2154
1863
|
/* div in BigDecimal sense */
|
|
2155
1864
|
ix = check_int_precision(n);
|
|
2156
1865
|
|
|
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
|
-
}
|
|
1866
|
+
av = GetBDValueMust(self);
|
|
1867
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
|
2170
1868
|
|
|
2171
1869
|
if (ix == 0) {
|
|
2172
|
-
ssize_t a_prec, b_prec;
|
|
2173
|
-
VpCountPrecisionAndScale(av, &a_prec, NULL);
|
|
2174
|
-
VpCountPrecisionAndScale(bv, &b_prec, NULL);
|
|
1870
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
|
1871
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
|
1872
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
|
2175
1873
|
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
|
2176
1874
|
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
|
2177
1875
|
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1876
|
+
if (limit && limit < ix) ix = limit;
|
|
2178
1877
|
}
|
|
2179
1878
|
|
|
2180
|
-
//
|
|
2181
|
-
|
|
1879
|
+
// Needs to calculate 1 extra digit for rounding.
|
|
1880
|
+
cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
|
|
1881
|
+
res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
|
|
1882
|
+
VpDivd(cv.real, res.real, av.real, bv.real);
|
|
2182
1883
|
|
|
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)) {
|
|
1884
|
+
if (!VpIsZero(res.real)) {
|
|
2189
1885
|
// Remainder value affects rounding result.
|
|
2190
|
-
// ROUND_UP cv = 0.1e0 with
|
|
1886
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
|
2191
1887
|
// 0.1e0 if remainder == 0
|
|
2192
1888
|
// 0.1000000001e0 if remainder != 0
|
|
2193
1889
|
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]++;
|
|
1890
|
+
while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
|
|
1891
|
+
if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
|
|
2196
1892
|
}
|
|
2197
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
|
2198
|
-
|
|
1893
|
+
VpLeftRound(cv.real, VpGetRoundMode(), ix);
|
|
1894
|
+
|
|
1895
|
+
RB_GC_GUARD(av.bigdecimal);
|
|
1896
|
+
RB_GC_GUARD(bv.bigdecimal);
|
|
1897
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1898
|
+
return CheckGetValue(cv);
|
|
2199
1899
|
}
|
|
2200
1900
|
|
|
2201
1901
|
/*
|
|
@@ -2271,18 +1971,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
|
2271
1971
|
static VALUE
|
|
2272
1972
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2273
1973
|
{
|
|
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
|
-
}
|
|
1974
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
|
2286
1975
|
}
|
|
2287
1976
|
|
|
2288
1977
|
/* call-seq:
|
|
@@ -2301,18 +1990,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
|
2301
1990
|
static VALUE
|
|
2302
1991
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2303
1992
|
{
|
|
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
|
-
}
|
|
1993
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
|
2316
1994
|
}
|
|
2317
1995
|
|
|
2318
1996
|
/*
|
|
@@ -2344,18 +2022,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
|
2344
2022
|
static VALUE
|
|
2345
2023
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2346
2024
|
{
|
|
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
|
-
}
|
|
2025
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
|
2359
2026
|
}
|
|
2360
2027
|
|
|
2361
2028
|
/*
|
|
@@ -2372,41 +2039,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
|
2372
2039
|
static VALUE
|
|
2373
2040
|
BigDecimal_abs(VALUE self)
|
|
2374
2041
|
{
|
|
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);
|
|
2042
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2043
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
2044
|
+
VpAsgn(c.real, a.real, 10);
|
|
2045
|
+
VpChangeSign(c.real, 1);
|
|
2046
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2047
|
+
return CheckGetValue(c);
|
|
2410
2048
|
}
|
|
2411
2049
|
|
|
2412
2050
|
/* Return the integer part of the number, as a BigDecimal.
|
|
@@ -2414,15 +2052,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
|
2414
2052
|
static VALUE
|
|
2415
2053
|
BigDecimal_fix(VALUE self)
|
|
2416
2054
|
{
|
|
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);
|
|
2055
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2056
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2057
|
+
VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2058
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2059
|
+
return CheckGetValue(c);
|
|
2426
2060
|
}
|
|
2427
2061
|
|
|
2428
2062
|
/* call-seq:
|
|
@@ -2454,13 +2088,12 @@ BigDecimal_fix(VALUE self)
|
|
|
2454
2088
|
static VALUE
|
|
2455
2089
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2456
2090
|
{
|
|
2457
|
-
|
|
2458
|
-
Real *c, *a;
|
|
2091
|
+
BDVALUE c, a;
|
|
2459
2092
|
int iLoc = 0;
|
|
2460
2093
|
VALUE vLoc;
|
|
2461
2094
|
VALUE vRound;
|
|
2462
2095
|
int round_to_int = 0;
|
|
2463
|
-
size_t mx
|
|
2096
|
+
size_t mx;
|
|
2464
2097
|
|
|
2465
2098
|
unsigned short sw = VpGetRoundMode();
|
|
2466
2099
|
|
|
@@ -2491,16 +2124,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2491
2124
|
break;
|
|
2492
2125
|
}
|
|
2493
2126
|
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2127
|
+
a = GetBDValueMust(self);
|
|
2128
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2129
|
+
c = NewZeroWrap(1, mx);
|
|
2130
|
+
|
|
2131
|
+
VpActiveRound(c.real, a.real, sw, iLoc);
|
|
2132
|
+
|
|
2133
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2134
|
+
|
|
2500
2135
|
if (round_to_int) {
|
|
2501
|
-
return BigDecimal_to_i(
|
|
2136
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2502
2137
|
}
|
|
2503
|
-
return
|
|
2138
|
+
return CheckGetValue(c);
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
static VALUE
|
|
2142
|
+
BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
|
|
2143
|
+
{
|
|
2144
|
+
BDVALUE c, a;
|
|
2145
|
+
int iLoc;
|
|
2146
|
+
VALUE vLoc;
|
|
2147
|
+
size_t mx;
|
|
2148
|
+
|
|
2149
|
+
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2150
|
+
iLoc = 0;
|
|
2151
|
+
}
|
|
2152
|
+
else {
|
|
2153
|
+
iLoc = NUM2INT(vLoc);
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
a = GetBDValueMust(self);
|
|
2157
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2158
|
+
c = NewZeroWrap(1, mx);
|
|
2159
|
+
VpActiveRound(c.real, a.real, rounding_mode, iLoc);
|
|
2160
|
+
|
|
2161
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2162
|
+
|
|
2163
|
+
if (argc == 0) {
|
|
2164
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2165
|
+
}
|
|
2166
|
+
return CheckGetValue(c);
|
|
2504
2167
|
}
|
|
2505
2168
|
|
|
2506
2169
|
/* call-seq:
|
|
@@ -2525,28 +2188,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2525
2188
|
static VALUE
|
|
2526
2189
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2527
2190
|
{
|
|
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);
|
|
2191
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
|
2550
2192
|
}
|
|
2551
2193
|
|
|
2552
2194
|
/* Return the fractional part of the number, as a BigDecimal.
|
|
@@ -2554,15 +2196,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
|
2554
2196
|
static VALUE
|
|
2555
2197
|
BigDecimal_frac(VALUE self)
|
|
2556
2198
|
{
|
|
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);
|
|
2199
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2200
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2201
|
+
VpFrac(c.real, a.real);
|
|
2202
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2203
|
+
return CheckGetValue(c);
|
|
2566
2204
|
}
|
|
2567
2205
|
|
|
2568
2206
|
/* call-seq:
|
|
@@ -2585,31 +2223,7 @@ BigDecimal_frac(VALUE self)
|
|
|
2585
2223
|
static VALUE
|
|
2586
2224
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2587
2225
|
{
|
|
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);
|
|
2226
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
|
2613
2227
|
}
|
|
2614
2228
|
|
|
2615
2229
|
/* call-seq:
|
|
@@ -2632,27 +2246,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
|
2632
2246
|
static VALUE
|
|
2633
2247
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2634
2248
|
{
|
|
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);
|
|
2249
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
|
2656
2250
|
}
|
|
2657
2251
|
|
|
2658
2252
|
/* call-seq:
|
|
@@ -2673,7 +2267,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2673
2267
|
* If s contains a number, a space is inserted after each group of that many
|
|
2674
2268
|
* digits, starting from '.' and counting outwards.
|
|
2675
2269
|
*
|
|
2676
|
-
* If s ends with an 'E',
|
|
2270
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
|
2677
2271
|
*
|
|
2678
2272
|
* If s ends with an 'F', conventional floating point notation is used.
|
|
2679
2273
|
*
|
|
@@ -2691,10 +2285,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2691
2285
|
static VALUE
|
|
2692
2286
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2693
2287
|
{
|
|
2694
|
-
ENTER(5);
|
|
2695
2288
|
int fmt = 0; /* 0: E format, 1: F format */
|
|
2696
2289
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
2697
|
-
|
|
2290
|
+
BDVALUE v;
|
|
2698
2291
|
volatile VALUE str;
|
|
2699
2292
|
char *psz;
|
|
2700
2293
|
char ch;
|
|
@@ -2702,7 +2295,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2702
2295
|
SIGNED_VALUE m;
|
|
2703
2296
|
VALUE f;
|
|
2704
2297
|
|
|
2705
|
-
|
|
2298
|
+
v = GetBDValueMust(self);
|
|
2706
2299
|
|
|
2707
2300
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
|
2708
2301
|
if (RB_TYPE_P(f, T_STRING)) {
|
|
@@ -2737,10 +2330,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2737
2330
|
}
|
|
2738
2331
|
}
|
|
2739
2332
|
if (fmt) {
|
|
2740
|
-
nc = VpNumOfChars(
|
|
2333
|
+
nc = VpNumOfChars(v.real, "F");
|
|
2741
2334
|
}
|
|
2742
2335
|
else {
|
|
2743
|
-
nc = VpNumOfChars(
|
|
2336
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2744
2337
|
}
|
|
2745
2338
|
if (mc > 0) {
|
|
2746
2339
|
nc += (nc + mc - 1) / mc + 1;
|
|
@@ -2750,12 +2343,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2750
2343
|
psz = RSTRING_PTR(str);
|
|
2751
2344
|
|
|
2752
2345
|
if (fmt) {
|
|
2753
|
-
VpToFString(
|
|
2346
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2754
2347
|
}
|
|
2755
2348
|
else {
|
|
2756
|
-
VpToString (
|
|
2349
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2757
2350
|
}
|
|
2758
2351
|
rb_str_resize(str, strlen(psz));
|
|
2352
|
+
|
|
2353
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2759
2354
|
return str;
|
|
2760
2355
|
}
|
|
2761
2356
|
|
|
@@ -2786,16 +2381,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2786
2381
|
static VALUE
|
|
2787
2382
|
BigDecimal_split(VALUE self)
|
|
2788
2383
|
{
|
|
2789
|
-
|
|
2790
|
-
Real *vp;
|
|
2384
|
+
BDVALUE v;
|
|
2791
2385
|
VALUE obj,str;
|
|
2792
2386
|
ssize_t e, s;
|
|
2793
2387
|
char *psz1;
|
|
2794
2388
|
|
|
2795
|
-
|
|
2796
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
2389
|
+
v = GetBDValueMust(self);
|
|
2390
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
2797
2391
|
psz1 = RSTRING_PTR(str);
|
|
2798
|
-
VpSzMantissa(
|
|
2392
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
|
2799
2393
|
s = 1;
|
|
2800
2394
|
if(psz1[0] == '-') {
|
|
2801
2395
|
size_t len = strlen(psz1 + 1);
|
|
@@ -2805,13 +2399,15 @@ BigDecimal_split(VALUE self)
|
|
|
2805
2399
|
s = -1;
|
|
2806
2400
|
}
|
|
2807
2401
|
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2808
|
-
e = VpExponent10(
|
|
2402
|
+
e = VpExponent10(v.real);
|
|
2809
2403
|
obj = rb_ary_new2(4);
|
|
2810
2404
|
rb_ary_push(obj, INT2FIX(s));
|
|
2811
2405
|
rb_ary_push(obj, str);
|
|
2812
2406
|
rb_str_resize(str, strlen(psz1));
|
|
2813
2407
|
rb_ary_push(obj, INT2FIX(10));
|
|
2814
2408
|
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2409
|
+
|
|
2410
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2815
2411
|
return obj;
|
|
2816
2412
|
}
|
|
2817
2413
|
|
|
@@ -2823,7 +2419,7 @@ BigDecimal_split(VALUE self)
|
|
|
2823
2419
|
static VALUE
|
|
2824
2420
|
BigDecimal_exponent(VALUE self)
|
|
2825
2421
|
{
|
|
2826
|
-
ssize_t e = VpExponent10(
|
|
2422
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
|
2827
2423
|
return SSIZET2NUM(e);
|
|
2828
2424
|
}
|
|
2829
2425
|
|
|
@@ -2835,49 +2431,78 @@ BigDecimal_exponent(VALUE self)
|
|
|
2835
2431
|
static VALUE
|
|
2836
2432
|
BigDecimal_inspect(VALUE self)
|
|
2837
2433
|
{
|
|
2838
|
-
|
|
2839
|
-
Real *vp;
|
|
2434
|
+
BDVALUE v;
|
|
2840
2435
|
volatile VALUE str;
|
|
2841
2436
|
size_t nc;
|
|
2842
2437
|
|
|
2843
|
-
|
|
2844
|
-
nc = VpNumOfChars(
|
|
2438
|
+
v = GetBDValueMust(self);
|
|
2439
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2845
2440
|
|
|
2846
2441
|
str = rb_str_new(0, nc);
|
|
2847
|
-
VpToString(
|
|
2442
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2848
2443
|
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
2444
|
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
{
|
|
2861
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
|
2445
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2446
|
+
return str;
|
|
2862
2447
|
}
|
|
2863
2448
|
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2449
|
+
/* Returns self * 10**v without changing the precision.
|
|
2450
|
+
* This method is currently for internal use.
|
|
2451
|
+
*
|
|
2452
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
|
2453
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
|
2454
|
+
*/
|
|
2455
|
+
static VALUE
|
|
2456
|
+
BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
2457
|
+
{
|
|
2458
|
+
BDVALUE a, c;
|
|
2459
|
+
ssize_t shift, exponentShift;
|
|
2460
|
+
bool shiftDown;
|
|
2461
|
+
size_t prec;
|
|
2462
|
+
DECDIG ex, iex;
|
|
2463
|
+
|
|
2464
|
+
a = GetBDValueMust(self);
|
|
2465
|
+
shift = NUM2SSIZET(rb_to_int(v));
|
|
2466
|
+
|
|
2467
|
+
if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
|
|
2468
|
+
|
|
2469
|
+
exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
|
|
2470
|
+
shift -= exponentShift * BASE_FIG;
|
|
2471
|
+
ex = 1;
|
|
2472
|
+
for (int i = 0; i < shift; i++) ex *= 10;
|
|
2473
|
+
shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
|
|
2474
|
+
iex = BASE / ex;
|
|
2475
|
+
|
|
2476
|
+
prec = a.real->Prec + shiftDown;
|
|
2477
|
+
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2478
|
+
if (shift == 0) {
|
|
2479
|
+
VpAsgn(c.real, a.real, 10);
|
|
2480
|
+
} else if (shiftDown) {
|
|
2481
|
+
DECDIG carry = 0;
|
|
2482
|
+
exponentShift++;
|
|
2483
|
+
for (size_t i = 0; i < a.real->Prec; i++) {
|
|
2484
|
+
DECDIG v = a.real->frac[i];
|
|
2485
|
+
c.real->frac[i] = carry * ex + v / iex;
|
|
2486
|
+
carry = v % iex;
|
|
2487
|
+
}
|
|
2488
|
+
c.real->frac[a.real->Prec] = carry * ex;
|
|
2489
|
+
} else {
|
|
2490
|
+
DECDIG carry = 0;
|
|
2491
|
+
for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
|
|
2492
|
+
DECDIG v = a.real->frac[i];
|
|
2493
|
+
c.real->frac[i] = v % iex * ex + carry;
|
|
2494
|
+
carry = v / iex;
|
|
2495
|
+
}
|
|
2875
2496
|
}
|
|
2876
|
-
|
|
2497
|
+
while (c.real->frac[prec - 1] == 0) prec--;
|
|
2498
|
+
c.real->Prec = prec;
|
|
2499
|
+
c.real->sign = a.real->sign;
|
|
2500
|
+
c.real->exponent = a.real->exponent;
|
|
2501
|
+
AddExponent(c.real, exponentShift);
|
|
2502
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2503
|
+
return CheckGetValue(c);
|
|
2877
2504
|
}
|
|
2878
2505
|
|
|
2879
|
-
#define is_positive(x) (!is_negative(x))
|
|
2880
|
-
|
|
2881
2506
|
inline static int
|
|
2882
2507
|
is_zero(VALUE x)
|
|
2883
2508
|
{
|
|
@@ -2901,344 +2526,6 @@ is_zero(VALUE x)
|
|
|
2901
2526
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
2902
2527
|
}
|
|
2903
2528
|
|
|
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)));
|
|
3196
|
-
}
|
|
3197
|
-
else {
|
|
3198
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
|
3199
|
-
}
|
|
3200
|
-
VpPowerByInt(y, x, int_exp);
|
|
3201
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
|
3202
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
|
3203
|
-
}
|
|
3204
|
-
return VpCheckGetValue(y);
|
|
3205
|
-
}
|
|
3206
|
-
|
|
3207
|
-
/* call-seq:
|
|
3208
|
-
* self ** other -> bigdecimal
|
|
3209
|
-
*
|
|
3210
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
|
3211
|
-
*
|
|
3212
|
-
* b = BigDecimal('3.14')
|
|
3213
|
-
* b ** 2 # => 0.98596e1
|
|
3214
|
-
* b ** 2.0 # => 0.98596e1
|
|
3215
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
|
3216
|
-
*
|
|
3217
|
-
* Related: BigDecimal#power.
|
|
3218
|
-
*
|
|
3219
|
-
*/
|
|
3220
|
-
static VALUE
|
|
3221
|
-
BigDecimal_power_op(VALUE self, VALUE exp)
|
|
3222
|
-
{
|
|
3223
|
-
return BigDecimal_power(1, &exp, self);
|
|
3224
|
-
}
|
|
3225
|
-
|
|
3226
|
-
/* :nodoc:
|
|
3227
|
-
*
|
|
3228
|
-
* private method for dup and clone the provided BigDecimal +other+
|
|
3229
|
-
*/
|
|
3230
|
-
static VALUE
|
|
3231
|
-
BigDecimal_initialize_copy(VALUE self, VALUE other)
|
|
3232
|
-
{
|
|
3233
|
-
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
|
|
3234
|
-
Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
|
|
3235
|
-
|
|
3236
|
-
if (self != other) {
|
|
3237
|
-
DATA_PTR(self) = VpCopy(pv, x);
|
|
3238
|
-
}
|
|
3239
|
-
return self;
|
|
3240
|
-
}
|
|
3241
|
-
|
|
3242
2529
|
/* :nodoc: */
|
|
3243
2530
|
static VALUE
|
|
3244
2531
|
BigDecimal_clone(VALUE self)
|
|
@@ -3277,20 +2564,18 @@ check_exception(VALUE bd)
|
|
|
3277
2564
|
|
|
3278
2565
|
Real *vp;
|
|
3279
2566
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3280
|
-
|
|
2567
|
+
VpCheckException(vp, false);
|
|
3281
2568
|
|
|
3282
2569
|
return bd;
|
|
3283
2570
|
}
|
|
3284
2571
|
|
|
3285
2572
|
static VALUE
|
|
3286
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
|
2573
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
3287
2574
|
{
|
|
3288
|
-
|
|
3289
|
-
|
|
2575
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3290
2576
|
Real *vp;
|
|
3291
2577
|
if (uval == 0) {
|
|
3292
2578
|
vp = rbd_allocate_struct(1);
|
|
3293
|
-
vp->MaxPrec = 1;
|
|
3294
2579
|
vp->Prec = 1;
|
|
3295
2580
|
vp->exponent = 1;
|
|
3296
2581
|
VpSetZero(vp, 1);
|
|
@@ -3298,7 +2583,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3298
2583
|
}
|
|
3299
2584
|
else if (uval < BASE) {
|
|
3300
2585
|
vp = rbd_allocate_struct(1);
|
|
3301
|
-
vp->MaxPrec = 1;
|
|
3302
2586
|
vp->Prec = 1;
|
|
3303
2587
|
vp->exponent = 1;
|
|
3304
2588
|
VpSetSign(vp, 1);
|
|
@@ -3324,21 +2608,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3324
2608
|
|
|
3325
2609
|
const size_t exp = len + ntz;
|
|
3326
2610
|
vp = rbd_allocate_struct(len);
|
|
3327
|
-
vp->MaxPrec = len;
|
|
3328
2611
|
vp->Prec = len;
|
|
3329
2612
|
vp->exponent = exp;
|
|
3330
2613
|
VpSetSign(vp, 1);
|
|
3331
2614
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
3332
2615
|
}
|
|
3333
2616
|
|
|
3334
|
-
return BigDecimal_wrap_struct(
|
|
2617
|
+
return BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3335
2618
|
}
|
|
3336
2619
|
|
|
3337
2620
|
static VALUE
|
|
3338
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
|
2621
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
3339
2622
|
{
|
|
3340
2623
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
3341
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
|
2624
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
3342
2625
|
if (ival < 0) {
|
|
3343
2626
|
Real *vp;
|
|
3344
2627
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
@@ -3348,7 +2631,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
|
|
|
3348
2631
|
}
|
|
3349
2632
|
|
|
3350
2633
|
static VALUE
|
|
3351
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
|
2634
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
|
3352
2635
|
{
|
|
3353
2636
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
|
3354
2637
|
|
|
@@ -3360,40 +2643,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
|
3360
2643
|
}
|
|
3361
2644
|
if (size <= sizeof(long)) {
|
|
3362
2645
|
if (sign < 0) {
|
|
3363
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
|
2646
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
|
3364
2647
|
}
|
|
3365
2648
|
else {
|
|
3366
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
|
2649
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
|
3367
2650
|
}
|
|
3368
2651
|
}
|
|
3369
2652
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
|
3370
2653
|
else if (size <= sizeof(LONG_LONG)) {
|
|
3371
2654
|
if (sign < 0) {
|
|
3372
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
|
2655
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
|
3373
2656
|
}
|
|
3374
2657
|
else {
|
|
3375
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
|
2658
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
|
3376
2659
|
}
|
|
3377
2660
|
}
|
|
3378
2661
|
#endif
|
|
3379
2662
|
else {
|
|
3380
2663
|
VALUE str = rb_big2str(val, 10);
|
|
3381
|
-
|
|
3382
|
-
|
|
2664
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
|
2665
|
+
RSTRING_PTR(str),
|
|
2666
|
+
rb_cBigDecimal,
|
|
2667
|
+
true,
|
|
2668
|
+
true
|
|
2669
|
+
));
|
|
3383
2670
|
RB_GC_GUARD(str);
|
|
3384
|
-
return
|
|
2671
|
+
return CheckGetValue(v);
|
|
3385
2672
|
}
|
|
3386
2673
|
}
|
|
3387
2674
|
|
|
3388
2675
|
static VALUE
|
|
3389
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
|
2676
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
|
3390
2677
|
{
|
|
3391
2678
|
assert(RB_INTEGER_TYPE_P(val));
|
|
3392
2679
|
if (FIXNUM_P(val)) {
|
|
3393
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
|
2680
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
|
3394
2681
|
}
|
|
3395
2682
|
else {
|
|
3396
|
-
return rb_big_convert_to_BigDecimal(val
|
|
2683
|
+
return rb_big_convert_to_BigDecimal(val);
|
|
3397
2684
|
}
|
|
3398
2685
|
}
|
|
3399
2686
|
|
|
@@ -3428,11 +2715,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3428
2715
|
}
|
|
3429
2716
|
|
|
3430
2717
|
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));
|
|
2718
|
+
digs = 0;
|
|
3436
2719
|
}
|
|
3437
2720
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
3438
2721
|
if (!raise_exception)
|
|
@@ -3547,7 +2830,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3547
2830
|
exp = -exp;
|
|
3548
2831
|
}
|
|
3549
2832
|
|
|
3550
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
|
2833
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
3551
2834
|
Real *vp;
|
|
3552
2835
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3553
2836
|
assert(vp->Prec == prec);
|
|
@@ -3570,28 +2853,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3570
2853
|
CLASS_OF(val));
|
|
3571
2854
|
}
|
|
3572
2855
|
|
|
3573
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
|
2856
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
|
3574
2857
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
|
3575
2858
|
return d;
|
|
3576
2859
|
}
|
|
3577
2860
|
|
|
3578
2861
|
static VALUE
|
|
3579
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
2862
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
3580
2863
|
{
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
|
3585
|
-
if (!vp)
|
|
3586
|
-
return Qnil;
|
|
3587
|
-
return VpCheckGetValue(vp);
|
|
2864
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
|
|
2865
|
+
if (v.bigdecimal_or_nil == Qnil) return Qnil;
|
|
2866
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3588
2867
|
}
|
|
3589
2868
|
|
|
3590
2869
|
static inline VALUE
|
|
3591
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
|
2870
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
3592
2871
|
{
|
|
3593
2872
|
const char *c_str = StringValueCStr(val);
|
|
3594
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
|
2873
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
3595
2874
|
}
|
|
3596
2875
|
|
|
3597
2876
|
static VALUE
|
|
@@ -3619,17 +2898,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3619
2898
|
if (digs == SIZE_MAX)
|
|
3620
2899
|
return check_exception(val);
|
|
3621
2900
|
|
|
2901
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3622
2902
|
Real *vp;
|
|
3623
2903
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
|
3624
|
-
|
|
3625
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
|
3626
2904
|
vp = VpCopy(NULL, vp);
|
|
2905
|
+
RB_GC_GUARD(val);
|
|
2906
|
+
|
|
2907
|
+
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3627
2908
|
/* TODO: rounding */
|
|
3628
|
-
|
|
3629
|
-
return VpCheckGetValue(vp);
|
|
2909
|
+
return check_exception(copy);
|
|
3630
2910
|
}
|
|
3631
2911
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
3632
|
-
return rb_inum_convert_to_BigDecimal(val
|
|
2912
|
+
return rb_inum_convert_to_BigDecimal(val);
|
|
3633
2913
|
}
|
|
3634
2914
|
else if (RB_FLOAT_TYPE_P(val)) {
|
|
3635
2915
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
|
@@ -3647,7 +2927,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3647
2927
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
|
3648
2928
|
}
|
|
3649
2929
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
3650
|
-
return rb_str_convert_to_BigDecimal(val,
|
|
2930
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
|
3651
2931
|
}
|
|
3652
2932
|
|
|
3653
2933
|
/* TODO: chheck to_d */
|
|
@@ -3661,7 +2941,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3661
2941
|
}
|
|
3662
2942
|
return Qnil;
|
|
3663
2943
|
}
|
|
3664
|
-
return rb_str_convert_to_BigDecimal(str,
|
|
2944
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
|
3665
2945
|
}
|
|
3666
2946
|
|
|
3667
2947
|
/* call-seq:
|
|
@@ -3682,12 +2962,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3682
2962
|
*
|
|
3683
2963
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
|
3684
2964
|
*
|
|
3685
|
-
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
|
|
2965
|
+
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
|
|
3686
2966
|
* BigDecimal(2) # => 0.2e1
|
|
3687
2967
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
|
3688
2968
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
|
3689
|
-
* #
|
|
3690
|
-
*
|
|
2969
|
+
* BigDecimal(2.0) # => 0.2e1
|
|
2970
|
+
* # Rational value requires ndigits.
|
|
3691
2971
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
|
3692
2972
|
*
|
|
3693
2973
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
|
@@ -3751,11 +3031,11 @@ static VALUE
|
|
|
3751
3031
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3752
3032
|
{
|
|
3753
3033
|
char const *c_str = StringValueCStr(str);
|
|
3754
|
-
|
|
3755
|
-
if (
|
|
3034
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3035
|
+
if (v.bigdecimal_or_nil == Qnil)
|
|
3756
3036
|
return Qnil;
|
|
3757
3037
|
else
|
|
3758
|
-
return
|
|
3038
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3759
3039
|
}
|
|
3760
3040
|
|
|
3761
3041
|
/*
|
|
@@ -3810,7 +3090,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
|
3810
3090
|
static VALUE
|
|
3811
3091
|
BigDecimal_sign(VALUE self)
|
|
3812
3092
|
{ /* sign */
|
|
3813
|
-
int s =
|
|
3093
|
+
int s = GetSelfVpValue(self)->sign;
|
|
3814
3094
|
return INT2FIX(s);
|
|
3815
3095
|
}
|
|
3816
3096
|
|
|
@@ -3882,310 +3162,15 @@ BigDecimal_save_rounding_mode(VALUE self)
|
|
|
3882
3162
|
* puts BigDecimal.limit
|
|
3883
3163
|
*
|
|
3884
3164
|
*/
|
|
3885
|
-
static VALUE
|
|
3886
|
-
BigDecimal_save_limit(VALUE self)
|
|
3887
|
-
{
|
|
3888
|
-
size_t const limit = VpGetPrecLimit();
|
|
3889
|
-
int state;
|
|
3890
|
-
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3891
|
-
VpSetPrecLimit(limit);
|
|
3892
|
-
if (state) rb_jump_tag(state);
|
|
3893
|
-
return ret;
|
|
3894
|
-
}
|
|
3895
|
-
|
|
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;
|
|
3165
|
+
static VALUE
|
|
3166
|
+
BigDecimal_save_limit(VALUE self)
|
|
3167
|
+
{
|
|
3168
|
+
size_t const limit = VpGetPrecLimit();
|
|
3169
|
+
int state;
|
|
3170
|
+
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3171
|
+
VpSetPrecLimit(limit);
|
|
3172
|
+
if (state) rb_jump_tag(state);
|
|
3173
|
+
return ret;
|
|
4189
3174
|
}
|
|
4190
3175
|
|
|
4191
3176
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
|
@@ -4239,6 +3224,34 @@ BigDecimal_literal(const char *str)
|
|
|
4239
3224
|
|
|
4240
3225
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
|
4241
3226
|
|
|
3227
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3228
|
+
VALUE
|
|
3229
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3230
|
+
BDVALUE a,b,c,d;
|
|
3231
|
+
size_t cn = NUM2INT(cprec);
|
|
3232
|
+
a = GetBDValueMust(self);
|
|
3233
|
+
b = GetBDValueMust(r);
|
|
3234
|
+
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3235
|
+
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3236
|
+
VpDivd(c.real, d.real, a.real, b.real);
|
|
3237
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3238
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3239
|
+
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
VALUE
|
|
3243
|
+
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3244
|
+
BDVALUE a,b,c;
|
|
3245
|
+
a = GetBDValueMust(self);
|
|
3246
|
+
b = GetBDValueMust(v);
|
|
3247
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3248
|
+
VpMult(c.real, a.real, b.real);
|
|
3249
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3250
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3251
|
+
return c.bigdecimal;
|
|
3252
|
+
}
|
|
3253
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3254
|
+
|
|
4242
3255
|
/* Document-class: BigDecimal
|
|
4243
3256
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
|
4244
3257
|
*
|
|
@@ -4355,14 +3368,16 @@ BigDecimal_literal(const char *str)
|
|
|
4355
3368
|
*
|
|
4356
3369
|
* When you require +bigdecimal/util+, the #to_d method will be
|
|
4357
3370
|
* available on BigDecimal and the native Integer, Float, Rational,
|
|
4358
|
-
* and
|
|
3371
|
+
* String, Complex, and NilClass classes:
|
|
4359
3372
|
*
|
|
4360
3373
|
* require 'bigdecimal/util'
|
|
4361
3374
|
*
|
|
4362
|
-
* 42.to_d
|
|
4363
|
-
* 0.5.to_d
|
|
4364
|
-
* (2/3r).to_d(3)
|
|
4365
|
-
* "0.5".to_d
|
|
3375
|
+
* 42.to_d # => 0.42e2
|
|
3376
|
+
* 0.5.to_d # => 0.5e0
|
|
3377
|
+
* (2/3r).to_d(3) # => 0.667e0
|
|
3378
|
+
* "0.5".to_d # => 0.5e0
|
|
3379
|
+
* Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
|
3380
|
+
* nil.to_d # => 0.0
|
|
4366
3381
|
*
|
|
4367
3382
|
* == Methods for Working with \JSON
|
|
4368
3383
|
*
|
|
@@ -4436,7 +3451,7 @@ Init_bigdecimal(void)
|
|
|
4436
3451
|
* guarantee that two groups could always be multiplied together without
|
|
4437
3452
|
* overflow.)
|
|
4438
3453
|
*/
|
|
4439
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
|
3454
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
|
4440
3455
|
|
|
4441
3456
|
/* Exceptions */
|
|
4442
3457
|
|
|
@@ -4547,7 +3562,6 @@ Init_bigdecimal(void)
|
|
|
4547
3562
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
4548
3563
|
|
|
4549
3564
|
/* instance methods */
|
|
4550
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
4551
3565
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
4552
3566
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
4553
3567
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -4578,14 +3592,11 @@ Init_bigdecimal(void)
|
|
|
4578
3592
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
|
4579
3593
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
|
4580
3594
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
|
4581
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
|
4582
3595
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
|
4583
3596
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
|
4584
3597
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
|
4585
3598
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
|
4586
3599
|
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
3600
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
|
4590
3601
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
|
4591
3602
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
|
@@ -4604,11 +3615,13 @@ Init_bigdecimal(void)
|
|
|
4604
3615
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
|
4605
3616
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
|
4606
3617
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
|
3618
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
|
4607
3619
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
|
4608
3620
|
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
3621
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3622
|
+
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3623
|
+
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3624
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
4612
3625
|
|
|
4613
3626
|
#define ROUNDING_MODE(i, name, value) \
|
|
4614
3627
|
id_##name = rb_intern_const(#name); \
|
|
@@ -4648,19 +3661,9 @@ Init_bigdecimal(void)
|
|
|
4648
3661
|
*/
|
|
4649
3662
|
#ifdef BIGDECIMAL_DEBUG
|
|
4650
3663
|
static int gfDebug = 1; /* Debug switch */
|
|
4651
|
-
#if 0
|
|
4652
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
|
4653
|
-
#endif
|
|
4654
3664
|
#endif /* BIGDECIMAL_DEBUG */
|
|
4655
3665
|
|
|
4656
3666
|
static Real *VpConstOne; /* constant 1.0 */
|
|
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)
|
|
4664
3667
|
|
|
4665
3668
|
enum op_sw {
|
|
4666
3669
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4670,11 +3673,9 @@ enum op_sw {
|
|
|
4670
3673
|
};
|
|
4671
3674
|
|
|
4672
3675
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
|
4673
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
4674
3676
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
|
4675
3677
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
|
4676
3678
|
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
3679
|
static void VpFormatSt(char *psz, size_t fFmt);
|
|
4679
3680
|
static int VpRdup(Real *m, size_t ind_m);
|
|
4680
3681
|
|
|
@@ -4733,10 +3734,10 @@ VpCheckException(Real *p, bool always)
|
|
|
4733
3734
|
}
|
|
4734
3735
|
|
|
4735
3736
|
static VALUE
|
|
4736
|
-
|
|
3737
|
+
CheckGetValue(BDVALUE v)
|
|
4737
3738
|
{
|
|
4738
|
-
VpCheckException(
|
|
4739
|
-
return
|
|
3739
|
+
VpCheckException(v.real, false);
|
|
3740
|
+
return v.bigdecimal;
|
|
4740
3741
|
}
|
|
4741
3742
|
|
|
4742
3743
|
/*
|
|
@@ -4768,12 +3769,10 @@ VpGetPrecLimit(void)
|
|
|
4768
3769
|
return NUM2SIZET(vlimit);
|
|
4769
3770
|
}
|
|
4770
3771
|
|
|
4771
|
-
VP_EXPORT
|
|
3772
|
+
VP_EXPORT void
|
|
4772
3773
|
VpSetPrecLimit(size_t n)
|
|
4773
3774
|
{
|
|
4774
|
-
size_t const s = VpGetPrecLimit();
|
|
4775
3775
|
bigdecimal_set_thread_local_precision_limit(n);
|
|
4776
|
-
return s;
|
|
4777
3776
|
}
|
|
4778
3777
|
|
|
4779
3778
|
/*
|
|
@@ -4888,15 +3887,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
|
4888
3887
|
return nzero;
|
|
4889
3888
|
}
|
|
4890
3889
|
|
|
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
3890
|
VP_EXPORT int
|
|
4901
3891
|
VpException(unsigned short f, const char *str,int always)
|
|
4902
3892
|
{
|
|
@@ -5048,7 +4038,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
|
5048
4038
|
case 'E':
|
|
5049
4039
|
/* fall through */
|
|
5050
4040
|
default:
|
|
5051
|
-
nc = BASE_FIG*
|
|
4041
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
|
5052
4042
|
}
|
|
5053
4043
|
return nc;
|
|
5054
4044
|
}
|
|
@@ -5074,28 +4064,13 @@ VpInit(DECDIG BaseVal)
|
|
|
5074
4064
|
VpGetDoubleNegZero();
|
|
5075
4065
|
|
|
5076
4066
|
/* Const 1.0 */
|
|
5077
|
-
VpConstOne =
|
|
5078
|
-
|
|
5079
|
-
/* Const 0.5 */
|
|
5080
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
|
5081
|
-
VpConstPt5->exponent = 0;
|
|
5082
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
|
4067
|
+
VpConstOne = NewZero(1, 1);
|
|
4068
|
+
VpSetOne(VpConstOne);
|
|
5083
4069
|
|
|
5084
4070
|
#ifdef BIGDECIMAL_DEBUG
|
|
5085
4071
|
gnAlloc = 0;
|
|
5086
4072
|
#endif /* BIGDECIMAL_DEBUG */
|
|
5087
4073
|
|
|
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
4074
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
|
5100
4075
|
}
|
|
5101
4076
|
|
|
@@ -5111,24 +4086,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
|
5111
4086
|
{
|
|
5112
4087
|
SIGNED_VALUE e = a->exponent;
|
|
5113
4088
|
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;
|
|
4089
|
+
if (e > 0 && n > 0) {
|
|
4090
|
+
if (n > VP_EXPONENT_MAX - e) goto overflow;
|
|
4091
|
+
} else if (e < 0 && n < 0) {
|
|
4092
|
+
if (n < VP_EXPONENT_MIN - e) goto underflow;
|
|
4093
|
+
} else if (m > VP_EXPONENT_MAX) {
|
|
4094
|
+
goto overflow;
|
|
4095
|
+
} else if (m < VP_EXPONENT_MIN) {
|
|
4096
|
+
goto underflow;
|
|
5132
4097
|
}
|
|
5133
4098
|
a->exponent = m;
|
|
5134
4099
|
return 1;
|
|
@@ -5169,7 +4134,6 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
5169
4134
|
while (*p && ISSPACE(*p)) ++p;
|
|
5170
4135
|
if (*p == '\0') {
|
|
5171
4136
|
Real *vp = rbd_allocate_struct(1);
|
|
5172
|
-
vp->MaxPrec = 1;
|
|
5173
4137
|
switch (table[i].sign) {
|
|
5174
4138
|
default:
|
|
5175
4139
|
UNREACHABLE; break;
|
|
@@ -5234,38 +4198,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
5234
4198
|
/*
|
|
5235
4199
|
* Allocates variable.
|
|
5236
4200
|
* [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.
|
|
4201
|
+
* szVal ... The value assigned(char).
|
|
5242
4202
|
*
|
|
5243
4203
|
* [Returns]
|
|
5244
4204
|
* Pointer to the newly allocated variable, or
|
|
5245
4205
|
* NULL be returned if memory allocation is failed,or any error.
|
|
5246
4206
|
*/
|
|
5247
4207
|
VP_EXPORT Real *
|
|
5248
|
-
VpAlloc(
|
|
4208
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
5249
4209
|
{
|
|
5250
4210
|
const char *orig_szVal = szVal;
|
|
5251
4211
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
5252
|
-
size_t len;
|
|
5253
4212
|
char v, *psz;
|
|
5254
4213
|
int sign=1;
|
|
5255
4214
|
Real *vp = NULL;
|
|
5256
4215
|
VALUE buf;
|
|
5257
4216
|
|
|
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
4217
|
/* Skipping leading spaces */
|
|
5270
4218
|
while (ISSPACE(*szVal)) szVal++;
|
|
5271
4219
|
|
|
@@ -5274,14 +4222,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5274
4222
|
return vp;
|
|
5275
4223
|
}
|
|
5276
4224
|
|
|
5277
|
-
/*
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
len = rbd_calculate_internal_digits(mx, false);
|
|
5283
|
-
++szVal;
|
|
5284
|
-
}
|
|
4225
|
+
/* Skip leading `#`.
|
|
4226
|
+
* It used to be a mark to indicate that an extra MaxPrec should be allocated,
|
|
4227
|
+
* but now it has no effect.
|
|
4228
|
+
*/
|
|
4229
|
+
if (*szVal == '#') ++szVal;
|
|
5285
4230
|
|
|
5286
4231
|
/* Scanning digits */
|
|
5287
4232
|
|
|
@@ -5428,7 +4373,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5428
4373
|
VALUE str;
|
|
5429
4374
|
invalid_value:
|
|
5430
4375
|
if (!strict_p) {
|
|
5431
|
-
|
|
4376
|
+
return NewZero(1, 1);
|
|
5432
4377
|
}
|
|
5433
4378
|
if (!exc) {
|
|
5434
4379
|
return NULL;
|
|
@@ -5439,11 +4384,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5439
4384
|
|
|
5440
4385
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
5441
4386
|
/* units for szVal[] */
|
|
5442
|
-
|
|
5443
|
-
nalloc = Max(nalloc, len);
|
|
5444
|
-
len = nalloc;
|
|
5445
|
-
vp = rbd_allocate_struct(len);
|
|
5446
|
-
vp->MaxPrec = len; /* set max precision */
|
|
4387
|
+
vp = rbd_allocate_struct(nalloc);
|
|
5447
4388
|
VpSetZero(vp, sign);
|
|
5448
4389
|
protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
|
|
5449
4390
|
rb_str_resize(buf, 0);
|
|
@@ -5483,7 +4424,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5483
4424
|
c->Prec = n;
|
|
5484
4425
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
|
5485
4426
|
/* Needs round ? */
|
|
5486
|
-
if (isw != 10) {
|
|
4427
|
+
if (isw != 10 && isw != -10) {
|
|
5487
4428
|
/* Not in ActiveRound */
|
|
5488
4429
|
if(c->Prec < a->Prec) {
|
|
5489
4430
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
|
@@ -5509,19 +4450,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5509
4450
|
VP_EXPORT size_t
|
|
5510
4451
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
|
5511
4452
|
{
|
|
5512
|
-
short sw, isw;
|
|
4453
|
+
short sw, isw, sign;
|
|
5513
4454
|
Real *a_ptr, *b_ptr;
|
|
5514
4455
|
size_t n, na, nb, i;
|
|
5515
4456
|
DECDIG mrv;
|
|
5516
4457
|
|
|
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
4458
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
|
5526
4459
|
|
|
5527
4460
|
/* check if a or b is zero */
|
|
@@ -5610,28 +4543,21 @@ end_if:
|
|
|
5610
4543
|
if (isw) { /* addition */
|
|
5611
4544
|
VpSetSign(c, 1);
|
|
5612
4545
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
|
5613
|
-
|
|
4546
|
+
sign = isw / 2;
|
|
5614
4547
|
}
|
|
5615
4548
|
else { /* subtraction */
|
|
5616
4549
|
VpSetSign(c, 1);
|
|
5617
4550
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
|
5618
|
-
|
|
5619
|
-
VpSetSign(c,VpGetSign(a));
|
|
5620
|
-
}
|
|
5621
|
-
else {
|
|
5622
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
|
5623
|
-
}
|
|
4551
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
|
5624
4552
|
}
|
|
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);
|
|
4553
|
+
if (VpIsInf(c)) {
|
|
4554
|
+
VpSetInf(c, sign);
|
|
5633
4555
|
}
|
|
5634
|
-
|
|
4556
|
+
else {
|
|
4557
|
+
VpSetSign(c, sign);
|
|
4558
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
|
4559
|
+
}
|
|
4560
|
+
|
|
5635
4561
|
return c->Prec * BASE_FIG;
|
|
5636
4562
|
}
|
|
5637
4563
|
|
|
@@ -5652,13 +4578,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
|
5652
4578
|
size_t c_pos;
|
|
5653
4579
|
DECDIG av, bv, carry, mrv;
|
|
5654
4580
|
|
|
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
4581
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5663
4582
|
a_pos = ap;
|
|
5664
4583
|
b_pos = bp;
|
|
@@ -5724,11 +4643,6 @@ Assign_a:
|
|
|
5724
4643
|
|
|
5725
4644
|
Exit:
|
|
5726
4645
|
|
|
5727
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5728
|
-
if (gfDebug) {
|
|
5729
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
|
5730
|
-
}
|
|
5731
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5732
4646
|
return mrv;
|
|
5733
4647
|
}
|
|
5734
4648
|
|
|
@@ -5747,13 +4661,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
|
5747
4661
|
size_t c_pos;
|
|
5748
4662
|
DECDIG av, bv, borrow, mrv;
|
|
5749
4663
|
|
|
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
4664
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5758
4665
|
a_pos = ap;
|
|
5759
4666
|
b_pos = bp;
|
|
@@ -5829,11 +4736,6 @@ Assign_a:
|
|
|
5829
4736
|
mrv = 0;
|
|
5830
4737
|
|
|
5831
4738
|
Exit:
|
|
5832
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5833
|
-
if (gfDebug) {
|
|
5834
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
|
5835
|
-
}
|
|
5836
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5837
4739
|
return mrv;
|
|
5838
4740
|
}
|
|
5839
4741
|
|
|
@@ -5964,19 +4866,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
5964
4866
|
VP_EXPORT size_t
|
|
5965
4867
|
VpMult(Real *c, Real *a, Real *b)
|
|
5966
4868
|
{
|
|
5967
|
-
size_t MxIndA, MxIndB, MxIndAB
|
|
4869
|
+
size_t MxIndA, MxIndB, MxIndAB;
|
|
5968
4870
|
size_t ind_c, i, ii, nc;
|
|
5969
4871
|
size_t ind_as, ind_ae, ind_bs;
|
|
5970
4872
|
DECDIG carry;
|
|
5971
4873
|
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 */
|
|
5980
4874
|
|
|
5981
4875
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
5982
4876
|
|
|
@@ -5987,39 +4881,28 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
5987
4881
|
}
|
|
5988
4882
|
|
|
5989
4883
|
if (VpIsOne(a)) {
|
|
5990
|
-
VpAsgn(c, b, VpGetSign(a));
|
|
4884
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
|
5991
4885
|
goto Exit;
|
|
5992
4886
|
}
|
|
5993
4887
|
if (VpIsOne(b)) {
|
|
5994
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
4888
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
|
5995
4889
|
goto Exit;
|
|
5996
4890
|
}
|
|
5997
4891
|
if (b->Prec > a->Prec) {
|
|
5998
4892
|
/* Adjust so that digits(a)>digits(b) */
|
|
5999
|
-
w = a;
|
|
4893
|
+
Real *w = a;
|
|
6000
4894
|
a = b;
|
|
6001
4895
|
b = w;
|
|
6002
4896
|
}
|
|
6003
|
-
w = NULL;
|
|
6004
4897
|
MxIndA = a->Prec - 1;
|
|
6005
4898
|
MxIndB = b->Prec - 1;
|
|
6006
|
-
MxIndC = c->MaxPrec - 1;
|
|
6007
4899
|
MxIndAB = a->Prec + b->Prec - 1;
|
|
6008
4900
|
|
|
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
|
-
|
|
6015
4901
|
/* set LHSV c info */
|
|
6016
4902
|
|
|
6017
4903
|
c->exponent = a->exponent; /* set exponent */
|
|
6018
|
-
if (!AddExponent(c, b->exponent)) {
|
|
6019
|
-
if (w) rbd_free_struct(c);
|
|
6020
|
-
return 0;
|
|
6021
|
-
}
|
|
6022
4904
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4905
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
|
6023
4906
|
carry = 0;
|
|
6024
4907
|
nc = ind_c = MxIndAB;
|
|
6025
4908
|
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
|
@@ -6066,29 +4949,18 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6066
4949
|
}
|
|
6067
4950
|
}
|
|
6068
4951
|
}
|
|
6069
|
-
|
|
6070
|
-
VpNmlz(c);
|
|
6071
|
-
VpAsgn(w, c, 1);
|
|
6072
|
-
rbd_free_struct(c);
|
|
6073
|
-
c = w;
|
|
6074
|
-
}
|
|
6075
|
-
else {
|
|
6076
|
-
VpLimitRound(c,0);
|
|
6077
|
-
}
|
|
4952
|
+
VpNmlz(c);
|
|
6078
4953
|
|
|
6079
4954
|
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
4955
|
return c->Prec*BASE_FIG;
|
|
6088
4956
|
}
|
|
6089
4957
|
|
|
6090
4958
|
/*
|
|
6091
4959
|
* c = a / b, remainder = r
|
|
4960
|
+
* XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
|
|
4961
|
+
* XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
|
|
4962
|
+
* 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
|
|
4963
|
+
* 0001_0000_0000 / 9999 = 0000_0001_0001
|
|
6092
4964
|
*/
|
|
6093
4965
|
VP_EXPORT size_t
|
|
6094
4966
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
@@ -6097,16 +4969,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6097
4969
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
|
6098
4970
|
size_t nLoop;
|
|
6099
4971
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
|
6100
|
-
DECDIG
|
|
4972
|
+
DECDIG borrow1, borrow2;
|
|
6101
4973
|
DECDIG_DBL qb;
|
|
6102
4974
|
|
|
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
4975
|
VpSetNaN(r);
|
|
6111
4976
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
|
6112
4977
|
if (VpIsZero(a) && VpIsZero(b)) {
|
|
@@ -6123,30 +4988,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6123
4988
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
|
6124
4989
|
goto Exit;
|
|
6125
4990
|
}
|
|
6126
|
-
if (VpIsOne(b)) {
|
|
6127
|
-
/* divide by one */
|
|
6128
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
6129
|
-
VpSetZero(r, VpGetSign(a));
|
|
6130
|
-
goto Exit;
|
|
6131
|
-
}
|
|
6132
4991
|
|
|
6133
4992
|
word_a = a->Prec;
|
|
6134
4993
|
word_b = b->Prec;
|
|
6135
4994
|
word_c = c->MaxPrec;
|
|
6136
4995
|
word_r = r->MaxPrec;
|
|
6137
4996
|
|
|
6138
|
-
if (word_a
|
|
4997
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
6139
4998
|
|
|
6140
|
-
|
|
6141
|
-
r->frac[
|
|
6142
|
-
|
|
6143
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
|
6144
|
-
++ind_r;
|
|
6145
|
-
}
|
|
6146
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
|
6147
|
-
|
|
6148
|
-
ind_c = 0;
|
|
6149
|
-
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
|
4999
|
+
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5000
|
+
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5001
|
+
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
6150
5002
|
|
|
6151
5003
|
/* initial procedure */
|
|
6152
5004
|
b1 = b1p1 = b->frac[0];
|
|
@@ -6161,15 +5013,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6161
5013
|
|
|
6162
5014
|
/* */
|
|
6163
5015
|
/* loop start */
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
ind_c = 1;
|
|
5016
|
+
nLoop = Min(word_c, word_r);
|
|
5017
|
+
ind_c = 0;
|
|
6167
5018
|
while (ind_c < nLoop) {
|
|
6168
5019
|
if (r->frac[ind_c] == 0) {
|
|
6169
5020
|
++ind_c;
|
|
6170
5021
|
continue;
|
|
6171
5022
|
}
|
|
6172
|
-
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
|
|
5023
|
+
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
|
|
6173
5024
|
if (r1r2 == b1b2) {
|
|
6174
5025
|
/* The first two word digits is the same */
|
|
6175
5026
|
ind_b = 2;
|
|
@@ -6182,26 +5033,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6182
5033
|
}
|
|
6183
5034
|
/* The first few word digits of r and b is the same and */
|
|
6184
5035
|
/* 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
|
-
}
|
|
5036
|
+
/* of b, so quotient is 1. */
|
|
5037
|
+
q = 1;
|
|
6203
5038
|
++c->frac[ind_c];
|
|
6204
|
-
|
|
5039
|
+
ind_r = b->Prec + ind_c - 1;
|
|
5040
|
+
goto sub_mult;
|
|
6205
5041
|
}
|
|
6206
5042
|
/* The first two word digits is not the same, */
|
|
6207
5043
|
/* then compare magnitude, and divide actually. */
|
|
@@ -6254,49 +5090,26 @@ sub_mult:
|
|
|
6254
5090
|
}
|
|
6255
5091
|
|
|
6256
5092
|
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
5093
|
}
|
|
6265
5094
|
/* End of operation, now final arrangement */
|
|
6266
5095
|
out_side:
|
|
6267
5096
|
c->Prec = word_c;
|
|
6268
5097
|
c->exponent = a->exponent;
|
|
6269
|
-
|
|
5098
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
5099
|
+
if (!AddExponent(c, 1)) return 0;
|
|
6270
5100
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
|
6271
5101
|
|
|
6272
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
6273
5102
|
VpNmlz(c); /* normalize c */
|
|
6274
5103
|
r->Prec = word_r;
|
|
6275
5104
|
r->exponent = a->exponent;
|
|
6276
|
-
if (!AddExponent(r, 1)) return 0;
|
|
6277
5105
|
VpSetSign(r, VpGetSign(a));
|
|
6278
5106
|
VpNmlz(r); /* normalize r(remainder) */
|
|
6279
5107
|
goto Exit;
|
|
6280
5108
|
|
|
6281
5109
|
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
5110
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
|
6292
5111
|
|
|
6293
5112
|
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
5113
|
return c->Prec * BASE_FIG;
|
|
6301
5114
|
}
|
|
6302
5115
|
|
|
@@ -6419,13 +5232,6 @@ Exit:
|
|
|
6419
5232
|
if (val > 1) val = 1;
|
|
6420
5233
|
else if (val < -1) val = -1;
|
|
6421
5234
|
|
|
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
5235
|
return (int)val;
|
|
6430
5236
|
}
|
|
6431
5237
|
|
|
@@ -6543,25 +5349,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
|
6543
5349
|
static void
|
|
6544
5350
|
VpFormatSt(char *psz, size_t fFmt)
|
|
6545
5351
|
{
|
|
6546
|
-
size_t
|
|
6547
|
-
char
|
|
5352
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
|
5353
|
+
char *p;
|
|
6548
5354
|
|
|
6549
5355
|
if (fFmt == 0) return;
|
|
6550
5356
|
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
5357
|
+
iend = strlen(psz);
|
|
5358
|
+
|
|
5359
|
+
if ((p = strchr(psz, '.'))) {
|
|
5360
|
+
idig = (p - psz) + 1;
|
|
5361
|
+
}
|
|
5362
|
+
if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
|
|
5363
|
+
iexp = p - psz;
|
|
5364
|
+
}
|
|
5365
|
+
if (idig == 0 || idig > iexp) return;
|
|
5366
|
+
|
|
5367
|
+
nspaces = (iexp - idig - 1) / fFmt;
|
|
5368
|
+
p = psz + iend + 1;
|
|
5369
|
+
for (size_t i = nspaces; i > 0; i--) {
|
|
5370
|
+
char *src = psz + idig + i * fFmt;
|
|
5371
|
+
char *dst = psz + idig + i * (fFmt + 1);
|
|
5372
|
+
memmove(dst, src, p - src);
|
|
5373
|
+
dst[-1] = ' ';
|
|
5374
|
+
p = src;
|
|
6565
5375
|
}
|
|
6566
5376
|
}
|
|
6567
5377
|
|
|
@@ -6843,7 +5653,7 @@ VP_EXPORT int
|
|
|
6843
5653
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
|
6844
5654
|
{
|
|
6845
5655
|
size_t i, j, ind_a, ma, mi, me;
|
|
6846
|
-
SIGNED_VALUE e
|
|
5656
|
+
SIGNED_VALUE e;
|
|
6847
5657
|
int sign, signe, exponent_overflow;
|
|
6848
5658
|
|
|
6849
5659
|
/* get exponent part */
|
|
@@ -6866,23 +5676,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6866
5676
|
++me;
|
|
6867
5677
|
}
|
|
6868
5678
|
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:
|
|
5679
|
+
int dig = exp_chr[i] - '0';
|
|
5680
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
5681
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
|
6882
5682
|
exponent_overflow = 1;
|
|
6883
|
-
e = es; /* keep sign */
|
|
6884
5683
|
break;
|
|
6885
5684
|
}
|
|
5685
|
+
e = e * 10 + signe * dig;
|
|
6886
5686
|
++i;
|
|
6887
5687
|
}
|
|
6888
5688
|
}
|
|
@@ -6901,34 +5701,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6901
5701
|
++mi;
|
|
6902
5702
|
}
|
|
6903
5703
|
}
|
|
5704
|
+
/* skip leading zeros in integer part */
|
|
5705
|
+
while (i < mi && int_chr[i] == '0') {
|
|
5706
|
+
++i;
|
|
5707
|
+
--ni;
|
|
5708
|
+
}
|
|
6904
5709
|
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
5710
|
+
/* set actual exponent size. */
|
|
5711
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
|
5712
|
+
exponent_overflow = 1;
|
|
5713
|
+
} else {
|
|
5714
|
+
e += ni;
|
|
5715
|
+
}
|
|
6910
5716
|
|
|
6911
5717
|
/* 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
|
-
}
|
|
5718
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
|
5719
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
|
5720
|
+
exponent_overflow = 1;
|
|
5721
|
+
} else {
|
|
5722
|
+
e += j;
|
|
6923
5723
|
}
|
|
6924
5724
|
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
if (exponent_overflow) {
|
|
5725
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
|
6928
5726
|
int zero = 1;
|
|
6929
5727
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
|
6930
5728
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
|
6931
|
-
if (!zero &&
|
|
5729
|
+
if (!zero && e > 0) {
|
|
6932
5730
|
VpSetInf(a, sign);
|
|
6933
5731
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
|
6934
5732
|
}
|
|
@@ -6978,7 +5776,7 @@ Final:
|
|
|
6978
5776
|
++j;
|
|
6979
5777
|
}
|
|
6980
5778
|
a->Prec = ind_a + 1;
|
|
6981
|
-
a->exponent =
|
|
5779
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
|
6982
5780
|
VpSetSign(a, sign);
|
|
6983
5781
|
VpNmlz(a);
|
|
6984
5782
|
return 1;
|
|
@@ -7050,254 +5848,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
|
7050
5848
|
*d *= VpGetSign(m);
|
|
7051
5849
|
|
|
7052
5850
|
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
5851
|
return f;
|
|
7061
5852
|
}
|
|
7062
5853
|
|
|
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
5854
|
/*
|
|
7302
5855
|
* Round relatively from the decimal point.
|
|
7303
5856
|
* f: rounding mode
|
|
@@ -7474,7 +6027,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
7474
6027
|
DECDIG v;
|
|
7475
6028
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
|
7476
6029
|
v = y->frac[0];
|
|
7477
|
-
nf -=
|
|
6030
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
|
7478
6031
|
while ((v /= 10) != 0) nf--;
|
|
7479
6032
|
nf += (ssize_t)BASE_FIG-1;
|
|
7480
6033
|
return VpMidRound(y, f, nf);
|
|
@@ -7581,7 +6134,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7581
6134
|
size_t my, ind_y, ind_x;
|
|
7582
6135
|
|
|
7583
6136
|
if (!VpHasVal(x)) {
|
|
7584
|
-
VpAsgn(y, x,
|
|
6137
|
+
VpAsgn(y, x, 10);
|
|
7585
6138
|
goto Exit;
|
|
7586
6139
|
}
|
|
7587
6140
|
|
|
@@ -7590,7 +6143,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7590
6143
|
goto Exit;
|
|
7591
6144
|
}
|
|
7592
6145
|
else if (x->exponent <= 0) {
|
|
7593
|
-
VpAsgn(y, x,
|
|
6146
|
+
VpAsgn(y, x, 10);
|
|
7594
6147
|
goto Exit;
|
|
7595
6148
|
}
|
|
7596
6149
|
|
|
@@ -7611,117 +6164,9 @@ VpFrac(Real *y, Real *x)
|
|
|
7611
6164
|
VpNmlz(y);
|
|
7612
6165
|
|
|
7613
6166
|
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
6167
|
return;
|
|
7621
6168
|
}
|
|
7622
6169
|
|
|
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
6170
|
#ifdef BIGDECIMAL_DEBUG
|
|
7726
6171
|
int
|
|
7727
6172
|
VpVarCheck(Real * v)
|