bigdecimal 3.2.2 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/bigdecimal/bigdecimal.c +744 -2268
- data/ext/bigdecimal/bigdecimal.h +4 -25
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/extconf.rb +3 -7
- data/ext/bigdecimal/missing.h +1 -93
- data/lib/bigdecimal/math.rb +88 -70
- data/lib/bigdecimal/util.rb +15 -14
- data/lib/bigdecimal.rb +340 -0
- metadata +1 -1
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.
|
34
|
+
#define BIGDECIMAL_VERSION "3.3.0"
|
35
35
|
|
36
36
|
/* #define ENABLE_NUMERIC_STRING */
|
37
37
|
|
38
38
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
39
39
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
40
40
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
41
|
+
#define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
42
|
+
|
43
|
+
/* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
|
44
|
+
#define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
|
45
|
+
/* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
|
46
|
+
#define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
|
47
|
+
#define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
|
48
|
+
#define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
|
41
49
|
|
42
50
|
VALUE rb_cBigDecimal;
|
43
|
-
VALUE rb_mBigMath;
|
44
51
|
|
45
52
|
static ID id_BigDecimal_exception_mode;
|
46
53
|
static ID id_BigDecimal_rounding_mode;
|
@@ -68,15 +75,28 @@ static struct {
|
|
68
75
|
uint8_t mode;
|
69
76
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
70
77
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
78
|
+
typedef struct {
|
79
|
+
VALUE bigdecimal;
|
80
|
+
Real *real;
|
81
|
+
} BDVALUE;
|
82
|
+
|
83
|
+
typedef struct {
|
84
|
+
VALUE bigdecimal_or_nil;
|
85
|
+
Real *real_or_null;
|
86
|
+
} NULLABLE_BDVALUE;
|
87
|
+
|
88
|
+
static inline BDVALUE
|
89
|
+
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
90
|
+
{
|
91
|
+
assert(v.real_or_null != NULL);
|
92
|
+
return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
|
93
|
+
}
|
94
|
+
|
95
|
+
static inline NULLABLE_BDVALUE
|
96
|
+
bdvalue_nullable(BDVALUE v)
|
97
|
+
{
|
98
|
+
return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
|
99
|
+
}
|
80
100
|
|
81
101
|
#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
|
82
102
|
#define BASE BIGDECIMAL_BASE
|
@@ -84,31 +104,6 @@ static struct {
|
|
84
104
|
#define HALF_BASE (BASE/2)
|
85
105
|
#define BASE1 (BASE/10)
|
86
106
|
|
87
|
-
#define LOG10_2 0.3010299956639812
|
88
|
-
|
89
|
-
#ifndef RRATIONAL_ZERO_P
|
90
|
-
# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
|
91
|
-
FIX2LONG(rb_rational_num(x)) == 0)
|
92
|
-
#endif
|
93
|
-
|
94
|
-
#ifndef RRATIONAL_NEGATIVE_P
|
95
|
-
# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
|
96
|
-
#endif
|
97
|
-
|
98
|
-
#ifndef DECIMAL_SIZE_OF_BITS
|
99
|
-
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
|
100
|
-
/* an approximation of ceil(n * log10(2)), upto 65536 at least */
|
101
|
-
#endif
|
102
|
-
|
103
|
-
#ifdef PRIsVALUE
|
104
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
105
|
-
# define RB_OBJ_STRING(obj) (obj)
|
106
|
-
#else
|
107
|
-
# define PRIsVALUE "s"
|
108
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
109
|
-
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
110
|
-
#endif
|
111
|
-
|
112
107
|
#ifndef MAYBE_UNUSED
|
113
108
|
# define MAYBE_UNUSED(x) x
|
114
109
|
#endif
|
@@ -145,6 +140,17 @@ check_allocation_count_nonzero(void)
|
|
145
140
|
# define check_allocation_count_nonzero() /* nothing */
|
146
141
|
#endif /* BIGDECIMAL_DEBUG */
|
147
142
|
|
143
|
+
/* VpMult VpDivd helpers */
|
144
|
+
#define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
|
145
|
+
/* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
|
146
|
+
/* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
|
147
|
+
#define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
|
148
|
+
/* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
|
149
|
+
#define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
|
150
|
+
|
151
|
+
static NULLABLE_BDVALUE
|
152
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
|
153
|
+
|
148
154
|
PUREFUNC(static inline size_t rbd_struct_size(size_t const));
|
149
155
|
|
150
156
|
static inline size_t
|
@@ -164,44 +170,10 @@ rbd_allocate_struct(size_t const internal_digits)
|
|
164
170
|
return real;
|
165
171
|
}
|
166
172
|
|
167
|
-
static size_t
|
168
|
-
rbd_calculate_internal_digits(size_t const digits, bool limit_precision)
|
169
|
-
{
|
170
|
-
size_t const len = roomof(digits, BASE_FIG);
|
171
|
-
if (limit_precision) {
|
172
|
-
size_t const prec_limit = VpGetPrecLimit();
|
173
|
-
if (prec_limit > 0) {
|
174
|
-
/* NOTE: 2 more digits for rounding and division */
|
175
|
-
size_t const max_len = roomof(prec_limit, BASE_FIG) + 2;
|
176
|
-
if (len > max_len)
|
177
|
-
return max_len;
|
178
|
-
}
|
179
|
-
}
|
180
|
-
|
181
|
-
return len;
|
182
|
-
}
|
183
|
-
|
184
173
|
static inline Real *
|
185
|
-
rbd_allocate_struct_decimal_digits(size_t const decimal_digits
|
186
|
-
{
|
187
|
-
size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision);
|
188
|
-
return rbd_allocate_struct(internal_digits);
|
189
|
-
}
|
190
|
-
|
191
|
-
static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp);
|
192
|
-
|
193
|
-
static Real *
|
194
|
-
rbd_reallocate_struct(Real *real, size_t const internal_digits)
|
174
|
+
rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
|
195
175
|
{
|
196
|
-
|
197
|
-
VALUE obj = real ? real->obj : 0;
|
198
|
-
Real *new_real = (Real *)ruby_xrealloc(real, size);
|
199
|
-
new_real->MaxPrec = internal_digits;
|
200
|
-
if (obj) {
|
201
|
-
new_real->obj = 0;
|
202
|
-
BigDecimal_wrap_struct(obj, new_real);
|
203
|
-
}
|
204
|
-
return new_real;
|
176
|
+
return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
|
205
177
|
}
|
206
178
|
|
207
179
|
static void
|
@@ -214,58 +186,16 @@ rbd_free_struct(Real *real)
|
|
214
186
|
}
|
215
187
|
}
|
216
188
|
|
189
|
+
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
|
217
190
|
#define NewZero rbd_allocate_struct_zero
|
218
|
-
static Real *
|
219
|
-
rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision)
|
220
|
-
{
|
221
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
|
222
|
-
VpSetZero(real, sign);
|
223
|
-
return real;
|
224
|
-
}
|
225
|
-
|
226
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits));
|
227
|
-
#define NewZeroLimited rbd_allocate_struct_zero_limited
|
228
|
-
static inline Real *
|
229
|
-
rbd_allocate_struct_zero_limited(int sign, size_t const digits)
|
230
|
-
{
|
231
|
-
return rbd_allocate_struct_zero(sign, digits, true);
|
232
|
-
}
|
233
|
-
|
234
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits));
|
235
|
-
#define NewZeroNolimit rbd_allocate_struct_zero_nolimit
|
236
191
|
static inline Real *
|
237
|
-
|
238
|
-
{
|
239
|
-
return rbd_allocate_struct_zero(sign, digits, false);
|
240
|
-
}
|
241
|
-
|
242
|
-
#define NewOne rbd_allocate_struct_one
|
243
|
-
static Real *
|
244
|
-
rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision)
|
192
|
+
rbd_allocate_struct_zero(int sign, size_t const digits)
|
245
193
|
{
|
246
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits
|
247
|
-
|
248
|
-
if (sign < 0)
|
249
|
-
VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
|
194
|
+
Real *real = rbd_allocate_struct_decimal_digits(digits);
|
195
|
+
VpSetZero(real, sign);
|
250
196
|
return real;
|
251
197
|
}
|
252
198
|
|
253
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits));
|
254
|
-
#define NewOneLimited rbd_allocate_struct_one_limited
|
255
|
-
static inline Real *
|
256
|
-
rbd_allocate_struct_one_limited(int sign, size_t const digits)
|
257
|
-
{
|
258
|
-
return rbd_allocate_struct_one(sign, digits, true);
|
259
|
-
}
|
260
|
-
|
261
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits));
|
262
|
-
#define NewOneNolimit rbd_allocate_struct_one_nolimit
|
263
|
-
static inline Real *
|
264
|
-
rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
265
|
-
{
|
266
|
-
return rbd_allocate_struct_one(sign, digits, false);
|
267
|
-
}
|
268
|
-
|
269
199
|
/*
|
270
200
|
* ================== Ruby Interface part ==========================
|
271
201
|
*/
|
@@ -277,7 +207,8 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
|
277
207
|
static unsigned short VpGetException(void);
|
278
208
|
static void VpSetException(unsigned short f);
|
279
209
|
static void VpCheckException(Real *p, bool always);
|
280
|
-
static
|
210
|
+
static int AddExponent(Real *a, SIGNED_VALUE n);
|
211
|
+
static VALUE CheckGetValue(BDVALUE v);
|
281
212
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
282
213
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
283
214
|
static Real *VpCopy(Real *pv, Real const* const x);
|
@@ -292,6 +223,8 @@ static VALUE BigDecimal_positive_infinity(void);
|
|
292
223
|
static VALUE BigDecimal_negative_infinity(void);
|
293
224
|
static VALUE BigDecimal_positive_zero(void);
|
294
225
|
static VALUE BigDecimal_negative_zero(void);
|
226
|
+
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
227
|
+
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
295
228
|
|
296
229
|
static void
|
297
230
|
BigDecimal_delete(void *pv)
|
@@ -319,58 +252,33 @@ static const rb_data_type_t BigDecimal_data_type = {
|
|
319
252
|
#endif
|
320
253
|
};
|
321
254
|
|
322
|
-
|
323
|
-
|
324
|
-
{
|
325
|
-
|
326
|
-
|
327
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
328
|
-
BigDecimal_wrap_struct(obj, real);
|
329
|
-
}
|
330
|
-
return real;
|
331
|
-
}
|
332
|
-
|
333
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
|
334
|
-
#define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
|
335
|
-
static inline Real *
|
336
|
-
rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
|
337
|
-
{
|
338
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
|
339
|
-
}
|
340
|
-
|
341
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
|
342
|
-
#define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
|
343
|
-
static inline Real *
|
344
|
-
rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
|
345
|
-
{
|
346
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
|
347
|
-
}
|
348
|
-
|
349
|
-
static Real *
|
350
|
-
rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
|
255
|
+
// TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
|
256
|
+
// We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
|
257
|
+
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
258
|
+
static NULL_WRAPPED_VALUE
|
259
|
+
BigDecimal_alloc_empty_struct(VALUE klass)
|
351
260
|
{
|
352
|
-
|
353
|
-
if (real != NULL) {
|
354
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
355
|
-
BigDecimal_wrap_struct(obj, real);
|
356
|
-
}
|
357
|
-
return real;
|
261
|
+
return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
|
358
262
|
}
|
359
263
|
|
360
|
-
|
361
|
-
|
362
|
-
static inline Real *
|
363
|
-
rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
|
264
|
+
static VALUE
|
265
|
+
BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
|
364
266
|
{
|
365
|
-
|
267
|
+
VALUE obj = v._obj;
|
268
|
+
assert(RTYPEDDATA_DATA(obj) == NULL);
|
269
|
+
RTYPEDDATA_DATA(obj) = real;
|
270
|
+
RB_OBJ_FREEZE(obj);
|
271
|
+
return obj;
|
366
272
|
}
|
367
273
|
|
368
|
-
MAYBE_UNUSED(static inline
|
369
|
-
#define
|
370
|
-
static
|
371
|
-
|
274
|
+
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
275
|
+
#define NewZeroWrap rbd_allocate_struct_zero_wrap
|
276
|
+
static BDVALUE
|
277
|
+
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
372
278
|
{
|
373
|
-
|
279
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
280
|
+
Real *real = rbd_allocate_struct_zero(sign, digits);
|
281
|
+
return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
|
374
282
|
}
|
375
283
|
|
376
284
|
static inline int
|
@@ -398,24 +306,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
|
|
398
306
|
}
|
399
307
|
|
400
308
|
static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
|
401
|
-
static VALUE rb_inum_convert_to_BigDecimal(VALUE val
|
309
|
+
static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
|
402
310
|
static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
403
311
|
static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
404
|
-
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str,
|
312
|
+
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
|
405
313
|
static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
406
314
|
|
407
|
-
static
|
408
|
-
|
315
|
+
static NULLABLE_BDVALUE
|
316
|
+
GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
409
317
|
{
|
410
|
-
const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
|
411
|
-
|
412
318
|
switch(TYPE(v)) {
|
413
319
|
case T_FLOAT:
|
414
|
-
v = rb_float_convert_to_BigDecimal(v,
|
320
|
+
v = rb_float_convert_to_BigDecimal(v, 0, true);
|
415
321
|
break;
|
416
322
|
|
417
323
|
case T_RATIONAL:
|
418
|
-
v = rb_rational_convert_to_BigDecimal(v,
|
324
|
+
v = rb_rational_convert_to_BigDecimal(v, prec, true);
|
419
325
|
break;
|
420
326
|
|
421
327
|
case T_DATA:
|
@@ -424,47 +330,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
|
|
424
330
|
}
|
425
331
|
break;
|
426
332
|
|
427
|
-
case T_FIXNUM:
|
428
|
-
|
429
|
-
|
430
|
-
v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
|
333
|
+
case T_FIXNUM:
|
334
|
+
case T_BIGNUM: {
|
335
|
+
v = rb_inum_convert_to_BigDecimal(v);
|
431
336
|
break;
|
432
337
|
}
|
433
338
|
|
434
339
|
#ifdef ENABLE_NUMERIC_STRING
|
435
340
|
case T_STRING: {
|
436
341
|
const char *c_str = StringValueCStr(v);
|
437
|
-
v = rb_cstr_convert_to_BigDecimal(c_str,
|
342
|
+
v = rb_cstr_convert_to_BigDecimal(c_str, must);
|
438
343
|
break;
|
439
344
|
}
|
440
345
|
#endif /* ENABLE_NUMERIC_STRING */
|
441
346
|
|
442
|
-
case T_BIGNUM: {
|
443
|
-
VALUE bg = rb_big2str(v, 10);
|
444
|
-
v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
|
445
|
-
RB_GC_GUARD(bg);
|
446
|
-
break;
|
447
|
-
}
|
448
|
-
|
449
347
|
default:
|
450
348
|
goto SomeOneMayDoIt;
|
451
349
|
}
|
452
350
|
|
453
351
|
Real *vp;
|
454
352
|
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
455
|
-
return vp;
|
353
|
+
return (NULLABLE_BDVALUE) { v, vp };
|
456
354
|
|
457
355
|
SomeOneMayDoIt:
|
458
356
|
if (must) {
|
459
357
|
cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
|
460
358
|
}
|
461
|
-
return NULL; /* NULL means to coerce */
|
359
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
|
360
|
+
}
|
361
|
+
|
362
|
+
static inline NULLABLE_BDVALUE
|
363
|
+
GetBDValueWithPrec(VALUE v, size_t prec)
|
364
|
+
{
|
365
|
+
return GetBDValueWithPrecInternal(v, prec, 0);
|
366
|
+
}
|
367
|
+
|
368
|
+
|
369
|
+
static inline BDVALUE
|
370
|
+
GetBDValueWithPrecMust(VALUE v, size_t prec)
|
371
|
+
{
|
372
|
+
return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
|
462
373
|
}
|
463
374
|
|
375
|
+
// self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
|
464
376
|
static inline Real*
|
465
|
-
|
377
|
+
GetSelfVpValue(VALUE self)
|
378
|
+
{
|
379
|
+
return GetBDValueWithPrecMust(self, 0).real;
|
380
|
+
}
|
381
|
+
|
382
|
+
static inline BDVALUE
|
383
|
+
GetBDValueMust(VALUE v)
|
466
384
|
{
|
467
|
-
return
|
385
|
+
return GetBDValueWithPrecMust(v, 0);
|
468
386
|
}
|
469
387
|
|
470
388
|
/* call-seq:
|
@@ -479,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,17 +416,18 @@ 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
|
|
@@ -623,10 +542,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
623
542
|
static void
|
624
543
|
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
625
544
|
{
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
VpCountPrecisionAndScale(p, out_precision, out_scale);
|
545
|
+
BDVALUE v = GetBDValueMust(self);
|
546
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
547
|
+
RB_GC_GUARD(v.bigdecimal);
|
630
548
|
}
|
631
549
|
|
632
550
|
/*
|
@@ -664,8 +582,8 @@ BigDecimal_precision(VALUE self)
|
|
664
582
|
* BigDecimal("1").scale # => 0
|
665
583
|
* BigDecimal("1.1").scale # => 1
|
666
584
|
* BigDecimal("3.1415").scale # => 4
|
667
|
-
* BigDecimal("-1e20").
|
668
|
-
* BigDecimal("1e-20").
|
585
|
+
* BigDecimal("-1e20").scale # => 0
|
586
|
+
* BigDecimal("1e-20").scale # => 20
|
669
587
|
* BigDecimal("Infinity").scale # => 0
|
670
588
|
* BigDecimal("-Infinity").scale # => 0
|
671
589
|
* BigDecimal("NaN").scale # => 0
|
@@ -715,25 +633,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
715
633
|
static VALUE
|
716
634
|
BigDecimal_n_significant_digits(VALUE self)
|
717
635
|
{
|
718
|
-
|
719
|
-
|
720
|
-
Real *p;
|
721
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
722
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
636
|
+
BDVALUE v = GetBDValueMust(self);
|
637
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
723
638
|
return INT2FIX(0);
|
724
639
|
}
|
725
640
|
|
726
|
-
ssize_t n =
|
727
|
-
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);
|
728
643
|
if (n == 0) return INT2FIX(0);
|
729
644
|
|
730
645
|
DECDIG x;
|
731
646
|
int nlz = BASE_FIG;
|
732
|
-
for (x =
|
647
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
733
648
|
|
734
649
|
int ntz = 0;
|
735
|
-
for (x =
|
650
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
736
651
|
|
652
|
+
RB_GC_GUARD(v.bigdecimal);
|
737
653
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
738
654
|
return SSIZET2NUM(n_significant_digits);
|
739
655
|
}
|
@@ -755,17 +671,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
755
671
|
static VALUE
|
756
672
|
BigDecimal_hash(VALUE self)
|
757
673
|
{
|
758
|
-
|
759
|
-
|
760
|
-
st_index_t hash;
|
761
|
-
|
762
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
763
|
-
hash = (st_index_t)p->sign;
|
674
|
+
BDVALUE v = GetBDValueMust(self);
|
675
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
764
676
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
765
677
|
if(hash == 2 || hash == (st_index_t)-2) {
|
766
|
-
hash ^= rb_memhash(
|
767
|
-
hash +=
|
678
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
679
|
+
hash += v.real->exponent;
|
768
680
|
}
|
681
|
+
RB_GC_GUARD(v.bigdecimal);
|
769
682
|
return ST2FIX(hash);
|
770
683
|
}
|
771
684
|
|
@@ -784,21 +697,22 @@ BigDecimal_hash(VALUE self)
|
|
784
697
|
static VALUE
|
785
698
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
786
699
|
{
|
787
|
-
|
788
|
-
Real *vp;
|
700
|
+
BDVALUE v;
|
789
701
|
char *psz;
|
790
702
|
VALUE dummy;
|
791
703
|
volatile VALUE dump;
|
792
704
|
size_t len;
|
793
705
|
|
794
706
|
rb_scan_args(argc, argv, "01", &dummy);
|
795
|
-
|
796
|
-
dump = rb_str_new(0, VpNumOfChars(
|
707
|
+
v = GetBDValueMust(self);
|
708
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
797
709
|
psz = RSTRING_PTR(dump);
|
798
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
710
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
799
711
|
len = strlen(psz);
|
800
|
-
VpToString(
|
712
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
801
713
|
rb_str_resize(dump, strlen(psz));
|
714
|
+
|
715
|
+
RB_GC_GUARD(v.bigdecimal);
|
802
716
|
return dump;
|
803
717
|
}
|
804
718
|
|
@@ -808,27 +722,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
808
722
|
static VALUE
|
809
723
|
BigDecimal_load(VALUE self, VALUE str)
|
810
724
|
{
|
811
|
-
|
812
|
-
Real *pv;
|
725
|
+
BDVALUE v;
|
813
726
|
unsigned char *pch;
|
814
727
|
unsigned char ch;
|
815
|
-
unsigned long m=0;
|
816
728
|
|
817
729
|
pch = (unsigned char *)StringValueCStr(str);
|
818
|
-
/* First
|
730
|
+
/* First skip max prec. Don't trust the value. */
|
819
731
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
820
732
|
if(!ISDIGIT(ch)) {
|
821
733
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
822
734
|
}
|
823
|
-
m = m*10 + (unsigned long)(ch-'0');
|
824
735
|
}
|
825
|
-
|
826
|
-
|
827
|
-
m /= VpBaseFig();
|
828
|
-
if (m && pv->MaxPrec > m) {
|
829
|
-
pv->MaxPrec = m+1;
|
830
|
-
}
|
831
|
-
return VpCheckGetValue(pv);
|
736
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
737
|
+
return CheckGetValue(v);
|
832
738
|
}
|
833
739
|
|
834
740
|
static unsigned short
|
@@ -1121,22 +1027,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
1121
1027
|
static size_t
|
1122
1028
|
GetAddSubPrec(Real *a, Real *b)
|
1123
1029
|
{
|
1124
|
-
size_t mxs;
|
1125
|
-
size_t mx = a->Prec;
|
1126
|
-
SIGNED_VALUE d;
|
1127
|
-
|
1128
1030
|
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
d = a->exponent - b->exponent;
|
1133
|
-
if (d < 0) d = -d;
|
1134
|
-
mx = mx + (size_t)d;
|
1135
|
-
if (mx < mxs) {
|
1136
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
1137
|
-
}
|
1138
|
-
}
|
1139
|
-
return mx;
|
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);
|
1140
1034
|
}
|
1141
1035
|
|
1142
1036
|
static inline SIGNED_VALUE
|
@@ -1156,39 +1050,13 @@ check_int_precision(VALUE v)
|
|
1156
1050
|
return n;
|
1157
1051
|
}
|
1158
1052
|
|
1159
|
-
static
|
1160
|
-
|
1161
|
-
{
|
1162
|
-
assert(is_kind_of_BigDecimal(obj));
|
1163
|
-
assert(vp != NULL);
|
1164
|
-
|
1165
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
1166
|
-
return obj;
|
1167
|
-
|
1168
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
1169
|
-
assert(vp->obj == 0);
|
1170
|
-
|
1171
|
-
RTYPEDDATA_DATA(obj) = vp;
|
1172
|
-
vp->obj = obj;
|
1173
|
-
RB_OBJ_FREEZE(obj);
|
1174
|
-
return obj;
|
1175
|
-
}
|
1176
|
-
|
1177
|
-
VP_EXPORT Real *
|
1178
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
1179
|
-
{
|
1180
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
1181
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
1182
|
-
if (!pv)
|
1183
|
-
return NULL;
|
1184
|
-
BigDecimal_wrap_struct(obj, pv);
|
1185
|
-
return pv;
|
1186
|
-
}
|
1187
|
-
|
1188
|
-
VP_EXPORT Real *
|
1189
|
-
VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
|
1053
|
+
static NULLABLE_BDVALUE
|
1054
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
1190
1055
|
{
|
1191
|
-
|
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 };
|
1192
1060
|
}
|
1193
1061
|
|
1194
1062
|
static Real *
|
@@ -1196,7 +1064,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
1196
1064
|
{
|
1197
1065
|
assert(x != NULL);
|
1198
1066
|
|
1199
|
-
pv =
|
1067
|
+
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
1200
1068
|
pv->MaxPrec = x->MaxPrec;
|
1201
1069
|
pv->Prec = x->Prec;
|
1202
1070
|
pv->exponent = x->exponent;
|
@@ -1211,7 +1079,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
1211
1079
|
static VALUE
|
1212
1080
|
BigDecimal_IsNaN(VALUE self)
|
1213
1081
|
{
|
1214
|
-
Real *p =
|
1082
|
+
Real *p = GetSelfVpValue(self);
|
1215
1083
|
if (VpIsNaN(p)) return Qtrue;
|
1216
1084
|
return Qfalse;
|
1217
1085
|
}
|
@@ -1222,7 +1090,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
1222
1090
|
static VALUE
|
1223
1091
|
BigDecimal_IsInfinite(VALUE self)
|
1224
1092
|
{
|
1225
|
-
Real *p =
|
1093
|
+
Real *p = GetSelfVpValue(self);
|
1226
1094
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
1227
1095
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
1228
1096
|
return Qnil;
|
@@ -1232,7 +1100,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
1232
1100
|
static VALUE
|
1233
1101
|
BigDecimal_IsFinite(VALUE self)
|
1234
1102
|
{
|
1235
|
-
Real *p =
|
1103
|
+
Real *p = GetSelfVpValue(self);
|
1236
1104
|
if (VpIsNaN(p)) return Qfalse;
|
1237
1105
|
if (VpIsInf(p)) return Qfalse;
|
1238
1106
|
return Qtrue;
|
@@ -1244,6 +1112,7 @@ BigDecimal_check_num(Real *p)
|
|
1244
1112
|
VpCheckException(p, true);
|
1245
1113
|
}
|
1246
1114
|
|
1115
|
+
static VALUE BigDecimal_fix(VALUE self);
|
1247
1116
|
static VALUE BigDecimal_split(VALUE self);
|
1248
1117
|
|
1249
1118
|
/* Returns the value as an Integer.
|
@@ -1253,44 +1122,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
1253
1122
|
static VALUE
|
1254
1123
|
BigDecimal_to_i(VALUE self)
|
1255
1124
|
{
|
1256
|
-
|
1257
|
-
|
1258
|
-
Real *p;
|
1125
|
+
BDVALUE v;
|
1126
|
+
VALUE ret;
|
1259
1127
|
|
1260
|
-
|
1261
|
-
BigDecimal_check_num(
|
1128
|
+
v = GetBDValueMust(self);
|
1129
|
+
BigDecimal_check_num(v.real);
|
1262
1130
|
|
1263
|
-
|
1264
|
-
if (
|
1265
|
-
|
1266
|
-
if (e <= nf) {
|
1267
|
-
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]));
|
1268
1134
|
}
|
1269
1135
|
else {
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
ret = rb_funcall(numerator, '*', 1,
|
1286
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
1287
|
-
INT2FIX(dpower)));
|
1288
|
-
}
|
1289
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
1290
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
1291
|
-
}
|
1292
|
-
return ret;
|
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
|
+
}
|
1293
1151
|
}
|
1152
|
+
|
1153
|
+
RB_GC_GUARD(v.bigdecimal);
|
1154
|
+
return ret;
|
1294
1155
|
}
|
1295
1156
|
|
1296
1157
|
/* Returns a new Float object having approximately the same value as the
|
@@ -1300,24 +1161,26 @@ BigDecimal_to_i(VALUE self)
|
|
1300
1161
|
static VALUE
|
1301
1162
|
BigDecimal_to_f(VALUE self)
|
1302
1163
|
{
|
1303
|
-
ENTER(1);
|
1304
|
-
Real *p;
|
1305
1164
|
double d;
|
1306
1165
|
SIGNED_VALUE e;
|
1307
1166
|
char *buf;
|
1308
1167
|
volatile VALUE str;
|
1168
|
+
BDVALUE v = GetBDValueMust(self);
|
1169
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
1309
1170
|
|
1310
|
-
|
1311
|
-
if (VpVtoD(&d, &e, p) != 1)
|
1171
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
1312
1172
|
return rb_float_new(d);
|
1313
1173
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
1314
1174
|
goto overflow;
|
1315
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
1175
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
1316
1176
|
goto underflow;
|
1317
1177
|
|
1318
|
-
str = rb_str_new(0, VpNumOfChars(
|
1178
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
1319
1179
|
buf = RSTRING_PTR(str);
|
1320
|
-
VpToString(
|
1180
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
1181
|
+
|
1182
|
+
RB_GC_GUARD(v.bigdecimal);
|
1183
|
+
|
1321
1184
|
errno = 0;
|
1322
1185
|
d = strtod(buf, 0);
|
1323
1186
|
if (errno == ERANGE) {
|
@@ -1328,14 +1191,14 @@ BigDecimal_to_f(VALUE self)
|
|
1328
1191
|
|
1329
1192
|
overflow:
|
1330
1193
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
1331
|
-
if (
|
1194
|
+
if (negative)
|
1332
1195
|
return rb_float_new(VpGetDoubleNegInf());
|
1333
1196
|
else
|
1334
1197
|
return rb_float_new(VpGetDoublePosInf());
|
1335
1198
|
|
1336
1199
|
underflow:
|
1337
1200
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
1338
|
-
if (
|
1201
|
+
if (negative)
|
1339
1202
|
return rb_float_new(-0.0);
|
1340
1203
|
else
|
1341
1204
|
return rb_float_new(0.0);
|
@@ -1347,15 +1210,16 @@ underflow:
|
|
1347
1210
|
static VALUE
|
1348
1211
|
BigDecimal_to_r(VALUE self)
|
1349
1212
|
{
|
1350
|
-
|
1213
|
+
BDVALUE v;
|
1351
1214
|
ssize_t sign, power, denomi_power;
|
1352
1215
|
VALUE a, digits, numerator;
|
1353
1216
|
|
1354
|
-
|
1355
|
-
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);
|
1356
1222
|
|
1357
|
-
sign = VpGetSign(p);
|
1358
|
-
power = VpExponent10(p);
|
1359
1223
|
a = BigDecimal_split(self);
|
1360
1224
|
digits = RARRAY_AREF(a, 1);
|
1361
1225
|
denomi_power = power - RSTRING_LEN(digits);
|
@@ -1376,6 +1240,14 @@ BigDecimal_to_r(VALUE self)
|
|
1376
1240
|
}
|
1377
1241
|
}
|
1378
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
|
+
|
1379
1251
|
/* The coerce method provides support for Ruby type coercion. It is not
|
1380
1252
|
* enabled by default.
|
1381
1253
|
*
|
@@ -1393,26 +1265,9 @@ BigDecimal_to_r(VALUE self)
|
|
1393
1265
|
static VALUE
|
1394
1266
|
BigDecimal_coerce(VALUE self, VALUE other)
|
1395
1267
|
{
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
1401
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
1402
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
1403
|
-
}
|
1404
|
-
else {
|
1405
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
1406
|
-
Real* pv = DATA_PTR(self);
|
1407
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
1408
|
-
}
|
1409
|
-
else {
|
1410
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
1411
|
-
}
|
1412
|
-
obj = rb_assoc_new(b->obj, self);
|
1413
|
-
}
|
1414
|
-
|
1415
|
-
return obj;
|
1268
|
+
Real* pv = DATA_PTR(self);
|
1269
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
1270
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
1416
1271
|
}
|
1417
1272
|
|
1418
1273
|
/*
|
@@ -1432,6 +1287,15 @@ BigDecimal_uplus(VALUE self)
|
|
1432
1287
|
return self;
|
1433
1288
|
}
|
1434
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
|
+
|
1435
1299
|
/*
|
1436
1300
|
* call-seq:
|
1437
1301
|
* self + value -> bigdecimal
|
@@ -1451,42 +1315,40 @@ BigDecimal_uplus(VALUE self)
|
|
1451
1315
|
static VALUE
|
1452
1316
|
BigDecimal_add(VALUE self, VALUE r)
|
1453
1317
|
{
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1318
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
1319
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
1320
|
+
}
|
1457
1321
|
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
1464
|
-
}
|
1465
|
-
else {
|
1466
|
-
b = GetVpValue(r, 0);
|
1467
|
-
}
|
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;
|
1468
1327
|
|
1469
|
-
|
1470
|
-
|
1328
|
+
a = GetBDValueMust(self);
|
1329
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
1471
1330
|
|
1472
|
-
if (VpIsNaN(
|
1473
|
-
if (VpIsNaN(
|
1331
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
1332
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
1474
1333
|
|
1475
|
-
mx = GetAddSubPrec(a, b);
|
1334
|
+
mx = GetAddSubPrec(a.real, b.real);
|
1476
1335
|
if (mx == (size_t)-1L) {
|
1477
|
-
|
1478
|
-
|
1336
|
+
/* a or b is inf */
|
1337
|
+
c = NewZeroWrap(1, BASE_FIG);
|
1338
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
1479
1339
|
}
|
1480
1340
|
else {
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
}
|
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);
|
1488
1347
|
}
|
1489
|
-
|
1348
|
+
|
1349
|
+
RB_GC_GUARD(a.bigdecimal);
|
1350
|
+
RB_GC_GUARD(b.bigdecimal);
|
1351
|
+
return CheckGetValue(c);
|
1490
1352
|
}
|
1491
1353
|
|
1492
1354
|
/*
|
@@ -1507,73 +1369,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
1507
1369
|
static VALUE
|
1508
1370
|
BigDecimal_sub(VALUE self, VALUE r)
|
1509
1371
|
{
|
1510
|
-
|
1511
|
-
|
1512
|
-
size_t mx;
|
1513
|
-
|
1514
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
1515
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
1516
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
1517
|
-
}
|
1518
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
1519
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
1520
|
-
}
|
1521
|
-
else {
|
1522
|
-
b = GetVpValue(r,0);
|
1523
|
-
}
|
1524
|
-
|
1525
|
-
if (!b) return DoSomeOne(self,r,'-');
|
1526
|
-
SAVE(b);
|
1527
|
-
|
1528
|
-
if (VpIsNaN(b)) return b->obj;
|
1529
|
-
if (VpIsNaN(a)) return a->obj;
|
1530
|
-
|
1531
|
-
mx = GetAddSubPrec(a,b);
|
1532
|
-
if (mx == (size_t)-1L) {
|
1533
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
1534
|
-
VpAddSub(c, a, b, -1);
|
1535
|
-
}
|
1536
|
-
else {
|
1537
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
|
1538
|
-
if (!mx) {
|
1539
|
-
VpSetInf(c,VpGetSign(a));
|
1540
|
-
}
|
1541
|
-
else {
|
1542
|
-
VpAddSub(c, a, b, -1);
|
1543
|
-
}
|
1544
|
-
}
|
1545
|
-
return VpCheckGetValue(c);
|
1372
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
1373
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
1546
1374
|
}
|
1547
1375
|
|
1548
1376
|
static VALUE
|
1549
1377
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
1550
1378
|
{
|
1551
|
-
ENTER(5);
|
1552
1379
|
SIGNED_VALUE e;
|
1553
|
-
|
1554
|
-
|
1555
|
-
switch (TYPE(r)) {
|
1556
|
-
case T_DATA:
|
1557
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
1558
|
-
/* fall through */
|
1559
|
-
case T_FIXNUM:
|
1560
|
-
/* fall through */
|
1561
|
-
case T_BIGNUM:
|
1562
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
1563
|
-
break;
|
1380
|
+
BDVALUE a = GetBDValueMust(self);
|
1381
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
1564
1382
|
|
1565
|
-
|
1566
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
1567
|
-
break;
|
1568
|
-
|
1569
|
-
case T_RATIONAL:
|
1570
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
1571
|
-
break;
|
1572
|
-
|
1573
|
-
default:
|
1574
|
-
break;
|
1575
|
-
}
|
1576
|
-
if (b == NULL) {
|
1383
|
+
if (b.real_or_null == NULL) {
|
1577
1384
|
ID f = 0;
|
1578
1385
|
|
1579
1386
|
switch (op) {
|
@@ -1602,8 +1409,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1602
1409
|
}
|
1603
1410
|
return rb_num_coerce_relop(self, r, f);
|
1604
1411
|
}
|
1605
|
-
|
1606
|
-
|
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
|
+
|
1607
1417
|
if (e == 999)
|
1608
1418
|
return (op == '*') ? Qnil : Qfalse;
|
1609
1419
|
switch (op) {
|
@@ -1643,7 +1453,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1643
1453
|
static VALUE
|
1644
1454
|
BigDecimal_zero(VALUE self)
|
1645
1455
|
{
|
1646
|
-
Real *a =
|
1456
|
+
Real *a = GetSelfVpValue(self);
|
1647
1457
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
1648
1458
|
}
|
1649
1459
|
|
@@ -1651,7 +1461,7 @@ BigDecimal_zero(VALUE self)
|
|
1651
1461
|
static VALUE
|
1652
1462
|
BigDecimal_nonzero(VALUE self)
|
1653
1463
|
{
|
1654
|
-
Real *a =
|
1464
|
+
Real *a = GetSelfVpValue(self);
|
1655
1465
|
return VpIsZero(a) ? Qnil : self;
|
1656
1466
|
}
|
1657
1467
|
|
@@ -1777,12 +1587,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
1777
1587
|
static VALUE
|
1778
1588
|
BigDecimal_neg(VALUE self)
|
1779
1589
|
{
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
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);
|
1786
1595
|
}
|
1787
1596
|
|
1788
1597
|
/*
|
@@ -1795,35 +1604,36 @@ BigDecimal_neg(VALUE self)
|
|
1795
1604
|
*
|
1796
1605
|
* See BigDecimal#mult.
|
1797
1606
|
*/
|
1798
|
-
|
1799
1607
|
static VALUE
|
1800
1608
|
BigDecimal_mult(VALUE self, VALUE r)
|
1801
1609
|
{
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1610
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
1611
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
1612
|
+
}
|
1805
1613
|
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1614
|
+
static VALUE
|
1615
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
1616
|
+
{
|
1617
|
+
BDVALUE a, b, c;
|
1618
|
+
|
1619
|
+
a = GetBDValueMust(self);
|
1620
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
1621
|
+
|
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);
|
1812
1626
|
}
|
1813
1627
|
else {
|
1814
|
-
|
1628
|
+
VpLimitRound(c.real, 0);
|
1815
1629
|
}
|
1816
1630
|
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
mx = a->Prec + b->Prec;
|
1821
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
1822
|
-
VpMult(c, a, b);
|
1823
|
-
return VpCheckGetValue(c);
|
1631
|
+
RB_GC_GUARD(a.bigdecimal);
|
1632
|
+
RB_GC_GUARD(b.bigdecimal);
|
1633
|
+
return CheckGetValue(c);
|
1824
1634
|
}
|
1825
1635
|
|
1826
|
-
static
|
1636
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
1827
1637
|
|
1828
1638
|
/* call-seq:
|
1829
1639
|
* a / b -> bigdecimal
|
@@ -1840,14 +1650,7 @@ static VALUE
|
|
1840
1650
|
BigDecimal_div(VALUE self, VALUE r)
|
1841
1651
|
/* For c = self/r: with round operation */
|
1842
1652
|
{
|
1843
|
-
if (
|
1844
|
-
!is_kind_of_BigDecimal(r) &&
|
1845
|
-
!RB_INTEGER_TYPE_P(r) &&
|
1846
|
-
!RB_TYPE_P(r, T_FLOAT) &&
|
1847
|
-
!RB_TYPE_P(r, T_RATIONAL)
|
1848
|
-
) {
|
1849
|
-
return DoSomeOne(self, r, '/');
|
1850
|
-
}
|
1653
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
1851
1654
|
return BigDecimal_div2(self, r, INT2FIX(0));
|
1852
1655
|
}
|
1853
1656
|
|
@@ -1893,114 +1696,109 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
1893
1696
|
/*
|
1894
1697
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
1895
1698
|
* div = (a.to_f/b).floor
|
1699
|
+
* In truncate mode, use truncate instead of floor.
|
1896
1700
|
*/
|
1897
|
-
static
|
1898
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
1701
|
+
static bool
|
1702
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
1899
1703
|
{
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
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;
|
1905
1708
|
|
1906
|
-
|
1907
|
-
SAVE(a);
|
1709
|
+
a = GetBDValueMust(self);
|
1908
1710
|
|
1909
|
-
|
1910
|
-
if (
|
1911
|
-
|
1912
|
-
}
|
1913
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
1914
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
1915
|
-
}
|
1916
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
1917
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
1918
|
-
}
|
1919
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
1920
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
1921
|
-
}
|
1711
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
1712
|
+
if (!b2.real_or_null) return false;
|
1713
|
+
b = bdvalue_nonnullable(b2);
|
1922
1714
|
|
1923
|
-
if (
|
1924
|
-
|
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;
|
1925
1719
|
}
|
1926
|
-
|
1927
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
1928
|
-
SAVE(b);
|
1929
|
-
|
1930
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
1931
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
1932
|
-
if (VpIsZero(b)) {
|
1720
|
+
if (VpIsZero(b.real)) {
|
1933
1721
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
1934
1722
|
}
|
1935
|
-
if (VpIsInf(a)) {
|
1936
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
1723
|
+
if (VpIsInf(a.real)) {
|
1724
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
1937
1725
|
VALUE inf = BigDecimal_positive_infinity();
|
1938
|
-
|
1726
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
1939
1727
|
}
|
1940
1728
|
else {
|
1941
1729
|
VALUE inf = BigDecimal_negative_infinity();
|
1942
|
-
|
1730
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
1943
1731
|
}
|
1944
1732
|
VALUE nan = BigDecimal_nan();
|
1945
|
-
|
1946
|
-
|
1947
|
-
}
|
1948
|
-
if (VpIsInf(b)) {
|
1949
|
-
VALUE zero = BigDecimal_positive_zero();
|
1950
|
-
TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
|
1951
|
-
*mod = a;
|
1952
|
-
return Qtrue;
|
1733
|
+
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
1734
|
+
goto Done;
|
1953
1735
|
}
|
1954
|
-
if (VpIsZero(a)) {
|
1736
|
+
if (VpIsZero(a.real)) {
|
1955
1737
|
VALUE zero = BigDecimal_positive_zero();
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1738
|
+
*div = *mod = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
1739
|
+
goto Done;
|
1740
|
+
}
|
1741
|
+
if (VpIsInf(b.real)) {
|
1742
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
1743
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
1744
|
+
VpSetOne(minus_one.real);
|
1745
|
+
VpSetSign(minus_one.real, -1);
|
1746
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
1747
|
+
*div = bdvalue_nullable(minus_one);
|
1748
|
+
*mod = bdvalue_nullable(b);
|
1749
|
+
} else {
|
1750
|
+
VALUE zero = BigDecimal_positive_zero();
|
1751
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
1752
|
+
*mod = bdvalue_nullable(a);
|
1753
|
+
}
|
1754
|
+
goto Done;
|
1755
|
+
}
|
1756
|
+
|
1757
|
+
a_exponent = VpExponent10(a.real);
|
1758
|
+
b_exponent = VpExponent10(b.real);
|
1759
|
+
mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
|
1760
|
+
dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
|
1761
|
+
|
1762
|
+
/* res is reused for VpDivd remainder and VpMult result */
|
1763
|
+
rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
|
1764
|
+
mx = VPMULT_RESULT_PREC(dv.real, b.real);
|
1765
|
+
res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
|
1766
|
+
/* AddSub needs one more prec */
|
1767
|
+
md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
|
1768
|
+
|
1769
|
+
VpDivd(dv.real, res.real, a.real, b.real);
|
1770
|
+
VpMidRound(dv.real, VP_ROUND_DOWN, 0);
|
1771
|
+
VpMult(res.real, dv.real, b.real);
|
1772
|
+
pl = VpGetPrecLimit();
|
1773
|
+
VpSetPrecLimit(0);
|
1774
|
+
VpAddSub(md.real, a.real, res.real, -1);
|
1775
|
+
VpSetPrecLimit(pl);
|
1980
1776
|
|
1981
|
-
if (!VpIsZero(
|
1777
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
1982
1778
|
/* result adjustment for negative case */
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
VpAddSub(
|
1988
|
-
|
1989
|
-
*
|
1779
|
+
BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
|
1780
|
+
BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
|
1781
|
+
VpSetPrecLimit(0);
|
1782
|
+
VpAddSub(dv2.real, dv.real, VpOne(), -1);
|
1783
|
+
VpAddSub(md2.real, md.real, b.real, 1);
|
1784
|
+
VpSetPrecLimit(pl);
|
1785
|
+
*div = bdvalue_nullable(dv2);
|
1786
|
+
*mod = bdvalue_nullable(md2);
|
1787
|
+
RB_GC_GUARD(dv2.bigdecimal);
|
1788
|
+
RB_GC_GUARD(md2.bigdecimal);
|
1990
1789
|
}
|
1991
1790
|
else {
|
1992
|
-
*div =
|
1993
|
-
*mod =
|
1791
|
+
*div = bdvalue_nullable(dv);
|
1792
|
+
*mod = bdvalue_nullable(md);
|
1994
1793
|
}
|
1995
|
-
return Qtrue;
|
1996
1794
|
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
return
|
1795
|
+
Done:
|
1796
|
+
RB_GC_GUARD(a.bigdecimal);
|
1797
|
+
RB_GC_GUARD(b.bigdecimal);
|
1798
|
+
RB_GC_GUARD(dv.bigdecimal);
|
1799
|
+
RB_GC_GUARD(md.bigdecimal);
|
1800
|
+
RB_GC_GUARD(res.bigdecimal);
|
1801
|
+
return true;
|
2004
1802
|
}
|
2005
1803
|
|
2006
1804
|
/* call-seq:
|
@@ -2014,85 +1812,31 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
2014
1812
|
static VALUE
|
2015
1813
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
2016
1814
|
{
|
2017
|
-
|
2018
|
-
Real *div = NULL, *mod = NULL;
|
1815
|
+
NULLABLE_BDVALUE div, mod;
|
2019
1816
|
|
2020
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
2021
|
-
|
2022
|
-
return VpCheckGetValue(mod);
|
1817
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
1818
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
2023
1819
|
}
|
2024
1820
|
return DoSomeOne(self, r, '%');
|
2025
1821
|
}
|
2026
1822
|
|
1823
|
+
/* call-seq:
|
1824
|
+
* remainder(value)
|
1825
|
+
*
|
1826
|
+
* Returns the remainder from dividing by the value.
|
1827
|
+
*
|
1828
|
+
* x.remainder(y) means x-y*(x/y).truncate
|
1829
|
+
*/
|
2027
1830
|
static VALUE
|
2028
|
-
|
1831
|
+
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
2029
1832
|
{
|
2030
|
-
|
2031
|
-
size_t mx;
|
2032
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
2033
|
-
Real *f = NULL;
|
1833
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
2034
1834
|
|
2035
|
-
|
2036
|
-
|
2037
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
1835
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
1836
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
2038
1837
|
}
|
2039
|
-
|
2040
|
-
|
2041
|
-
}
|
2042
|
-
else {
|
2043
|
-
b = GetVpValue(r, 0);
|
2044
|
-
}
|
2045
|
-
|
2046
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
2047
|
-
SAVE(b);
|
2048
|
-
|
2049
|
-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
|
2050
|
-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
|
2051
|
-
VpSetZero(*dv, 1);
|
2052
|
-
*rv = a;
|
2053
|
-
return Qnil;
|
2054
|
-
}
|
2055
|
-
|
2056
|
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
|
2057
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2058
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2059
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2060
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2061
|
-
|
2062
|
-
VpDivd(c, res, a, b);
|
2063
|
-
|
2064
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
2065
|
-
|
2066
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
2067
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
2068
|
-
|
2069
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
2070
|
-
|
2071
|
-
VpFrac(f, c);
|
2072
|
-
VpMult(rr, f, b);
|
2073
|
-
VpAddSub(ff, res, rr, 1);
|
2074
|
-
|
2075
|
-
*dv = d;
|
2076
|
-
*rv = ff;
|
2077
|
-
return Qnil;
|
2078
|
-
}
|
2079
|
-
|
2080
|
-
/* call-seq:
|
2081
|
-
* remainder(value)
|
2082
|
-
*
|
2083
|
-
* Returns the remainder from dividing by the value.
|
2084
|
-
*
|
2085
|
-
* x.remainder(y) means x-y*(x/y).truncate
|
2086
|
-
*/
|
2087
|
-
static VALUE
|
2088
|
-
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
2089
|
-
{
|
2090
|
-
VALUE f;
|
2091
|
-
Real *d, *rv = 0;
|
2092
|
-
f = BigDecimal_divremain(self, r, &d, &rv);
|
2093
|
-
if (!NIL_P(f)) return f;
|
2094
|
-
return VpCheckGetValue(rv);
|
2095
|
-
}
|
1838
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
1839
|
+
}
|
2096
1840
|
|
2097
1841
|
/* call-seq:
|
2098
1842
|
* divmod(value)
|
@@ -2119,12 +1863,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2119
1863
|
static VALUE
|
2120
1864
|
BigDecimal_divmod(VALUE self, VALUE r)
|
2121
1865
|
{
|
2122
|
-
|
2123
|
-
Real *div = NULL, *mod = NULL;
|
1866
|
+
NULLABLE_BDVALUE div, mod;
|
2124
1867
|
|
2125
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
2126
|
-
|
2127
|
-
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
|
1868
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
1869
|
+
return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
|
2128
1870
|
}
|
2129
1871
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
2130
1872
|
}
|
@@ -2136,17 +1878,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
2136
1878
|
static inline VALUE
|
2137
1879
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
2138
1880
|
{
|
2139
|
-
ENTER(5);
|
2140
1881
|
SIGNED_VALUE ix;
|
2141
|
-
|
2142
|
-
Real *av = NULL, *bv = NULL, *cv = NULL;
|
2143
|
-
size_t mx, pl;
|
1882
|
+
BDVALUE av, bv, cv, res;
|
2144
1883
|
|
2145
1884
|
if (NIL_P(n)) { /* div in Float sense */
|
2146
|
-
|
2147
|
-
|
2148
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
2149
|
-
return BigDecimal_to_i(
|
1885
|
+
NULLABLE_BDVALUE div;
|
1886
|
+
NULLABLE_BDVALUE mod;
|
1887
|
+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
|
1888
|
+
return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
|
2150
1889
|
}
|
2151
1890
|
return DoSomeOne(self, b, rb_intern("div"));
|
2152
1891
|
}
|
@@ -2154,48 +1893,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2154
1893
|
/* div in BigDecimal sense */
|
2155
1894
|
ix = check_int_precision(n);
|
2156
1895
|
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
GUARD_OBJ(av, GetVpValue(self, 1));
|
2161
|
-
if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) {
|
2162
|
-
/* TODO: I want to refactor this precision control for a float value later
|
2163
|
-
* by introducing an implicit conversion function instead of
|
2164
|
-
* GetVpValueWithPrec. */
|
2165
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1));
|
2166
|
-
}
|
2167
|
-
else {
|
2168
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1));
|
2169
|
-
}
|
1896
|
+
av = GetBDValueMust(self);
|
1897
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
2170
1898
|
|
2171
1899
|
if (ix == 0) {
|
2172
|
-
ssize_t a_prec, b_prec;
|
2173
|
-
VpCountPrecisionAndScale(av, &a_prec, NULL);
|
2174
|
-
VpCountPrecisionAndScale(bv, &b_prec, NULL);
|
1900
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
1901
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
1902
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
2175
1903
|
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
2176
1904
|
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
2177
1905
|
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
1906
|
+
if (limit && limit < ix) ix = limit;
|
2178
1907
|
}
|
2179
1908
|
|
2180
|
-
//
|
2181
|
-
|
1909
|
+
// Needs to calculate 1 extra digit for rounding.
|
1910
|
+
cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
|
1911
|
+
res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
|
1912
|
+
VpDivd(cv.real, res.real, av.real, bv.real);
|
2182
1913
|
|
2183
|
-
|
2184
|
-
if (mx <= av->Prec) mx = av->Prec + 1;
|
2185
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig()));
|
2186
|
-
VpDivd(cv, res, av, bv);
|
2187
|
-
VpSetPrecLimit(pl);
|
2188
|
-
if (!VpIsZero(res)) {
|
1914
|
+
if (!VpIsZero(res.real)) {
|
2189
1915
|
// Remainder value affects rounding result.
|
2190
|
-
// ROUND_UP cv = 0.1e0 with
|
1916
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
2191
1917
|
// 0.1e0 if remainder == 0
|
2192
1918
|
// 0.1000000001e0 if remainder != 0
|
2193
1919
|
size_t idx = roomof(ix, BASE_FIG);
|
2194
|
-
while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0;
|
2195
|
-
if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++;
|
1920
|
+
while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
|
1921
|
+
if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
|
2196
1922
|
}
|
2197
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
2198
|
-
|
1923
|
+
VpLeftRound(cv.real, VpGetRoundMode(), ix);
|
1924
|
+
|
1925
|
+
RB_GC_GUARD(av.bigdecimal);
|
1926
|
+
RB_GC_GUARD(bv.bigdecimal);
|
1927
|
+
RB_GC_GUARD(res.bigdecimal);
|
1928
|
+
return CheckGetValue(cv);
|
2199
1929
|
}
|
2200
1930
|
|
2201
1931
|
/*
|
@@ -2271,18 +2001,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
2271
2001
|
static VALUE
|
2272
2002
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
2273
2003
|
{
|
2274
|
-
|
2275
|
-
Real *cv;
|
2276
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2277
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
2278
|
-
else {
|
2279
|
-
size_t pl = VpSetPrecLimit(0);
|
2280
|
-
VALUE c = BigDecimal_add(self, b);
|
2281
|
-
VpSetPrecLimit(pl);
|
2282
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2283
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2284
|
-
return VpCheckGetValue(cv);
|
2285
|
-
}
|
2004
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
2286
2005
|
}
|
2287
2006
|
|
2288
2007
|
/* call-seq:
|
@@ -2301,18 +2020,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2301
2020
|
static VALUE
|
2302
2021
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
2303
2022
|
{
|
2304
|
-
|
2305
|
-
Real *cv;
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2307
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
2308
|
-
else {
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
2310
|
-
VALUE c = BigDecimal_sub(self, b);
|
2311
|
-
VpSetPrecLimit(pl);
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2314
|
-
return VpCheckGetValue(cv);
|
2315
|
-
}
|
2023
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
2316
2024
|
}
|
2317
2025
|
|
2318
2026
|
/*
|
@@ -2344,18 +2052,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2344
2052
|
static VALUE
|
2345
2053
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
2346
2054
|
{
|
2347
|
-
|
2348
|
-
Real *cv;
|
2349
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2350
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
2351
|
-
else {
|
2352
|
-
size_t pl = VpSetPrecLimit(0);
|
2353
|
-
VALUE c = BigDecimal_mult(self, b);
|
2354
|
-
VpSetPrecLimit(pl);
|
2355
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2356
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2357
|
-
return VpCheckGetValue(cv);
|
2358
|
-
}
|
2055
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
2359
2056
|
}
|
2360
2057
|
|
2361
2058
|
/*
|
@@ -2372,41 +2069,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2372
2069
|
static VALUE
|
2373
2070
|
BigDecimal_abs(VALUE self)
|
2374
2071
|
{
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2381
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2382
|
-
VpAsgn(c, a, 1);
|
2383
|
-
VpChangeSign(c, 1);
|
2384
|
-
return VpCheckGetValue(c);
|
2385
|
-
}
|
2386
|
-
|
2387
|
-
/* call-seq:
|
2388
|
-
* sqrt(n)
|
2389
|
-
*
|
2390
|
-
* Returns the square root of the value.
|
2391
|
-
*
|
2392
|
-
* Result has at least n significant digits.
|
2393
|
-
*/
|
2394
|
-
static VALUE
|
2395
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
2396
|
-
{
|
2397
|
-
ENTER(5);
|
2398
|
-
Real *c, *a;
|
2399
|
-
size_t mx, n;
|
2400
|
-
|
2401
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2402
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2403
|
-
|
2404
|
-
n = check_int_precision(nFig);
|
2405
|
-
n += VpDblFig() + VpBaseFig();
|
2406
|
-
if (mx <= n) mx = n;
|
2407
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2408
|
-
VpSqrt(c, a);
|
2409
|
-
return VpCheckGetValue(c);
|
2072
|
+
BDVALUE a = GetBDValueMust(self);
|
2073
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
2074
|
+
VpAsgn(c.real, a.real, 10);
|
2075
|
+
VpChangeSign(c.real, 1);
|
2076
|
+
RB_GC_GUARD(a.bigdecimal);
|
2077
|
+
return CheckGetValue(c);
|
2410
2078
|
}
|
2411
2079
|
|
2412
2080
|
/* Return the integer part of the number, as a BigDecimal.
|
@@ -2414,15 +2082,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2414
2082
|
static VALUE
|
2415
2083
|
BigDecimal_fix(VALUE self)
|
2416
2084
|
{
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
2423
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2424
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
2425
|
-
return VpCheckGetValue(c);
|
2085
|
+
BDVALUE a = GetBDValueMust(self);
|
2086
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
2087
|
+
VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
|
2088
|
+
RB_GC_GUARD(a.bigdecimal);
|
2089
|
+
return CheckGetValue(c);
|
2426
2090
|
}
|
2427
2091
|
|
2428
2092
|
/* call-seq:
|
@@ -2454,13 +2118,12 @@ BigDecimal_fix(VALUE self)
|
|
2454
2118
|
static VALUE
|
2455
2119
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
2456
2120
|
{
|
2457
|
-
|
2458
|
-
Real *c, *a;
|
2121
|
+
BDVALUE c, a;
|
2459
2122
|
int iLoc = 0;
|
2460
2123
|
VALUE vLoc;
|
2461
2124
|
VALUE vRound;
|
2462
2125
|
int round_to_int = 0;
|
2463
|
-
size_t mx
|
2126
|
+
size_t mx;
|
2464
2127
|
|
2465
2128
|
unsigned short sw = VpGetRoundMode();
|
2466
2129
|
|
@@ -2491,16 +2154,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2491
2154
|
break;
|
2492
2155
|
}
|
2493
2156
|
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2157
|
+
a = GetBDValueMust(self);
|
2158
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
2159
|
+
c = NewZeroWrap(1, mx);
|
2160
|
+
|
2161
|
+
VpActiveRound(c.real, a.real, sw, iLoc);
|
2162
|
+
|
2163
|
+
RB_GC_GUARD(a.bigdecimal);
|
2164
|
+
|
2500
2165
|
if (round_to_int) {
|
2501
|
-
return BigDecimal_to_i(
|
2166
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
2167
|
+
}
|
2168
|
+
return CheckGetValue(c);
|
2169
|
+
}
|
2170
|
+
|
2171
|
+
static VALUE
|
2172
|
+
BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
|
2173
|
+
{
|
2174
|
+
BDVALUE c, a;
|
2175
|
+
int iLoc;
|
2176
|
+
VALUE vLoc;
|
2177
|
+
size_t mx;
|
2178
|
+
|
2179
|
+
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
2180
|
+
iLoc = 0;
|
2181
|
+
}
|
2182
|
+
else {
|
2183
|
+
iLoc = NUM2INT(vLoc);
|
2502
2184
|
}
|
2503
|
-
|
2185
|
+
|
2186
|
+
a = GetBDValueMust(self);
|
2187
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
2188
|
+
c = NewZeroWrap(1, mx);
|
2189
|
+
VpActiveRound(c.real, a.real, rounding_mode, iLoc);
|
2190
|
+
|
2191
|
+
RB_GC_GUARD(a.bigdecimal);
|
2192
|
+
|
2193
|
+
if (argc == 0) {
|
2194
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
2195
|
+
}
|
2196
|
+
return CheckGetValue(c);
|
2504
2197
|
}
|
2505
2198
|
|
2506
2199
|
/* call-seq:
|
@@ -2525,28 +2218,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2525
2218
|
static VALUE
|
2526
2219
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
2527
2220
|
{
|
2528
|
-
|
2529
|
-
Real *c, *a;
|
2530
|
-
int iLoc;
|
2531
|
-
VALUE vLoc;
|
2532
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2533
|
-
|
2534
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
2535
|
-
iLoc = 0;
|
2536
|
-
}
|
2537
|
-
else {
|
2538
|
-
iLoc = NUM2INT(vLoc);
|
2539
|
-
}
|
2540
|
-
|
2541
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2542
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2543
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2544
|
-
VpSetPrecLimit(pl);
|
2545
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
2546
|
-
if (argc == 0) {
|
2547
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2548
|
-
}
|
2549
|
-
return VpCheckGetValue(c);
|
2221
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
2550
2222
|
}
|
2551
2223
|
|
2552
2224
|
/* Return the fractional part of the number, as a BigDecimal.
|
@@ -2554,15 +2226,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2554
2226
|
static VALUE
|
2555
2227
|
BigDecimal_frac(VALUE self)
|
2556
2228
|
{
|
2557
|
-
|
2558
|
-
|
2559
|
-
|
2560
|
-
|
2561
|
-
|
2562
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2563
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2564
|
-
VpFrac(c, a);
|
2565
|
-
return VpCheckGetValue(c);
|
2229
|
+
BDVALUE a = GetBDValueMust(self);
|
2230
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
2231
|
+
VpFrac(c.real, a.real);
|
2232
|
+
RB_GC_GUARD(a.bigdecimal);
|
2233
|
+
return CheckGetValue(c);
|
2566
2234
|
}
|
2567
2235
|
|
2568
2236
|
/* call-seq:
|
@@ -2585,31 +2253,7 @@ BigDecimal_frac(VALUE self)
|
|
2585
2253
|
static VALUE
|
2586
2254
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
2587
2255
|
{
|
2588
|
-
|
2589
|
-
Real *c, *a;
|
2590
|
-
int iLoc;
|
2591
|
-
VALUE vLoc;
|
2592
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2593
|
-
|
2594
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
2595
|
-
iLoc = 0;
|
2596
|
-
}
|
2597
|
-
else {
|
2598
|
-
iLoc = NUM2INT(vLoc);
|
2599
|
-
}
|
2600
|
-
|
2601
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2602
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2603
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2604
|
-
VpSetPrecLimit(pl);
|
2605
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
2606
|
-
#ifdef BIGDECIMAL_DEBUG
|
2607
|
-
VPrint(stderr, "floor: c=%\n", c);
|
2608
|
-
#endif
|
2609
|
-
if (argc == 0) {
|
2610
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2611
|
-
}
|
2612
|
-
return VpCheckGetValue(c);
|
2256
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
2613
2257
|
}
|
2614
2258
|
|
2615
2259
|
/* call-seq:
|
@@ -2632,27 +2276,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2632
2276
|
static VALUE
|
2633
2277
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
2634
2278
|
{
|
2635
|
-
|
2636
|
-
Real *c, *a;
|
2637
|
-
int iLoc;
|
2638
|
-
VALUE vLoc;
|
2639
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2640
|
-
|
2641
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
2642
|
-
iLoc = 0;
|
2643
|
-
} else {
|
2644
|
-
iLoc = NUM2INT(vLoc);
|
2645
|
-
}
|
2646
|
-
|
2647
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2648
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2649
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2650
|
-
VpSetPrecLimit(pl);
|
2651
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
2652
|
-
if (argc == 0) {
|
2653
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2654
|
-
}
|
2655
|
-
return VpCheckGetValue(c);
|
2279
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
2656
2280
|
}
|
2657
2281
|
|
2658
2282
|
/* call-seq:
|
@@ -2673,7 +2297,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2673
2297
|
* If s contains a number, a space is inserted after each group of that many
|
2674
2298
|
* digits, starting from '.' and counting outwards.
|
2675
2299
|
*
|
2676
|
-
* If s ends with an 'E',
|
2300
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
2677
2301
|
*
|
2678
2302
|
* If s ends with an 'F', conventional floating point notation is used.
|
2679
2303
|
*
|
@@ -2691,10 +2315,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2691
2315
|
static VALUE
|
2692
2316
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
2693
2317
|
{
|
2694
|
-
ENTER(5);
|
2695
2318
|
int fmt = 0; /* 0: E format, 1: F format */
|
2696
2319
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
2697
|
-
|
2320
|
+
BDVALUE v;
|
2698
2321
|
volatile VALUE str;
|
2699
2322
|
char *psz;
|
2700
2323
|
char ch;
|
@@ -2702,7 +2325,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2702
2325
|
SIGNED_VALUE m;
|
2703
2326
|
VALUE f;
|
2704
2327
|
|
2705
|
-
|
2328
|
+
v = GetBDValueMust(self);
|
2706
2329
|
|
2707
2330
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
2708
2331
|
if (RB_TYPE_P(f, T_STRING)) {
|
@@ -2737,10 +2360,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2737
2360
|
}
|
2738
2361
|
}
|
2739
2362
|
if (fmt) {
|
2740
|
-
nc = VpNumOfChars(
|
2363
|
+
nc = VpNumOfChars(v.real, "F");
|
2741
2364
|
}
|
2742
2365
|
else {
|
2743
|
-
nc = VpNumOfChars(
|
2366
|
+
nc = VpNumOfChars(v.real, "E");
|
2744
2367
|
}
|
2745
2368
|
if (mc > 0) {
|
2746
2369
|
nc += (nc + mc - 1) / mc + 1;
|
@@ -2750,12 +2373,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2750
2373
|
psz = RSTRING_PTR(str);
|
2751
2374
|
|
2752
2375
|
if (fmt) {
|
2753
|
-
VpToFString(
|
2376
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
2754
2377
|
}
|
2755
2378
|
else {
|
2756
|
-
VpToString (
|
2379
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
2757
2380
|
}
|
2758
2381
|
rb_str_resize(str, strlen(psz));
|
2382
|
+
|
2383
|
+
RB_GC_GUARD(v.bigdecimal);
|
2759
2384
|
return str;
|
2760
2385
|
}
|
2761
2386
|
|
@@ -2786,16 +2411,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2786
2411
|
static VALUE
|
2787
2412
|
BigDecimal_split(VALUE self)
|
2788
2413
|
{
|
2789
|
-
|
2790
|
-
Real *vp;
|
2414
|
+
BDVALUE v;
|
2791
2415
|
VALUE obj,str;
|
2792
2416
|
ssize_t e, s;
|
2793
2417
|
char *psz1;
|
2794
2418
|
|
2795
|
-
|
2796
|
-
str = rb_str_new(0, VpNumOfChars(
|
2419
|
+
v = GetBDValueMust(self);
|
2420
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
2797
2421
|
psz1 = RSTRING_PTR(str);
|
2798
|
-
VpSzMantissa(
|
2422
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
2799
2423
|
s = 1;
|
2800
2424
|
if(psz1[0] == '-') {
|
2801
2425
|
size_t len = strlen(psz1 + 1);
|
@@ -2805,13 +2429,15 @@ BigDecimal_split(VALUE self)
|
|
2805
2429
|
s = -1;
|
2806
2430
|
}
|
2807
2431
|
if (psz1[0] == 'N') s = 0; /* NaN */
|
2808
|
-
e = VpExponent10(
|
2432
|
+
e = VpExponent10(v.real);
|
2809
2433
|
obj = rb_ary_new2(4);
|
2810
2434
|
rb_ary_push(obj, INT2FIX(s));
|
2811
2435
|
rb_ary_push(obj, str);
|
2812
2436
|
rb_str_resize(str, strlen(psz1));
|
2813
2437
|
rb_ary_push(obj, INT2FIX(10));
|
2814
2438
|
rb_ary_push(obj, SSIZET2NUM(e));
|
2439
|
+
|
2440
|
+
RB_GC_GUARD(v.bigdecimal);
|
2815
2441
|
return obj;
|
2816
2442
|
}
|
2817
2443
|
|
@@ -2823,7 +2449,7 @@ BigDecimal_split(VALUE self)
|
|
2823
2449
|
static VALUE
|
2824
2450
|
BigDecimal_exponent(VALUE self)
|
2825
2451
|
{
|
2826
|
-
ssize_t e = VpExponent10(
|
2452
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
2827
2453
|
return SSIZET2NUM(e);
|
2828
2454
|
}
|
2829
2455
|
|
@@ -2835,49 +2461,78 @@ BigDecimal_exponent(VALUE self)
|
|
2835
2461
|
static VALUE
|
2836
2462
|
BigDecimal_inspect(VALUE self)
|
2837
2463
|
{
|
2838
|
-
|
2839
|
-
Real *vp;
|
2464
|
+
BDVALUE v;
|
2840
2465
|
volatile VALUE str;
|
2841
2466
|
size_t nc;
|
2842
2467
|
|
2843
|
-
|
2844
|
-
nc = VpNumOfChars(
|
2468
|
+
v = GetBDValueMust(self);
|
2469
|
+
nc = VpNumOfChars(v.real, "E");
|
2845
2470
|
|
2846
2471
|
str = rb_str_new(0, nc);
|
2847
|
-
VpToString(
|
2472
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
2848
2473
|
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
2849
|
-
return str;
|
2850
|
-
}
|
2851
2474
|
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
|
2856
|
-
#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
|
2857
|
-
|
2858
|
-
inline static int
|
2859
|
-
is_integer(VALUE x)
|
2860
|
-
{
|
2861
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
2475
|
+
RB_GC_GUARD(v.bigdecimal);
|
2476
|
+
return str;
|
2862
2477
|
}
|
2863
2478
|
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2479
|
+
/* Returns self * 10**v without changing the precision.
|
2480
|
+
* This method is currently for internal use.
|
2481
|
+
*
|
2482
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
2483
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
2484
|
+
*/
|
2485
|
+
static VALUE
|
2486
|
+
BigDecimal_decimal_shift(VALUE self, VALUE v)
|
2487
|
+
{
|
2488
|
+
BDVALUE a, c;
|
2489
|
+
ssize_t shift, exponentShift;
|
2490
|
+
bool shiftDown;
|
2491
|
+
size_t prec;
|
2492
|
+
DECDIG ex, iex;
|
2493
|
+
|
2494
|
+
a = GetBDValueMust(self);
|
2495
|
+
shift = NUM2SSIZET(rb_to_int(v));
|
2496
|
+
|
2497
|
+
if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
|
2498
|
+
|
2499
|
+
exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
|
2500
|
+
shift -= exponentShift * BASE_FIG;
|
2501
|
+
ex = 1;
|
2502
|
+
for (int i = 0; i < shift; i++) ex *= 10;
|
2503
|
+
shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
|
2504
|
+
iex = BASE / ex;
|
2505
|
+
|
2506
|
+
prec = a.real->Prec + shiftDown;
|
2507
|
+
c = NewZeroWrap(1, prec * BASE_FIG);
|
2508
|
+
if (shift == 0) {
|
2509
|
+
VpAsgn(c.real, a.real, 1);
|
2510
|
+
} else if (shiftDown) {
|
2511
|
+
DECDIG carry = 0;
|
2512
|
+
exponentShift++;
|
2513
|
+
for (size_t i = 0; i < a.real->Prec; i++) {
|
2514
|
+
DECDIG v = a.real->frac[i];
|
2515
|
+
c.real->frac[i] = carry * ex + v / iex;
|
2516
|
+
carry = v % iex;
|
2517
|
+
}
|
2518
|
+
c.real->frac[a.real->Prec] = carry * ex;
|
2519
|
+
} else {
|
2520
|
+
DECDIG carry = 0;
|
2521
|
+
for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
|
2522
|
+
DECDIG v = a.real->frac[i];
|
2523
|
+
c.real->frac[i] = v % iex * ex + carry;
|
2524
|
+
carry = v / iex;
|
2525
|
+
}
|
2875
2526
|
}
|
2876
|
-
|
2527
|
+
while (c.real->frac[prec - 1] == 0) prec--;
|
2528
|
+
c.real->Prec = prec;
|
2529
|
+
c.real->sign = a.real->sign;
|
2530
|
+
c.real->exponent = a.real->exponent;
|
2531
|
+
AddExponent(c.real, exponentShift);
|
2532
|
+
RB_GC_GUARD(a.bigdecimal);
|
2533
|
+
return CheckGetValue(c);
|
2877
2534
|
}
|
2878
2535
|
|
2879
|
-
#define is_positive(x) (!is_negative(x))
|
2880
|
-
|
2881
2536
|
inline static int
|
2882
2537
|
is_zero(VALUE x)
|
2883
2538
|
{
|
@@ -2901,344 +2556,6 @@ is_zero(VALUE x)
|
|
2901
2556
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
2902
2557
|
}
|
2903
2558
|
|
2904
|
-
inline static int
|
2905
|
-
is_one(VALUE x)
|
2906
|
-
{
|
2907
|
-
VALUE num, den;
|
2908
|
-
|
2909
|
-
switch (TYPE(x)) {
|
2910
|
-
case T_FIXNUM:
|
2911
|
-
return FIX2LONG(x) == 1;
|
2912
|
-
|
2913
|
-
case T_BIGNUM:
|
2914
|
-
return Qfalse;
|
2915
|
-
|
2916
|
-
case T_RATIONAL:
|
2917
|
-
num = rb_rational_num(x);
|
2918
|
-
den = rb_rational_den(x);
|
2919
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
2920
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
2921
|
-
|
2922
|
-
default:
|
2923
|
-
break;
|
2924
|
-
}
|
2925
|
-
|
2926
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
2927
|
-
}
|
2928
|
-
|
2929
|
-
inline static int
|
2930
|
-
is_even(VALUE x)
|
2931
|
-
{
|
2932
|
-
switch (TYPE(x)) {
|
2933
|
-
case T_FIXNUM:
|
2934
|
-
return (FIX2LONG(x) % 2) == 0;
|
2935
|
-
|
2936
|
-
case T_BIGNUM:
|
2937
|
-
{
|
2938
|
-
unsigned long l;
|
2939
|
-
rb_big_pack(x, &l, 1);
|
2940
|
-
return l % 2 == 0;
|
2941
|
-
}
|
2942
|
-
|
2943
|
-
default:
|
2944
|
-
break;
|
2945
|
-
}
|
2946
|
-
|
2947
|
-
return 0;
|
2948
|
-
}
|
2949
|
-
|
2950
|
-
static VALUE
|
2951
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
2952
|
-
{
|
2953
|
-
VALUE log_x, multiplied, y;
|
2954
|
-
volatile VALUE obj = exp->obj;
|
2955
|
-
|
2956
|
-
if (VpIsZero(exp)) {
|
2957
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
2958
|
-
}
|
2959
|
-
|
2960
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
2961
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
2962
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
2963
|
-
RB_GC_GUARD(obj);
|
2964
|
-
|
2965
|
-
return y;
|
2966
|
-
}
|
2967
|
-
|
2968
|
-
/* call-seq:
|
2969
|
-
* power(n)
|
2970
|
-
* power(n, prec)
|
2971
|
-
*
|
2972
|
-
* Returns the value raised to the power of n.
|
2973
|
-
*
|
2974
|
-
* Note that n must be an Integer.
|
2975
|
-
*
|
2976
|
-
* Also available as the operator **.
|
2977
|
-
*/
|
2978
|
-
static VALUE
|
2979
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
2980
|
-
{
|
2981
|
-
ENTER(5);
|
2982
|
-
VALUE vexp, prec;
|
2983
|
-
Real* exp = NULL;
|
2984
|
-
Real *x, *y;
|
2985
|
-
ssize_t mp, ma, n;
|
2986
|
-
SIGNED_VALUE int_exp;
|
2987
|
-
double d;
|
2988
|
-
|
2989
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
2990
|
-
|
2991
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
2992
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
2993
|
-
|
2994
|
-
if (VpIsNaN(x)) {
|
2995
|
-
y = NewZeroWrapLimited(1, n);
|
2996
|
-
VpSetNaN(y);
|
2997
|
-
RB_GC_GUARD(y->obj);
|
2998
|
-
return VpCheckGetValue(y);
|
2999
|
-
}
|
3000
|
-
|
3001
|
-
retry:
|
3002
|
-
switch (TYPE(vexp)) {
|
3003
|
-
case T_FIXNUM:
|
3004
|
-
break;
|
3005
|
-
|
3006
|
-
case T_BIGNUM:
|
3007
|
-
break;
|
3008
|
-
|
3009
|
-
case T_FLOAT:
|
3010
|
-
d = RFLOAT_VALUE(vexp);
|
3011
|
-
if (d == round(d)) {
|
3012
|
-
if (FIXABLE(d)) {
|
3013
|
-
vexp = LONG2FIX((long)d);
|
3014
|
-
}
|
3015
|
-
else {
|
3016
|
-
vexp = rb_dbl2big(d);
|
3017
|
-
}
|
3018
|
-
goto retry;
|
3019
|
-
}
|
3020
|
-
if (NIL_P(prec)) {
|
3021
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
3022
|
-
}
|
3023
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
3024
|
-
break;
|
3025
|
-
|
3026
|
-
case T_RATIONAL:
|
3027
|
-
if (is_zero(rb_rational_num(vexp))) {
|
3028
|
-
if (is_positive(vexp)) {
|
3029
|
-
vexp = INT2FIX(0);
|
3030
|
-
goto retry;
|
3031
|
-
}
|
3032
|
-
}
|
3033
|
-
else if (is_one(rb_rational_den(vexp))) {
|
3034
|
-
vexp = rb_rational_num(vexp);
|
3035
|
-
goto retry;
|
3036
|
-
}
|
3037
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
3038
|
-
if (NIL_P(prec)) {
|
3039
|
-
n += n;
|
3040
|
-
}
|
3041
|
-
break;
|
3042
|
-
|
3043
|
-
case T_DATA:
|
3044
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
3045
|
-
VALUE zero = INT2FIX(0);
|
3046
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
3047
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
3048
|
-
vexp = BigDecimal_to_i(vexp);
|
3049
|
-
goto retry;
|
3050
|
-
}
|
3051
|
-
if (NIL_P(prec)) {
|
3052
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
3053
|
-
n += y->Prec*VpBaseFig();
|
3054
|
-
}
|
3055
|
-
exp = DATA_PTR(vexp);
|
3056
|
-
break;
|
3057
|
-
}
|
3058
|
-
/* fall through */
|
3059
|
-
default:
|
3060
|
-
rb_raise(rb_eTypeError,
|
3061
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
3062
|
-
RB_OBJ_CLASSNAME(vexp));
|
3063
|
-
}
|
3064
|
-
|
3065
|
-
if (VpIsZero(x)) {
|
3066
|
-
if (is_negative(vexp)) {
|
3067
|
-
y = NewZeroWrapNolimit(1, n);
|
3068
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3069
|
-
if (is_integer(vexp)) {
|
3070
|
-
if (is_even(vexp)) {
|
3071
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
3072
|
-
VpSetPosInf(y);
|
3073
|
-
}
|
3074
|
-
else {
|
3075
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
3076
|
-
VpSetNegInf(y);
|
3077
|
-
}
|
3078
|
-
}
|
3079
|
-
else {
|
3080
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
3081
|
-
VpSetPosInf(y);
|
3082
|
-
}
|
3083
|
-
}
|
3084
|
-
else {
|
3085
|
-
/* (+0) ** (-num) -> Infinity */
|
3086
|
-
VpSetPosInf(y);
|
3087
|
-
}
|
3088
|
-
RB_GC_GUARD(y->obj);
|
3089
|
-
return VpCheckGetValue(y);
|
3090
|
-
}
|
3091
|
-
else if (is_zero(vexp)) {
|
3092
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3093
|
-
}
|
3094
|
-
else {
|
3095
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3096
|
-
}
|
3097
|
-
}
|
3098
|
-
|
3099
|
-
if (is_zero(vexp)) {
|
3100
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3101
|
-
}
|
3102
|
-
else if (is_one(vexp)) {
|
3103
|
-
return self;
|
3104
|
-
}
|
3105
|
-
|
3106
|
-
if (VpIsInf(x)) {
|
3107
|
-
if (is_negative(vexp)) {
|
3108
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3109
|
-
if (is_integer(vexp)) {
|
3110
|
-
if (is_even(vexp)) {
|
3111
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
3112
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3113
|
-
}
|
3114
|
-
else {
|
3115
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
3116
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3117
|
-
}
|
3118
|
-
}
|
3119
|
-
else {
|
3120
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
3121
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3122
|
-
}
|
3123
|
-
}
|
3124
|
-
else {
|
3125
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3126
|
-
}
|
3127
|
-
}
|
3128
|
-
else {
|
3129
|
-
y = NewZeroWrapLimited(1, n);
|
3130
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3131
|
-
if (is_integer(vexp)) {
|
3132
|
-
if (is_even(vexp)) {
|
3133
|
-
VpSetPosInf(y);
|
3134
|
-
}
|
3135
|
-
else {
|
3136
|
-
VpSetNegInf(y);
|
3137
|
-
}
|
3138
|
-
}
|
3139
|
-
else {
|
3140
|
-
/* TODO: support complex */
|
3141
|
-
rb_raise(rb_eMathDomainError,
|
3142
|
-
"a non-integral exponent for a negative base");
|
3143
|
-
}
|
3144
|
-
}
|
3145
|
-
else {
|
3146
|
-
VpSetPosInf(y);
|
3147
|
-
}
|
3148
|
-
return VpCheckGetValue(y);
|
3149
|
-
}
|
3150
|
-
}
|
3151
|
-
|
3152
|
-
if (exp != NULL) {
|
3153
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
3154
|
-
}
|
3155
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
3156
|
-
VALUE abs_value = BigDecimal_abs(self);
|
3157
|
-
if (is_one(abs_value)) {
|
3158
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3159
|
-
}
|
3160
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
3161
|
-
if (is_negative(vexp)) {
|
3162
|
-
y = NewZeroWrapLimited(1, n);
|
3163
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
3164
|
-
return VpCheckGetValue(y);
|
3165
|
-
}
|
3166
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
3167
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3168
|
-
}
|
3169
|
-
else {
|
3170
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3171
|
-
}
|
3172
|
-
}
|
3173
|
-
else {
|
3174
|
-
if (is_positive(vexp)) {
|
3175
|
-
y = NewZeroWrapLimited(1, n);
|
3176
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
3177
|
-
return VpCheckGetValue(y);
|
3178
|
-
}
|
3179
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
3180
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3181
|
-
}
|
3182
|
-
else {
|
3183
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3184
|
-
}
|
3185
|
-
}
|
3186
|
-
}
|
3187
|
-
|
3188
|
-
int_exp = FIX2LONG(vexp);
|
3189
|
-
ma = int_exp;
|
3190
|
-
if (ma < 0) ma = -ma;
|
3191
|
-
if (ma == 0) ma = 1;
|
3192
|
-
|
3193
|
-
if (VpIsDef(x)) {
|
3194
|
-
mp = x->Prec * (VpBaseFig() + 1);
|
3195
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
3196
|
-
}
|
3197
|
-
else {
|
3198
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
3199
|
-
}
|
3200
|
-
VpPowerByInt(y, x, int_exp);
|
3201
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
3202
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
3203
|
-
}
|
3204
|
-
return VpCheckGetValue(y);
|
3205
|
-
}
|
3206
|
-
|
3207
|
-
/* call-seq:
|
3208
|
-
* self ** other -> bigdecimal
|
3209
|
-
*
|
3210
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
3211
|
-
*
|
3212
|
-
* b = BigDecimal('3.14')
|
3213
|
-
* b ** 2 # => 0.98596e1
|
3214
|
-
* b ** 2.0 # => 0.98596e1
|
3215
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
3216
|
-
*
|
3217
|
-
* Related: BigDecimal#power.
|
3218
|
-
*
|
3219
|
-
*/
|
3220
|
-
static VALUE
|
3221
|
-
BigDecimal_power_op(VALUE self, VALUE exp)
|
3222
|
-
{
|
3223
|
-
return BigDecimal_power(1, &exp, self);
|
3224
|
-
}
|
3225
|
-
|
3226
|
-
/* :nodoc:
|
3227
|
-
*
|
3228
|
-
* private method for dup and clone the provided BigDecimal +other+
|
3229
|
-
*/
|
3230
|
-
static VALUE
|
3231
|
-
BigDecimal_initialize_copy(VALUE self, VALUE other)
|
3232
|
-
{
|
3233
|
-
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
|
3234
|
-
Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
|
3235
|
-
|
3236
|
-
if (self != other) {
|
3237
|
-
DATA_PTR(self) = VpCopy(pv, x);
|
3238
|
-
}
|
3239
|
-
return self;
|
3240
|
-
}
|
3241
|
-
|
3242
2559
|
/* :nodoc: */
|
3243
2560
|
static VALUE
|
3244
2561
|
BigDecimal_clone(VALUE self)
|
@@ -3277,20 +2594,18 @@ check_exception(VALUE bd)
|
|
3277
2594
|
|
3278
2595
|
Real *vp;
|
3279
2596
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
3280
|
-
|
2597
|
+
VpCheckException(vp, false);
|
3281
2598
|
|
3282
2599
|
return bd;
|
3283
2600
|
}
|
3284
2601
|
|
3285
2602
|
static VALUE
|
3286
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
2603
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
3287
2604
|
{
|
3288
|
-
|
3289
|
-
|
2605
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
3290
2606
|
Real *vp;
|
3291
2607
|
if (uval == 0) {
|
3292
2608
|
vp = rbd_allocate_struct(1);
|
3293
|
-
vp->MaxPrec = 1;
|
3294
2609
|
vp->Prec = 1;
|
3295
2610
|
vp->exponent = 1;
|
3296
2611
|
VpSetZero(vp, 1);
|
@@ -3298,7 +2613,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
3298
2613
|
}
|
3299
2614
|
else if (uval < BASE) {
|
3300
2615
|
vp = rbd_allocate_struct(1);
|
3301
|
-
vp->MaxPrec = 1;
|
3302
2616
|
vp->Prec = 1;
|
3303
2617
|
vp->exponent = 1;
|
3304
2618
|
VpSetSign(vp, 1);
|
@@ -3324,21 +2638,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
3324
2638
|
|
3325
2639
|
const size_t exp = len + ntz;
|
3326
2640
|
vp = rbd_allocate_struct(len);
|
3327
|
-
vp->MaxPrec = len;
|
3328
2641
|
vp->Prec = len;
|
3329
2642
|
vp->exponent = exp;
|
3330
2643
|
VpSetSign(vp, 1);
|
3331
2644
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
3332
2645
|
}
|
3333
2646
|
|
3334
|
-
return BigDecimal_wrap_struct(
|
2647
|
+
return BigDecimal_wrap_struct(null_wrapped, vp);
|
3335
2648
|
}
|
3336
2649
|
|
3337
2650
|
static VALUE
|
3338
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
2651
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
3339
2652
|
{
|
3340
2653
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
3341
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
2654
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
3342
2655
|
if (ival < 0) {
|
3343
2656
|
Real *vp;
|
3344
2657
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
@@ -3348,7 +2661,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
|
|
3348
2661
|
}
|
3349
2662
|
|
3350
2663
|
static VALUE
|
3351
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
2664
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
3352
2665
|
{
|
3353
2666
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
3354
2667
|
|
@@ -3360,40 +2673,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
3360
2673
|
}
|
3361
2674
|
if (size <= sizeof(long)) {
|
3362
2675
|
if (sign < 0) {
|
3363
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
2676
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
3364
2677
|
}
|
3365
2678
|
else {
|
3366
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
2679
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
3367
2680
|
}
|
3368
2681
|
}
|
3369
2682
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
3370
2683
|
else if (size <= sizeof(LONG_LONG)) {
|
3371
2684
|
if (sign < 0) {
|
3372
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
2685
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
3373
2686
|
}
|
3374
2687
|
else {
|
3375
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
2688
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
3376
2689
|
}
|
3377
2690
|
}
|
3378
2691
|
#endif
|
3379
2692
|
else {
|
3380
2693
|
VALUE str = rb_big2str(val, 10);
|
3381
|
-
|
3382
|
-
|
2694
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
2695
|
+
RSTRING_PTR(str),
|
2696
|
+
rb_cBigDecimal,
|
2697
|
+
true,
|
2698
|
+
true
|
2699
|
+
));
|
3383
2700
|
RB_GC_GUARD(str);
|
3384
|
-
return
|
2701
|
+
return CheckGetValue(v);
|
3385
2702
|
}
|
3386
2703
|
}
|
3387
2704
|
|
3388
2705
|
static VALUE
|
3389
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
2706
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
3390
2707
|
{
|
3391
2708
|
assert(RB_INTEGER_TYPE_P(val));
|
3392
2709
|
if (FIXNUM_P(val)) {
|
3393
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
2710
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
3394
2711
|
}
|
3395
2712
|
else {
|
3396
|
-
return rb_big_convert_to_BigDecimal(val
|
2713
|
+
return rb_big_convert_to_BigDecimal(val);
|
3397
2714
|
}
|
3398
2715
|
}
|
3399
2716
|
|
@@ -3428,11 +2745,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3428
2745
|
}
|
3429
2746
|
|
3430
2747
|
if (digs == SIZE_MAX) {
|
3431
|
-
|
3432
|
-
return Qnil;
|
3433
|
-
rb_raise(rb_eArgError,
|
3434
|
-
"can't omit precision for a %"PRIsVALUE".",
|
3435
|
-
CLASS_OF(val));
|
2748
|
+
digs = 0;
|
3436
2749
|
}
|
3437
2750
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
3438
2751
|
if (!raise_exception)
|
@@ -3547,7 +2860,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3547
2860
|
exp = -exp;
|
3548
2861
|
}
|
3549
2862
|
|
3550
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
2863
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
3551
2864
|
Real *vp;
|
3552
2865
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
3553
2866
|
assert(vp->Prec == prec);
|
@@ -3570,28 +2883,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3570
2883
|
CLASS_OF(val));
|
3571
2884
|
}
|
3572
2885
|
|
3573
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
2886
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
3574
2887
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
3575
2888
|
return d;
|
3576
2889
|
}
|
3577
2890
|
|
3578
2891
|
static VALUE
|
3579
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
2892
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
3580
2893
|
{
|
3581
|
-
|
3582
|
-
|
3583
|
-
|
3584
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
3585
|
-
if (!vp)
|
3586
|
-
return Qnil;
|
3587
|
-
return VpCheckGetValue(vp);
|
2894
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
|
2895
|
+
if (v.bigdecimal_or_nil == Qnil) return Qnil;
|
2896
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
3588
2897
|
}
|
3589
2898
|
|
3590
2899
|
static inline VALUE
|
3591
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
2900
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
3592
2901
|
{
|
3593
2902
|
const char *c_str = StringValueCStr(val);
|
3594
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
2903
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
3595
2904
|
}
|
3596
2905
|
|
3597
2906
|
static VALUE
|
@@ -3619,17 +2928,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3619
2928
|
if (digs == SIZE_MAX)
|
3620
2929
|
return check_exception(val);
|
3621
2930
|
|
2931
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
3622
2932
|
Real *vp;
|
3623
2933
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
3624
|
-
|
3625
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
3626
2934
|
vp = VpCopy(NULL, vp);
|
2935
|
+
RB_GC_GUARD(val);
|
2936
|
+
|
2937
|
+
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
3627
2938
|
/* TODO: rounding */
|
3628
|
-
|
3629
|
-
return VpCheckGetValue(vp);
|
2939
|
+
return check_exception(copy);
|
3630
2940
|
}
|
3631
2941
|
else if (RB_INTEGER_TYPE_P(val)) {
|
3632
|
-
return rb_inum_convert_to_BigDecimal(val
|
2942
|
+
return rb_inum_convert_to_BigDecimal(val);
|
3633
2943
|
}
|
3634
2944
|
else if (RB_FLOAT_TYPE_P(val)) {
|
3635
2945
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
@@ -3647,7 +2957,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3647
2957
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
3648
2958
|
}
|
3649
2959
|
else if (RB_TYPE_P(val, T_STRING)) {
|
3650
|
-
return rb_str_convert_to_BigDecimal(val,
|
2960
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
3651
2961
|
}
|
3652
2962
|
|
3653
2963
|
/* TODO: chheck to_d */
|
@@ -3661,7 +2971,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3661
2971
|
}
|
3662
2972
|
return Qnil;
|
3663
2973
|
}
|
3664
|
-
return rb_str_convert_to_BigDecimal(str,
|
2974
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
3665
2975
|
}
|
3666
2976
|
|
3667
2977
|
/* call-seq:
|
@@ -3682,12 +2992,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3682
2992
|
*
|
3683
2993
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
3684
2994
|
*
|
3685
|
-
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
|
2995
|
+
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
|
3686
2996
|
* BigDecimal(2) # => 0.2e1
|
3687
2997
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
3688
2998
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
3689
|
-
* #
|
3690
|
-
*
|
2999
|
+
* BigDecimal(2.0) # => 0.2e1
|
3000
|
+
* # Rational value requires ndigits.
|
3691
3001
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
3692
3002
|
*
|
3693
3003
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
@@ -3751,11 +3061,11 @@ static VALUE
|
|
3751
3061
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
3752
3062
|
{
|
3753
3063
|
char const *c_str = StringValueCStr(str);
|
3754
|
-
|
3755
|
-
if (
|
3064
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
3065
|
+
if (v.bigdecimal_or_nil == Qnil)
|
3756
3066
|
return Qnil;
|
3757
3067
|
else
|
3758
|
-
return
|
3068
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
3759
3069
|
}
|
3760
3070
|
|
3761
3071
|
/*
|
@@ -3810,7 +3120,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
3810
3120
|
static VALUE
|
3811
3121
|
BigDecimal_sign(VALUE self)
|
3812
3122
|
{ /* sign */
|
3813
|
-
int s =
|
3123
|
+
int s = GetSelfVpValue(self)->sign;
|
3814
3124
|
return INT2FIX(s);
|
3815
3125
|
}
|
3816
3126
|
|
@@ -3882,310 +3192,15 @@ BigDecimal_save_rounding_mode(VALUE self)
|
|
3882
3192
|
* puts BigDecimal.limit
|
3883
3193
|
*
|
3884
3194
|
*/
|
3885
|
-
static VALUE
|
3886
|
-
BigDecimal_save_limit(VALUE self)
|
3887
|
-
{
|
3888
|
-
size_t const limit = VpGetPrecLimit();
|
3889
|
-
int state;
|
3890
|
-
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
3891
|
-
VpSetPrecLimit(limit);
|
3892
|
-
if (state) rb_jump_tag(state);
|
3893
|
-
return ret;
|
3894
|
-
}
|
3895
|
-
|
3896
|
-
/* call-seq:
|
3897
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
3898
|
-
*
|
3899
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
3900
|
-
* power of +decimal+, to the specified number of digits of precision.
|
3901
|
-
*
|
3902
|
-
* If +decimal+ is infinity, returns Infinity.
|
3903
|
-
*
|
3904
|
-
* If +decimal+ is NaN, returns NaN.
|
3905
|
-
*/
|
3906
|
-
static VALUE
|
3907
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
3908
|
-
{
|
3909
|
-
ssize_t prec, n, i;
|
3910
|
-
Real* vx = NULL;
|
3911
|
-
VALUE one, d, y;
|
3912
|
-
int negative = 0;
|
3913
|
-
int infinite = 0;
|
3914
|
-
int nan = 0;
|
3915
|
-
double flo;
|
3916
|
-
|
3917
|
-
prec = NUM2SSIZET(vprec);
|
3918
|
-
if (prec <= 0) {
|
3919
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
3920
|
-
}
|
3921
|
-
|
3922
|
-
/* TODO: the following switch statement is almost same as one in the
|
3923
|
-
* BigDecimalCmp function. */
|
3924
|
-
switch (TYPE(x)) {
|
3925
|
-
case T_DATA:
|
3926
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
3927
|
-
vx = DATA_PTR(x);
|
3928
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
3929
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
3930
|
-
nan = VpIsNaN(vx);
|
3931
|
-
break;
|
3932
|
-
|
3933
|
-
case T_FIXNUM:
|
3934
|
-
/* fall through */
|
3935
|
-
case T_BIGNUM:
|
3936
|
-
vx = GetVpValue(x, 0);
|
3937
|
-
break;
|
3938
|
-
|
3939
|
-
case T_FLOAT:
|
3940
|
-
flo = RFLOAT_VALUE(x);
|
3941
|
-
negative = flo < 0;
|
3942
|
-
infinite = isinf(flo);
|
3943
|
-
nan = isnan(flo);
|
3944
|
-
if (!infinite && !nan) {
|
3945
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
3946
|
-
}
|
3947
|
-
break;
|
3948
|
-
|
3949
|
-
case T_RATIONAL:
|
3950
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
3951
|
-
break;
|
3952
|
-
|
3953
|
-
default:
|
3954
|
-
break;
|
3955
|
-
}
|
3956
|
-
if (infinite) {
|
3957
|
-
if (negative) {
|
3958
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
3959
|
-
}
|
3960
|
-
else {
|
3961
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
3962
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
3963
|
-
RB_GC_GUARD(vy->obj);
|
3964
|
-
return VpCheckGetValue(vy);
|
3965
|
-
}
|
3966
|
-
}
|
3967
|
-
else if (nan) {
|
3968
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
3969
|
-
VpSetNaN(vy);
|
3970
|
-
RB_GC_GUARD(vy->obj);
|
3971
|
-
return VpCheckGetValue(vy);
|
3972
|
-
}
|
3973
|
-
else if (vx == NULL) {
|
3974
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
3975
|
-
}
|
3976
|
-
x = vx->obj;
|
3977
|
-
|
3978
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
3979
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
3980
|
-
if (negative) {
|
3981
|
-
VALUE x_zero = INT2NUM(1);
|
3982
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
3983
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
3984
|
-
vx = DATA_PTR(x);
|
3985
|
-
VpSetSign(vx, 1);
|
3986
|
-
}
|
3987
|
-
|
3988
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
3989
|
-
y = one;
|
3990
|
-
d = y;
|
3991
|
-
i = 1;
|
3992
|
-
|
3993
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
3994
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
3995
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
3996
|
-
ssize_t m = n - vabs(ey - ed);
|
3997
|
-
|
3998
|
-
rb_thread_check_ints();
|
3999
|
-
|
4000
|
-
if (m <= 0) {
|
4001
|
-
break;
|
4002
|
-
}
|
4003
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
4004
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
4005
|
-
}
|
4006
|
-
|
4007
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
4008
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
4009
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
4010
|
-
++i; /* i <- i + 1 */
|
4011
|
-
}
|
4012
|
-
|
4013
|
-
if (negative) {
|
4014
|
-
return BigDecimal_div2(one, y, vprec);
|
4015
|
-
}
|
4016
|
-
else {
|
4017
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
4018
|
-
return BigDecimal_round(1, &vprec, y);
|
4019
|
-
}
|
4020
|
-
|
4021
|
-
RB_GC_GUARD(one);
|
4022
|
-
RB_GC_GUARD(x);
|
4023
|
-
RB_GC_GUARD(y);
|
4024
|
-
RB_GC_GUARD(d);
|
4025
|
-
}
|
4026
|
-
|
4027
|
-
/* call-seq:
|
4028
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
4029
|
-
*
|
4030
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
4031
|
-
* digits of precision, +numeric+.
|
4032
|
-
*
|
4033
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
4034
|
-
*
|
4035
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
4036
|
-
*
|
4037
|
-
* If +decimal+ is NaN, returns NaN.
|
4038
|
-
*/
|
4039
|
-
static VALUE
|
4040
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
4041
|
-
{
|
4042
|
-
ssize_t prec, n, i;
|
4043
|
-
SIGNED_VALUE expo;
|
4044
|
-
Real* vx = NULL;
|
4045
|
-
VALUE vn, one, two, w, x2, y, d;
|
4046
|
-
int zero = 0;
|
4047
|
-
int negative = 0;
|
4048
|
-
int infinite = 0;
|
4049
|
-
int nan = 0;
|
4050
|
-
double flo;
|
4051
|
-
long fix;
|
4052
|
-
|
4053
|
-
if (!is_integer(vprec)) {
|
4054
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
4055
|
-
}
|
4056
|
-
|
4057
|
-
prec = NUM2SSIZET(vprec);
|
4058
|
-
if (prec <= 0) {
|
4059
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
4060
|
-
}
|
4061
|
-
|
4062
|
-
/* TODO: the following switch statement is almost same as one in the
|
4063
|
-
* BigDecimalCmp function. */
|
4064
|
-
switch (TYPE(x)) {
|
4065
|
-
case T_DATA:
|
4066
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
4067
|
-
vx = DATA_PTR(x);
|
4068
|
-
zero = VpIsZero(vx);
|
4069
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
4070
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
4071
|
-
nan = VpIsNaN(vx);
|
4072
|
-
break;
|
4073
|
-
|
4074
|
-
case T_FIXNUM:
|
4075
|
-
fix = FIX2LONG(x);
|
4076
|
-
zero = fix == 0;
|
4077
|
-
negative = fix < 0;
|
4078
|
-
goto get_vp_value;
|
4079
|
-
|
4080
|
-
case T_BIGNUM:
|
4081
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
4082
|
-
zero = i == 0;
|
4083
|
-
negative = i < 0;
|
4084
|
-
get_vp_value:
|
4085
|
-
if (zero || negative) break;
|
4086
|
-
vx = GetVpValue(x, 0);
|
4087
|
-
break;
|
4088
|
-
|
4089
|
-
case T_FLOAT:
|
4090
|
-
flo = RFLOAT_VALUE(x);
|
4091
|
-
zero = flo == 0;
|
4092
|
-
negative = flo < 0;
|
4093
|
-
infinite = isinf(flo);
|
4094
|
-
nan = isnan(flo);
|
4095
|
-
if (!zero && !negative && !infinite && !nan) {
|
4096
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
4097
|
-
}
|
4098
|
-
break;
|
4099
|
-
|
4100
|
-
case T_RATIONAL:
|
4101
|
-
zero = RRATIONAL_ZERO_P(x);
|
4102
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
4103
|
-
if (zero || negative) break;
|
4104
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
4105
|
-
break;
|
4106
|
-
|
4107
|
-
case T_COMPLEX:
|
4108
|
-
rb_raise(rb_eMathDomainError,
|
4109
|
-
"Complex argument for BigMath.log");
|
4110
|
-
|
4111
|
-
default:
|
4112
|
-
break;
|
4113
|
-
}
|
4114
|
-
if (infinite && !negative) {
|
4115
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
4116
|
-
RB_GC_GUARD(vy->obj);
|
4117
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
4118
|
-
return VpCheckGetValue(vy);
|
4119
|
-
}
|
4120
|
-
else if (nan) {
|
4121
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
4122
|
-
RB_GC_GUARD(vy->obj);
|
4123
|
-
VpSetNaN(vy);
|
4124
|
-
return VpCheckGetValue(vy);
|
4125
|
-
}
|
4126
|
-
else if (zero || negative) {
|
4127
|
-
rb_raise(rb_eMathDomainError,
|
4128
|
-
"Zero or negative argument for log");
|
4129
|
-
}
|
4130
|
-
else if (vx == NULL) {
|
4131
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
4132
|
-
}
|
4133
|
-
x = VpCheckGetValue(vx);
|
4134
|
-
|
4135
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
4136
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
4137
|
-
|
4138
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
4139
|
-
vn = SSIZET2NUM(n);
|
4140
|
-
expo = VpExponent10(vx);
|
4141
|
-
if (expo < 0 || expo >= 3) {
|
4142
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
4143
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
4144
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
4145
|
-
}
|
4146
|
-
else {
|
4147
|
-
expo = 0;
|
4148
|
-
}
|
4149
|
-
w = BigDecimal_sub(x, one);
|
4150
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
4151
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
4152
|
-
y = x;
|
4153
|
-
d = y;
|
4154
|
-
i = 1;
|
4155
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
4156
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
4157
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
4158
|
-
ssize_t m = n - vabs(ey - ed);
|
4159
|
-
if (m <= 0) {
|
4160
|
-
break;
|
4161
|
-
}
|
4162
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
4163
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
4164
|
-
}
|
4165
|
-
|
4166
|
-
x = BigDecimal_mult2(x2, x, vn);
|
4167
|
-
i += 2;
|
4168
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
4169
|
-
y = BigDecimal_add(y, d);
|
4170
|
-
}
|
4171
|
-
|
4172
|
-
y = BigDecimal_mult(y, two);
|
4173
|
-
if (expo != 0) {
|
4174
|
-
VALUE log10, vexpo, dy;
|
4175
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
4176
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
4177
|
-
dy = BigDecimal_mult(log10, vexpo);
|
4178
|
-
y = BigDecimal_add(y, dy);
|
4179
|
-
}
|
4180
|
-
|
4181
|
-
RB_GC_GUARD(one);
|
4182
|
-
RB_GC_GUARD(two);
|
4183
|
-
RB_GC_GUARD(vn);
|
4184
|
-
RB_GC_GUARD(x2);
|
4185
|
-
RB_GC_GUARD(y);
|
4186
|
-
RB_GC_GUARD(d);
|
4187
|
-
|
4188
|
-
return y;
|
3195
|
+
static VALUE
|
3196
|
+
BigDecimal_save_limit(VALUE self)
|
3197
|
+
{
|
3198
|
+
size_t const limit = VpGetPrecLimit();
|
3199
|
+
int state;
|
3200
|
+
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
3201
|
+
VpSetPrecLimit(limit);
|
3202
|
+
if (state) rb_jump_tag(state);
|
3203
|
+
return ret;
|
4189
3204
|
}
|
4190
3205
|
|
4191
3206
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
@@ -4239,6 +3254,34 @@ BigDecimal_literal(const char *str)
|
|
4239
3254
|
|
4240
3255
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
4241
3256
|
|
3257
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
3258
|
+
VALUE
|
3259
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
3260
|
+
BDVALUE a,b,c,d;
|
3261
|
+
size_t cn = NUM2INT(cprec);
|
3262
|
+
a = GetBDValueMust(self);
|
3263
|
+
b = GetBDValueMust(r);
|
3264
|
+
c = NewZeroWrap(1, cn * BASE_FIG);
|
3265
|
+
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
3266
|
+
VpDivd(c.real, d.real, a.real, b.real);
|
3267
|
+
RB_GC_GUARD(a.bigdecimal);
|
3268
|
+
RB_GC_GUARD(b.bigdecimal);
|
3269
|
+
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
3270
|
+
}
|
3271
|
+
|
3272
|
+
VALUE
|
3273
|
+
BigDecimal_vpmult(VALUE self, VALUE v) {
|
3274
|
+
BDVALUE a,b,c;
|
3275
|
+
a = GetBDValueMust(self);
|
3276
|
+
b = GetBDValueMust(v);
|
3277
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
3278
|
+
VpMult(c.real, a.real, b.real);
|
3279
|
+
RB_GC_GUARD(a.bigdecimal);
|
3280
|
+
RB_GC_GUARD(b.bigdecimal);
|
3281
|
+
return c.bigdecimal;
|
3282
|
+
}
|
3283
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
3284
|
+
|
4242
3285
|
/* Document-class: BigDecimal
|
4243
3286
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
4244
3287
|
*
|
@@ -4355,14 +3398,16 @@ BigDecimal_literal(const char *str)
|
|
4355
3398
|
*
|
4356
3399
|
* When you require +bigdecimal/util+, the #to_d method will be
|
4357
3400
|
* available on BigDecimal and the native Integer, Float, Rational,
|
4358
|
-
* and
|
3401
|
+
* String, Complex, and NilClass classes:
|
4359
3402
|
*
|
4360
3403
|
* require 'bigdecimal/util'
|
4361
3404
|
*
|
4362
|
-
* 42.to_d
|
4363
|
-
* 0.5.to_d
|
4364
|
-
* (2/3r).to_d(3)
|
4365
|
-
* "0.5".to_d
|
3405
|
+
* 42.to_d # => 0.42e2
|
3406
|
+
* 0.5.to_d # => 0.5e0
|
3407
|
+
* (2/3r).to_d(3) # => 0.667e0
|
3408
|
+
* "0.5".to_d # => 0.5e0
|
3409
|
+
* Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
3410
|
+
* nil.to_d # => 0.0
|
4366
3411
|
*
|
4367
3412
|
* == Methods for Working with \JSON
|
4368
3413
|
*
|
@@ -4436,7 +3481,7 @@ Init_bigdecimal(void)
|
|
4436
3481
|
* guarantee that two groups could always be multiplied together without
|
4437
3482
|
* overflow.)
|
4438
3483
|
*/
|
4439
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
3484
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
4440
3485
|
|
4441
3486
|
/* Exceptions */
|
4442
3487
|
|
@@ -4578,14 +3623,11 @@ Init_bigdecimal(void)
|
|
4578
3623
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
4579
3624
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
4580
3625
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
4581
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
4582
3626
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
4583
3627
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
4584
3628
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
4585
3629
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
4586
3630
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
4587
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
4588
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
4589
3631
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
4590
3632
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
4591
3633
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
@@ -4604,11 +3646,13 @@ Init_bigdecimal(void)
|
|
4604
3646
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
4605
3647
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
4606
3648
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
3649
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
4607
3650
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
4608
3651
|
|
4609
|
-
|
4610
|
-
|
4611
|
-
|
3652
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
3653
|
+
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
3654
|
+
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
3655
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
4612
3656
|
|
4613
3657
|
#define ROUNDING_MODE(i, name, value) \
|
4614
3658
|
id_##name = rb_intern_const(#name); \
|
@@ -4648,19 +3692,9 @@ Init_bigdecimal(void)
|
|
4648
3692
|
*/
|
4649
3693
|
#ifdef BIGDECIMAL_DEBUG
|
4650
3694
|
static int gfDebug = 1; /* Debug switch */
|
4651
|
-
#if 0
|
4652
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
4653
|
-
#endif
|
4654
3695
|
#endif /* BIGDECIMAL_DEBUG */
|
4655
3696
|
|
4656
3697
|
static Real *VpConstOne; /* constant 1.0 */
|
4657
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
4658
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
4659
|
-
/* used in VpSqrt() */
|
4660
|
-
|
4661
|
-
/* ETC */
|
4662
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
4663
|
-
#define StrCmp(x,y) strcmp(x,y)
|
4664
3698
|
|
4665
3699
|
enum op_sw {
|
4666
3700
|
OP_SW_ADD = 1, /* + */
|
@@ -4670,11 +3704,9 @@ enum op_sw {
|
|
4670
3704
|
};
|
4671
3705
|
|
4672
3706
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
4673
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
4674
3707
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
4675
3708
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
4676
3709
|
static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
|
4677
|
-
static int VpNmlz(Real *a);
|
4678
3710
|
static void VpFormatSt(char *psz, size_t fFmt);
|
4679
3711
|
static int VpRdup(Real *m, size_t ind_m);
|
4680
3712
|
|
@@ -4733,10 +3765,10 @@ VpCheckException(Real *p, bool always)
|
|
4733
3765
|
}
|
4734
3766
|
|
4735
3767
|
static VALUE
|
4736
|
-
|
3768
|
+
CheckGetValue(BDVALUE v)
|
4737
3769
|
{
|
4738
|
-
VpCheckException(
|
4739
|
-
return
|
3770
|
+
VpCheckException(v.real, false);
|
3771
|
+
return v.bigdecimal;
|
4740
3772
|
}
|
4741
3773
|
|
4742
3774
|
/*
|
@@ -4768,12 +3800,10 @@ VpGetPrecLimit(void)
|
|
4768
3800
|
return NUM2SIZET(vlimit);
|
4769
3801
|
}
|
4770
3802
|
|
4771
|
-
VP_EXPORT
|
3803
|
+
VP_EXPORT void
|
4772
3804
|
VpSetPrecLimit(size_t n)
|
4773
3805
|
{
|
4774
|
-
size_t const s = VpGetPrecLimit();
|
4775
3806
|
bigdecimal_set_thread_local_precision_limit(n);
|
4776
|
-
return s;
|
4777
3807
|
}
|
4778
3808
|
|
4779
3809
|
/*
|
@@ -4888,15 +3918,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
4888
3918
|
return nzero;
|
4889
3919
|
}
|
4890
3920
|
|
4891
|
-
#if 0 /* unused */
|
4892
|
-
VP_EXPORT int
|
4893
|
-
VpIsNegDoubleZero(double v)
|
4894
|
-
{
|
4895
|
-
double z = VpGetDoubleNegZero();
|
4896
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
4897
|
-
}
|
4898
|
-
#endif
|
4899
|
-
|
4900
3921
|
VP_EXPORT int
|
4901
3922
|
VpException(unsigned short f, const char *str,int always)
|
4902
3923
|
{
|
@@ -5048,7 +4069,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
5048
4069
|
case 'E':
|
5049
4070
|
/* fall through */
|
5050
4071
|
default:
|
5051
|
-
nc = BASE_FIG*
|
4072
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
5052
4073
|
}
|
5053
4074
|
return nc;
|
5054
4075
|
}
|
@@ -5074,28 +4095,13 @@ VpInit(DECDIG BaseVal)
|
|
5074
4095
|
VpGetDoubleNegZero();
|
5075
4096
|
|
5076
4097
|
/* Const 1.0 */
|
5077
|
-
VpConstOne =
|
5078
|
-
|
5079
|
-
/* Const 0.5 */
|
5080
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
5081
|
-
VpConstPt5->exponent = 0;
|
5082
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
4098
|
+
VpConstOne = NewZero(1, 1);
|
4099
|
+
VpSetOne(VpConstOne);
|
5083
4100
|
|
5084
4101
|
#ifdef BIGDECIMAL_DEBUG
|
5085
4102
|
gnAlloc = 0;
|
5086
4103
|
#endif /* BIGDECIMAL_DEBUG */
|
5087
4104
|
|
5088
|
-
#ifdef BIGDECIMAL_DEBUG
|
5089
|
-
if (gfDebug) {
|
5090
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
5091
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
5092
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
5093
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
5094
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
5095
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
5096
|
-
}
|
5097
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5098
|
-
|
5099
4105
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
5100
4106
|
}
|
5101
4107
|
|
@@ -5111,24 +4117,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
5111
4117
|
{
|
5112
4118
|
SIGNED_VALUE e = a->exponent;
|
5113
4119
|
SIGNED_VALUE m = e+n;
|
5114
|
-
|
5115
|
-
|
5116
|
-
|
5117
|
-
|
5118
|
-
|
5119
|
-
|
5120
|
-
|
5121
|
-
|
5122
|
-
if (eb - mb > 0) goto overflow;
|
5123
|
-
}
|
5124
|
-
}
|
5125
|
-
else if (n < 0) {
|
5126
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
5127
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
5128
|
-
goto underflow;
|
5129
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
5130
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
5131
|
-
if (mb - eb > 0) goto underflow;
|
4120
|
+
if (e > 0 && n > 0) {
|
4121
|
+
if (n > VP_EXPONENT_MAX - e) goto overflow;
|
4122
|
+
} else if (e < 0 && n < 0) {
|
4123
|
+
if (n < VP_EXPONENT_MIN - e) goto underflow;
|
4124
|
+
} else if (m > VP_EXPONENT_MAX) {
|
4125
|
+
goto overflow;
|
4126
|
+
} else if (m < VP_EXPONENT_MIN) {
|
4127
|
+
goto underflow;
|
5132
4128
|
}
|
5133
4129
|
a->exponent = m;
|
5134
4130
|
return 1;
|
@@ -5169,7 +4165,6 @@ bigdecimal_parse_special_string(const char *str)
|
|
5169
4165
|
while (*p && ISSPACE(*p)) ++p;
|
5170
4166
|
if (*p == '\0') {
|
5171
4167
|
Real *vp = rbd_allocate_struct(1);
|
5172
|
-
vp->MaxPrec = 1;
|
5173
4168
|
switch (table[i].sign) {
|
5174
4169
|
default:
|
5175
4170
|
UNREACHABLE; break;
|
@@ -5234,38 +4229,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
5234
4229
|
/*
|
5235
4230
|
* Allocates variable.
|
5236
4231
|
* [Input]
|
5237
|
-
*
|
5238
|
-
* The mx will be the number of significant digits can to be stored.
|
5239
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
5240
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
5241
|
-
* so that the full precision specified by szVal is allocated.
|
4232
|
+
* szVal ... The value assigned(char).
|
5242
4233
|
*
|
5243
4234
|
* [Returns]
|
5244
4235
|
* Pointer to the newly allocated variable, or
|
5245
4236
|
* NULL be returned if memory allocation is failed,or any error.
|
5246
4237
|
*/
|
5247
4238
|
VP_EXPORT Real *
|
5248
|
-
VpAlloc(
|
4239
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
5249
4240
|
{
|
5250
4241
|
const char *orig_szVal = szVal;
|
5251
4242
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
5252
|
-
size_t len;
|
5253
4243
|
char v, *psz;
|
5254
4244
|
int sign=1;
|
5255
4245
|
Real *vp = NULL;
|
5256
4246
|
VALUE buf;
|
5257
4247
|
|
5258
|
-
if (szVal == NULL) {
|
5259
|
-
return_zero:
|
5260
|
-
/* necessary to be able to store */
|
5261
|
-
/* at least mx digits. */
|
5262
|
-
/* szVal==NULL ==> allocate zero value. */
|
5263
|
-
vp = rbd_allocate_struct(mx);
|
5264
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
5265
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
5266
|
-
return vp;
|
5267
|
-
}
|
5268
|
-
|
5269
4248
|
/* Skipping leading spaces */
|
5270
4249
|
while (ISSPACE(*szVal)) szVal++;
|
5271
4250
|
|
@@ -5274,14 +4253,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5274
4253
|
return vp;
|
5275
4254
|
}
|
5276
4255
|
|
5277
|
-
/*
|
5278
|
-
|
5279
|
-
|
5280
|
-
|
5281
|
-
|
5282
|
-
len = rbd_calculate_internal_digits(mx, false);
|
5283
|
-
++szVal;
|
5284
|
-
}
|
4256
|
+
/* Skip leading `#`.
|
4257
|
+
* It used to be a mark to indicate that an extra MaxPrec should be allocated,
|
4258
|
+
* but now it has no effect.
|
4259
|
+
*/
|
4260
|
+
if (*szVal == '#') ++szVal;
|
5285
4261
|
|
5286
4262
|
/* Scanning digits */
|
5287
4263
|
|
@@ -5428,7 +4404,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5428
4404
|
VALUE str;
|
5429
4405
|
invalid_value:
|
5430
4406
|
if (!strict_p) {
|
5431
|
-
|
4407
|
+
return NewZero(1, 1);
|
5432
4408
|
}
|
5433
4409
|
if (!exc) {
|
5434
4410
|
return NULL;
|
@@ -5439,11 +4415,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5439
4415
|
|
5440
4416
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
5441
4417
|
/* units for szVal[] */
|
5442
|
-
|
5443
|
-
nalloc = Max(nalloc, len);
|
5444
|
-
len = nalloc;
|
5445
|
-
vp = rbd_allocate_struct(len);
|
5446
|
-
vp->MaxPrec = len; /* set max precision */
|
4418
|
+
vp = rbd_allocate_struct(nalloc);
|
5447
4419
|
VpSetZero(vp, sign);
|
5448
4420
|
protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
|
5449
4421
|
rb_str_resize(buf, 0);
|
@@ -5483,7 +4455,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
5483
4455
|
c->Prec = n;
|
5484
4456
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
5485
4457
|
/* Needs round ? */
|
5486
|
-
if (isw != 10) {
|
4458
|
+
if (isw != 10 && isw != -10) {
|
5487
4459
|
/* Not in ActiveRound */
|
5488
4460
|
if(c->Prec < a->Prec) {
|
5489
4461
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
@@ -5509,19 +4481,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
5509
4481
|
VP_EXPORT size_t
|
5510
4482
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
5511
4483
|
{
|
5512
|
-
short sw, isw;
|
4484
|
+
short sw, isw, sign;
|
5513
4485
|
Real *a_ptr, *b_ptr;
|
5514
4486
|
size_t n, na, nb, i;
|
5515
4487
|
DECDIG mrv;
|
5516
4488
|
|
5517
|
-
#ifdef BIGDECIMAL_DEBUG
|
5518
|
-
if (gfDebug) {
|
5519
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
5520
|
-
VPrint(stdout, " b=% \n", b);
|
5521
|
-
printf(" operation=%d\n", operation);
|
5522
|
-
}
|
5523
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5524
|
-
|
5525
4489
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
5526
4490
|
|
5527
4491
|
/* check if a or b is zero */
|
@@ -5610,28 +4574,21 @@ end_if:
|
|
5610
4574
|
if (isw) { /* addition */
|
5611
4575
|
VpSetSign(c, 1);
|
5612
4576
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
5613
|
-
|
4577
|
+
sign = isw / 2;
|
5614
4578
|
}
|
5615
4579
|
else { /* subtraction */
|
5616
4580
|
VpSetSign(c, 1);
|
5617
4581
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
5618
|
-
|
5619
|
-
VpSetSign(c,VpGetSign(a));
|
5620
|
-
}
|
5621
|
-
else {
|
5622
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
5623
|
-
}
|
4582
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
5624
4583
|
}
|
5625
|
-
|
5626
|
-
|
5627
|
-
#ifdef BIGDECIMAL_DEBUG
|
5628
|
-
if (gfDebug) {
|
5629
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
5630
|
-
VPrint(stdout, " a=% \n", a);
|
5631
|
-
VPrint(stdout, " b=% \n", b);
|
5632
|
-
printf(" operation=%d\n", operation);
|
4584
|
+
if (VpIsInf(c)) {
|
4585
|
+
VpSetInf(c, sign);
|
5633
4586
|
}
|
5634
|
-
|
4587
|
+
else {
|
4588
|
+
VpSetSign(c, sign);
|
4589
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
4590
|
+
}
|
4591
|
+
|
5635
4592
|
return c->Prec * BASE_FIG;
|
5636
4593
|
}
|
5637
4594
|
|
@@ -5652,13 +4609,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
5652
4609
|
size_t c_pos;
|
5653
4610
|
DECDIG av, bv, carry, mrv;
|
5654
4611
|
|
5655
|
-
#ifdef BIGDECIMAL_DEBUG
|
5656
|
-
if (gfDebug) {
|
5657
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
5658
|
-
VPrint(stdout, " b = %\n", b);
|
5659
|
-
}
|
5660
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5661
|
-
|
5662
4612
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
5663
4613
|
a_pos = ap;
|
5664
4614
|
b_pos = bp;
|
@@ -5724,11 +4674,6 @@ Assign_a:
|
|
5724
4674
|
|
5725
4675
|
Exit:
|
5726
4676
|
|
5727
|
-
#ifdef BIGDECIMAL_DEBUG
|
5728
|
-
if (gfDebug) {
|
5729
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
5730
|
-
}
|
5731
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5732
4677
|
return mrv;
|
5733
4678
|
}
|
5734
4679
|
|
@@ -5747,13 +4692,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
5747
4692
|
size_t c_pos;
|
5748
4693
|
DECDIG av, bv, borrow, mrv;
|
5749
4694
|
|
5750
|
-
#ifdef BIGDECIMAL_DEBUG
|
5751
|
-
if (gfDebug) {
|
5752
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
5753
|
-
VPrint(stdout, " b = %\n", b);
|
5754
|
-
}
|
5755
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5756
|
-
|
5757
4695
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
5758
4696
|
a_pos = ap;
|
5759
4697
|
b_pos = bp;
|
@@ -5829,11 +4767,6 @@ Assign_a:
|
|
5829
4767
|
mrv = 0;
|
5830
4768
|
|
5831
4769
|
Exit:
|
5832
|
-
#ifdef BIGDECIMAL_DEBUG
|
5833
|
-
if (gfDebug) {
|
5834
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
5835
|
-
}
|
5836
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5837
4770
|
return mrv;
|
5838
4771
|
}
|
5839
4772
|
|
@@ -5964,19 +4897,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
5964
4897
|
VP_EXPORT size_t
|
5965
4898
|
VpMult(Real *c, Real *a, Real *b)
|
5966
4899
|
{
|
5967
|
-
size_t MxIndA, MxIndB, MxIndAB
|
4900
|
+
size_t MxIndA, MxIndB, MxIndAB;
|
5968
4901
|
size_t ind_c, i, ii, nc;
|
5969
4902
|
size_t ind_as, ind_ae, ind_bs;
|
5970
4903
|
DECDIG carry;
|
5971
4904
|
DECDIG_DBL s;
|
5972
|
-
Real *w;
|
5973
|
-
|
5974
|
-
#ifdef BIGDECIMAL_DEBUG
|
5975
|
-
if (gfDebug) {
|
5976
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
5977
|
-
VPrint(stdout, " b=% \n", b);
|
5978
|
-
}
|
5979
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5980
4905
|
|
5981
4906
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
5982
4907
|
|
@@ -5987,39 +4912,28 @@ VpMult(Real *c, Real *a, Real *b)
|
|
5987
4912
|
}
|
5988
4913
|
|
5989
4914
|
if (VpIsOne(a)) {
|
5990
|
-
VpAsgn(c, b, VpGetSign(a));
|
4915
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
5991
4916
|
goto Exit;
|
5992
4917
|
}
|
5993
4918
|
if (VpIsOne(b)) {
|
5994
|
-
VpAsgn(c, a, VpGetSign(b));
|
4919
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
5995
4920
|
goto Exit;
|
5996
4921
|
}
|
5997
4922
|
if (b->Prec > a->Prec) {
|
5998
4923
|
/* Adjust so that digits(a)>digits(b) */
|
5999
|
-
w = a;
|
4924
|
+
Real *w = a;
|
6000
4925
|
a = b;
|
6001
4926
|
b = w;
|
6002
4927
|
}
|
6003
|
-
w = NULL;
|
6004
4928
|
MxIndA = a->Prec - 1;
|
6005
4929
|
MxIndB = b->Prec - 1;
|
6006
|
-
MxIndC = c->MaxPrec - 1;
|
6007
4930
|
MxIndAB = a->Prec + b->Prec - 1;
|
6008
4931
|
|
6009
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
6010
|
-
w = c;
|
6011
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
6012
|
-
MxIndC = MxIndAB;
|
6013
|
-
}
|
6014
|
-
|
6015
4932
|
/* set LHSV c info */
|
6016
4933
|
|
6017
4934
|
c->exponent = a->exponent; /* set exponent */
|
6018
|
-
if (!AddExponent(c, b->exponent)) {
|
6019
|
-
if (w) rbd_free_struct(c);
|
6020
|
-
return 0;
|
6021
|
-
}
|
6022
4935
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
4936
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
6023
4937
|
carry = 0;
|
6024
4938
|
nc = ind_c = MxIndAB;
|
6025
4939
|
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
@@ -6066,29 +4980,18 @@ VpMult(Real *c, Real *a, Real *b)
|
|
6066
4980
|
}
|
6067
4981
|
}
|
6068
4982
|
}
|
6069
|
-
|
6070
|
-
VpNmlz(c);
|
6071
|
-
VpAsgn(w, c, 1);
|
6072
|
-
rbd_free_struct(c);
|
6073
|
-
c = w;
|
6074
|
-
}
|
6075
|
-
else {
|
6076
|
-
VpLimitRound(c,0);
|
6077
|
-
}
|
4983
|
+
VpNmlz(c);
|
6078
4984
|
|
6079
4985
|
Exit:
|
6080
|
-
#ifdef BIGDECIMAL_DEBUG
|
6081
|
-
if (gfDebug) {
|
6082
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
6083
|
-
VPrint(stdout, " a=% \n", a);
|
6084
|
-
VPrint(stdout, " b=% \n", b);
|
6085
|
-
}
|
6086
|
-
#endif /*BIGDECIMAL_DEBUG */
|
6087
4986
|
return c->Prec*BASE_FIG;
|
6088
4987
|
}
|
6089
4988
|
|
6090
4989
|
/*
|
6091
4990
|
* c = a / b, remainder = r
|
4991
|
+
* XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
|
4992
|
+
* XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
|
4993
|
+
* 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
|
4994
|
+
* 0001_0000_0000 / 9999 = 0000_0001_0001
|
6092
4995
|
*/
|
6093
4996
|
VP_EXPORT size_t
|
6094
4997
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
@@ -6097,16 +5000,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6097
5000
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
6098
5001
|
size_t nLoop;
|
6099
5002
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
6100
|
-
DECDIG
|
5003
|
+
DECDIG borrow1, borrow2;
|
6101
5004
|
DECDIG_DBL qb;
|
6102
5005
|
|
6103
|
-
#ifdef BIGDECIMAL_DEBUG
|
6104
|
-
if (gfDebug) {
|
6105
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
6106
|
-
VPrint(stdout, " b=% \n", b);
|
6107
|
-
}
|
6108
|
-
#endif /*BIGDECIMAL_DEBUG */
|
6109
|
-
|
6110
5006
|
VpSetNaN(r);
|
6111
5007
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
6112
5008
|
if (VpIsZero(a) && VpIsZero(b)) {
|
@@ -6123,30 +5019,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6123
5019
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
6124
5020
|
goto Exit;
|
6125
5021
|
}
|
6126
|
-
if (VpIsOne(b)) {
|
6127
|
-
/* divide by one */
|
6128
|
-
VpAsgn(c, a, VpGetSign(b));
|
6129
|
-
VpSetZero(r, VpGetSign(a));
|
6130
|
-
goto Exit;
|
6131
|
-
}
|
6132
5022
|
|
6133
5023
|
word_a = a->Prec;
|
6134
5024
|
word_b = b->Prec;
|
6135
5025
|
word_c = c->MaxPrec;
|
6136
5026
|
word_r = r->MaxPrec;
|
6137
5027
|
|
6138
|
-
if (word_a
|
5028
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
6139
5029
|
|
6140
|
-
|
6141
|
-
r->frac[
|
6142
|
-
|
6143
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
6144
|
-
++ind_r;
|
6145
|
-
}
|
6146
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
6147
|
-
|
6148
|
-
ind_c = 0;
|
6149
|
-
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
5030
|
+
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
5031
|
+
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
5032
|
+
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
6150
5033
|
|
6151
5034
|
/* initial procedure */
|
6152
5035
|
b1 = b1p1 = b->frac[0];
|
@@ -6161,15 +5044,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6161
5044
|
|
6162
5045
|
/* */
|
6163
5046
|
/* loop start */
|
6164
|
-
|
6165
|
-
|
6166
|
-
ind_c = 1;
|
5047
|
+
nLoop = Min(word_c, word_r);
|
5048
|
+
ind_c = 0;
|
6167
5049
|
while (ind_c < nLoop) {
|
6168
5050
|
if (r->frac[ind_c] == 0) {
|
6169
5051
|
++ind_c;
|
6170
5052
|
continue;
|
6171
5053
|
}
|
6172
|
-
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
|
5054
|
+
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
|
6173
5055
|
if (r1r2 == b1b2) {
|
6174
5056
|
/* The first two word digits is the same */
|
6175
5057
|
ind_b = 2;
|
@@ -6182,26 +5064,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6182
5064
|
}
|
6183
5065
|
/* The first few word digits of r and b is the same and */
|
6184
5066
|
/* the first different word digit of w is greater than that */
|
6185
|
-
/* of b, so quotient is 1
|
6186
|
-
|
6187
|
-
ind_b = b->Prec - 1;
|
6188
|
-
ind_r = ind_c + ind_b;
|
6189
|
-
if (ind_r >= word_r) goto space_error;
|
6190
|
-
n = ind_b;
|
6191
|
-
for (i = 0; i <= n; ++i) {
|
6192
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
6193
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
6194
|
-
borrow = 1;
|
6195
|
-
}
|
6196
|
-
else {
|
6197
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
6198
|
-
borrow = 0;
|
6199
|
-
}
|
6200
|
-
--ind_r;
|
6201
|
-
--ind_b;
|
6202
|
-
}
|
5067
|
+
/* of b, so quotient is 1. */
|
5068
|
+
q = 1;
|
6203
5069
|
++c->frac[ind_c];
|
6204
|
-
|
5070
|
+
ind_r = b->Prec + ind_c - 1;
|
5071
|
+
goto sub_mult;
|
6205
5072
|
}
|
6206
5073
|
/* The first two word digits is not the same, */
|
6207
5074
|
/* then compare magnitude, and divide actually. */
|
@@ -6254,49 +5121,26 @@ sub_mult:
|
|
6254
5121
|
}
|
6255
5122
|
|
6256
5123
|
r->frac[ind_r] -= borrow2;
|
6257
|
-
carry:
|
6258
|
-
ind_r = ind_c;
|
6259
|
-
while (c->frac[ind_r] >= BASE) {
|
6260
|
-
c->frac[ind_r] -= BASE;
|
6261
|
-
--ind_r;
|
6262
|
-
++c->frac[ind_r];
|
6263
|
-
}
|
6264
5124
|
}
|
6265
5125
|
/* End of operation, now final arrangement */
|
6266
5126
|
out_side:
|
6267
5127
|
c->Prec = word_c;
|
6268
5128
|
c->exponent = a->exponent;
|
6269
|
-
|
5129
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
5130
|
+
if (!AddExponent(c, 1)) return 0;
|
6270
5131
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
6271
5132
|
|
6272
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
6273
5133
|
VpNmlz(c); /* normalize c */
|
6274
5134
|
r->Prec = word_r;
|
6275
5135
|
r->exponent = a->exponent;
|
6276
|
-
if (!AddExponent(r, 1)) return 0;
|
6277
5136
|
VpSetSign(r, VpGetSign(a));
|
6278
5137
|
VpNmlz(r); /* normalize r(remainder) */
|
6279
5138
|
goto Exit;
|
6280
5139
|
|
6281
5140
|
space_error:
|
6282
|
-
#ifdef BIGDECIMAL_DEBUG
|
6283
|
-
if (gfDebug) {
|
6284
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
6285
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
6286
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
6287
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
6288
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
6289
|
-
}
|
6290
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6291
5141
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
6292
5142
|
|
6293
5143
|
Exit:
|
6294
|
-
#ifdef BIGDECIMAL_DEBUG
|
6295
|
-
if (gfDebug) {
|
6296
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
6297
|
-
VPrint(stdout, " r=% \n", r);
|
6298
|
-
}
|
6299
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6300
5144
|
return c->Prec * BASE_FIG;
|
6301
5145
|
}
|
6302
5146
|
|
@@ -6419,13 +5263,6 @@ Exit:
|
|
6419
5263
|
if (val > 1) val = 1;
|
6420
5264
|
else if (val < -1) val = -1;
|
6421
5265
|
|
6422
|
-
#ifdef BIGDECIMAL_DEBUG
|
6423
|
-
if (gfDebug) {
|
6424
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
6425
|
-
VPrint(stdout, " b=%\n", b);
|
6426
|
-
printf(" ans=%d\n", val);
|
6427
|
-
}
|
6428
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6429
5266
|
return (int)val;
|
6430
5267
|
}
|
6431
5268
|
|
@@ -6543,25 +5380,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
6543
5380
|
static void
|
6544
5381
|
VpFormatSt(char *psz, size_t fFmt)
|
6545
5382
|
{
|
6546
|
-
size_t
|
6547
|
-
char
|
5383
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
5384
|
+
char *p;
|
6548
5385
|
|
6549
5386
|
if (fFmt == 0) return;
|
6550
5387
|
|
6551
|
-
|
6552
|
-
|
6553
|
-
|
6554
|
-
|
6555
|
-
|
6556
|
-
|
6557
|
-
|
6558
|
-
|
6559
|
-
|
6560
|
-
|
6561
|
-
|
6562
|
-
|
6563
|
-
|
6564
|
-
|
5388
|
+
iend = strlen(psz);
|
5389
|
+
|
5390
|
+
if ((p = strchr(psz, '.'))) {
|
5391
|
+
idig = (p - psz) + 1;
|
5392
|
+
}
|
5393
|
+
if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
|
5394
|
+
iexp = p - psz;
|
5395
|
+
}
|
5396
|
+
if (idig == 0 || idig > iexp) return;
|
5397
|
+
|
5398
|
+
nspaces = (iexp - idig - 1) / fFmt;
|
5399
|
+
p = psz + iend + 1;
|
5400
|
+
for (size_t i = nspaces; i > 0; i--) {
|
5401
|
+
char *src = psz + idig + i * fFmt;
|
5402
|
+
char *dst = psz + idig + i * (fFmt + 1);
|
5403
|
+
memmove(dst, src, p - src);
|
5404
|
+
dst[-1] = ' ';
|
5405
|
+
p = src;
|
6565
5406
|
}
|
6566
5407
|
}
|
6567
5408
|
|
@@ -6843,7 +5684,7 @@ VP_EXPORT int
|
|
6843
5684
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
6844
5685
|
{
|
6845
5686
|
size_t i, j, ind_a, ma, mi, me;
|
6846
|
-
SIGNED_VALUE e
|
5687
|
+
SIGNED_VALUE e;
|
6847
5688
|
int sign, signe, exponent_overflow;
|
6848
5689
|
|
6849
5690
|
/* get exponent part */
|
@@ -6866,23 +5707,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
6866
5707
|
++me;
|
6867
5708
|
}
|
6868
5709
|
while (i < me) {
|
6869
|
-
|
6870
|
-
|
6871
|
-
|
6872
|
-
}
|
6873
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
6874
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
6875
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
6876
|
-
goto exp_overflow;
|
6877
|
-
e = e * 10 + exp_chr[i] - '0';
|
6878
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
6879
|
-
goto exp_overflow;
|
6880
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
6881
|
-
exp_overflow:
|
5710
|
+
int dig = exp_chr[i] - '0';
|
5711
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
5712
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
6882
5713
|
exponent_overflow = 1;
|
6883
|
-
e = es; /* keep sign */
|
6884
5714
|
break;
|
6885
5715
|
}
|
5716
|
+
e = e * 10 + signe * dig;
|
6886
5717
|
++i;
|
6887
5718
|
}
|
6888
5719
|
}
|
@@ -6901,34 +5732,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
6901
5732
|
++mi;
|
6902
5733
|
}
|
6903
5734
|
}
|
5735
|
+
/* skip leading zeros in integer part */
|
5736
|
+
while (i < mi && int_chr[i] == '0') {
|
5737
|
+
++i;
|
5738
|
+
--ni;
|
5739
|
+
}
|
6904
5740
|
|
6905
|
-
|
6906
|
-
|
6907
|
-
|
6908
|
-
|
6909
|
-
|
5741
|
+
/* set actual exponent size. */
|
5742
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
5743
|
+
exponent_overflow = 1;
|
5744
|
+
} else {
|
5745
|
+
e += ni;
|
5746
|
+
}
|
6910
5747
|
|
6911
5748
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
6912
|
-
j =
|
6913
|
-
|
6914
|
-
|
6915
|
-
|
6916
|
-
|
6917
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
6918
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
6919
|
-
if (ef) {
|
6920
|
-
++j; /* Means to add one more preceding zero */
|
6921
|
-
++e;
|
6922
|
-
}
|
5749
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
5750
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
5751
|
+
exponent_overflow = 1;
|
5752
|
+
} else {
|
5753
|
+
e += j;
|
6923
5754
|
}
|
6924
5755
|
|
6925
|
-
|
6926
|
-
|
6927
|
-
if (exponent_overflow) {
|
5756
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
6928
5757
|
int zero = 1;
|
6929
5758
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
6930
5759
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
6931
|
-
if (!zero &&
|
5760
|
+
if (!zero && e > 0) {
|
6932
5761
|
VpSetInf(a, sign);
|
6933
5762
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
6934
5763
|
}
|
@@ -6978,7 +5807,7 @@ Final:
|
|
6978
5807
|
++j;
|
6979
5808
|
}
|
6980
5809
|
a->Prec = ind_a + 1;
|
6981
|
-
a->exponent =
|
5810
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
6982
5811
|
VpSetSign(a, sign);
|
6983
5812
|
VpNmlz(a);
|
6984
5813
|
return 1;
|
@@ -7050,254 +5879,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
7050
5879
|
*d *= VpGetSign(m);
|
7051
5880
|
|
7052
5881
|
Exit:
|
7053
|
-
#ifdef BIGDECIMAL_DEBUG
|
7054
|
-
if (gfDebug) {
|
7055
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
7056
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
7057
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
7058
|
-
}
|
7059
|
-
#endif /*BIGDECIMAL_DEBUG */
|
7060
5882
|
return f;
|
7061
5883
|
}
|
7062
5884
|
|
7063
|
-
/*
|
7064
|
-
* m <- d
|
7065
|
-
*/
|
7066
|
-
VP_EXPORT void
|
7067
|
-
VpDtoV(Real *m, double d)
|
7068
|
-
{
|
7069
|
-
size_t ind_m, mm;
|
7070
|
-
SIGNED_VALUE ne;
|
7071
|
-
DECDIG i;
|
7072
|
-
double val, val2;
|
7073
|
-
|
7074
|
-
if (isnan(d)) {
|
7075
|
-
VpSetNaN(m);
|
7076
|
-
goto Exit;
|
7077
|
-
}
|
7078
|
-
if (isinf(d)) {
|
7079
|
-
if (d > 0.0) VpSetPosInf(m);
|
7080
|
-
else VpSetNegInf(m);
|
7081
|
-
goto Exit;
|
7082
|
-
}
|
7083
|
-
|
7084
|
-
if (d == 0.0) {
|
7085
|
-
VpSetZero(m, 1);
|
7086
|
-
goto Exit;
|
7087
|
-
}
|
7088
|
-
val = (d > 0.) ? d : -d;
|
7089
|
-
ne = 0;
|
7090
|
-
if (val >= 1.0) {
|
7091
|
-
while (val >= 1.0) {
|
7092
|
-
val /= (double)BASE;
|
7093
|
-
++ne;
|
7094
|
-
}
|
7095
|
-
}
|
7096
|
-
else {
|
7097
|
-
val2 = 1.0 / (double)BASE;
|
7098
|
-
while (val < val2) {
|
7099
|
-
val *= (double)BASE;
|
7100
|
-
--ne;
|
7101
|
-
}
|
7102
|
-
}
|
7103
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
7104
|
-
|
7105
|
-
mm = m->MaxPrec;
|
7106
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
7107
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
7108
|
-
val *= (double)BASE;
|
7109
|
-
i = (DECDIG)val;
|
7110
|
-
val -= (double)i;
|
7111
|
-
m->frac[ind_m] = i;
|
7112
|
-
}
|
7113
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
7114
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
7115
|
-
m->Prec = ind_m + 1;
|
7116
|
-
m->exponent = ne;
|
7117
|
-
|
7118
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
7119
|
-
(DECDIG)(val*(double)BASE));
|
7120
|
-
|
7121
|
-
Exit:
|
7122
|
-
#ifdef BIGDECIMAL_DEBUG
|
7123
|
-
if (gfDebug) {
|
7124
|
-
printf("VpDtoV d=%30.30e\n", d);
|
7125
|
-
VPrint(stdout, " m=%\n", m);
|
7126
|
-
}
|
7127
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7128
|
-
return;
|
7129
|
-
}
|
7130
|
-
|
7131
|
-
/*
|
7132
|
-
* m <- ival
|
7133
|
-
*/
|
7134
|
-
#if 0 /* unused */
|
7135
|
-
VP_EXPORT void
|
7136
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
7137
|
-
{
|
7138
|
-
size_t mm, ind_m;
|
7139
|
-
size_t val, v1, v2, v;
|
7140
|
-
int isign;
|
7141
|
-
SIGNED_VALUE ne;
|
7142
|
-
|
7143
|
-
if (ival == 0) {
|
7144
|
-
VpSetZero(m, 1);
|
7145
|
-
goto Exit;
|
7146
|
-
}
|
7147
|
-
isign = 1;
|
7148
|
-
val = ival;
|
7149
|
-
if (ival < 0) {
|
7150
|
-
isign = -1;
|
7151
|
-
val =(size_t)(-ival);
|
7152
|
-
}
|
7153
|
-
ne = 0;
|
7154
|
-
ind_m = 0;
|
7155
|
-
mm = m->MaxPrec;
|
7156
|
-
while (ind_m < mm) {
|
7157
|
-
m->frac[ind_m] = 0;
|
7158
|
-
++ind_m;
|
7159
|
-
}
|
7160
|
-
ind_m = 0;
|
7161
|
-
while (val > 0) {
|
7162
|
-
if (val) {
|
7163
|
-
v1 = val;
|
7164
|
-
v2 = 1;
|
7165
|
-
while (v1 >= BASE) {
|
7166
|
-
v1 /= BASE;
|
7167
|
-
v2 *= BASE;
|
7168
|
-
}
|
7169
|
-
val = val - v2 * v1;
|
7170
|
-
v = v1;
|
7171
|
-
}
|
7172
|
-
else {
|
7173
|
-
v = 0;
|
7174
|
-
}
|
7175
|
-
m->frac[ind_m] = v;
|
7176
|
-
++ind_m;
|
7177
|
-
++ne;
|
7178
|
-
}
|
7179
|
-
m->Prec = ind_m - 1;
|
7180
|
-
m->exponent = ne;
|
7181
|
-
VpSetSign(m, isign);
|
7182
|
-
VpNmlz(m);
|
7183
|
-
|
7184
|
-
Exit:
|
7185
|
-
#ifdef BIGDECIMAL_DEBUG
|
7186
|
-
if (gfDebug) {
|
7187
|
-
printf(" VpItoV i=%d\n", ival);
|
7188
|
-
VPrint(stdout, " m=%\n", m);
|
7189
|
-
}
|
7190
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7191
|
-
return;
|
7192
|
-
}
|
7193
|
-
#endif
|
7194
|
-
|
7195
|
-
/*
|
7196
|
-
* y = SQRT(x), y*y - x =>0
|
7197
|
-
*/
|
7198
|
-
VP_EXPORT int
|
7199
|
-
VpSqrt(Real *y, Real *x)
|
7200
|
-
{
|
7201
|
-
Real *f = NULL;
|
7202
|
-
Real *r = NULL;
|
7203
|
-
size_t y_prec;
|
7204
|
-
SIGNED_VALUE n, e;
|
7205
|
-
ssize_t nr;
|
7206
|
-
double val;
|
7207
|
-
|
7208
|
-
/* Zero or +Infinity ? */
|
7209
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
7210
|
-
VpAsgn(y,x,1);
|
7211
|
-
goto Exit;
|
7212
|
-
}
|
7213
|
-
|
7214
|
-
/* Negative ? */
|
7215
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
7216
|
-
VpSetNaN(y);
|
7217
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
7218
|
-
}
|
7219
|
-
|
7220
|
-
/* NaN ? */
|
7221
|
-
if (VpIsNaN(x)) {
|
7222
|
-
VpSetNaN(y);
|
7223
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
7224
|
-
}
|
7225
|
-
|
7226
|
-
/* One ? */
|
7227
|
-
if (VpIsOne(x)) {
|
7228
|
-
VpSetOne(y);
|
7229
|
-
goto Exit;
|
7230
|
-
}
|
7231
|
-
|
7232
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
7233
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
7234
|
-
|
7235
|
-
/* allocate temporally variables */
|
7236
|
-
/* TODO: reconsider MaxPrec of f and r */
|
7237
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
7238
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
7239
|
-
|
7240
|
-
nr = 0;
|
7241
|
-
y_prec = y->MaxPrec;
|
7242
|
-
|
7243
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
7244
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
7245
|
-
n = e / 2;
|
7246
|
-
if (e - n * 2 != 0) {
|
7247
|
-
val /= BASE;
|
7248
|
-
n = (e + 1) / 2;
|
7249
|
-
}
|
7250
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
7251
|
-
y->exponent += n;
|
7252
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
7253
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
7254
|
-
f->MaxPrec = y->MaxPrec + 1;
|
7255
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
7256
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
7257
|
-
|
7258
|
-
/*
|
7259
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
7260
|
-
*/
|
7261
|
-
do {
|
7262
|
-
y->MaxPrec *= 2;
|
7263
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
7264
|
-
f->MaxPrec = y->MaxPrec;
|
7265
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
7266
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
7267
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
7268
|
-
if (VpIsZero(f))
|
7269
|
-
goto converge;
|
7270
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
7271
|
-
VpAsgn(y, r, 1); /* y = r */
|
7272
|
-
} while (++nr < n);
|
7273
|
-
|
7274
|
-
#ifdef BIGDECIMAL_DEBUG
|
7275
|
-
if (gfDebug) {
|
7276
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
7277
|
-
}
|
7278
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7279
|
-
y->MaxPrec = y_prec;
|
7280
|
-
|
7281
|
-
converge:
|
7282
|
-
VpChangeSign(y, 1);
|
7283
|
-
#ifdef BIGDECIMAL_DEBUG
|
7284
|
-
if (gfDebug) {
|
7285
|
-
VpMult(r, y, y);
|
7286
|
-
VpAddSub(f, x, r, -1);
|
7287
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
7288
|
-
VPrint(stdout, " y =% \n", y);
|
7289
|
-
VPrint(stdout, " x =% \n", x);
|
7290
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
7291
|
-
}
|
7292
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7293
|
-
y->MaxPrec = y_prec;
|
7294
|
-
|
7295
|
-
Exit:
|
7296
|
-
rbd_free_struct(f);
|
7297
|
-
rbd_free_struct(r);
|
7298
|
-
return 1;
|
7299
|
-
}
|
7300
|
-
|
7301
5885
|
/*
|
7302
5886
|
* Round relatively from the decimal point.
|
7303
5887
|
* f: rounding mode
|
@@ -7474,7 +6058,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
7474
6058
|
DECDIG v;
|
7475
6059
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
7476
6060
|
v = y->frac[0];
|
7477
|
-
nf -=
|
6061
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
7478
6062
|
while ((v /= 10) != 0) nf--;
|
7479
6063
|
nf += (ssize_t)BASE_FIG-1;
|
7480
6064
|
return VpMidRound(y, f, nf);
|
@@ -7611,117 +6195,9 @@ VpFrac(Real *y, Real *x)
|
|
7611
6195
|
VpNmlz(y);
|
7612
6196
|
|
7613
6197
|
Exit:
|
7614
|
-
#ifdef BIGDECIMAL_DEBUG
|
7615
|
-
if (gfDebug) {
|
7616
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
7617
|
-
VPrint(stdout, " x=%\n", x);
|
7618
|
-
}
|
7619
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7620
6198
|
return;
|
7621
6199
|
}
|
7622
6200
|
|
7623
|
-
/*
|
7624
|
-
* y = x ** n
|
7625
|
-
*/
|
7626
|
-
VP_EXPORT int
|
7627
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
7628
|
-
{
|
7629
|
-
size_t s, ss;
|
7630
|
-
ssize_t sign;
|
7631
|
-
Real *w1 = NULL;
|
7632
|
-
Real *w2 = NULL;
|
7633
|
-
|
7634
|
-
if (VpIsZero(x)) {
|
7635
|
-
if (n == 0) {
|
7636
|
-
VpSetOne(y);
|
7637
|
-
goto Exit;
|
7638
|
-
}
|
7639
|
-
sign = VpGetSign(x);
|
7640
|
-
if (n < 0) {
|
7641
|
-
n = -n;
|
7642
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
7643
|
-
VpSetInf(y, sign);
|
7644
|
-
}
|
7645
|
-
else {
|
7646
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
7647
|
-
VpSetZero(y,sign);
|
7648
|
-
}
|
7649
|
-
goto Exit;
|
7650
|
-
}
|
7651
|
-
if (VpIsNaN(x)) {
|
7652
|
-
VpSetNaN(y);
|
7653
|
-
goto Exit;
|
7654
|
-
}
|
7655
|
-
if (VpIsInf(x)) {
|
7656
|
-
if (n == 0) {
|
7657
|
-
VpSetOne(y);
|
7658
|
-
goto Exit;
|
7659
|
-
}
|
7660
|
-
if (n > 0) {
|
7661
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
7662
|
-
goto Exit;
|
7663
|
-
}
|
7664
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
7665
|
-
goto Exit;
|
7666
|
-
}
|
7667
|
-
|
7668
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
7669
|
-
/* abs(x) = 1 */
|
7670
|
-
VpSetOne(y);
|
7671
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
7672
|
-
if ((n % 2) == 0) goto Exit;
|
7673
|
-
VpSetSign(y, -1);
|
7674
|
-
goto Exit;
|
7675
|
-
}
|
7676
|
-
|
7677
|
-
if (n > 0) sign = 1;
|
7678
|
-
else if (n < 0) {
|
7679
|
-
sign = -1;
|
7680
|
-
n = -n;
|
7681
|
-
}
|
7682
|
-
else {
|
7683
|
-
VpSetOne(y);
|
7684
|
-
goto Exit;
|
7685
|
-
}
|
7686
|
-
|
7687
|
-
/* Allocate working variables */
|
7688
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
7689
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
7690
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
7691
|
-
|
7692
|
-
/* calculation start */
|
7693
|
-
|
7694
|
-
VpAsgn(y, x, 1);
|
7695
|
-
--n;
|
7696
|
-
while (n > 0) {
|
7697
|
-
VpAsgn(w1, x, 1);
|
7698
|
-
s = 1;
|
7699
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
7700
|
-
VpMult(w2, w1, w1);
|
7701
|
-
VpAsgn(w1, w2, 1);
|
7702
|
-
}
|
7703
|
-
n -= (SIGNED_VALUE)ss;
|
7704
|
-
VpMult(w2, y, w1);
|
7705
|
-
VpAsgn(y, w2, 1);
|
7706
|
-
}
|
7707
|
-
if (sign < 0) {
|
7708
|
-
VpDivd(w1, w2, VpConstOne, y);
|
7709
|
-
VpAsgn(y, w1, 1);
|
7710
|
-
}
|
7711
|
-
|
7712
|
-
Exit:
|
7713
|
-
#ifdef BIGDECIMAL_DEBUG
|
7714
|
-
if (gfDebug) {
|
7715
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
7716
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
7717
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
7718
|
-
}
|
7719
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7720
|
-
rbd_free_struct(w2);
|
7721
|
-
rbd_free_struct(w1);
|
7722
|
-
return 1;
|
7723
|
-
}
|
7724
|
-
|
7725
6201
|
#ifdef BIGDECIMAL_DEBUG
|
7726
6202
|
int
|
7727
6203
|
VpVarCheck(Real * v)
|