bigdecimal 3.1.8 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/bigdecimal/bigdecimal.c +774 -2330
- data/ext/bigdecimal/bigdecimal.h +4 -25
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/extconf.rb +13 -15
- data/ext/bigdecimal/missing.c +2 -1
- data/ext/bigdecimal/missing.h +1 -93
- data/lib/bigdecimal/math.rb +89 -72
- data/lib/bigdecimal/util.rb +16 -15
- data/lib/bigdecimal.rb +351 -0
- metadata +3 -6
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 "3.1
|
|
34
|
+
#define BIGDECIMAL_VERSION "3.3.1"
|
|
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,7 +397,7 @@ GetVpValue(VALUE v, int must)
|
|
|
479
397
|
static inline VALUE
|
|
480
398
|
BigDecimal_double_fig(VALUE self)
|
|
481
399
|
{
|
|
482
|
-
return INT2FIX(
|
|
400
|
+
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
483
401
|
}
|
|
484
402
|
|
|
485
403
|
/* call-seq:
|
|
@@ -498,30 +416,26 @@ BigDecimal_double_fig(VALUE self)
|
|
|
498
416
|
static VALUE
|
|
499
417
|
BigDecimal_prec(VALUE self)
|
|
500
418
|
{
|
|
501
|
-
|
|
502
|
-
Real *p;
|
|
419
|
+
BDVALUE v;
|
|
503
420
|
VALUE obj;
|
|
504
421
|
|
|
505
422
|
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
|
|
506
423
|
"BigDecimal#precs is deprecated and will be removed in the future; "
|
|
507
424
|
"use BigDecimal#precision instead.");
|
|
508
425
|
|
|
509
|
-
|
|
510
|
-
obj = rb_assoc_new(SIZET2NUM(
|
|
511
|
-
SIZET2NUM(
|
|
426
|
+
v = GetBDValueMust(self);
|
|
427
|
+
obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
|
|
428
|
+
SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
|
|
429
|
+
|
|
430
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
512
431
|
return obj;
|
|
513
432
|
}
|
|
514
433
|
|
|
515
434
|
static void
|
|
516
|
-
|
|
435
|
+
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
517
436
|
{
|
|
518
|
-
ENTER(1);
|
|
519
|
-
|
|
520
437
|
if (out_precision == NULL && out_scale == NULL)
|
|
521
438
|
return;
|
|
522
|
-
|
|
523
|
-
Real *p;
|
|
524
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
525
439
|
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
526
440
|
zero:
|
|
527
441
|
if (out_precision) *out_precision = 0;
|
|
@@ -625,6 +539,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
|
|
|
625
539
|
}
|
|
626
540
|
}
|
|
627
541
|
|
|
542
|
+
static void
|
|
543
|
+
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
|
544
|
+
{
|
|
545
|
+
BDVALUE v = GetBDValueMust(self);
|
|
546
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
|
547
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
548
|
+
}
|
|
549
|
+
|
|
628
550
|
/*
|
|
629
551
|
* call-seq:
|
|
630
552
|
* precision -> integer
|
|
@@ -660,8 +582,8 @@ BigDecimal_precision(VALUE self)
|
|
|
660
582
|
* BigDecimal("1").scale # => 0
|
|
661
583
|
* BigDecimal("1.1").scale # => 1
|
|
662
584
|
* BigDecimal("3.1415").scale # => 4
|
|
663
|
-
* BigDecimal("-1e20").
|
|
664
|
-
* BigDecimal("1e-20").
|
|
585
|
+
* BigDecimal("-1e20").scale # => 0
|
|
586
|
+
* BigDecimal("1e-20").scale # => 20
|
|
665
587
|
* BigDecimal("Infinity").scale # => 0
|
|
666
588
|
* BigDecimal("-Infinity").scale # => 0
|
|
667
589
|
* BigDecimal("NaN").scale # => 0
|
|
@@ -711,25 +633,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
|
711
633
|
static VALUE
|
|
712
634
|
BigDecimal_n_significant_digits(VALUE self)
|
|
713
635
|
{
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
Real *p;
|
|
717
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
718
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
636
|
+
BDVALUE v = GetBDValueMust(self);
|
|
637
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
|
719
638
|
return INT2FIX(0);
|
|
720
639
|
}
|
|
721
640
|
|
|
722
|
-
ssize_t n =
|
|
723
|
-
for (n =
|
|
641
|
+
ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
|
|
642
|
+
for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
|
|
724
643
|
if (n == 0) return INT2FIX(0);
|
|
725
644
|
|
|
726
645
|
DECDIG x;
|
|
727
646
|
int nlz = BASE_FIG;
|
|
728
|
-
for (x =
|
|
647
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
|
729
648
|
|
|
730
649
|
int ntz = 0;
|
|
731
|
-
for (x =
|
|
650
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
|
732
651
|
|
|
652
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
733
653
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
|
734
654
|
return SSIZET2NUM(n_significant_digits);
|
|
735
655
|
}
|
|
@@ -751,17 +671,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
|
751
671
|
static VALUE
|
|
752
672
|
BigDecimal_hash(VALUE self)
|
|
753
673
|
{
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
st_index_t hash;
|
|
757
|
-
|
|
758
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
759
|
-
hash = (st_index_t)p->sign;
|
|
674
|
+
BDVALUE v = GetBDValueMust(self);
|
|
675
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
|
760
676
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
|
761
677
|
if(hash == 2 || hash == (st_index_t)-2) {
|
|
762
|
-
hash ^= rb_memhash(
|
|
763
|
-
hash +=
|
|
678
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
|
679
|
+
hash += v.real->exponent;
|
|
764
680
|
}
|
|
681
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
765
682
|
return ST2FIX(hash);
|
|
766
683
|
}
|
|
767
684
|
|
|
@@ -780,21 +697,22 @@ BigDecimal_hash(VALUE self)
|
|
|
780
697
|
static VALUE
|
|
781
698
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
782
699
|
{
|
|
783
|
-
|
|
784
|
-
Real *vp;
|
|
700
|
+
BDVALUE v;
|
|
785
701
|
char *psz;
|
|
786
702
|
VALUE dummy;
|
|
787
703
|
volatile VALUE dump;
|
|
788
704
|
size_t len;
|
|
789
705
|
|
|
790
706
|
rb_scan_args(argc, argv, "01", &dummy);
|
|
791
|
-
|
|
792
|
-
dump = rb_str_new(0, VpNumOfChars(
|
|
707
|
+
v = GetBDValueMust(self);
|
|
708
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
|
793
709
|
psz = RSTRING_PTR(dump);
|
|
794
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
|
710
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
|
795
711
|
len = strlen(psz);
|
|
796
|
-
VpToString(
|
|
712
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
|
797
713
|
rb_str_resize(dump, strlen(psz));
|
|
714
|
+
|
|
715
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
798
716
|
return dump;
|
|
799
717
|
}
|
|
800
718
|
|
|
@@ -804,27 +722,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
|
804
722
|
static VALUE
|
|
805
723
|
BigDecimal_load(VALUE self, VALUE str)
|
|
806
724
|
{
|
|
807
|
-
|
|
808
|
-
Real *pv;
|
|
725
|
+
BDVALUE v;
|
|
809
726
|
unsigned char *pch;
|
|
810
727
|
unsigned char ch;
|
|
811
|
-
unsigned long m=0;
|
|
812
728
|
|
|
813
729
|
pch = (unsigned char *)StringValueCStr(str);
|
|
814
|
-
/* First
|
|
730
|
+
/* First skip max prec. Don't trust the value. */
|
|
815
731
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
|
816
732
|
if(!ISDIGIT(ch)) {
|
|
817
733
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
|
818
734
|
}
|
|
819
|
-
m = m*10 + (unsigned long)(ch-'0');
|
|
820
735
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
m /= VpBaseFig();
|
|
824
|
-
if (m && pv->MaxPrec > m) {
|
|
825
|
-
pv->MaxPrec = m+1;
|
|
826
|
-
}
|
|
827
|
-
return VpCheckGetValue(pv);
|
|
736
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
737
|
+
return CheckGetValue(v);
|
|
828
738
|
}
|
|
829
739
|
|
|
830
740
|
static unsigned short
|
|
@@ -1117,22 +1027,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1117
1027
|
static size_t
|
|
1118
1028
|
GetAddSubPrec(Real *a, Real *b)
|
|
1119
1029
|
{
|
|
1120
|
-
size_t mxs;
|
|
1121
|
-
size_t mx = a->Prec;
|
|
1122
|
-
SIGNED_VALUE d;
|
|
1123
|
-
|
|
1124
1030
|
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
d = a->exponent - b->exponent;
|
|
1129
|
-
if (d < 0) d = -d;
|
|
1130
|
-
mx = mx + (size_t)d;
|
|
1131
|
-
if (mx < mxs) {
|
|
1132
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
return mx;
|
|
1031
|
+
ssize_t min_a = a->exponent - a->Prec;
|
|
1032
|
+
ssize_t min_b = b->exponent - b->Prec;
|
|
1033
|
+
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
1136
1034
|
}
|
|
1137
1035
|
|
|
1138
1036
|
static inline SIGNED_VALUE
|
|
@@ -1152,39 +1050,13 @@ check_int_precision(VALUE v)
|
|
|
1152
1050
|
return n;
|
|
1153
1051
|
}
|
|
1154
1052
|
|
|
1155
|
-
static
|
|
1156
|
-
|
|
1157
|
-
{
|
|
1158
|
-
assert(is_kind_of_BigDecimal(obj));
|
|
1159
|
-
assert(vp != NULL);
|
|
1160
|
-
|
|
1161
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
|
1162
|
-
return obj;
|
|
1163
|
-
|
|
1164
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
1165
|
-
assert(vp->obj == 0);
|
|
1166
|
-
|
|
1167
|
-
RTYPEDDATA_DATA(obj) = vp;
|
|
1168
|
-
vp->obj = obj;
|
|
1169
|
-
RB_OBJ_FREEZE(obj);
|
|
1170
|
-
return obj;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
VP_EXPORT Real *
|
|
1174
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1175
|
-
{
|
|
1176
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
1177
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
|
1178
|
-
if (!pv)
|
|
1179
|
-
return NULL;
|
|
1180
|
-
BigDecimal_wrap_struct(obj, pv);
|
|
1181
|
-
return pv;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
VP_EXPORT Real *
|
|
1185
|
-
VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
|
|
1053
|
+
static NULLABLE_BDVALUE
|
|
1054
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1186
1055
|
{
|
|
1187
|
-
|
|
1056
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
|
|
1057
|
+
Real *pv = VpAlloc(str, strict_p, raise_exception);
|
|
1058
|
+
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1059
|
+
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
|
|
1188
1060
|
}
|
|
1189
1061
|
|
|
1190
1062
|
static Real *
|
|
@@ -1192,7 +1064,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1192
1064
|
{
|
|
1193
1065
|
assert(x != NULL);
|
|
1194
1066
|
|
|
1195
|
-
pv =
|
|
1067
|
+
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1196
1068
|
pv->MaxPrec = x->MaxPrec;
|
|
1197
1069
|
pv->Prec = x->Prec;
|
|
1198
1070
|
pv->exponent = x->exponent;
|
|
@@ -1207,7 +1079,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1207
1079
|
static VALUE
|
|
1208
1080
|
BigDecimal_IsNaN(VALUE self)
|
|
1209
1081
|
{
|
|
1210
|
-
Real *p =
|
|
1082
|
+
Real *p = GetSelfVpValue(self);
|
|
1211
1083
|
if (VpIsNaN(p)) return Qtrue;
|
|
1212
1084
|
return Qfalse;
|
|
1213
1085
|
}
|
|
@@ -1218,7 +1090,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
|
1218
1090
|
static VALUE
|
|
1219
1091
|
BigDecimal_IsInfinite(VALUE self)
|
|
1220
1092
|
{
|
|
1221
|
-
Real *p =
|
|
1093
|
+
Real *p = GetSelfVpValue(self);
|
|
1222
1094
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
|
1223
1095
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
|
1224
1096
|
return Qnil;
|
|
@@ -1228,7 +1100,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
|
1228
1100
|
static VALUE
|
|
1229
1101
|
BigDecimal_IsFinite(VALUE self)
|
|
1230
1102
|
{
|
|
1231
|
-
Real *p =
|
|
1103
|
+
Real *p = GetSelfVpValue(self);
|
|
1232
1104
|
if (VpIsNaN(p)) return Qfalse;
|
|
1233
1105
|
if (VpIsInf(p)) return Qfalse;
|
|
1234
1106
|
return Qtrue;
|
|
@@ -1240,6 +1112,7 @@ BigDecimal_check_num(Real *p)
|
|
|
1240
1112
|
VpCheckException(p, true);
|
|
1241
1113
|
}
|
|
1242
1114
|
|
|
1115
|
+
static VALUE BigDecimal_fix(VALUE self);
|
|
1243
1116
|
static VALUE BigDecimal_split(VALUE self);
|
|
1244
1117
|
|
|
1245
1118
|
/* Returns the value as an Integer.
|
|
@@ -1249,44 +1122,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
|
1249
1122
|
static VALUE
|
|
1250
1123
|
BigDecimal_to_i(VALUE self)
|
|
1251
1124
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
Real *p;
|
|
1125
|
+
BDVALUE v;
|
|
1126
|
+
VALUE ret;
|
|
1255
1127
|
|
|
1256
|
-
|
|
1257
|
-
BigDecimal_check_num(
|
|
1128
|
+
v = GetBDValueMust(self);
|
|
1129
|
+
BigDecimal_check_num(v.real);
|
|
1258
1130
|
|
|
1259
|
-
|
|
1260
|
-
if (
|
|
1261
|
-
|
|
1262
|
-
if (e <= nf) {
|
|
1263
|
-
return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
|
|
1131
|
+
if (v.real->exponent <= 0) return INT2FIX(0);
|
|
1132
|
+
if (v.real->exponent == 1) {
|
|
1133
|
+
ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
|
|
1264
1134
|
}
|
|
1265
1135
|
else {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
ret = rb_funcall(numerator, '*', 1,
|
|
1282
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
|
1283
|
-
INT2FIX(dpower)));
|
|
1284
|
-
}
|
|
1285
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
|
1286
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1287
|
-
}
|
|
1288
|
-
return ret;
|
|
1136
|
+
VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
|
|
1137
|
+
VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
|
|
1138
|
+
ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
|
|
1139
|
+
ret = rb_funcall(digits, rb_intern("to_i"), 0);
|
|
1140
|
+
|
|
1141
|
+
if (BIGDECIMAL_NEGATIVE_P(v.real)) {
|
|
1142
|
+
ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
|
|
1143
|
+
}
|
|
1144
|
+
if (dpower) {
|
|
1145
|
+
VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
|
|
1146
|
+
// In Ruby < 3.4, int**int may return Float::INFINITY
|
|
1147
|
+
if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1148
|
+
|
|
1149
|
+
ret = rb_funcall(ret, '*', 1, pow10);
|
|
1150
|
+
}
|
|
1289
1151
|
}
|
|
1152
|
+
|
|
1153
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1154
|
+
return ret;
|
|
1290
1155
|
}
|
|
1291
1156
|
|
|
1292
1157
|
/* Returns a new Float object having approximately the same value as the
|
|
@@ -1296,24 +1161,26 @@ BigDecimal_to_i(VALUE self)
|
|
|
1296
1161
|
static VALUE
|
|
1297
1162
|
BigDecimal_to_f(VALUE self)
|
|
1298
1163
|
{
|
|
1299
|
-
ENTER(1);
|
|
1300
|
-
Real *p;
|
|
1301
1164
|
double d;
|
|
1302
1165
|
SIGNED_VALUE e;
|
|
1303
1166
|
char *buf;
|
|
1304
1167
|
volatile VALUE str;
|
|
1168
|
+
BDVALUE v = GetBDValueMust(self);
|
|
1169
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
|
1305
1170
|
|
|
1306
|
-
|
|
1307
|
-
if (VpVtoD(&d, &e, p) != 1)
|
|
1171
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
|
1308
1172
|
return rb_float_new(d);
|
|
1309
1173
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
|
1310
1174
|
goto overflow;
|
|
1311
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
|
1175
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
|
1312
1176
|
goto underflow;
|
|
1313
1177
|
|
|
1314
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
1178
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
1315
1179
|
buf = RSTRING_PTR(str);
|
|
1316
|
-
VpToString(
|
|
1180
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
|
1181
|
+
|
|
1182
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1183
|
+
|
|
1317
1184
|
errno = 0;
|
|
1318
1185
|
d = strtod(buf, 0);
|
|
1319
1186
|
if (errno == ERANGE) {
|
|
@@ -1324,14 +1191,14 @@ BigDecimal_to_f(VALUE self)
|
|
|
1324
1191
|
|
|
1325
1192
|
overflow:
|
|
1326
1193
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
|
1327
|
-
if (
|
|
1194
|
+
if (negative)
|
|
1328
1195
|
return rb_float_new(VpGetDoubleNegInf());
|
|
1329
1196
|
else
|
|
1330
1197
|
return rb_float_new(VpGetDoublePosInf());
|
|
1331
1198
|
|
|
1332
1199
|
underflow:
|
|
1333
1200
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
|
1334
|
-
if (
|
|
1201
|
+
if (negative)
|
|
1335
1202
|
return rb_float_new(-0.0);
|
|
1336
1203
|
else
|
|
1337
1204
|
return rb_float_new(0.0);
|
|
@@ -1343,15 +1210,16 @@ underflow:
|
|
|
1343
1210
|
static VALUE
|
|
1344
1211
|
BigDecimal_to_r(VALUE self)
|
|
1345
1212
|
{
|
|
1346
|
-
|
|
1213
|
+
BDVALUE v;
|
|
1347
1214
|
ssize_t sign, power, denomi_power;
|
|
1348
1215
|
VALUE a, digits, numerator;
|
|
1349
1216
|
|
|
1350
|
-
|
|
1351
|
-
BigDecimal_check_num(
|
|
1217
|
+
v = GetBDValueMust(self);
|
|
1218
|
+
BigDecimal_check_num(v.real);
|
|
1219
|
+
sign = VpGetSign(v.real);
|
|
1220
|
+
power = VpExponent10(v.real);
|
|
1221
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1352
1222
|
|
|
1353
|
-
sign = VpGetSign(p);
|
|
1354
|
-
power = VpExponent10(p);
|
|
1355
1223
|
a = BigDecimal_split(self);
|
|
1356
1224
|
digits = RARRAY_AREF(a, 1);
|
|
1357
1225
|
denomi_power = power - RSTRING_LEN(digits);
|
|
@@ -1372,6 +1240,14 @@ BigDecimal_to_r(VALUE self)
|
|
|
1372
1240
|
}
|
|
1373
1241
|
}
|
|
1374
1242
|
|
|
1243
|
+
static size_t
|
|
1244
|
+
GetCoercePrec(Real *a, size_t prec)
|
|
1245
|
+
{
|
|
1246
|
+
if (prec == 0) prec = a->Prec * BASE_FIG;
|
|
1247
|
+
if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1248
|
+
return prec;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1375
1251
|
/* The coerce method provides support for Ruby type coercion. It is not
|
|
1376
1252
|
* enabled by default.
|
|
1377
1253
|
*
|
|
@@ -1389,26 +1265,9 @@ BigDecimal_to_r(VALUE self)
|
|
|
1389
1265
|
static VALUE
|
|
1390
1266
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1391
1267
|
{
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
|
1397
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
|
1398
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
|
1399
|
-
}
|
|
1400
|
-
else {
|
|
1401
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
|
1402
|
-
Real* pv = DATA_PTR(self);
|
|
1403
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
|
1404
|
-
}
|
|
1405
|
-
else {
|
|
1406
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
|
1407
|
-
}
|
|
1408
|
-
obj = rb_assoc_new(b->obj, self);
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
return obj;
|
|
1268
|
+
Real* pv = DATA_PTR(self);
|
|
1269
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1270
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
|
1412
1271
|
}
|
|
1413
1272
|
|
|
1414
1273
|
/*
|
|
@@ -1428,6 +1287,15 @@ BigDecimal_uplus(VALUE self)
|
|
|
1428
1287
|
return self;
|
|
1429
1288
|
}
|
|
1430
1289
|
|
|
1290
|
+
static bool
|
|
1291
|
+
is_coerceable_to_BigDecimal(VALUE r)
|
|
1292
|
+
{
|
|
1293
|
+
return is_kind_of_BigDecimal(r) ||
|
|
1294
|
+
RB_INTEGER_TYPE_P(r) ||
|
|
1295
|
+
RB_TYPE_P(r, T_FLOAT) ||
|
|
1296
|
+
RB_TYPE_P(r, T_RATIONAL);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1431
1299
|
/*
|
|
1432
1300
|
* call-seq:
|
|
1433
1301
|
* self + value -> bigdecimal
|
|
@@ -1447,45 +1315,44 @@ BigDecimal_uplus(VALUE self)
|
|
|
1447
1315
|
static VALUE
|
|
1448
1316
|
BigDecimal_add(VALUE self, VALUE r)
|
|
1449
1317
|
{
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1318
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
|
1319
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
|
1320
|
+
}
|
|
1453
1321
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1460
|
-
}
|
|
1461
|
-
else {
|
|
1462
|
-
b = GetVpValue(r, 0);
|
|
1463
|
-
}
|
|
1322
|
+
static VALUE
|
|
1323
|
+
BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
1324
|
+
{
|
|
1325
|
+
BDVALUE a, b, c;
|
|
1326
|
+
size_t mx;
|
|
1464
1327
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1328
|
+
a = GetBDValueMust(self);
|
|
1329
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1467
1330
|
|
|
1468
|
-
if (VpIsNaN(
|
|
1469
|
-
if (VpIsNaN(
|
|
1331
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1332
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1470
1333
|
|
|
1471
|
-
mx = GetAddSubPrec(a, b);
|
|
1334
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1472
1335
|
if (mx == (size_t)-1L) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1336
|
+
/* a or b is inf */
|
|
1337
|
+
c = NewZeroWrap(1, BASE_FIG);
|
|
1338
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1475
1339
|
}
|
|
1476
1340
|
else {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1341
|
+
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1342
|
+
size_t pl = VpGetPrecLimit();
|
|
1343
|
+
if (prec) VpSetPrecLimit(prec);
|
|
1344
|
+
// Let VpAddSub round the result
|
|
1345
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1346
|
+
if (prec) VpSetPrecLimit(pl);
|
|
1484
1347
|
}
|
|
1485
|
-
|
|
1348
|
+
|
|
1349
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1350
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1351
|
+
return CheckGetValue(c);
|
|
1486
1352
|
}
|
|
1487
1353
|
|
|
1488
|
-
/*
|
|
1354
|
+
/*
|
|
1355
|
+
* call-seq:
|
|
1489
1356
|
* self - value -> bigdecimal
|
|
1490
1357
|
*
|
|
1491
1358
|
* Returns the \BigDecimal difference of +self+ and +value+:
|
|
@@ -1502,73 +1369,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
|
1502
1369
|
static VALUE
|
|
1503
1370
|
BigDecimal_sub(VALUE self, VALUE r)
|
|
1504
1371
|
{
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
size_t mx;
|
|
1508
|
-
|
|
1509
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
|
1510
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1511
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1512
|
-
}
|
|
1513
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1514
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1515
|
-
}
|
|
1516
|
-
else {
|
|
1517
|
-
b = GetVpValue(r,0);
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
if (!b) return DoSomeOne(self,r,'-');
|
|
1521
|
-
SAVE(b);
|
|
1522
|
-
|
|
1523
|
-
if (VpIsNaN(b)) return b->obj;
|
|
1524
|
-
if (VpIsNaN(a)) return a->obj;
|
|
1525
|
-
|
|
1526
|
-
mx = GetAddSubPrec(a,b);
|
|
1527
|
-
if (mx == (size_t)-1L) {
|
|
1528
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
|
1529
|
-
VpAddSub(c, a, b, -1);
|
|
1530
|
-
}
|
|
1531
|
-
else {
|
|
1532
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
|
|
1533
|
-
if (!mx) {
|
|
1534
|
-
VpSetInf(c,VpGetSign(a));
|
|
1535
|
-
}
|
|
1536
|
-
else {
|
|
1537
|
-
VpAddSub(c, a, b, -1);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
return VpCheckGetValue(c);
|
|
1372
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
|
1373
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
|
1541
1374
|
}
|
|
1542
1375
|
|
|
1543
1376
|
static VALUE
|
|
1544
1377
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1545
1378
|
{
|
|
1546
|
-
ENTER(5);
|
|
1547
1379
|
SIGNED_VALUE e;
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
switch (TYPE(r)) {
|
|
1551
|
-
case T_DATA:
|
|
1552
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
|
1553
|
-
/* fall through */
|
|
1554
|
-
case T_FIXNUM:
|
|
1555
|
-
/* fall through */
|
|
1556
|
-
case T_BIGNUM:
|
|
1557
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
|
1558
|
-
break;
|
|
1559
|
-
|
|
1560
|
-
case T_FLOAT:
|
|
1561
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
|
1562
|
-
break;
|
|
1380
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1381
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1563
1382
|
|
|
1564
|
-
|
|
1565
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
|
1566
|
-
break;
|
|
1567
|
-
|
|
1568
|
-
default:
|
|
1569
|
-
break;
|
|
1570
|
-
}
|
|
1571
|
-
if (b == NULL) {
|
|
1383
|
+
if (b.real_or_null == NULL) {
|
|
1572
1384
|
ID f = 0;
|
|
1573
1385
|
|
|
1574
1386
|
switch (op) {
|
|
@@ -1597,8 +1409,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1597
1409
|
}
|
|
1598
1410
|
return rb_num_coerce_relop(self, r, f);
|
|
1599
1411
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1412
|
+
e = VpComp(a.real, b.real_or_null);
|
|
1413
|
+
|
|
1414
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1415
|
+
RB_GC_GUARD(b.bigdecimal_or_nil);
|
|
1416
|
+
|
|
1602
1417
|
if (e == 999)
|
|
1603
1418
|
return (op == '*') ? Qnil : Qfalse;
|
|
1604
1419
|
switch (op) {
|
|
@@ -1638,7 +1453,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1638
1453
|
static VALUE
|
|
1639
1454
|
BigDecimal_zero(VALUE self)
|
|
1640
1455
|
{
|
|
1641
|
-
Real *a =
|
|
1456
|
+
Real *a = GetSelfVpValue(self);
|
|
1642
1457
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
|
1643
1458
|
}
|
|
1644
1459
|
|
|
@@ -1646,7 +1461,7 @@ BigDecimal_zero(VALUE self)
|
|
|
1646
1461
|
static VALUE
|
|
1647
1462
|
BigDecimal_nonzero(VALUE self)
|
|
1648
1463
|
{
|
|
1649
|
-
Real *a =
|
|
1464
|
+
Real *a = GetSelfVpValue(self);
|
|
1650
1465
|
return VpIsZero(a) ? Qnil : self;
|
|
1651
1466
|
}
|
|
1652
1467
|
|
|
@@ -1772,12 +1587,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
|
1772
1587
|
static VALUE
|
|
1773
1588
|
BigDecimal_neg(VALUE self)
|
|
1774
1589
|
{
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
return VpCheckGetValue(c);
|
|
1590
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1591
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
1592
|
+
VpAsgn(c.real, a.real, -10);
|
|
1593
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1594
|
+
return CheckGetValue(c);
|
|
1781
1595
|
}
|
|
1782
1596
|
|
|
1783
1597
|
/*
|
|
@@ -1790,84 +1604,36 @@ BigDecimal_neg(VALUE self)
|
|
|
1790
1604
|
*
|
|
1791
1605
|
* See BigDecimal#mult.
|
|
1792
1606
|
*/
|
|
1793
|
-
|
|
1794
1607
|
static VALUE
|
|
1795
1608
|
BigDecimal_mult(VALUE self, VALUE r)
|
|
1796
1609
|
{
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
size_t mx;
|
|
1800
|
-
|
|
1801
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
1802
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1803
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1804
|
-
}
|
|
1805
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1806
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1807
|
-
}
|
|
1808
|
-
else {
|
|
1809
|
-
b = GetVpValue(r,0);
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
if (!b) return DoSomeOne(self, r, '*');
|
|
1813
|
-
SAVE(b);
|
|
1814
|
-
|
|
1815
|
-
mx = a->Prec + b->Prec;
|
|
1816
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
|
1817
|
-
VpMult(c, a, b);
|
|
1818
|
-
return VpCheckGetValue(c);
|
|
1610
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
|
1611
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
|
1819
1612
|
}
|
|
1820
1613
|
|
|
1821
1614
|
static VALUE
|
|
1822
|
-
|
|
1823
|
-
/* For c = self.div(r): with round operation */
|
|
1615
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
|
1824
1616
|
{
|
|
1825
|
-
|
|
1826
|
-
Real *a, *b;
|
|
1827
|
-
ssize_t a_prec, b_prec;
|
|
1828
|
-
size_t mx;
|
|
1617
|
+
BDVALUE a, b, c;
|
|
1829
1618
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1619
|
+
a = GetBDValueMust(self);
|
|
1620
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1832
1621
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1838
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1839
|
-
}
|
|
1840
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1841
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1842
|
-
}
|
|
1843
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1844
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1622
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
1623
|
+
VpMult(c.real, a.real, b.real);
|
|
1624
|
+
if (prec) {
|
|
1625
|
+
VpLeftRound(c.real, VpGetRoundMode(), prec);
|
|
1845
1626
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
return DoSomeOne(self, r, '/');
|
|
1627
|
+
else {
|
|
1628
|
+
VpLimitRound(c.real, 0);
|
|
1849
1629
|
}
|
|
1850
1630
|
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
|
1856
|
-
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
|
1857
|
-
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
|
1858
|
-
mx *= 2;
|
|
1859
|
-
|
|
1860
|
-
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
|
1861
|
-
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
|
1862
|
-
|
|
1863
|
-
GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
|
|
1864
|
-
GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
|
|
1865
|
-
VpDivd(*c, *res, a, b);
|
|
1866
|
-
|
|
1867
|
-
return Qnil;
|
|
1631
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1632
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1633
|
+
return CheckGetValue(c);
|
|
1868
1634
|
}
|
|
1869
1635
|
|
|
1870
|
-
static
|
|
1636
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
|
1871
1637
|
|
|
1872
1638
|
/* call-seq:
|
|
1873
1639
|
* a / b -> bigdecimal
|
|
@@ -1884,20 +1650,8 @@ static VALUE
|
|
|
1884
1650
|
BigDecimal_div(VALUE self, VALUE r)
|
|
1885
1651
|
/* For c = self/r: with round operation */
|
|
1886
1652
|
{
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
r = BigDecimal_divide(self, r, &c, &res, &div);
|
|
1890
|
-
if (!NIL_P(r)) return r; /* coerced by other */
|
|
1891
|
-
SAVE(c); SAVE(res); SAVE(div);
|
|
1892
|
-
/* a/b = c + r/b */
|
|
1893
|
-
/* c xxxxx
|
|
1894
|
-
r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
|
|
1895
|
-
*/
|
|
1896
|
-
/* Round */
|
|
1897
|
-
if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
|
|
1898
|
-
VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
|
|
1899
|
-
}
|
|
1900
|
-
return VpCheckGetValue(c);
|
|
1653
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
|
1654
|
+
return BigDecimal_div2(self, r, INT2FIX(0));
|
|
1901
1655
|
}
|
|
1902
1656
|
|
|
1903
1657
|
static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
|
|
@@ -1942,119 +1696,115 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
|
1942
1696
|
/*
|
|
1943
1697
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
|
1944
1698
|
* div = (a.to_f/b).floor
|
|
1699
|
+
* In truncate mode, use truncate instead of floor.
|
|
1945
1700
|
*/
|
|
1946
|
-
static
|
|
1947
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
|
1701
|
+
static bool
|
|
1702
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
|
1948
1703
|
{
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
size_t mx;
|
|
1704
|
+
BDVALUE a, b, dv, md, res;
|
|
1705
|
+
NULLABLE_BDVALUE b2;
|
|
1706
|
+
ssize_t a_exponent, b_exponent;
|
|
1707
|
+
size_t mx, rx, pl;
|
|
1954
1708
|
|
|
1955
|
-
|
|
1956
|
-
SAVE(a);
|
|
1709
|
+
a = GetBDValueMust(self);
|
|
1957
1710
|
|
|
1958
|
-
|
|
1959
|
-
if (
|
|
1960
|
-
|
|
1961
|
-
}
|
|
1962
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1963
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1964
|
-
}
|
|
1965
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1966
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1967
|
-
}
|
|
1968
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1969
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1970
|
-
}
|
|
1711
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1712
|
+
if (!b2.real_or_null) return false;
|
|
1713
|
+
b = bdvalue_nonnullable(b2);
|
|
1971
1714
|
|
|
1972
|
-
if (
|
|
1973
|
-
|
|
1715
|
+
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1716
|
+
VALUE nan = BigDecimal_nan();
|
|
1717
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1718
|
+
goto Done;
|
|
1974
1719
|
}
|
|
1975
|
-
|
|
1976
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
|
1977
|
-
SAVE(b);
|
|
1978
|
-
|
|
1979
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
|
1980
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
|
1981
|
-
if (VpIsZero(b)) {
|
|
1720
|
+
if (VpIsZero(b.real)) {
|
|
1982
1721
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
|
1983
1722
|
}
|
|
1984
|
-
if (VpIsInf(a)) {
|
|
1985
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
|
1723
|
+
if (VpIsInf(a.real)) {
|
|
1724
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1986
1725
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1987
|
-
|
|
1726
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1988
1727
|
}
|
|
1989
1728
|
else {
|
|
1990
1729
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1991
|
-
|
|
1730
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1992
1731
|
}
|
|
1993
1732
|
VALUE nan = BigDecimal_nan();
|
|
1994
|
-
|
|
1995
|
-
|
|
1733
|
+
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1734
|
+
goto Done;
|
|
1996
1735
|
}
|
|
1997
|
-
if (
|
|
1736
|
+
if (VpIsZero(a.real)) {
|
|
1998
1737
|
VALUE zero = BigDecimal_positive_zero();
|
|
1999
|
-
|
|
2000
|
-
*mod = a;
|
|
2001
|
-
|
|
1738
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1739
|
+
*mod = bdvalue_nullable(a);
|
|
1740
|
+
goto Done;
|
|
1741
|
+
}
|
|
1742
|
+
if (VpIsInf(b.real)) {
|
|
1743
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
|
1744
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
|
1745
|
+
VpSetOne(minus_one.real);
|
|
1746
|
+
VpSetSign(minus_one.real, -1);
|
|
1747
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
|
1748
|
+
*div = bdvalue_nullable(minus_one);
|
|
1749
|
+
*mod = bdvalue_nullable(b);
|
|
1750
|
+
} else {
|
|
1751
|
+
VALUE zero = BigDecimal_positive_zero();
|
|
1752
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1753
|
+
*mod = bdvalue_nullable(a);
|
|
1754
|
+
}
|
|
1755
|
+
goto Done;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
a_exponent = VpExponent10(a.real);
|
|
1759
|
+
b_exponent = VpExponent10(b.real);
|
|
1760
|
+
mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
|
|
1761
|
+
dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
|
|
1762
|
+
|
|
1763
|
+
/* res is reused for VpDivd remainder and VpMult result */
|
|
1764
|
+
rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
|
|
1765
|
+
mx = VPMULT_RESULT_PREC(dv.real, b.real);
|
|
1766
|
+
res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
|
|
1767
|
+
/* AddSub needs one more prec */
|
|
1768
|
+
md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
|
|
1769
|
+
|
|
1770
|
+
VpDivd(dv.real, res.real, a.real, b.real);
|
|
1771
|
+
VpMidRound(dv.real, VP_ROUND_DOWN, 0);
|
|
1772
|
+
VpMult(res.real, dv.real, b.real);
|
|
1773
|
+
pl = VpGetPrecLimit();
|
|
1774
|
+
VpSetPrecLimit(0);
|
|
1775
|
+
VpAddSub(md.real, a.real, res.real, -1);
|
|
1776
|
+
VpSetPrecLimit(pl);
|
|
1777
|
+
|
|
1778
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
|
1779
|
+
/* result adjustment for negative case */
|
|
1780
|
+
BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
|
|
1781
|
+
BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
|
|
1782
|
+
VpSetPrecLimit(0);
|
|
1783
|
+
VpAddSub(dv2.real, dv.real, VpOne(), -1);
|
|
1784
|
+
VpAddSub(md2.real, md.real, b.real, 1);
|
|
1785
|
+
VpSetPrecLimit(pl);
|
|
1786
|
+
*div = bdvalue_nullable(dv2);
|
|
1787
|
+
*mod = bdvalue_nullable(md2);
|
|
1788
|
+
RB_GC_GUARD(dv2.bigdecimal);
|
|
1789
|
+
RB_GC_GUARD(md2.bigdecimal);
|
|
2002
1790
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
|
|
2007
|
-
return Qtrue;
|
|
1791
|
+
else {
|
|
1792
|
+
*div = bdvalue_nullable(dv);
|
|
1793
|
+
*mod = bdvalue_nullable(md);
|
|
2008
1794
|
}
|
|
2009
1795
|
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
|
|
2020
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
|
|
2021
|
-
VpDivd(c, res, a, b);
|
|
2022
|
-
|
|
2023
|
-
mx = c->Prec * BASE_FIG;
|
|
2024
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
|
2025
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0);
|
|
2026
|
-
|
|
2027
|
-
VpMult(res, d, b);
|
|
2028
|
-
VpAddSub(c, a, res, -1);
|
|
2029
|
-
|
|
2030
|
-
if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
|
|
2031
|
-
/* result adjustment for negative case */
|
|
2032
|
-
res = rbd_reallocate_struct(res, d->MaxPrec);
|
|
2033
|
-
res->MaxPrec = d->MaxPrec;
|
|
2034
|
-
VpAddSub(res, d, VpOne(), -1);
|
|
2035
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
|
|
2036
|
-
VpAddSub(d, c, b, 1);
|
|
2037
|
-
*div = res;
|
|
2038
|
-
*mod = d;
|
|
2039
|
-
}
|
|
2040
|
-
else {
|
|
2041
|
-
*div = d;
|
|
2042
|
-
*mod = c;
|
|
2043
|
-
}
|
|
2044
|
-
return Qtrue;
|
|
2045
|
-
|
|
2046
|
-
NaN:
|
|
2047
|
-
{
|
|
2048
|
-
VALUE nan = BigDecimal_nan();
|
|
2049
|
-
TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
|
|
2050
|
-
TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
|
|
2051
|
-
}
|
|
2052
|
-
return Qtrue;
|
|
2053
|
-
}
|
|
1796
|
+
Done:
|
|
1797
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1798
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1799
|
+
RB_GC_GUARD(dv.bigdecimal);
|
|
1800
|
+
RB_GC_GUARD(md.bigdecimal);
|
|
1801
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1802
|
+
return true;
|
|
1803
|
+
}
|
|
2054
1804
|
|
|
2055
1805
|
/* call-seq:
|
|
2056
|
-
*
|
|
2057
|
-
*
|
|
1806
|
+
* a % b
|
|
1807
|
+
* a.modulo(b)
|
|
2058
1808
|
*
|
|
2059
1809
|
* Returns the modulus from dividing by b.
|
|
2060
1810
|
*
|
|
@@ -2063,71 +1813,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
|
2063
1813
|
static VALUE
|
|
2064
1814
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
|
2065
1815
|
{
|
|
2066
|
-
|
|
2067
|
-
Real *div = NULL, *mod = NULL;
|
|
1816
|
+
NULLABLE_BDVALUE div, mod;
|
|
2068
1817
|
|
|
2069
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2070
|
-
|
|
2071
|
-
return VpCheckGetValue(mod);
|
|
1818
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1819
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
2072
1820
|
}
|
|
2073
1821
|
return DoSomeOne(self, r, '%');
|
|
2074
1822
|
}
|
|
2075
1823
|
|
|
2076
|
-
static VALUE
|
|
2077
|
-
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
2078
|
-
{
|
|
2079
|
-
ENTER(10);
|
|
2080
|
-
size_t mx;
|
|
2081
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
|
2082
|
-
Real *f = NULL;
|
|
2083
|
-
|
|
2084
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2085
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
2086
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
2087
|
-
}
|
|
2088
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
2089
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
2090
|
-
}
|
|
2091
|
-
else {
|
|
2092
|
-
b = GetVpValue(r, 0);
|
|
2093
|
-
}
|
|
2094
|
-
|
|
2095
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2096
|
-
SAVE(b);
|
|
2097
|
-
|
|
2098
|
-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
|
|
2099
|
-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
|
|
2100
|
-
VpSetZero(*dv, 1);
|
|
2101
|
-
*rv = a;
|
|
2102
|
-
return Qnil;
|
|
2103
|
-
}
|
|
2104
|
-
|
|
2105
|
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
|
|
2106
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2107
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2108
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2109
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2110
|
-
|
|
2111
|
-
VpDivd(c, res, a, b);
|
|
2112
|
-
|
|
2113
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
|
2114
|
-
|
|
2115
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
|
2116
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
|
2117
|
-
|
|
2118
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2119
|
-
|
|
2120
|
-
VpFrac(f, c);
|
|
2121
|
-
VpMult(rr, f, b);
|
|
2122
|
-
VpAddSub(ff, res, rr, 1);
|
|
2123
|
-
|
|
2124
|
-
*dv = d;
|
|
2125
|
-
*rv = ff;
|
|
2126
|
-
return Qnil;
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
1824
|
/* call-seq:
|
|
2130
|
-
*
|
|
1825
|
+
* remainder(value)
|
|
2131
1826
|
*
|
|
2132
1827
|
* Returns the remainder from dividing by the value.
|
|
2133
1828
|
*
|
|
@@ -2136,15 +1831,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
|
2136
1831
|
static VALUE
|
|
2137
1832
|
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2138
1833
|
{
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
1834
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
|
1835
|
+
|
|
1836
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
|
1837
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
1838
|
+
}
|
|
1839
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2144
1840
|
}
|
|
2145
1841
|
|
|
2146
1842
|
/* call-seq:
|
|
2147
|
-
*
|
|
1843
|
+
* divmod(value)
|
|
2148
1844
|
*
|
|
2149
1845
|
* Divides by the specified value, and returns the quotient and modulus
|
|
2150
1846
|
* as BigDecimal numbers. The quotient is rounded towards negative infinity.
|
|
@@ -2168,12 +1864,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
|
2168
1864
|
static VALUE
|
|
2169
1865
|
BigDecimal_divmod(VALUE self, VALUE r)
|
|
2170
1866
|
{
|
|
2171
|
-
|
|
2172
|
-
Real *div = NULL, *mod = NULL;
|
|
1867
|
+
NULLABLE_BDVALUE div, mod;
|
|
2173
1868
|
|
|
2174
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2175
|
-
|
|
2176
|
-
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
|
|
1869
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1870
|
+
return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
2177
1871
|
}
|
|
2178
1872
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
2179
1873
|
}
|
|
@@ -2185,47 +1879,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
2185
1879
|
static inline VALUE
|
|
2186
1880
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2187
1881
|
{
|
|
2188
|
-
ENTER(5);
|
|
2189
1882
|
SIGNED_VALUE ix;
|
|
1883
|
+
BDVALUE av, bv, cv, res;
|
|
2190
1884
|
|
|
2191
1885
|
if (NIL_P(n)) { /* div in Float sense */
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
|
2195
|
-
return BigDecimal_to_i(
|
|
1886
|
+
NULLABLE_BDVALUE div;
|
|
1887
|
+
NULLABLE_BDVALUE mod;
|
|
1888
|
+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
|
|
1889
|
+
return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
|
|
2196
1890
|
}
|
|
2197
1891
|
return DoSomeOne(self, b, rb_intern("div"));
|
|
2198
1892
|
}
|
|
2199
1893
|
|
|
2200
1894
|
/* div in BigDecimal sense */
|
|
2201
1895
|
ix = check_int_precision(n);
|
|
1896
|
+
|
|
1897
|
+
av = GetBDValueMust(self);
|
|
1898
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
|
1899
|
+
|
|
2202
1900
|
if (ix == 0) {
|
|
2203
|
-
|
|
1901
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
|
1902
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
|
1903
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
|
1904
|
+
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
|
1905
|
+
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
|
1906
|
+
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1907
|
+
if (limit && limit < ix) ix = limit;
|
|
2204
1908
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2220
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
|
|
2221
|
-
mx = av->Prec + bv->Prec + 2;
|
|
2222
|
-
if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
|
|
2223
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
|
|
2224
|
-
VpDivd(cv, res, av, bv);
|
|
2225
|
-
VpSetPrecLimit(pl);
|
|
2226
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
|
2227
|
-
return VpCheckGetValue(cv);
|
|
1909
|
+
|
|
1910
|
+
// Needs to calculate 1 extra digit for rounding.
|
|
1911
|
+
cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
|
|
1912
|
+
res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
|
|
1913
|
+
VpDivd(cv.real, res.real, av.real, bv.real);
|
|
1914
|
+
|
|
1915
|
+
if (!VpIsZero(res.real)) {
|
|
1916
|
+
// Remainder value affects rounding result.
|
|
1917
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
|
1918
|
+
// 0.1e0 if remainder == 0
|
|
1919
|
+
// 0.1000000001e0 if remainder != 0
|
|
1920
|
+
size_t idx = roomof(ix, BASE_FIG);
|
|
1921
|
+
while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
|
|
1922
|
+
if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
|
|
2228
1923
|
}
|
|
1924
|
+
VpLeftRound(cv.real, VpGetRoundMode(), ix);
|
|
1925
|
+
|
|
1926
|
+
RB_GC_GUARD(av.bigdecimal);
|
|
1927
|
+
RB_GC_GUARD(bv.bigdecimal);
|
|
1928
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1929
|
+
return CheckGetValue(cv);
|
|
2229
1930
|
}
|
|
2230
1931
|
|
|
2231
1932
|
/*
|
|
@@ -2301,22 +2002,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
|
2301
2002
|
static VALUE
|
|
2302
2003
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2303
2004
|
{
|
|
2304
|
-
|
|
2305
|
-
Real *cv;
|
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2307
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
|
2308
|
-
else {
|
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2310
|
-
VALUE c = BigDecimal_add(self, b);
|
|
2311
|
-
VpSetPrecLimit(pl);
|
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2314
|
-
return VpCheckGetValue(cv);
|
|
2315
|
-
}
|
|
2005
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
|
2316
2006
|
}
|
|
2317
2007
|
|
|
2318
2008
|
/* call-seq:
|
|
2319
|
-
*
|
|
2009
|
+
* sub(value, digits) -> bigdecimal
|
|
2320
2010
|
*
|
|
2321
2011
|
* Subtract the specified value.
|
|
2322
2012
|
*
|
|
@@ -2331,18 +2021,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
|
2331
2021
|
static VALUE
|
|
2332
2022
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2333
2023
|
{
|
|
2334
|
-
|
|
2335
|
-
Real *cv;
|
|
2336
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2337
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
|
2338
|
-
else {
|
|
2339
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2340
|
-
VALUE c = BigDecimal_sub(self, b);
|
|
2341
|
-
VpSetPrecLimit(pl);
|
|
2342
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2343
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2344
|
-
return VpCheckGetValue(cv);
|
|
2345
|
-
}
|
|
2024
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
|
2346
2025
|
}
|
|
2347
2026
|
|
|
2348
2027
|
/*
|
|
@@ -2374,18 +2053,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
|
2374
2053
|
static VALUE
|
|
2375
2054
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2376
2055
|
{
|
|
2377
|
-
|
|
2378
|
-
Real *cv;
|
|
2379
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2380
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
|
2381
|
-
else {
|
|
2382
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2383
|
-
VALUE c = BigDecimal_mult(self, b);
|
|
2384
|
-
VpSetPrecLimit(pl);
|
|
2385
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2386
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2387
|
-
return VpCheckGetValue(cv);
|
|
2388
|
-
}
|
|
2056
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
|
2389
2057
|
}
|
|
2390
2058
|
|
|
2391
2059
|
/*
|
|
@@ -2402,41 +2070,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
|
2402
2070
|
static VALUE
|
|
2403
2071
|
BigDecimal_abs(VALUE self)
|
|
2404
2072
|
{
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2412
|
-
VpAsgn(c, a, 1);
|
|
2413
|
-
VpChangeSign(c, 1);
|
|
2414
|
-
return VpCheckGetValue(c);
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
/* call-seq:
|
|
2418
|
-
* sqrt(n)
|
|
2419
|
-
*
|
|
2420
|
-
* Returns the square root of the value.
|
|
2421
|
-
*
|
|
2422
|
-
* Result has at least n significant digits.
|
|
2423
|
-
*/
|
|
2424
|
-
static VALUE
|
|
2425
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2426
|
-
{
|
|
2427
|
-
ENTER(5);
|
|
2428
|
-
Real *c, *a;
|
|
2429
|
-
size_t mx, n;
|
|
2430
|
-
|
|
2431
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2432
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2433
|
-
|
|
2434
|
-
n = check_int_precision(nFig);
|
|
2435
|
-
n += VpDblFig() + VpBaseFig();
|
|
2436
|
-
if (mx <= n) mx = n;
|
|
2437
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2438
|
-
VpSqrt(c, a);
|
|
2439
|
-
return VpCheckGetValue(c);
|
|
2073
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2074
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
2075
|
+
VpAsgn(c.real, a.real, 10);
|
|
2076
|
+
VpChangeSign(c.real, 1);
|
|
2077
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2078
|
+
return CheckGetValue(c);
|
|
2440
2079
|
}
|
|
2441
2080
|
|
|
2442
2081
|
/* Return the integer part of the number, as a BigDecimal.
|
|
@@ -2444,22 +2083,18 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
|
2444
2083
|
static VALUE
|
|
2445
2084
|
BigDecimal_fix(VALUE self)
|
|
2446
2085
|
{
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
|
2453
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2454
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2455
|
-
return VpCheckGetValue(c);
|
|
2086
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2087
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2088
|
+
VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2089
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2090
|
+
return CheckGetValue(c);
|
|
2456
2091
|
}
|
|
2457
2092
|
|
|
2458
2093
|
/* call-seq:
|
|
2459
|
-
*
|
|
2094
|
+
* round(n, mode)
|
|
2460
2095
|
*
|
|
2461
2096
|
* Round to the nearest integer (by default), returning the result as a
|
|
2462
|
-
* BigDecimal if n is specified, or as an Integer if it isn't.
|
|
2097
|
+
* BigDecimal if n is specified and positive, or as an Integer if it isn't.
|
|
2463
2098
|
*
|
|
2464
2099
|
* BigDecimal('3.14159').round #=> 3
|
|
2465
2100
|
* BigDecimal('8.7').round #=> 9
|
|
@@ -2467,6 +2102,7 @@ BigDecimal_fix(VALUE self)
|
|
|
2467
2102
|
*
|
|
2468
2103
|
* BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
|
|
2469
2104
|
* BigDecimal('3.14159').round.class.name #=> "Integer"
|
|
2105
|
+
* BigDecimal('3.14159').round(0).class.name #=> "Integer"
|
|
2470
2106
|
*
|
|
2471
2107
|
* If n is specified and positive, the fractional part of the result has no
|
|
2472
2108
|
* more than that many digits.
|
|
@@ -2483,13 +2119,12 @@ BigDecimal_fix(VALUE self)
|
|
|
2483
2119
|
static VALUE
|
|
2484
2120
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2485
2121
|
{
|
|
2486
|
-
|
|
2487
|
-
Real *c, *a;
|
|
2122
|
+
BDVALUE c, a;
|
|
2488
2123
|
int iLoc = 0;
|
|
2489
2124
|
VALUE vLoc;
|
|
2490
2125
|
VALUE vRound;
|
|
2491
2126
|
int round_to_int = 0;
|
|
2492
|
-
size_t mx
|
|
2127
|
+
size_t mx;
|
|
2493
2128
|
|
|
2494
2129
|
unsigned short sw = VpGetRoundMode();
|
|
2495
2130
|
|
|
@@ -2520,20 +2155,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2520
2155
|
break;
|
|
2521
2156
|
}
|
|
2522
2157
|
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2158
|
+
a = GetBDValueMust(self);
|
|
2159
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2160
|
+
c = NewZeroWrap(1, mx);
|
|
2161
|
+
|
|
2162
|
+
VpActiveRound(c.real, a.real, sw, iLoc);
|
|
2163
|
+
|
|
2164
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2165
|
+
|
|
2529
2166
|
if (round_to_int) {
|
|
2530
|
-
return BigDecimal_to_i(
|
|
2167
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2168
|
+
}
|
|
2169
|
+
return CheckGetValue(c);
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
static VALUE
|
|
2173
|
+
BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
|
|
2174
|
+
{
|
|
2175
|
+
BDVALUE c, a;
|
|
2176
|
+
int iLoc;
|
|
2177
|
+
VALUE vLoc;
|
|
2178
|
+
size_t mx;
|
|
2179
|
+
|
|
2180
|
+
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2181
|
+
iLoc = 0;
|
|
2531
2182
|
}
|
|
2532
|
-
|
|
2183
|
+
else {
|
|
2184
|
+
iLoc = NUM2INT(vLoc);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
a = GetBDValueMust(self);
|
|
2188
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2189
|
+
c = NewZeroWrap(1, mx);
|
|
2190
|
+
VpActiveRound(c.real, a.real, rounding_mode, iLoc);
|
|
2191
|
+
|
|
2192
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2193
|
+
|
|
2194
|
+
if (argc == 0) {
|
|
2195
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2196
|
+
}
|
|
2197
|
+
return CheckGetValue(c);
|
|
2533
2198
|
}
|
|
2534
2199
|
|
|
2535
2200
|
/* call-seq:
|
|
2536
|
-
*
|
|
2201
|
+
* truncate(n)
|
|
2537
2202
|
*
|
|
2538
2203
|
* Truncate to the nearest integer (by default), returning the result as a
|
|
2539
2204
|
* BigDecimal.
|
|
@@ -2554,28 +2219,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2554
2219
|
static VALUE
|
|
2555
2220
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2556
2221
|
{
|
|
2557
|
-
|
|
2558
|
-
Real *c, *a;
|
|
2559
|
-
int iLoc;
|
|
2560
|
-
VALUE vLoc;
|
|
2561
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2562
|
-
|
|
2563
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2564
|
-
iLoc = 0;
|
|
2565
|
-
}
|
|
2566
|
-
else {
|
|
2567
|
-
iLoc = NUM2INT(vLoc);
|
|
2568
|
-
}
|
|
2569
|
-
|
|
2570
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2571
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2572
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2573
|
-
VpSetPrecLimit(pl);
|
|
2574
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
|
2575
|
-
if (argc == 0) {
|
|
2576
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2577
|
-
}
|
|
2578
|
-
return VpCheckGetValue(c);
|
|
2222
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
|
2579
2223
|
}
|
|
2580
2224
|
|
|
2581
2225
|
/* Return the fractional part of the number, as a BigDecimal.
|
|
@@ -2583,19 +2227,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
|
2583
2227
|
static VALUE
|
|
2584
2228
|
BigDecimal_frac(VALUE self)
|
|
2585
2229
|
{
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2592
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2593
|
-
VpFrac(c, a);
|
|
2594
|
-
return VpCheckGetValue(c);
|
|
2230
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2231
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2232
|
+
VpFrac(c.real, a.real);
|
|
2233
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2234
|
+
return CheckGetValue(c);
|
|
2595
2235
|
}
|
|
2596
2236
|
|
|
2597
2237
|
/* call-seq:
|
|
2598
|
-
*
|
|
2238
|
+
* floor(n)
|
|
2599
2239
|
*
|
|
2600
2240
|
* Return the largest integer less than or equal to the value, as a BigDecimal.
|
|
2601
2241
|
*
|
|
@@ -2614,35 +2254,11 @@ BigDecimal_frac(VALUE self)
|
|
|
2614
2254
|
static VALUE
|
|
2615
2255
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2616
2256
|
{
|
|
2617
|
-
|
|
2618
|
-
Real *c, *a;
|
|
2619
|
-
int iLoc;
|
|
2620
|
-
VALUE vLoc;
|
|
2621
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2622
|
-
|
|
2623
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
|
2624
|
-
iLoc = 0;
|
|
2625
|
-
}
|
|
2626
|
-
else {
|
|
2627
|
-
iLoc = NUM2INT(vLoc);
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2631
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2632
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2633
|
-
VpSetPrecLimit(pl);
|
|
2634
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
|
2635
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
2636
|
-
VPrint(stderr, "floor: c=%\n", c);
|
|
2637
|
-
#endif
|
|
2638
|
-
if (argc == 0) {
|
|
2639
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2640
|
-
}
|
|
2641
|
-
return VpCheckGetValue(c);
|
|
2257
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
|
2642
2258
|
}
|
|
2643
2259
|
|
|
2644
2260
|
/* call-seq:
|
|
2645
|
-
*
|
|
2261
|
+
* ceil(n)
|
|
2646
2262
|
*
|
|
2647
2263
|
* Return the smallest integer greater than or equal to the value, as a BigDecimal.
|
|
2648
2264
|
*
|
|
@@ -2661,31 +2277,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
|
2661
2277
|
static VALUE
|
|
2662
2278
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2663
2279
|
{
|
|
2664
|
-
|
|
2665
|
-
Real *c, *a;
|
|
2666
|
-
int iLoc;
|
|
2667
|
-
VALUE vLoc;
|
|
2668
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2669
|
-
|
|
2670
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2671
|
-
iLoc = 0;
|
|
2672
|
-
} else {
|
|
2673
|
-
iLoc = NUM2INT(vLoc);
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2677
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2678
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2679
|
-
VpSetPrecLimit(pl);
|
|
2680
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
|
2681
|
-
if (argc == 0) {
|
|
2682
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2683
|
-
}
|
|
2684
|
-
return VpCheckGetValue(c);
|
|
2280
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
|
2685
2281
|
}
|
|
2686
2282
|
|
|
2687
2283
|
/* call-seq:
|
|
2688
|
-
*
|
|
2284
|
+
* to_s(s)
|
|
2689
2285
|
*
|
|
2690
2286
|
* Converts the value to a string.
|
|
2691
2287
|
*
|
|
@@ -2702,7 +2298,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2702
2298
|
* If s contains a number, a space is inserted after each group of that many
|
|
2703
2299
|
* digits, starting from '.' and counting outwards.
|
|
2704
2300
|
*
|
|
2705
|
-
* If s ends with an 'E',
|
|
2301
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
|
2706
2302
|
*
|
|
2707
2303
|
* If s ends with an 'F', conventional floating point notation is used.
|
|
2708
2304
|
*
|
|
@@ -2720,10 +2316,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2720
2316
|
static VALUE
|
|
2721
2317
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2722
2318
|
{
|
|
2723
|
-
ENTER(5);
|
|
2724
2319
|
int fmt = 0; /* 0: E format, 1: F format */
|
|
2725
2320
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
2726
|
-
|
|
2321
|
+
BDVALUE v;
|
|
2727
2322
|
volatile VALUE str;
|
|
2728
2323
|
char *psz;
|
|
2729
2324
|
char ch;
|
|
@@ -2731,7 +2326,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2731
2326
|
SIGNED_VALUE m;
|
|
2732
2327
|
VALUE f;
|
|
2733
2328
|
|
|
2734
|
-
|
|
2329
|
+
v = GetBDValueMust(self);
|
|
2735
2330
|
|
|
2736
2331
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
|
2737
2332
|
if (RB_TYPE_P(f, T_STRING)) {
|
|
@@ -2766,10 +2361,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2766
2361
|
}
|
|
2767
2362
|
}
|
|
2768
2363
|
if (fmt) {
|
|
2769
|
-
nc = VpNumOfChars(
|
|
2364
|
+
nc = VpNumOfChars(v.real, "F");
|
|
2770
2365
|
}
|
|
2771
2366
|
else {
|
|
2772
|
-
nc = VpNumOfChars(
|
|
2367
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2773
2368
|
}
|
|
2774
2369
|
if (mc > 0) {
|
|
2775
2370
|
nc += (nc + mc - 1) / mc + 1;
|
|
@@ -2779,12 +2374,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2779
2374
|
psz = RSTRING_PTR(str);
|
|
2780
2375
|
|
|
2781
2376
|
if (fmt) {
|
|
2782
|
-
VpToFString(
|
|
2377
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2783
2378
|
}
|
|
2784
2379
|
else {
|
|
2785
|
-
VpToString (
|
|
2380
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2786
2381
|
}
|
|
2787
2382
|
rb_str_resize(str, strlen(psz));
|
|
2383
|
+
|
|
2384
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2788
2385
|
return str;
|
|
2789
2386
|
}
|
|
2790
2387
|
|
|
@@ -2815,16 +2412,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2815
2412
|
static VALUE
|
|
2816
2413
|
BigDecimal_split(VALUE self)
|
|
2817
2414
|
{
|
|
2818
|
-
|
|
2819
|
-
Real *vp;
|
|
2415
|
+
BDVALUE v;
|
|
2820
2416
|
VALUE obj,str;
|
|
2821
2417
|
ssize_t e, s;
|
|
2822
2418
|
char *psz1;
|
|
2823
2419
|
|
|
2824
|
-
|
|
2825
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
2420
|
+
v = GetBDValueMust(self);
|
|
2421
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
2826
2422
|
psz1 = RSTRING_PTR(str);
|
|
2827
|
-
VpSzMantissa(
|
|
2423
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
|
2828
2424
|
s = 1;
|
|
2829
2425
|
if(psz1[0] == '-') {
|
|
2830
2426
|
size_t len = strlen(psz1 + 1);
|
|
@@ -2834,13 +2430,15 @@ BigDecimal_split(VALUE self)
|
|
|
2834
2430
|
s = -1;
|
|
2835
2431
|
}
|
|
2836
2432
|
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2837
|
-
e = VpExponent10(
|
|
2433
|
+
e = VpExponent10(v.real);
|
|
2838
2434
|
obj = rb_ary_new2(4);
|
|
2839
2435
|
rb_ary_push(obj, INT2FIX(s));
|
|
2840
2436
|
rb_ary_push(obj, str);
|
|
2841
2437
|
rb_str_resize(str, strlen(psz1));
|
|
2842
2438
|
rb_ary_push(obj, INT2FIX(10));
|
|
2843
2439
|
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2440
|
+
|
|
2441
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2844
2442
|
return obj;
|
|
2845
2443
|
}
|
|
2846
2444
|
|
|
@@ -2852,7 +2450,7 @@ BigDecimal_split(VALUE self)
|
|
|
2852
2450
|
static VALUE
|
|
2853
2451
|
BigDecimal_exponent(VALUE self)
|
|
2854
2452
|
{
|
|
2855
|
-
ssize_t e = VpExponent10(
|
|
2453
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
|
2856
2454
|
return SSIZET2NUM(e);
|
|
2857
2455
|
}
|
|
2858
2456
|
|
|
@@ -2864,49 +2462,78 @@ BigDecimal_exponent(VALUE self)
|
|
|
2864
2462
|
static VALUE
|
|
2865
2463
|
BigDecimal_inspect(VALUE self)
|
|
2866
2464
|
{
|
|
2867
|
-
|
|
2868
|
-
Real *vp;
|
|
2465
|
+
BDVALUE v;
|
|
2869
2466
|
volatile VALUE str;
|
|
2870
2467
|
size_t nc;
|
|
2871
2468
|
|
|
2872
|
-
|
|
2873
|
-
nc = VpNumOfChars(
|
|
2469
|
+
v = GetBDValueMust(self);
|
|
2470
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2874
2471
|
|
|
2875
2472
|
str = rb_str_new(0, nc);
|
|
2876
|
-
VpToString(
|
|
2473
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2877
2474
|
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
|
2878
|
-
return str;
|
|
2879
|
-
}
|
|
2880
|
-
|
|
2881
|
-
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
|
2882
|
-
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
|
2883
2475
|
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
inline static int
|
|
2888
|
-
is_integer(VALUE x)
|
|
2889
|
-
{
|
|
2890
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
|
2476
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2477
|
+
return str;
|
|
2891
2478
|
}
|
|
2892
2479
|
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2480
|
+
/* Returns self * 10**v without changing the precision.
|
|
2481
|
+
* This method is currently for internal use.
|
|
2482
|
+
*
|
|
2483
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
|
2484
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
|
2485
|
+
*/
|
|
2486
|
+
static VALUE
|
|
2487
|
+
BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
2488
|
+
{
|
|
2489
|
+
BDVALUE a, c;
|
|
2490
|
+
ssize_t shift, exponentShift;
|
|
2491
|
+
bool shiftDown;
|
|
2492
|
+
size_t prec;
|
|
2493
|
+
DECDIG ex, iex;
|
|
2494
|
+
|
|
2495
|
+
a = GetBDValueMust(self);
|
|
2496
|
+
shift = NUM2SSIZET(rb_to_int(v));
|
|
2497
|
+
|
|
2498
|
+
if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
|
|
2499
|
+
|
|
2500
|
+
exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
|
|
2501
|
+
shift -= exponentShift * BASE_FIG;
|
|
2502
|
+
ex = 1;
|
|
2503
|
+
for (int i = 0; i < shift; i++) ex *= 10;
|
|
2504
|
+
shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
|
|
2505
|
+
iex = BASE / ex;
|
|
2506
|
+
|
|
2507
|
+
prec = a.real->Prec + shiftDown;
|
|
2508
|
+
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2509
|
+
if (shift == 0) {
|
|
2510
|
+
VpAsgn(c.real, a.real, 1);
|
|
2511
|
+
} else if (shiftDown) {
|
|
2512
|
+
DECDIG carry = 0;
|
|
2513
|
+
exponentShift++;
|
|
2514
|
+
for (size_t i = 0; i < a.real->Prec; i++) {
|
|
2515
|
+
DECDIG v = a.real->frac[i];
|
|
2516
|
+
c.real->frac[i] = carry * ex + v / iex;
|
|
2517
|
+
carry = v % iex;
|
|
2518
|
+
}
|
|
2519
|
+
c.real->frac[a.real->Prec] = carry * ex;
|
|
2520
|
+
} else {
|
|
2521
|
+
DECDIG carry = 0;
|
|
2522
|
+
for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
|
|
2523
|
+
DECDIG v = a.real->frac[i];
|
|
2524
|
+
c.real->frac[i] = v % iex * ex + carry;
|
|
2525
|
+
carry = v / iex;
|
|
2526
|
+
}
|
|
2904
2527
|
}
|
|
2905
|
-
|
|
2528
|
+
while (c.real->frac[prec - 1] == 0) prec--;
|
|
2529
|
+
c.real->Prec = prec;
|
|
2530
|
+
c.real->sign = a.real->sign;
|
|
2531
|
+
c.real->exponent = a.real->exponent;
|
|
2532
|
+
AddExponent(c.real, exponentShift);
|
|
2533
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2534
|
+
return CheckGetValue(c);
|
|
2906
2535
|
}
|
|
2907
2536
|
|
|
2908
|
-
#define is_positive(x) (!is_negative(x))
|
|
2909
|
-
|
|
2910
2537
|
inline static int
|
|
2911
2538
|
is_zero(VALUE x)
|
|
2912
2539
|
{
|
|
@@ -2930,344 +2557,6 @@ is_zero(VALUE x)
|
|
|
2930
2557
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
2931
2558
|
}
|
|
2932
2559
|
|
|
2933
|
-
inline static int
|
|
2934
|
-
is_one(VALUE x)
|
|
2935
|
-
{
|
|
2936
|
-
VALUE num, den;
|
|
2937
|
-
|
|
2938
|
-
switch (TYPE(x)) {
|
|
2939
|
-
case T_FIXNUM:
|
|
2940
|
-
return FIX2LONG(x) == 1;
|
|
2941
|
-
|
|
2942
|
-
case T_BIGNUM:
|
|
2943
|
-
return Qfalse;
|
|
2944
|
-
|
|
2945
|
-
case T_RATIONAL:
|
|
2946
|
-
num = rb_rational_num(x);
|
|
2947
|
-
den = rb_rational_den(x);
|
|
2948
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
|
2949
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
|
2950
|
-
|
|
2951
|
-
default:
|
|
2952
|
-
break;
|
|
2953
|
-
}
|
|
2954
|
-
|
|
2955
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
|
2956
|
-
}
|
|
2957
|
-
|
|
2958
|
-
inline static int
|
|
2959
|
-
is_even(VALUE x)
|
|
2960
|
-
{
|
|
2961
|
-
switch (TYPE(x)) {
|
|
2962
|
-
case T_FIXNUM:
|
|
2963
|
-
return (FIX2LONG(x) % 2) == 0;
|
|
2964
|
-
|
|
2965
|
-
case T_BIGNUM:
|
|
2966
|
-
{
|
|
2967
|
-
unsigned long l;
|
|
2968
|
-
rb_big_pack(x, &l, 1);
|
|
2969
|
-
return l % 2 == 0;
|
|
2970
|
-
}
|
|
2971
|
-
|
|
2972
|
-
default:
|
|
2973
|
-
break;
|
|
2974
|
-
}
|
|
2975
|
-
|
|
2976
|
-
return 0;
|
|
2977
|
-
}
|
|
2978
|
-
|
|
2979
|
-
static VALUE
|
|
2980
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
|
2981
|
-
{
|
|
2982
|
-
VALUE log_x, multiplied, y;
|
|
2983
|
-
volatile VALUE obj = exp->obj;
|
|
2984
|
-
|
|
2985
|
-
if (VpIsZero(exp)) {
|
|
2986
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
2987
|
-
}
|
|
2988
|
-
|
|
2989
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
|
2990
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
|
2991
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
|
2992
|
-
RB_GC_GUARD(obj);
|
|
2993
|
-
|
|
2994
|
-
return y;
|
|
2995
|
-
}
|
|
2996
|
-
|
|
2997
|
-
/* call-seq:
|
|
2998
|
-
* power(n)
|
|
2999
|
-
* power(n, prec)
|
|
3000
|
-
*
|
|
3001
|
-
* Returns the value raised to the power of n.
|
|
3002
|
-
*
|
|
3003
|
-
* Note that n must be an Integer.
|
|
3004
|
-
*
|
|
3005
|
-
* Also available as the operator **.
|
|
3006
|
-
*/
|
|
3007
|
-
static VALUE
|
|
3008
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
|
3009
|
-
{
|
|
3010
|
-
ENTER(5);
|
|
3011
|
-
VALUE vexp, prec;
|
|
3012
|
-
Real* exp = NULL;
|
|
3013
|
-
Real *x, *y;
|
|
3014
|
-
ssize_t mp, ma, n;
|
|
3015
|
-
SIGNED_VALUE int_exp;
|
|
3016
|
-
double d;
|
|
3017
|
-
|
|
3018
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
|
3019
|
-
|
|
3020
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
|
3021
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
|
3022
|
-
|
|
3023
|
-
if (VpIsNaN(x)) {
|
|
3024
|
-
y = NewZeroWrapLimited(1, n);
|
|
3025
|
-
VpSetNaN(y);
|
|
3026
|
-
RB_GC_GUARD(y->obj);
|
|
3027
|
-
return VpCheckGetValue(y);
|
|
3028
|
-
}
|
|
3029
|
-
|
|
3030
|
-
retry:
|
|
3031
|
-
switch (TYPE(vexp)) {
|
|
3032
|
-
case T_FIXNUM:
|
|
3033
|
-
break;
|
|
3034
|
-
|
|
3035
|
-
case T_BIGNUM:
|
|
3036
|
-
break;
|
|
3037
|
-
|
|
3038
|
-
case T_FLOAT:
|
|
3039
|
-
d = RFLOAT_VALUE(vexp);
|
|
3040
|
-
if (d == round(d)) {
|
|
3041
|
-
if (FIXABLE(d)) {
|
|
3042
|
-
vexp = LONG2FIX((long)d);
|
|
3043
|
-
}
|
|
3044
|
-
else {
|
|
3045
|
-
vexp = rb_dbl2big(d);
|
|
3046
|
-
}
|
|
3047
|
-
goto retry;
|
|
3048
|
-
}
|
|
3049
|
-
if (NIL_P(prec)) {
|
|
3050
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
|
3051
|
-
}
|
|
3052
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
|
3053
|
-
break;
|
|
3054
|
-
|
|
3055
|
-
case T_RATIONAL:
|
|
3056
|
-
if (is_zero(rb_rational_num(vexp))) {
|
|
3057
|
-
if (is_positive(vexp)) {
|
|
3058
|
-
vexp = INT2FIX(0);
|
|
3059
|
-
goto retry;
|
|
3060
|
-
}
|
|
3061
|
-
}
|
|
3062
|
-
else if (is_one(rb_rational_den(vexp))) {
|
|
3063
|
-
vexp = rb_rational_num(vexp);
|
|
3064
|
-
goto retry;
|
|
3065
|
-
}
|
|
3066
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
|
3067
|
-
if (NIL_P(prec)) {
|
|
3068
|
-
n += n;
|
|
3069
|
-
}
|
|
3070
|
-
break;
|
|
3071
|
-
|
|
3072
|
-
case T_DATA:
|
|
3073
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
|
3074
|
-
VALUE zero = INT2FIX(0);
|
|
3075
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
|
3076
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
|
3077
|
-
vexp = BigDecimal_to_i(vexp);
|
|
3078
|
-
goto retry;
|
|
3079
|
-
}
|
|
3080
|
-
if (NIL_P(prec)) {
|
|
3081
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
|
3082
|
-
n += y->Prec*VpBaseFig();
|
|
3083
|
-
}
|
|
3084
|
-
exp = DATA_PTR(vexp);
|
|
3085
|
-
break;
|
|
3086
|
-
}
|
|
3087
|
-
/* fall through */
|
|
3088
|
-
default:
|
|
3089
|
-
rb_raise(rb_eTypeError,
|
|
3090
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
|
3091
|
-
RB_OBJ_CLASSNAME(vexp));
|
|
3092
|
-
}
|
|
3093
|
-
|
|
3094
|
-
if (VpIsZero(x)) {
|
|
3095
|
-
if (is_negative(vexp)) {
|
|
3096
|
-
y = NewZeroWrapNolimit(1, n);
|
|
3097
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3098
|
-
if (is_integer(vexp)) {
|
|
3099
|
-
if (is_even(vexp)) {
|
|
3100
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
|
3101
|
-
VpSetPosInf(y);
|
|
3102
|
-
}
|
|
3103
|
-
else {
|
|
3104
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
|
3105
|
-
VpSetNegInf(y);
|
|
3106
|
-
}
|
|
3107
|
-
}
|
|
3108
|
-
else {
|
|
3109
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
|
3110
|
-
VpSetPosInf(y);
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
3113
|
-
else {
|
|
3114
|
-
/* (+0) ** (-num) -> Infinity */
|
|
3115
|
-
VpSetPosInf(y);
|
|
3116
|
-
}
|
|
3117
|
-
RB_GC_GUARD(y->obj);
|
|
3118
|
-
return VpCheckGetValue(y);
|
|
3119
|
-
}
|
|
3120
|
-
else if (is_zero(vexp)) {
|
|
3121
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3122
|
-
}
|
|
3123
|
-
else {
|
|
3124
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3125
|
-
}
|
|
3126
|
-
}
|
|
3127
|
-
|
|
3128
|
-
if (is_zero(vexp)) {
|
|
3129
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3130
|
-
}
|
|
3131
|
-
else if (is_one(vexp)) {
|
|
3132
|
-
return self;
|
|
3133
|
-
}
|
|
3134
|
-
|
|
3135
|
-
if (VpIsInf(x)) {
|
|
3136
|
-
if (is_negative(vexp)) {
|
|
3137
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3138
|
-
if (is_integer(vexp)) {
|
|
3139
|
-
if (is_even(vexp)) {
|
|
3140
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
|
3141
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3142
|
-
}
|
|
3143
|
-
else {
|
|
3144
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
|
3145
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3146
|
-
}
|
|
3147
|
-
}
|
|
3148
|
-
else {
|
|
3149
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
|
3150
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3151
|
-
}
|
|
3152
|
-
}
|
|
3153
|
-
else {
|
|
3154
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3155
|
-
}
|
|
3156
|
-
}
|
|
3157
|
-
else {
|
|
3158
|
-
y = NewZeroWrapLimited(1, n);
|
|
3159
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3160
|
-
if (is_integer(vexp)) {
|
|
3161
|
-
if (is_even(vexp)) {
|
|
3162
|
-
VpSetPosInf(y);
|
|
3163
|
-
}
|
|
3164
|
-
else {
|
|
3165
|
-
VpSetNegInf(y);
|
|
3166
|
-
}
|
|
3167
|
-
}
|
|
3168
|
-
else {
|
|
3169
|
-
/* TODO: support complex */
|
|
3170
|
-
rb_raise(rb_eMathDomainError,
|
|
3171
|
-
"a non-integral exponent for a negative base");
|
|
3172
|
-
}
|
|
3173
|
-
}
|
|
3174
|
-
else {
|
|
3175
|
-
VpSetPosInf(y);
|
|
3176
|
-
}
|
|
3177
|
-
return VpCheckGetValue(y);
|
|
3178
|
-
}
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
if (exp != NULL) {
|
|
3182
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
|
3183
|
-
}
|
|
3184
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
|
3185
|
-
VALUE abs_value = BigDecimal_abs(self);
|
|
3186
|
-
if (is_one(abs_value)) {
|
|
3187
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3188
|
-
}
|
|
3189
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
|
3190
|
-
if (is_negative(vexp)) {
|
|
3191
|
-
y = NewZeroWrapLimited(1, n);
|
|
3192
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3193
|
-
return VpCheckGetValue(y);
|
|
3194
|
-
}
|
|
3195
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3196
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3197
|
-
}
|
|
3198
|
-
else {
|
|
3199
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
else {
|
|
3203
|
-
if (is_positive(vexp)) {
|
|
3204
|
-
y = NewZeroWrapLimited(1, n);
|
|
3205
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3206
|
-
return VpCheckGetValue(y);
|
|
3207
|
-
}
|
|
3208
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3209
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3210
|
-
}
|
|
3211
|
-
else {
|
|
3212
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3213
|
-
}
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
3216
|
-
|
|
3217
|
-
int_exp = FIX2LONG(vexp);
|
|
3218
|
-
ma = int_exp;
|
|
3219
|
-
if (ma < 0) ma = -ma;
|
|
3220
|
-
if (ma == 0) ma = 1;
|
|
3221
|
-
|
|
3222
|
-
if (VpIsDef(x)) {
|
|
3223
|
-
mp = x->Prec * (VpBaseFig() + 1);
|
|
3224
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
|
3225
|
-
}
|
|
3226
|
-
else {
|
|
3227
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
|
3228
|
-
}
|
|
3229
|
-
VpPowerByInt(y, x, int_exp);
|
|
3230
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
|
3231
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
|
3232
|
-
}
|
|
3233
|
-
return VpCheckGetValue(y);
|
|
3234
|
-
}
|
|
3235
|
-
|
|
3236
|
-
/* call-seq:
|
|
3237
|
-
* self ** other -> bigdecimal
|
|
3238
|
-
*
|
|
3239
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
|
3240
|
-
*
|
|
3241
|
-
* b = BigDecimal('3.14')
|
|
3242
|
-
* b ** 2 # => 0.98596e1
|
|
3243
|
-
* b ** 2.0 # => 0.98596e1
|
|
3244
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
|
3245
|
-
*
|
|
3246
|
-
* Related: BigDecimal#power.
|
|
3247
|
-
*
|
|
3248
|
-
*/
|
|
3249
|
-
static VALUE
|
|
3250
|
-
BigDecimal_power_op(VALUE self, VALUE exp)
|
|
3251
|
-
{
|
|
3252
|
-
return BigDecimal_power(1, &exp, self);
|
|
3253
|
-
}
|
|
3254
|
-
|
|
3255
|
-
/* :nodoc:
|
|
3256
|
-
*
|
|
3257
|
-
* private method for dup and clone the provided BigDecimal +other+
|
|
3258
|
-
*/
|
|
3259
|
-
static VALUE
|
|
3260
|
-
BigDecimal_initialize_copy(VALUE self, VALUE other)
|
|
3261
|
-
{
|
|
3262
|
-
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
|
|
3263
|
-
Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
|
|
3264
|
-
|
|
3265
|
-
if (self != other) {
|
|
3266
|
-
DATA_PTR(self) = VpCopy(pv, x);
|
|
3267
|
-
}
|
|
3268
|
-
return self;
|
|
3269
|
-
}
|
|
3270
|
-
|
|
3271
2560
|
/* :nodoc: */
|
|
3272
2561
|
static VALUE
|
|
3273
2562
|
BigDecimal_clone(VALUE self)
|
|
@@ -3306,20 +2595,18 @@ check_exception(VALUE bd)
|
|
|
3306
2595
|
|
|
3307
2596
|
Real *vp;
|
|
3308
2597
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3309
|
-
|
|
2598
|
+
VpCheckException(vp, false);
|
|
3310
2599
|
|
|
3311
2600
|
return bd;
|
|
3312
2601
|
}
|
|
3313
2602
|
|
|
3314
2603
|
static VALUE
|
|
3315
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
|
2604
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
3316
2605
|
{
|
|
3317
|
-
|
|
3318
|
-
|
|
2606
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3319
2607
|
Real *vp;
|
|
3320
2608
|
if (uval == 0) {
|
|
3321
2609
|
vp = rbd_allocate_struct(1);
|
|
3322
|
-
vp->MaxPrec = 1;
|
|
3323
2610
|
vp->Prec = 1;
|
|
3324
2611
|
vp->exponent = 1;
|
|
3325
2612
|
VpSetZero(vp, 1);
|
|
@@ -3327,7 +2614,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3327
2614
|
}
|
|
3328
2615
|
else if (uval < BASE) {
|
|
3329
2616
|
vp = rbd_allocate_struct(1);
|
|
3330
|
-
vp->MaxPrec = 1;
|
|
3331
2617
|
vp->Prec = 1;
|
|
3332
2618
|
vp->exponent = 1;
|
|
3333
2619
|
VpSetSign(vp, 1);
|
|
@@ -3353,21 +2639,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3353
2639
|
|
|
3354
2640
|
const size_t exp = len + ntz;
|
|
3355
2641
|
vp = rbd_allocate_struct(len);
|
|
3356
|
-
vp->MaxPrec = len;
|
|
3357
2642
|
vp->Prec = len;
|
|
3358
2643
|
vp->exponent = exp;
|
|
3359
2644
|
VpSetSign(vp, 1);
|
|
3360
2645
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
3361
2646
|
}
|
|
3362
2647
|
|
|
3363
|
-
return BigDecimal_wrap_struct(
|
|
2648
|
+
return BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3364
2649
|
}
|
|
3365
2650
|
|
|
3366
2651
|
static VALUE
|
|
3367
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
|
2652
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
3368
2653
|
{
|
|
3369
2654
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
3370
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
|
2655
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
3371
2656
|
if (ival < 0) {
|
|
3372
2657
|
Real *vp;
|
|
3373
2658
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
@@ -3377,7 +2662,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
|
|
|
3377
2662
|
}
|
|
3378
2663
|
|
|
3379
2664
|
static VALUE
|
|
3380
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
|
2665
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
|
3381
2666
|
{
|
|
3382
2667
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
|
3383
2668
|
|
|
@@ -3389,40 +2674,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
|
3389
2674
|
}
|
|
3390
2675
|
if (size <= sizeof(long)) {
|
|
3391
2676
|
if (sign < 0) {
|
|
3392
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
|
2677
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
|
3393
2678
|
}
|
|
3394
2679
|
else {
|
|
3395
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
|
2680
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
|
3396
2681
|
}
|
|
3397
2682
|
}
|
|
3398
2683
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
|
3399
2684
|
else if (size <= sizeof(LONG_LONG)) {
|
|
3400
2685
|
if (sign < 0) {
|
|
3401
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
|
2686
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
|
3402
2687
|
}
|
|
3403
2688
|
else {
|
|
3404
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
|
2689
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
|
3405
2690
|
}
|
|
3406
2691
|
}
|
|
3407
2692
|
#endif
|
|
3408
2693
|
else {
|
|
3409
2694
|
VALUE str = rb_big2str(val, 10);
|
|
3410
|
-
|
|
3411
|
-
|
|
2695
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
|
2696
|
+
RSTRING_PTR(str),
|
|
2697
|
+
rb_cBigDecimal,
|
|
2698
|
+
true,
|
|
2699
|
+
true
|
|
2700
|
+
));
|
|
3412
2701
|
RB_GC_GUARD(str);
|
|
3413
|
-
return
|
|
2702
|
+
return CheckGetValue(v);
|
|
3414
2703
|
}
|
|
3415
2704
|
}
|
|
3416
2705
|
|
|
3417
2706
|
static VALUE
|
|
3418
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
|
2707
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
|
3419
2708
|
{
|
|
3420
2709
|
assert(RB_INTEGER_TYPE_P(val));
|
|
3421
2710
|
if (FIXNUM_P(val)) {
|
|
3422
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
|
2711
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
|
3423
2712
|
}
|
|
3424
2713
|
else {
|
|
3425
|
-
return rb_big_convert_to_BigDecimal(val
|
|
2714
|
+
return rb_big_convert_to_BigDecimal(val);
|
|
3426
2715
|
}
|
|
3427
2716
|
}
|
|
3428
2717
|
|
|
@@ -3457,11 +2746,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3457
2746
|
}
|
|
3458
2747
|
|
|
3459
2748
|
if (digs == SIZE_MAX) {
|
|
3460
|
-
|
|
3461
|
-
return Qnil;
|
|
3462
|
-
rb_raise(rb_eArgError,
|
|
3463
|
-
"can't omit precision for a %"PRIsVALUE".",
|
|
3464
|
-
CLASS_OF(val));
|
|
2749
|
+
digs = 0;
|
|
3465
2750
|
}
|
|
3466
2751
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
3467
2752
|
if (!raise_exception)
|
|
@@ -3576,7 +2861,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3576
2861
|
exp = -exp;
|
|
3577
2862
|
}
|
|
3578
2863
|
|
|
3579
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
|
2864
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
3580
2865
|
Real *vp;
|
|
3581
2866
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3582
2867
|
assert(vp->Prec == prec);
|
|
@@ -3599,28 +2884,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3599
2884
|
CLASS_OF(val));
|
|
3600
2885
|
}
|
|
3601
2886
|
|
|
3602
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
|
2887
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
|
3603
2888
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
|
3604
2889
|
return d;
|
|
3605
2890
|
}
|
|
3606
2891
|
|
|
3607
2892
|
static VALUE
|
|
3608
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
2893
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
3609
2894
|
{
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
|
3614
|
-
if (!vp)
|
|
3615
|
-
return Qnil;
|
|
3616
|
-
return VpCheckGetValue(vp);
|
|
2895
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
|
|
2896
|
+
if (v.bigdecimal_or_nil == Qnil) return Qnil;
|
|
2897
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3617
2898
|
}
|
|
3618
2899
|
|
|
3619
2900
|
static inline VALUE
|
|
3620
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
|
2901
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
3621
2902
|
{
|
|
3622
2903
|
const char *c_str = StringValueCStr(val);
|
|
3623
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
|
2904
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
3624
2905
|
}
|
|
3625
2906
|
|
|
3626
2907
|
static VALUE
|
|
@@ -3648,17 +2929,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3648
2929
|
if (digs == SIZE_MAX)
|
|
3649
2930
|
return check_exception(val);
|
|
3650
2931
|
|
|
2932
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3651
2933
|
Real *vp;
|
|
3652
2934
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
|
3653
|
-
|
|
3654
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
|
3655
2935
|
vp = VpCopy(NULL, vp);
|
|
2936
|
+
RB_GC_GUARD(val);
|
|
2937
|
+
|
|
2938
|
+
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3656
2939
|
/* TODO: rounding */
|
|
3657
|
-
|
|
3658
|
-
return VpCheckGetValue(vp);
|
|
2940
|
+
return check_exception(copy);
|
|
3659
2941
|
}
|
|
3660
2942
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
3661
|
-
return rb_inum_convert_to_BigDecimal(val
|
|
2943
|
+
return rb_inum_convert_to_BigDecimal(val);
|
|
3662
2944
|
}
|
|
3663
2945
|
else if (RB_FLOAT_TYPE_P(val)) {
|
|
3664
2946
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
|
@@ -3676,7 +2958,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3676
2958
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
|
3677
2959
|
}
|
|
3678
2960
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
3679
|
-
return rb_str_convert_to_BigDecimal(val,
|
|
2961
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
|
3680
2962
|
}
|
|
3681
2963
|
|
|
3682
2964
|
/* TODO: chheck to_d */
|
|
@@ -3690,7 +2972,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3690
2972
|
}
|
|
3691
2973
|
return Qnil;
|
|
3692
2974
|
}
|
|
3693
|
-
return rb_str_convert_to_BigDecimal(str,
|
|
2975
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
|
3694
2976
|
}
|
|
3695
2977
|
|
|
3696
2978
|
/* call-seq:
|
|
@@ -3711,12 +2993,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3711
2993
|
*
|
|
3712
2994
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
|
3713
2995
|
*
|
|
3714
|
-
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
|
|
2996
|
+
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
|
|
3715
2997
|
* BigDecimal(2) # => 0.2e1
|
|
3716
2998
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
|
3717
2999
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
|
3718
|
-
* #
|
|
3719
|
-
*
|
|
3000
|
+
* BigDecimal(2.0) # => 0.2e1
|
|
3001
|
+
* # Rational value requires ndigits.
|
|
3720
3002
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
|
3721
3003
|
*
|
|
3722
3004
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
|
@@ -3780,15 +3062,16 @@ static VALUE
|
|
|
3780
3062
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3781
3063
|
{
|
|
3782
3064
|
char const *c_str = StringValueCStr(str);
|
|
3783
|
-
|
|
3784
|
-
if (
|
|
3065
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3066
|
+
if (v.bigdecimal_or_nil == Qnil)
|
|
3785
3067
|
return Qnil;
|
|
3786
3068
|
else
|
|
3787
|
-
return
|
|
3069
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3788
3070
|
}
|
|
3789
3071
|
|
|
3790
|
-
/*
|
|
3791
|
-
*
|
|
3072
|
+
/*
|
|
3073
|
+
* call-seq:
|
|
3074
|
+
* BigDecimal.limit(digits)
|
|
3792
3075
|
*
|
|
3793
3076
|
* Limit the number of significant digits in newly created BigDecimal
|
|
3794
3077
|
* numbers to the specified value. Rounding is performed as necessary,
|
|
@@ -3838,7 +3121,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
|
3838
3121
|
static VALUE
|
|
3839
3122
|
BigDecimal_sign(VALUE self)
|
|
3840
3123
|
{ /* sign */
|
|
3841
|
-
int s =
|
|
3124
|
+
int s = GetSelfVpValue(self)->sign;
|
|
3842
3125
|
return INT2FIX(s);
|
|
3843
3126
|
}
|
|
3844
3127
|
|
|
@@ -3911,309 +3194,14 @@ BigDecimal_save_rounding_mode(VALUE self)
|
|
|
3911
3194
|
*
|
|
3912
3195
|
*/
|
|
3913
3196
|
static VALUE
|
|
3914
|
-
BigDecimal_save_limit(VALUE self)
|
|
3915
|
-
{
|
|
3916
|
-
size_t const limit = VpGetPrecLimit();
|
|
3917
|
-
int state;
|
|
3918
|
-
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3919
|
-
VpSetPrecLimit(limit);
|
|
3920
|
-
if (state) rb_jump_tag(state);
|
|
3921
|
-
return ret;
|
|
3922
|
-
}
|
|
3923
|
-
|
|
3924
|
-
/* call-seq:
|
|
3925
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
|
3926
|
-
*
|
|
3927
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
|
3928
|
-
* power of +decimal+, to the specified number of digits of precision.
|
|
3929
|
-
*
|
|
3930
|
-
* If +decimal+ is infinity, returns Infinity.
|
|
3931
|
-
*
|
|
3932
|
-
* If +decimal+ is NaN, returns NaN.
|
|
3933
|
-
*/
|
|
3934
|
-
static VALUE
|
|
3935
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
|
3936
|
-
{
|
|
3937
|
-
ssize_t prec, n, i;
|
|
3938
|
-
Real* vx = NULL;
|
|
3939
|
-
VALUE one, d, y;
|
|
3940
|
-
int negative = 0;
|
|
3941
|
-
int infinite = 0;
|
|
3942
|
-
int nan = 0;
|
|
3943
|
-
double flo;
|
|
3944
|
-
|
|
3945
|
-
prec = NUM2SSIZET(vprec);
|
|
3946
|
-
if (prec <= 0) {
|
|
3947
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
3948
|
-
}
|
|
3949
|
-
|
|
3950
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
3951
|
-
* BigDecimalCmp function. */
|
|
3952
|
-
switch (TYPE(x)) {
|
|
3953
|
-
case T_DATA:
|
|
3954
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
3955
|
-
vx = DATA_PTR(x);
|
|
3956
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
3957
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
3958
|
-
nan = VpIsNaN(vx);
|
|
3959
|
-
break;
|
|
3960
|
-
|
|
3961
|
-
case T_FIXNUM:
|
|
3962
|
-
/* fall through */
|
|
3963
|
-
case T_BIGNUM:
|
|
3964
|
-
vx = GetVpValue(x, 0);
|
|
3965
|
-
break;
|
|
3966
|
-
|
|
3967
|
-
case T_FLOAT:
|
|
3968
|
-
flo = RFLOAT_VALUE(x);
|
|
3969
|
-
negative = flo < 0;
|
|
3970
|
-
infinite = isinf(flo);
|
|
3971
|
-
nan = isnan(flo);
|
|
3972
|
-
if (!infinite && !nan) {
|
|
3973
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
|
3974
|
-
}
|
|
3975
|
-
break;
|
|
3976
|
-
|
|
3977
|
-
case T_RATIONAL:
|
|
3978
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
|
3979
|
-
break;
|
|
3980
|
-
|
|
3981
|
-
default:
|
|
3982
|
-
break;
|
|
3983
|
-
}
|
|
3984
|
-
if (infinite) {
|
|
3985
|
-
if (negative) {
|
|
3986
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
|
3987
|
-
}
|
|
3988
|
-
else {
|
|
3989
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3990
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
3991
|
-
RB_GC_GUARD(vy->obj);
|
|
3992
|
-
return VpCheckGetValue(vy);
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
|
-
else if (nan) {
|
|
3996
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3997
|
-
VpSetNaN(vy);
|
|
3998
|
-
RB_GC_GUARD(vy->obj);
|
|
3999
|
-
return VpCheckGetValue(vy);
|
|
4000
|
-
}
|
|
4001
|
-
else if (vx == NULL) {
|
|
4002
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4003
|
-
}
|
|
4004
|
-
x = vx->obj;
|
|
4005
|
-
|
|
4006
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4007
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4008
|
-
if (negative) {
|
|
4009
|
-
VALUE x_zero = INT2NUM(1);
|
|
4010
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
|
4011
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
|
4012
|
-
vx = DATA_PTR(x);
|
|
4013
|
-
VpSetSign(vx, 1);
|
|
4014
|
-
}
|
|
4015
|
-
|
|
4016
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4017
|
-
y = one;
|
|
4018
|
-
d = y;
|
|
4019
|
-
i = 1;
|
|
4020
|
-
|
|
4021
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4022
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4023
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4024
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4025
|
-
|
|
4026
|
-
rb_thread_check_ints();
|
|
4027
|
-
|
|
4028
|
-
if (m <= 0) {
|
|
4029
|
-
break;
|
|
4030
|
-
}
|
|
4031
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4032
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4033
|
-
}
|
|
4034
|
-
|
|
4035
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
|
4036
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
|
4037
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
|
4038
|
-
++i; /* i <- i + 1 */
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
|
-
if (negative) {
|
|
4042
|
-
return BigDecimal_div2(one, y, vprec);
|
|
4043
|
-
}
|
|
4044
|
-
else {
|
|
4045
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
|
4046
|
-
return BigDecimal_round(1, &vprec, y);
|
|
4047
|
-
}
|
|
4048
|
-
|
|
4049
|
-
RB_GC_GUARD(one);
|
|
4050
|
-
RB_GC_GUARD(x);
|
|
4051
|
-
RB_GC_GUARD(y);
|
|
4052
|
-
RB_GC_GUARD(d);
|
|
4053
|
-
}
|
|
4054
|
-
|
|
4055
|
-
/* call-seq:
|
|
4056
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
|
4057
|
-
*
|
|
4058
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
|
4059
|
-
* digits of precision, +numeric+.
|
|
4060
|
-
*
|
|
4061
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
|
4062
|
-
*
|
|
4063
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
|
4064
|
-
*
|
|
4065
|
-
* If +decimal+ is NaN, returns NaN.
|
|
4066
|
-
*/
|
|
4067
|
-
static VALUE
|
|
4068
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
|
4069
|
-
{
|
|
4070
|
-
ssize_t prec, n, i;
|
|
4071
|
-
SIGNED_VALUE expo;
|
|
4072
|
-
Real* vx = NULL;
|
|
4073
|
-
VALUE vn, one, two, w, x2, y, d;
|
|
4074
|
-
int zero = 0;
|
|
4075
|
-
int negative = 0;
|
|
4076
|
-
int infinite = 0;
|
|
4077
|
-
int nan = 0;
|
|
4078
|
-
double flo;
|
|
4079
|
-
long fix;
|
|
4080
|
-
|
|
4081
|
-
if (!is_integer(vprec)) {
|
|
4082
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
|
4083
|
-
}
|
|
4084
|
-
|
|
4085
|
-
prec = NUM2SSIZET(vprec);
|
|
4086
|
-
if (prec <= 0) {
|
|
4087
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
4088
|
-
}
|
|
4089
|
-
|
|
4090
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
4091
|
-
* BigDecimalCmp function. */
|
|
4092
|
-
switch (TYPE(x)) {
|
|
4093
|
-
case T_DATA:
|
|
4094
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
4095
|
-
vx = DATA_PTR(x);
|
|
4096
|
-
zero = VpIsZero(vx);
|
|
4097
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4098
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
4099
|
-
nan = VpIsNaN(vx);
|
|
4100
|
-
break;
|
|
4101
|
-
|
|
4102
|
-
case T_FIXNUM:
|
|
4103
|
-
fix = FIX2LONG(x);
|
|
4104
|
-
zero = fix == 0;
|
|
4105
|
-
negative = fix < 0;
|
|
4106
|
-
goto get_vp_value;
|
|
4107
|
-
|
|
4108
|
-
case T_BIGNUM:
|
|
4109
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
|
4110
|
-
zero = i == 0;
|
|
4111
|
-
negative = i < 0;
|
|
4112
|
-
get_vp_value:
|
|
4113
|
-
if (zero || negative) break;
|
|
4114
|
-
vx = GetVpValue(x, 0);
|
|
4115
|
-
break;
|
|
4116
|
-
|
|
4117
|
-
case T_FLOAT:
|
|
4118
|
-
flo = RFLOAT_VALUE(x);
|
|
4119
|
-
zero = flo == 0;
|
|
4120
|
-
negative = flo < 0;
|
|
4121
|
-
infinite = isinf(flo);
|
|
4122
|
-
nan = isnan(flo);
|
|
4123
|
-
if (!zero && !negative && !infinite && !nan) {
|
|
4124
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
|
4125
|
-
}
|
|
4126
|
-
break;
|
|
4127
|
-
|
|
4128
|
-
case T_RATIONAL:
|
|
4129
|
-
zero = RRATIONAL_ZERO_P(x);
|
|
4130
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
|
4131
|
-
if (zero || negative) break;
|
|
4132
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
|
4133
|
-
break;
|
|
4134
|
-
|
|
4135
|
-
case T_COMPLEX:
|
|
4136
|
-
rb_raise(rb_eMathDomainError,
|
|
4137
|
-
"Complex argument for BigMath.log");
|
|
4138
|
-
|
|
4139
|
-
default:
|
|
4140
|
-
break;
|
|
4141
|
-
}
|
|
4142
|
-
if (infinite && !negative) {
|
|
4143
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
|
4144
|
-
RB_GC_GUARD(vy->obj);
|
|
4145
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
4146
|
-
return VpCheckGetValue(vy);
|
|
4147
|
-
}
|
|
4148
|
-
else if (nan) {
|
|
4149
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
4150
|
-
RB_GC_GUARD(vy->obj);
|
|
4151
|
-
VpSetNaN(vy);
|
|
4152
|
-
return VpCheckGetValue(vy);
|
|
4153
|
-
}
|
|
4154
|
-
else if (zero || negative) {
|
|
4155
|
-
rb_raise(rb_eMathDomainError,
|
|
4156
|
-
"Zero or negative argument for log");
|
|
4157
|
-
}
|
|
4158
|
-
else if (vx == NULL) {
|
|
4159
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4160
|
-
}
|
|
4161
|
-
x = VpCheckGetValue(vx);
|
|
4162
|
-
|
|
4163
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4164
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
|
4165
|
-
|
|
4166
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4167
|
-
vn = SSIZET2NUM(n);
|
|
4168
|
-
expo = VpExponent10(vx);
|
|
4169
|
-
if (expo < 0 || expo >= 3) {
|
|
4170
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
|
4171
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
|
4172
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
|
4173
|
-
}
|
|
4174
|
-
else {
|
|
4175
|
-
expo = 0;
|
|
4176
|
-
}
|
|
4177
|
-
w = BigDecimal_sub(x, one);
|
|
4178
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
|
4179
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
|
4180
|
-
y = x;
|
|
4181
|
-
d = y;
|
|
4182
|
-
i = 1;
|
|
4183
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4184
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4185
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4186
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4187
|
-
if (m <= 0) {
|
|
4188
|
-
break;
|
|
4189
|
-
}
|
|
4190
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4191
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4192
|
-
}
|
|
4193
|
-
|
|
4194
|
-
x = BigDecimal_mult2(x2, x, vn);
|
|
4195
|
-
i += 2;
|
|
4196
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
|
4197
|
-
y = BigDecimal_add(y, d);
|
|
4198
|
-
}
|
|
4199
|
-
|
|
4200
|
-
y = BigDecimal_mult(y, two);
|
|
4201
|
-
if (expo != 0) {
|
|
4202
|
-
VALUE log10, vexpo, dy;
|
|
4203
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
|
4204
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
|
4205
|
-
dy = BigDecimal_mult(log10, vexpo);
|
|
4206
|
-
y = BigDecimal_add(y, dy);
|
|
4207
|
-
}
|
|
4208
|
-
|
|
4209
|
-
RB_GC_GUARD(one);
|
|
4210
|
-
RB_GC_GUARD(two);
|
|
4211
|
-
RB_GC_GUARD(vn);
|
|
4212
|
-
RB_GC_GUARD(x2);
|
|
4213
|
-
RB_GC_GUARD(y);
|
|
4214
|
-
RB_GC_GUARD(d);
|
|
4215
|
-
|
|
4216
|
-
return y;
|
|
3197
|
+
BigDecimal_save_limit(VALUE self)
|
|
3198
|
+
{
|
|
3199
|
+
size_t const limit = VpGetPrecLimit();
|
|
3200
|
+
int state;
|
|
3201
|
+
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3202
|
+
VpSetPrecLimit(limit);
|
|
3203
|
+
if (state) rb_jump_tag(state);
|
|
3204
|
+
return ret;
|
|
4217
3205
|
}
|
|
4218
3206
|
|
|
4219
3207
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
|
@@ -4267,6 +3255,34 @@ BigDecimal_literal(const char *str)
|
|
|
4267
3255
|
|
|
4268
3256
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
|
4269
3257
|
|
|
3258
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3259
|
+
VALUE
|
|
3260
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3261
|
+
BDVALUE a,b,c,d;
|
|
3262
|
+
size_t cn = NUM2INT(cprec);
|
|
3263
|
+
a = GetBDValueMust(self);
|
|
3264
|
+
b = GetBDValueMust(r);
|
|
3265
|
+
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3266
|
+
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3267
|
+
VpDivd(c.real, d.real, a.real, b.real);
|
|
3268
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3269
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3270
|
+
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
VALUE
|
|
3274
|
+
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3275
|
+
BDVALUE a,b,c;
|
|
3276
|
+
a = GetBDValueMust(self);
|
|
3277
|
+
b = GetBDValueMust(v);
|
|
3278
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3279
|
+
VpMult(c.real, a.real, b.real);
|
|
3280
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3281
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3282
|
+
return c.bigdecimal;
|
|
3283
|
+
}
|
|
3284
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3285
|
+
|
|
4270
3286
|
/* Document-class: BigDecimal
|
|
4271
3287
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
|
4272
3288
|
*
|
|
@@ -4383,14 +3399,16 @@ BigDecimal_literal(const char *str)
|
|
|
4383
3399
|
*
|
|
4384
3400
|
* When you require +bigdecimal/util+, the #to_d method will be
|
|
4385
3401
|
* available on BigDecimal and the native Integer, Float, Rational,
|
|
4386
|
-
* and
|
|
3402
|
+
* String, Complex, and NilClass classes:
|
|
4387
3403
|
*
|
|
4388
3404
|
* require 'bigdecimal/util'
|
|
4389
3405
|
*
|
|
4390
|
-
* 42.to_d
|
|
4391
|
-
* 0.5.to_d
|
|
4392
|
-
* (2/3r).to_d(3)
|
|
4393
|
-
* "0.5".to_d
|
|
3406
|
+
* 42.to_d # => 0.42e2
|
|
3407
|
+
* 0.5.to_d # => 0.5e0
|
|
3408
|
+
* (2/3r).to_d(3) # => 0.667e0
|
|
3409
|
+
* "0.5".to_d # => 0.5e0
|
|
3410
|
+
* Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
|
3411
|
+
* nil.to_d # => 0.0
|
|
4394
3412
|
*
|
|
4395
3413
|
* == Methods for Working with \JSON
|
|
4396
3414
|
*
|
|
@@ -4464,7 +3482,7 @@ Init_bigdecimal(void)
|
|
|
4464
3482
|
* guarantee that two groups could always be multiplied together without
|
|
4465
3483
|
* overflow.)
|
|
4466
3484
|
*/
|
|
4467
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
|
3485
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
|
4468
3486
|
|
|
4469
3487
|
/* Exceptions */
|
|
4470
3488
|
|
|
@@ -4606,14 +3624,11 @@ Init_bigdecimal(void)
|
|
|
4606
3624
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
|
4607
3625
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
|
4608
3626
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
|
4609
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
|
4610
3627
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
|
4611
3628
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
|
4612
3629
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
|
4613
3630
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
|
4614
3631
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
|
4615
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
|
4616
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
|
4617
3632
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
|
4618
3633
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
|
4619
3634
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
|
@@ -4632,11 +3647,13 @@ Init_bigdecimal(void)
|
|
|
4632
3647
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
|
4633
3648
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
|
4634
3649
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
|
3650
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
|
4635
3651
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
|
4636
3652
|
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
3653
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3654
|
+
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3655
|
+
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3656
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
4640
3657
|
|
|
4641
3658
|
#define ROUNDING_MODE(i, name, value) \
|
|
4642
3659
|
id_##name = rb_intern_const(#name); \
|
|
@@ -4676,19 +3693,9 @@ Init_bigdecimal(void)
|
|
|
4676
3693
|
*/
|
|
4677
3694
|
#ifdef BIGDECIMAL_DEBUG
|
|
4678
3695
|
static int gfDebug = 1; /* Debug switch */
|
|
4679
|
-
#if 0
|
|
4680
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
|
4681
|
-
#endif
|
|
4682
3696
|
#endif /* BIGDECIMAL_DEBUG */
|
|
4683
3697
|
|
|
4684
3698
|
static Real *VpConstOne; /* constant 1.0 */
|
|
4685
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
|
4686
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
|
4687
|
-
/* used in VpSqrt() */
|
|
4688
|
-
|
|
4689
|
-
/* ETC */
|
|
4690
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
|
4691
|
-
#define StrCmp(x,y) strcmp(x,y)
|
|
4692
3699
|
|
|
4693
3700
|
enum op_sw {
|
|
4694
3701
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4698,11 +3705,9 @@ enum op_sw {
|
|
|
4698
3705
|
};
|
|
4699
3706
|
|
|
4700
3707
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
|
4701
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
4702
3708
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
|
4703
3709
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
|
4704
3710
|
static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
|
|
4705
|
-
static int VpNmlz(Real *a);
|
|
4706
3711
|
static void VpFormatSt(char *psz, size_t fFmt);
|
|
4707
3712
|
static int VpRdup(Real *m, size_t ind_m);
|
|
4708
3713
|
|
|
@@ -4761,10 +3766,10 @@ VpCheckException(Real *p, bool always)
|
|
|
4761
3766
|
}
|
|
4762
3767
|
|
|
4763
3768
|
static VALUE
|
|
4764
|
-
|
|
3769
|
+
CheckGetValue(BDVALUE v)
|
|
4765
3770
|
{
|
|
4766
|
-
VpCheckException(
|
|
4767
|
-
return
|
|
3771
|
+
VpCheckException(v.real, false);
|
|
3772
|
+
return v.bigdecimal;
|
|
4768
3773
|
}
|
|
4769
3774
|
|
|
4770
3775
|
/*
|
|
@@ -4796,12 +3801,10 @@ VpGetPrecLimit(void)
|
|
|
4796
3801
|
return NUM2SIZET(vlimit);
|
|
4797
3802
|
}
|
|
4798
3803
|
|
|
4799
|
-
VP_EXPORT
|
|
3804
|
+
VP_EXPORT void
|
|
4800
3805
|
VpSetPrecLimit(size_t n)
|
|
4801
3806
|
{
|
|
4802
|
-
size_t const s = VpGetPrecLimit();
|
|
4803
3807
|
bigdecimal_set_thread_local_precision_limit(n);
|
|
4804
|
-
return s;
|
|
4805
3808
|
}
|
|
4806
3809
|
|
|
4807
3810
|
/*
|
|
@@ -4916,15 +3919,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
|
4916
3919
|
return nzero;
|
|
4917
3920
|
}
|
|
4918
3921
|
|
|
4919
|
-
#if 0 /* unused */
|
|
4920
|
-
VP_EXPORT int
|
|
4921
|
-
VpIsNegDoubleZero(double v)
|
|
4922
|
-
{
|
|
4923
|
-
double z = VpGetDoubleNegZero();
|
|
4924
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
|
4925
|
-
}
|
|
4926
|
-
#endif
|
|
4927
|
-
|
|
4928
3922
|
VP_EXPORT int
|
|
4929
3923
|
VpException(unsigned short f, const char *str,int always)
|
|
4930
3924
|
{
|
|
@@ -5076,7 +4070,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
|
5076
4070
|
case 'E':
|
|
5077
4071
|
/* fall through */
|
|
5078
4072
|
default:
|
|
5079
|
-
nc = BASE_FIG*
|
|
4073
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
|
5080
4074
|
}
|
|
5081
4075
|
return nc;
|
|
5082
4076
|
}
|
|
@@ -5102,28 +4096,13 @@ VpInit(DECDIG BaseVal)
|
|
|
5102
4096
|
VpGetDoubleNegZero();
|
|
5103
4097
|
|
|
5104
4098
|
/* Const 1.0 */
|
|
5105
|
-
VpConstOne =
|
|
5106
|
-
|
|
5107
|
-
/* Const 0.5 */
|
|
5108
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
|
5109
|
-
VpConstPt5->exponent = 0;
|
|
5110
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
|
4099
|
+
VpConstOne = NewZero(1, 1);
|
|
4100
|
+
VpSetOne(VpConstOne);
|
|
5111
4101
|
|
|
5112
4102
|
#ifdef BIGDECIMAL_DEBUG
|
|
5113
4103
|
gnAlloc = 0;
|
|
5114
4104
|
#endif /* BIGDECIMAL_DEBUG */
|
|
5115
4105
|
|
|
5116
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5117
|
-
if (gfDebug) {
|
|
5118
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
|
5119
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
|
5120
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
|
5121
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
|
5122
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
|
5123
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
5124
|
-
}
|
|
5125
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5126
|
-
|
|
5127
4106
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
|
5128
4107
|
}
|
|
5129
4108
|
|
|
@@ -5139,24 +4118,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
|
5139
4118
|
{
|
|
5140
4119
|
SIGNED_VALUE e = a->exponent;
|
|
5141
4120
|
SIGNED_VALUE m = e+n;
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
if (eb - mb > 0) goto overflow;
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
else if (n < 0) {
|
|
5154
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
|
5155
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
5156
|
-
goto underflow;
|
|
5157
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
|
5158
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
|
5159
|
-
if (mb - eb > 0) goto underflow;
|
|
4121
|
+
if (e > 0 && n > 0) {
|
|
4122
|
+
if (n > VP_EXPONENT_MAX - e) goto overflow;
|
|
4123
|
+
} else if (e < 0 && n < 0) {
|
|
4124
|
+
if (n < VP_EXPONENT_MIN - e) goto underflow;
|
|
4125
|
+
} else if (m > VP_EXPONENT_MAX) {
|
|
4126
|
+
goto overflow;
|
|
4127
|
+
} else if (m < VP_EXPONENT_MIN) {
|
|
4128
|
+
goto underflow;
|
|
5160
4129
|
}
|
|
5161
4130
|
a->exponent = m;
|
|
5162
4131
|
return 1;
|
|
@@ -5197,7 +4166,6 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
5197
4166
|
while (*p && ISSPACE(*p)) ++p;
|
|
5198
4167
|
if (*p == '\0') {
|
|
5199
4168
|
Real *vp = rbd_allocate_struct(1);
|
|
5200
|
-
vp->MaxPrec = 1;
|
|
5201
4169
|
switch (table[i].sign) {
|
|
5202
4170
|
default:
|
|
5203
4171
|
UNREACHABLE; break;
|
|
@@ -5262,38 +4230,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
5262
4230
|
/*
|
|
5263
4231
|
* Allocates variable.
|
|
5264
4232
|
* [Input]
|
|
5265
|
-
*
|
|
5266
|
-
* The mx will be the number of significant digits can to be stored.
|
|
5267
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
|
5268
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
|
5269
|
-
* so that the full precision specified by szVal is allocated.
|
|
4233
|
+
* szVal ... The value assigned(char).
|
|
5270
4234
|
*
|
|
5271
4235
|
* [Returns]
|
|
5272
4236
|
* Pointer to the newly allocated variable, or
|
|
5273
4237
|
* NULL be returned if memory allocation is failed,or any error.
|
|
5274
4238
|
*/
|
|
5275
4239
|
VP_EXPORT Real *
|
|
5276
|
-
VpAlloc(
|
|
4240
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
5277
4241
|
{
|
|
5278
4242
|
const char *orig_szVal = szVal;
|
|
5279
|
-
size_t i, j, ni, ipf, nf, ipe, ne,
|
|
5280
|
-
size_t len;
|
|
4243
|
+
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
5281
4244
|
char v, *psz;
|
|
5282
4245
|
int sign=1;
|
|
5283
4246
|
Real *vp = NULL;
|
|
5284
4247
|
VALUE buf;
|
|
5285
4248
|
|
|
5286
|
-
if (szVal == NULL) {
|
|
5287
|
-
return_zero:
|
|
5288
|
-
/* necessary to be able to store */
|
|
5289
|
-
/* at least mx digits. */
|
|
5290
|
-
/* szVal==NULL ==> allocate zero value. */
|
|
5291
|
-
vp = rbd_allocate_struct(mx);
|
|
5292
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
|
5293
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
|
5294
|
-
return vp;
|
|
5295
|
-
}
|
|
5296
|
-
|
|
5297
4249
|
/* Skipping leading spaces */
|
|
5298
4250
|
while (ISSPACE(*szVal)) szVal++;
|
|
5299
4251
|
|
|
@@ -5302,14 +4254,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5302
4254
|
return vp;
|
|
5303
4255
|
}
|
|
5304
4256
|
|
|
5305
|
-
/*
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
len = rbd_calculate_internal_digits(mx, false);
|
|
5311
|
-
++szVal;
|
|
5312
|
-
}
|
|
4257
|
+
/* Skip leading `#`.
|
|
4258
|
+
* It used to be a mark to indicate that an extra MaxPrec should be allocated,
|
|
4259
|
+
* but now it has no effect.
|
|
4260
|
+
*/
|
|
4261
|
+
if (*szVal == '#') ++szVal;
|
|
5313
4262
|
|
|
5314
4263
|
/* Scanning digits */
|
|
5315
4264
|
|
|
@@ -5362,13 +4311,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5362
4311
|
ne = 0; /* number of digits in the exponential part */
|
|
5363
4312
|
ipf = 0; /* index of the beginning of the fractional part */
|
|
5364
4313
|
ipe = 0; /* index of the beginning of the exponential part */
|
|
5365
|
-
dot_seen = 0;
|
|
5366
4314
|
exp_seen = 0;
|
|
5367
4315
|
|
|
5368
4316
|
if (v != '\0') {
|
|
5369
4317
|
/* Scanning fractional part */
|
|
5370
4318
|
if ((psz[i] = szVal[j]) == '.') {
|
|
5371
|
-
dot_seen = 1;
|
|
5372
4319
|
++i;
|
|
5373
4320
|
++j;
|
|
5374
4321
|
ipf = i;
|
|
@@ -5384,9 +4331,6 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5384
4331
|
}
|
|
5385
4332
|
if (!strict_p) {
|
|
5386
4333
|
v = psz[i] = '\0';
|
|
5387
|
-
if (nf == 0) {
|
|
5388
|
-
dot_seen = 0;
|
|
5389
|
-
}
|
|
5390
4334
|
break;
|
|
5391
4335
|
}
|
|
5392
4336
|
goto invalid_value;
|
|
@@ -5457,11 +4401,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5457
4401
|
|
|
5458
4402
|
psz[i] = '\0';
|
|
5459
4403
|
|
|
5460
|
-
if (strict_p && ((
|
|
4404
|
+
if (strict_p && ((ni == 0 && nf == 0) || (exp_seen && ne == 0))) {
|
|
5461
4405
|
VALUE str;
|
|
5462
4406
|
invalid_value:
|
|
5463
4407
|
if (!strict_p) {
|
|
5464
|
-
|
|
4408
|
+
return NewZero(1, 1);
|
|
5465
4409
|
}
|
|
5466
4410
|
if (!exc) {
|
|
5467
4411
|
return NULL;
|
|
@@ -5472,11 +4416,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5472
4416
|
|
|
5473
4417
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
5474
4418
|
/* units for szVal[] */
|
|
5475
|
-
|
|
5476
|
-
nalloc = Max(nalloc, len);
|
|
5477
|
-
len = nalloc;
|
|
5478
|
-
vp = rbd_allocate_struct(len);
|
|
5479
|
-
vp->MaxPrec = len; /* set max precision */
|
|
4419
|
+
vp = rbd_allocate_struct(nalloc);
|
|
5480
4420
|
VpSetZero(vp, sign);
|
|
5481
4421
|
protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
|
|
5482
4422
|
rb_str_resize(buf, 0);
|
|
@@ -5516,7 +4456,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5516
4456
|
c->Prec = n;
|
|
5517
4457
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
|
5518
4458
|
/* Needs round ? */
|
|
5519
|
-
if (isw != 10) {
|
|
4459
|
+
if (isw != 10 && isw != -10) {
|
|
5520
4460
|
/* Not in ActiveRound */
|
|
5521
4461
|
if(c->Prec < a->Prec) {
|
|
5522
4462
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
|
@@ -5542,19 +4482,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5542
4482
|
VP_EXPORT size_t
|
|
5543
4483
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
|
5544
4484
|
{
|
|
5545
|
-
short sw, isw;
|
|
4485
|
+
short sw, isw, sign;
|
|
5546
4486
|
Real *a_ptr, *b_ptr;
|
|
5547
4487
|
size_t n, na, nb, i;
|
|
5548
4488
|
DECDIG mrv;
|
|
5549
4489
|
|
|
5550
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5551
|
-
if (gfDebug) {
|
|
5552
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
|
5553
|
-
VPrint(stdout, " b=% \n", b);
|
|
5554
|
-
printf(" operation=%d\n", operation);
|
|
5555
|
-
}
|
|
5556
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5557
|
-
|
|
5558
4490
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
|
5559
4491
|
|
|
5560
4492
|
/* check if a or b is zero */
|
|
@@ -5643,28 +4575,21 @@ end_if:
|
|
|
5643
4575
|
if (isw) { /* addition */
|
|
5644
4576
|
VpSetSign(c, 1);
|
|
5645
4577
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
|
5646
|
-
|
|
4578
|
+
sign = isw / 2;
|
|
5647
4579
|
}
|
|
5648
4580
|
else { /* subtraction */
|
|
5649
4581
|
VpSetSign(c, 1);
|
|
5650
4582
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
|
5651
|
-
|
|
5652
|
-
VpSetSign(c,VpGetSign(a));
|
|
5653
|
-
}
|
|
5654
|
-
else {
|
|
5655
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
|
5656
|
-
}
|
|
4583
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
|
5657
4584
|
}
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5661
|
-
if (gfDebug) {
|
|
5662
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
|
5663
|
-
VPrint(stdout, " a=% \n", a);
|
|
5664
|
-
VPrint(stdout, " b=% \n", b);
|
|
5665
|
-
printf(" operation=%d\n", operation);
|
|
4585
|
+
if (VpIsInf(c)) {
|
|
4586
|
+
VpSetInf(c, sign);
|
|
5666
4587
|
}
|
|
5667
|
-
|
|
4588
|
+
else {
|
|
4589
|
+
VpSetSign(c, sign);
|
|
4590
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
|
4591
|
+
}
|
|
4592
|
+
|
|
5668
4593
|
return c->Prec * BASE_FIG;
|
|
5669
4594
|
}
|
|
5670
4595
|
|
|
@@ -5685,13 +4610,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
|
5685
4610
|
size_t c_pos;
|
|
5686
4611
|
DECDIG av, bv, carry, mrv;
|
|
5687
4612
|
|
|
5688
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5689
|
-
if (gfDebug) {
|
|
5690
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
|
5691
|
-
VPrint(stdout, " b = %\n", b);
|
|
5692
|
-
}
|
|
5693
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5694
|
-
|
|
5695
4613
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5696
4614
|
a_pos = ap;
|
|
5697
4615
|
b_pos = bp;
|
|
@@ -5757,11 +4675,6 @@ Assign_a:
|
|
|
5757
4675
|
|
|
5758
4676
|
Exit:
|
|
5759
4677
|
|
|
5760
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5761
|
-
if (gfDebug) {
|
|
5762
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
|
5763
|
-
}
|
|
5764
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5765
4678
|
return mrv;
|
|
5766
4679
|
}
|
|
5767
4680
|
|
|
@@ -5780,13 +4693,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
|
5780
4693
|
size_t c_pos;
|
|
5781
4694
|
DECDIG av, bv, borrow, mrv;
|
|
5782
4695
|
|
|
5783
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5784
|
-
if (gfDebug) {
|
|
5785
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
|
5786
|
-
VPrint(stdout, " b = %\n", b);
|
|
5787
|
-
}
|
|
5788
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5789
|
-
|
|
5790
4696
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5791
4697
|
a_pos = ap;
|
|
5792
4698
|
b_pos = bp;
|
|
@@ -5862,11 +4768,6 @@ Assign_a:
|
|
|
5862
4768
|
mrv = 0;
|
|
5863
4769
|
|
|
5864
4770
|
Exit:
|
|
5865
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5866
|
-
if (gfDebug) {
|
|
5867
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
|
5868
|
-
}
|
|
5869
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5870
4771
|
return mrv;
|
|
5871
4772
|
}
|
|
5872
4773
|
|
|
@@ -5997,19 +4898,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
5997
4898
|
VP_EXPORT size_t
|
|
5998
4899
|
VpMult(Real *c, Real *a, Real *b)
|
|
5999
4900
|
{
|
|
6000
|
-
size_t MxIndA, MxIndB, MxIndAB
|
|
4901
|
+
size_t MxIndA, MxIndB, MxIndAB;
|
|
6001
4902
|
size_t ind_c, i, ii, nc;
|
|
6002
4903
|
size_t ind_as, ind_ae, ind_bs;
|
|
6003
4904
|
DECDIG carry;
|
|
6004
4905
|
DECDIG_DBL s;
|
|
6005
|
-
Real *w;
|
|
6006
|
-
|
|
6007
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6008
|
-
if (gfDebug) {
|
|
6009
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
|
6010
|
-
VPrint(stdout, " b=% \n", b);
|
|
6011
|
-
}
|
|
6012
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6013
4906
|
|
|
6014
4907
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
6015
4908
|
|
|
@@ -6020,39 +4913,28 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6020
4913
|
}
|
|
6021
4914
|
|
|
6022
4915
|
if (VpIsOne(a)) {
|
|
6023
|
-
VpAsgn(c, b, VpGetSign(a));
|
|
4916
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
|
6024
4917
|
goto Exit;
|
|
6025
4918
|
}
|
|
6026
4919
|
if (VpIsOne(b)) {
|
|
6027
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
4920
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
|
6028
4921
|
goto Exit;
|
|
6029
4922
|
}
|
|
6030
4923
|
if (b->Prec > a->Prec) {
|
|
6031
4924
|
/* Adjust so that digits(a)>digits(b) */
|
|
6032
|
-
w = a;
|
|
4925
|
+
Real *w = a;
|
|
6033
4926
|
a = b;
|
|
6034
4927
|
b = w;
|
|
6035
4928
|
}
|
|
6036
|
-
w = NULL;
|
|
6037
4929
|
MxIndA = a->Prec - 1;
|
|
6038
4930
|
MxIndB = b->Prec - 1;
|
|
6039
|
-
MxIndC = c->MaxPrec - 1;
|
|
6040
4931
|
MxIndAB = a->Prec + b->Prec - 1;
|
|
6041
4932
|
|
|
6042
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
|
6043
|
-
w = c;
|
|
6044
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
|
6045
|
-
MxIndC = MxIndAB;
|
|
6046
|
-
}
|
|
6047
|
-
|
|
6048
4933
|
/* set LHSV c info */
|
|
6049
4934
|
|
|
6050
4935
|
c->exponent = a->exponent; /* set exponent */
|
|
6051
|
-
if (!AddExponent(c, b->exponent)) {
|
|
6052
|
-
if (w) rbd_free_struct(c);
|
|
6053
|
-
return 0;
|
|
6054
|
-
}
|
|
6055
4936
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4937
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
|
6056
4938
|
carry = 0;
|
|
6057
4939
|
nc = ind_c = MxIndAB;
|
|
6058
4940
|
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
|
@@ -6099,29 +4981,18 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6099
4981
|
}
|
|
6100
4982
|
}
|
|
6101
4983
|
}
|
|
6102
|
-
|
|
6103
|
-
VpNmlz(c);
|
|
6104
|
-
VpAsgn(w, c, 1);
|
|
6105
|
-
rbd_free_struct(c);
|
|
6106
|
-
c = w;
|
|
6107
|
-
}
|
|
6108
|
-
else {
|
|
6109
|
-
VpLimitRound(c,0);
|
|
6110
|
-
}
|
|
4984
|
+
VpNmlz(c);
|
|
6111
4985
|
|
|
6112
4986
|
Exit:
|
|
6113
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6114
|
-
if (gfDebug) {
|
|
6115
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
|
6116
|
-
VPrint(stdout, " a=% \n", a);
|
|
6117
|
-
VPrint(stdout, " b=% \n", b);
|
|
6118
|
-
}
|
|
6119
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6120
4987
|
return c->Prec*BASE_FIG;
|
|
6121
4988
|
}
|
|
6122
4989
|
|
|
6123
4990
|
/*
|
|
6124
4991
|
* c = a / b, remainder = r
|
|
4992
|
+
* XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
|
|
4993
|
+
* XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
|
|
4994
|
+
* 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
|
|
4995
|
+
* 0001_0000_0000 / 9999 = 0000_0001_0001
|
|
6125
4996
|
*/
|
|
6126
4997
|
VP_EXPORT size_t
|
|
6127
4998
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
@@ -6130,16 +5001,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6130
5001
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
|
6131
5002
|
size_t nLoop;
|
|
6132
5003
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
|
6133
|
-
DECDIG
|
|
5004
|
+
DECDIG borrow1, borrow2;
|
|
6134
5005
|
DECDIG_DBL qb;
|
|
6135
5006
|
|
|
6136
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6137
|
-
if (gfDebug) {
|
|
6138
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
|
6139
|
-
VPrint(stdout, " b=% \n", b);
|
|
6140
|
-
}
|
|
6141
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6142
|
-
|
|
6143
5007
|
VpSetNaN(r);
|
|
6144
5008
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
|
6145
5009
|
if (VpIsZero(a) && VpIsZero(b)) {
|
|
@@ -6156,30 +5020,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6156
5020
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
|
6157
5021
|
goto Exit;
|
|
6158
5022
|
}
|
|
6159
|
-
if (VpIsOne(b)) {
|
|
6160
|
-
/* divide by one */
|
|
6161
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
6162
|
-
VpSetZero(r, VpGetSign(a));
|
|
6163
|
-
goto Exit;
|
|
6164
|
-
}
|
|
6165
5023
|
|
|
6166
5024
|
word_a = a->Prec;
|
|
6167
5025
|
word_b = b->Prec;
|
|
6168
5026
|
word_c = c->MaxPrec;
|
|
6169
5027
|
word_r = r->MaxPrec;
|
|
6170
5028
|
|
|
6171
|
-
if (word_a >= word_r) goto space_error;
|
|
5029
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
6172
5030
|
|
|
6173
|
-
|
|
6174
|
-
r->frac[
|
|
6175
|
-
|
|
6176
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
|
6177
|
-
++ind_r;
|
|
6178
|
-
}
|
|
6179
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
|
6180
|
-
|
|
6181
|
-
ind_c = 0;
|
|
6182
|
-
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
|
5031
|
+
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5032
|
+
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5033
|
+
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
6183
5034
|
|
|
6184
5035
|
/* initial procedure */
|
|
6185
5036
|
b1 = b1p1 = b->frac[0];
|
|
@@ -6194,15 +5045,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6194
5045
|
|
|
6195
5046
|
/* */
|
|
6196
5047
|
/* loop start */
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
ind_c = 1;
|
|
5048
|
+
nLoop = Min(word_c, word_r);
|
|
5049
|
+
ind_c = 0;
|
|
6200
5050
|
while (ind_c < nLoop) {
|
|
6201
5051
|
if (r->frac[ind_c] == 0) {
|
|
6202
5052
|
++ind_c;
|
|
6203
5053
|
continue;
|
|
6204
5054
|
}
|
|
6205
|
-
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
|
|
5055
|
+
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
|
|
6206
5056
|
if (r1r2 == b1b2) {
|
|
6207
5057
|
/* The first two word digits is the same */
|
|
6208
5058
|
ind_b = 2;
|
|
@@ -6215,26 +5065,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6215
5065
|
}
|
|
6216
5066
|
/* The first few word digits of r and b is the same and */
|
|
6217
5067
|
/* the first different word digit of w is greater than that */
|
|
6218
|
-
/* of b, so quotient is 1
|
|
6219
|
-
|
|
6220
|
-
ind_b = b->Prec - 1;
|
|
6221
|
-
ind_r = ind_c + ind_b;
|
|
6222
|
-
if (ind_r >= word_r) goto space_error;
|
|
6223
|
-
n = ind_b;
|
|
6224
|
-
for (i = 0; i <= n; ++i) {
|
|
6225
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
|
6226
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
|
6227
|
-
borrow = 1;
|
|
6228
|
-
}
|
|
6229
|
-
else {
|
|
6230
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
|
6231
|
-
borrow = 0;
|
|
6232
|
-
}
|
|
6233
|
-
--ind_r;
|
|
6234
|
-
--ind_b;
|
|
6235
|
-
}
|
|
5068
|
+
/* of b, so quotient is 1. */
|
|
5069
|
+
q = 1;
|
|
6236
5070
|
++c->frac[ind_c];
|
|
6237
|
-
|
|
5071
|
+
ind_r = b->Prec + ind_c - 1;
|
|
5072
|
+
goto sub_mult;
|
|
6238
5073
|
}
|
|
6239
5074
|
/* The first two word digits is not the same, */
|
|
6240
5075
|
/* then compare magnitude, and divide actually. */
|
|
@@ -6287,49 +5122,26 @@ sub_mult:
|
|
|
6287
5122
|
}
|
|
6288
5123
|
|
|
6289
5124
|
r->frac[ind_r] -= borrow2;
|
|
6290
|
-
carry:
|
|
6291
|
-
ind_r = ind_c;
|
|
6292
|
-
while (c->frac[ind_r] >= BASE) {
|
|
6293
|
-
c->frac[ind_r] -= BASE;
|
|
6294
|
-
--ind_r;
|
|
6295
|
-
++c->frac[ind_r];
|
|
6296
|
-
}
|
|
6297
5125
|
}
|
|
6298
5126
|
/* End of operation, now final arrangement */
|
|
6299
5127
|
out_side:
|
|
6300
5128
|
c->Prec = word_c;
|
|
6301
5129
|
c->exponent = a->exponent;
|
|
6302
|
-
|
|
5130
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
5131
|
+
if (!AddExponent(c, 1)) return 0;
|
|
6303
5132
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
|
6304
5133
|
|
|
6305
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
6306
5134
|
VpNmlz(c); /* normalize c */
|
|
6307
5135
|
r->Prec = word_r;
|
|
6308
5136
|
r->exponent = a->exponent;
|
|
6309
|
-
if (!AddExponent(r, 1)) return 0;
|
|
6310
5137
|
VpSetSign(r, VpGetSign(a));
|
|
6311
5138
|
VpNmlz(r); /* normalize r(remainder) */
|
|
6312
5139
|
goto Exit;
|
|
6313
5140
|
|
|
6314
5141
|
space_error:
|
|
6315
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6316
|
-
if (gfDebug) {
|
|
6317
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
|
6318
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
|
6319
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
|
6320
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
|
6321
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
|
6322
|
-
}
|
|
6323
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6324
5142
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
|
6325
5143
|
|
|
6326
5144
|
Exit:
|
|
6327
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6328
|
-
if (gfDebug) {
|
|
6329
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
|
6330
|
-
VPrint(stdout, " r=% \n", r);
|
|
6331
|
-
}
|
|
6332
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6333
5145
|
return c->Prec * BASE_FIG;
|
|
6334
5146
|
}
|
|
6335
5147
|
|
|
@@ -6452,13 +5264,6 @@ Exit:
|
|
|
6452
5264
|
if (val > 1) val = 1;
|
|
6453
5265
|
else if (val < -1) val = -1;
|
|
6454
5266
|
|
|
6455
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6456
|
-
if (gfDebug) {
|
|
6457
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
|
6458
|
-
VPrint(stdout, " b=%\n", b);
|
|
6459
|
-
printf(" ans=%d\n", val);
|
|
6460
|
-
}
|
|
6461
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6462
5267
|
return (int)val;
|
|
6463
5268
|
}
|
|
6464
5269
|
|
|
@@ -6576,25 +5381,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
|
6576
5381
|
static void
|
|
6577
5382
|
VpFormatSt(char *psz, size_t fFmt)
|
|
6578
5383
|
{
|
|
6579
|
-
size_t
|
|
6580
|
-
char
|
|
5384
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
|
5385
|
+
char *p;
|
|
6581
5386
|
|
|
6582
5387
|
if (fFmt == 0) return;
|
|
6583
5388
|
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
5389
|
+
iend = strlen(psz);
|
|
5390
|
+
|
|
5391
|
+
if ((p = strchr(psz, '.'))) {
|
|
5392
|
+
idig = (p - psz) + 1;
|
|
5393
|
+
}
|
|
5394
|
+
if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
|
|
5395
|
+
iexp = p - psz;
|
|
5396
|
+
}
|
|
5397
|
+
if (idig == 0 || idig > iexp) return;
|
|
5398
|
+
|
|
5399
|
+
nspaces = (iexp - idig - 1) / fFmt;
|
|
5400
|
+
p = psz + iend + 1;
|
|
5401
|
+
for (size_t i = nspaces; i > 0; i--) {
|
|
5402
|
+
char *src = psz + idig + i * fFmt;
|
|
5403
|
+
char *dst = psz + idig + i * (fFmt + 1);
|
|
5404
|
+
memmove(dst, src, p - src);
|
|
5405
|
+
dst[-1] = ' ';
|
|
5406
|
+
p = src;
|
|
6598
5407
|
}
|
|
6599
5408
|
}
|
|
6600
5409
|
|
|
@@ -6876,7 +5685,7 @@ VP_EXPORT int
|
|
|
6876
5685
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
|
6877
5686
|
{
|
|
6878
5687
|
size_t i, j, ind_a, ma, mi, me;
|
|
6879
|
-
SIGNED_VALUE e
|
|
5688
|
+
SIGNED_VALUE e;
|
|
6880
5689
|
int sign, signe, exponent_overflow;
|
|
6881
5690
|
|
|
6882
5691
|
/* get exponent part */
|
|
@@ -6899,23 +5708,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6899
5708
|
++me;
|
|
6900
5709
|
}
|
|
6901
5710
|
while (i < me) {
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
}
|
|
6906
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
|
6907
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
6908
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
|
6909
|
-
goto exp_overflow;
|
|
6910
|
-
e = e * 10 + exp_chr[i] - '0';
|
|
6911
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
6912
|
-
goto exp_overflow;
|
|
6913
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
|
6914
|
-
exp_overflow:
|
|
5711
|
+
int dig = exp_chr[i] - '0';
|
|
5712
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
5713
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
|
6915
5714
|
exponent_overflow = 1;
|
|
6916
|
-
e = es; /* keep sign */
|
|
6917
5715
|
break;
|
|
6918
5716
|
}
|
|
5717
|
+
e = e * 10 + signe * dig;
|
|
6919
5718
|
++i;
|
|
6920
5719
|
}
|
|
6921
5720
|
}
|
|
@@ -6934,34 +5733,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6934
5733
|
++mi;
|
|
6935
5734
|
}
|
|
6936
5735
|
}
|
|
5736
|
+
/* skip leading zeros in integer part */
|
|
5737
|
+
while (i < mi && int_chr[i] == '0') {
|
|
5738
|
+
++i;
|
|
5739
|
+
--ni;
|
|
5740
|
+
}
|
|
6937
5741
|
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
5742
|
+
/* set actual exponent size. */
|
|
5743
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
|
5744
|
+
exponent_overflow = 1;
|
|
5745
|
+
} else {
|
|
5746
|
+
e += ni;
|
|
5747
|
+
}
|
|
6943
5748
|
|
|
6944
5749
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
|
6945
|
-
j =
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
|
6951
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
|
6952
|
-
if (ef) {
|
|
6953
|
-
++j; /* Means to add one more preceding zero */
|
|
6954
|
-
++e;
|
|
6955
|
-
}
|
|
5750
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
|
5751
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
|
5752
|
+
exponent_overflow = 1;
|
|
5753
|
+
} else {
|
|
5754
|
+
e += j;
|
|
6956
5755
|
}
|
|
6957
5756
|
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
if (exponent_overflow) {
|
|
5757
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
|
6961
5758
|
int zero = 1;
|
|
6962
5759
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
|
6963
5760
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
|
6964
|
-
if (!zero &&
|
|
5761
|
+
if (!zero && e > 0) {
|
|
6965
5762
|
VpSetInf(a, sign);
|
|
6966
5763
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
|
6967
5764
|
}
|
|
@@ -7011,7 +5808,7 @@ Final:
|
|
|
7011
5808
|
++j;
|
|
7012
5809
|
}
|
|
7013
5810
|
a->Prec = ind_a + 1;
|
|
7014
|
-
a->exponent =
|
|
5811
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
|
7015
5812
|
VpSetSign(a, sign);
|
|
7016
5813
|
VpNmlz(a);
|
|
7017
5814
|
return 1;
|
|
@@ -7083,254 +5880,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
|
7083
5880
|
*d *= VpGetSign(m);
|
|
7084
5881
|
|
|
7085
5882
|
Exit:
|
|
7086
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7087
|
-
if (gfDebug) {
|
|
7088
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
|
7089
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
|
7090
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
7091
|
-
}
|
|
7092
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
7093
5883
|
return f;
|
|
7094
5884
|
}
|
|
7095
5885
|
|
|
7096
|
-
/*
|
|
7097
|
-
* m <- d
|
|
7098
|
-
*/
|
|
7099
|
-
VP_EXPORT void
|
|
7100
|
-
VpDtoV(Real *m, double d)
|
|
7101
|
-
{
|
|
7102
|
-
size_t ind_m, mm;
|
|
7103
|
-
SIGNED_VALUE ne;
|
|
7104
|
-
DECDIG i;
|
|
7105
|
-
double val, val2;
|
|
7106
|
-
|
|
7107
|
-
if (isnan(d)) {
|
|
7108
|
-
VpSetNaN(m);
|
|
7109
|
-
goto Exit;
|
|
7110
|
-
}
|
|
7111
|
-
if (isinf(d)) {
|
|
7112
|
-
if (d > 0.0) VpSetPosInf(m);
|
|
7113
|
-
else VpSetNegInf(m);
|
|
7114
|
-
goto Exit;
|
|
7115
|
-
}
|
|
7116
|
-
|
|
7117
|
-
if (d == 0.0) {
|
|
7118
|
-
VpSetZero(m, 1);
|
|
7119
|
-
goto Exit;
|
|
7120
|
-
}
|
|
7121
|
-
val = (d > 0.) ? d : -d;
|
|
7122
|
-
ne = 0;
|
|
7123
|
-
if (val >= 1.0) {
|
|
7124
|
-
while (val >= 1.0) {
|
|
7125
|
-
val /= (double)BASE;
|
|
7126
|
-
++ne;
|
|
7127
|
-
}
|
|
7128
|
-
}
|
|
7129
|
-
else {
|
|
7130
|
-
val2 = 1.0 / (double)BASE;
|
|
7131
|
-
while (val < val2) {
|
|
7132
|
-
val *= (double)BASE;
|
|
7133
|
-
--ne;
|
|
7134
|
-
}
|
|
7135
|
-
}
|
|
7136
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
|
7137
|
-
|
|
7138
|
-
mm = m->MaxPrec;
|
|
7139
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
|
7140
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
|
7141
|
-
val *= (double)BASE;
|
|
7142
|
-
i = (DECDIG)val;
|
|
7143
|
-
val -= (double)i;
|
|
7144
|
-
m->frac[ind_m] = i;
|
|
7145
|
-
}
|
|
7146
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
|
7147
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
|
7148
|
-
m->Prec = ind_m + 1;
|
|
7149
|
-
m->exponent = ne;
|
|
7150
|
-
|
|
7151
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
|
7152
|
-
(DECDIG)(val*(double)BASE));
|
|
7153
|
-
|
|
7154
|
-
Exit:
|
|
7155
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7156
|
-
if (gfDebug) {
|
|
7157
|
-
printf("VpDtoV d=%30.30e\n", d);
|
|
7158
|
-
VPrint(stdout, " m=%\n", m);
|
|
7159
|
-
}
|
|
7160
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7161
|
-
return;
|
|
7162
|
-
}
|
|
7163
|
-
|
|
7164
|
-
/*
|
|
7165
|
-
* m <- ival
|
|
7166
|
-
*/
|
|
7167
|
-
#if 0 /* unused */
|
|
7168
|
-
VP_EXPORT void
|
|
7169
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
|
7170
|
-
{
|
|
7171
|
-
size_t mm, ind_m;
|
|
7172
|
-
size_t val, v1, v2, v;
|
|
7173
|
-
int isign;
|
|
7174
|
-
SIGNED_VALUE ne;
|
|
7175
|
-
|
|
7176
|
-
if (ival == 0) {
|
|
7177
|
-
VpSetZero(m, 1);
|
|
7178
|
-
goto Exit;
|
|
7179
|
-
}
|
|
7180
|
-
isign = 1;
|
|
7181
|
-
val = ival;
|
|
7182
|
-
if (ival < 0) {
|
|
7183
|
-
isign = -1;
|
|
7184
|
-
val =(size_t)(-ival);
|
|
7185
|
-
}
|
|
7186
|
-
ne = 0;
|
|
7187
|
-
ind_m = 0;
|
|
7188
|
-
mm = m->MaxPrec;
|
|
7189
|
-
while (ind_m < mm) {
|
|
7190
|
-
m->frac[ind_m] = 0;
|
|
7191
|
-
++ind_m;
|
|
7192
|
-
}
|
|
7193
|
-
ind_m = 0;
|
|
7194
|
-
while (val > 0) {
|
|
7195
|
-
if (val) {
|
|
7196
|
-
v1 = val;
|
|
7197
|
-
v2 = 1;
|
|
7198
|
-
while (v1 >= BASE) {
|
|
7199
|
-
v1 /= BASE;
|
|
7200
|
-
v2 *= BASE;
|
|
7201
|
-
}
|
|
7202
|
-
val = val - v2 * v1;
|
|
7203
|
-
v = v1;
|
|
7204
|
-
}
|
|
7205
|
-
else {
|
|
7206
|
-
v = 0;
|
|
7207
|
-
}
|
|
7208
|
-
m->frac[ind_m] = v;
|
|
7209
|
-
++ind_m;
|
|
7210
|
-
++ne;
|
|
7211
|
-
}
|
|
7212
|
-
m->Prec = ind_m - 1;
|
|
7213
|
-
m->exponent = ne;
|
|
7214
|
-
VpSetSign(m, isign);
|
|
7215
|
-
VpNmlz(m);
|
|
7216
|
-
|
|
7217
|
-
Exit:
|
|
7218
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7219
|
-
if (gfDebug) {
|
|
7220
|
-
printf(" VpItoV i=%d\n", ival);
|
|
7221
|
-
VPrint(stdout, " m=%\n", m);
|
|
7222
|
-
}
|
|
7223
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7224
|
-
return;
|
|
7225
|
-
}
|
|
7226
|
-
#endif
|
|
7227
|
-
|
|
7228
|
-
/*
|
|
7229
|
-
* y = SQRT(x), y*y - x =>0
|
|
7230
|
-
*/
|
|
7231
|
-
VP_EXPORT int
|
|
7232
|
-
VpSqrt(Real *y, Real *x)
|
|
7233
|
-
{
|
|
7234
|
-
Real *f = NULL;
|
|
7235
|
-
Real *r = NULL;
|
|
7236
|
-
size_t y_prec;
|
|
7237
|
-
SIGNED_VALUE n, e;
|
|
7238
|
-
ssize_t nr;
|
|
7239
|
-
double val;
|
|
7240
|
-
|
|
7241
|
-
/* Zero or +Infinity ? */
|
|
7242
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
|
7243
|
-
VpAsgn(y,x,1);
|
|
7244
|
-
goto Exit;
|
|
7245
|
-
}
|
|
7246
|
-
|
|
7247
|
-
/* Negative ? */
|
|
7248
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
7249
|
-
VpSetNaN(y);
|
|
7250
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
|
7251
|
-
}
|
|
7252
|
-
|
|
7253
|
-
/* NaN ? */
|
|
7254
|
-
if (VpIsNaN(x)) {
|
|
7255
|
-
VpSetNaN(y);
|
|
7256
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
|
7257
|
-
}
|
|
7258
|
-
|
|
7259
|
-
/* One ? */
|
|
7260
|
-
if (VpIsOne(x)) {
|
|
7261
|
-
VpSetOne(y);
|
|
7262
|
-
goto Exit;
|
|
7263
|
-
}
|
|
7264
|
-
|
|
7265
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
|
7266
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
|
7267
|
-
|
|
7268
|
-
/* allocate temporally variables */
|
|
7269
|
-
/* TODO: reconsider MaxPrec of f and r */
|
|
7270
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
|
7271
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
|
7272
|
-
|
|
7273
|
-
nr = 0;
|
|
7274
|
-
y_prec = y->MaxPrec;
|
|
7275
|
-
|
|
7276
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
|
7277
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
|
7278
|
-
n = e / 2;
|
|
7279
|
-
if (e - n * 2 != 0) {
|
|
7280
|
-
val /= BASE;
|
|
7281
|
-
n = (e + 1) / 2;
|
|
7282
|
-
}
|
|
7283
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
|
7284
|
-
y->exponent += n;
|
|
7285
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
|
7286
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
|
7287
|
-
f->MaxPrec = y->MaxPrec + 1;
|
|
7288
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
|
7289
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
|
7290
|
-
|
|
7291
|
-
/*
|
|
7292
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
|
7293
|
-
*/
|
|
7294
|
-
do {
|
|
7295
|
-
y->MaxPrec *= 2;
|
|
7296
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
|
7297
|
-
f->MaxPrec = y->MaxPrec;
|
|
7298
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
|
7299
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
|
7300
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
|
7301
|
-
if (VpIsZero(f))
|
|
7302
|
-
goto converge;
|
|
7303
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
|
7304
|
-
VpAsgn(y, r, 1); /* y = r */
|
|
7305
|
-
} while (++nr < n);
|
|
7306
|
-
|
|
7307
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7308
|
-
if (gfDebug) {
|
|
7309
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
|
7310
|
-
}
|
|
7311
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7312
|
-
y->MaxPrec = y_prec;
|
|
7313
|
-
|
|
7314
|
-
converge:
|
|
7315
|
-
VpChangeSign(y, 1);
|
|
7316
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7317
|
-
if (gfDebug) {
|
|
7318
|
-
VpMult(r, y, y);
|
|
7319
|
-
VpAddSub(f, x, r, -1);
|
|
7320
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
|
7321
|
-
VPrint(stdout, " y =% \n", y);
|
|
7322
|
-
VPrint(stdout, " x =% \n", x);
|
|
7323
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
|
7324
|
-
}
|
|
7325
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7326
|
-
y->MaxPrec = y_prec;
|
|
7327
|
-
|
|
7328
|
-
Exit:
|
|
7329
|
-
rbd_free_struct(f);
|
|
7330
|
-
rbd_free_struct(r);
|
|
7331
|
-
return 1;
|
|
7332
|
-
}
|
|
7333
|
-
|
|
7334
5886
|
/*
|
|
7335
5887
|
* Round relatively from the decimal point.
|
|
7336
5888
|
* f: rounding mode
|
|
@@ -7507,7 +6059,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
7507
6059
|
DECDIG v;
|
|
7508
6060
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
|
7509
6061
|
v = y->frac[0];
|
|
7510
|
-
nf -=
|
|
6062
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
|
7511
6063
|
while ((v /= 10) != 0) nf--;
|
|
7512
6064
|
nf += (ssize_t)BASE_FIG-1;
|
|
7513
6065
|
return VpMidRound(y, f, nf);
|
|
@@ -7644,117 +6196,9 @@ VpFrac(Real *y, Real *x)
|
|
|
7644
6196
|
VpNmlz(y);
|
|
7645
6197
|
|
|
7646
6198
|
Exit:
|
|
7647
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7648
|
-
if (gfDebug) {
|
|
7649
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
|
7650
|
-
VPrint(stdout, " x=%\n", x);
|
|
7651
|
-
}
|
|
7652
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7653
6199
|
return;
|
|
7654
6200
|
}
|
|
7655
6201
|
|
|
7656
|
-
/*
|
|
7657
|
-
* y = x ** n
|
|
7658
|
-
*/
|
|
7659
|
-
VP_EXPORT int
|
|
7660
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
|
7661
|
-
{
|
|
7662
|
-
size_t s, ss;
|
|
7663
|
-
ssize_t sign;
|
|
7664
|
-
Real *w1 = NULL;
|
|
7665
|
-
Real *w2 = NULL;
|
|
7666
|
-
|
|
7667
|
-
if (VpIsZero(x)) {
|
|
7668
|
-
if (n == 0) {
|
|
7669
|
-
VpSetOne(y);
|
|
7670
|
-
goto Exit;
|
|
7671
|
-
}
|
|
7672
|
-
sign = VpGetSign(x);
|
|
7673
|
-
if (n < 0) {
|
|
7674
|
-
n = -n;
|
|
7675
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7676
|
-
VpSetInf(y, sign);
|
|
7677
|
-
}
|
|
7678
|
-
else {
|
|
7679
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7680
|
-
VpSetZero(y,sign);
|
|
7681
|
-
}
|
|
7682
|
-
goto Exit;
|
|
7683
|
-
}
|
|
7684
|
-
if (VpIsNaN(x)) {
|
|
7685
|
-
VpSetNaN(y);
|
|
7686
|
-
goto Exit;
|
|
7687
|
-
}
|
|
7688
|
-
if (VpIsInf(x)) {
|
|
7689
|
-
if (n == 0) {
|
|
7690
|
-
VpSetOne(y);
|
|
7691
|
-
goto Exit;
|
|
7692
|
-
}
|
|
7693
|
-
if (n > 0) {
|
|
7694
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7695
|
-
goto Exit;
|
|
7696
|
-
}
|
|
7697
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7698
|
-
goto Exit;
|
|
7699
|
-
}
|
|
7700
|
-
|
|
7701
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
|
7702
|
-
/* abs(x) = 1 */
|
|
7703
|
-
VpSetOne(y);
|
|
7704
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
|
7705
|
-
if ((n % 2) == 0) goto Exit;
|
|
7706
|
-
VpSetSign(y, -1);
|
|
7707
|
-
goto Exit;
|
|
7708
|
-
}
|
|
7709
|
-
|
|
7710
|
-
if (n > 0) sign = 1;
|
|
7711
|
-
else if (n < 0) {
|
|
7712
|
-
sign = -1;
|
|
7713
|
-
n = -n;
|
|
7714
|
-
}
|
|
7715
|
-
else {
|
|
7716
|
-
VpSetOne(y);
|
|
7717
|
-
goto Exit;
|
|
7718
|
-
}
|
|
7719
|
-
|
|
7720
|
-
/* Allocate working variables */
|
|
7721
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
|
7722
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
|
7723
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
|
7724
|
-
|
|
7725
|
-
/* calculation start */
|
|
7726
|
-
|
|
7727
|
-
VpAsgn(y, x, 1);
|
|
7728
|
-
--n;
|
|
7729
|
-
while (n > 0) {
|
|
7730
|
-
VpAsgn(w1, x, 1);
|
|
7731
|
-
s = 1;
|
|
7732
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
|
7733
|
-
VpMult(w2, w1, w1);
|
|
7734
|
-
VpAsgn(w1, w2, 1);
|
|
7735
|
-
}
|
|
7736
|
-
n -= (SIGNED_VALUE)ss;
|
|
7737
|
-
VpMult(w2, y, w1);
|
|
7738
|
-
VpAsgn(y, w2, 1);
|
|
7739
|
-
}
|
|
7740
|
-
if (sign < 0) {
|
|
7741
|
-
VpDivd(w1, w2, VpConstOne, y);
|
|
7742
|
-
VpAsgn(y, w1, 1);
|
|
7743
|
-
}
|
|
7744
|
-
|
|
7745
|
-
Exit:
|
|
7746
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7747
|
-
if (gfDebug) {
|
|
7748
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
|
7749
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
|
7750
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
|
7751
|
-
}
|
|
7752
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7753
|
-
rbd_free_struct(w2);
|
|
7754
|
-
rbd_free_struct(w1);
|
|
7755
|
-
return 1;
|
|
7756
|
-
}
|
|
7757
|
-
|
|
7758
6202
|
#ifdef BIGDECIMAL_DEBUG
|
|
7759
6203
|
int
|
|
7760
6204
|
VpVarCheck(Real * v)
|