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