bigdecimal 3.2.2 → 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 +721 -2269
- data/ext/bigdecimal/bigdecimal.h +4 -25
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/extconf.rb +3 -7
- data/ext/bigdecimal/missing.h +1 -93
- data/lib/bigdecimal/math.rb +9 -6
- data/lib/bigdecimal.rb +324 -0
- metadata +1 -1
data/ext/bigdecimal/bigdecimal.c
CHANGED
@@ -31,16 +31,23 @@
|
|
31
31
|
#include "bits.h"
|
32
32
|
#include "static_assert.h"
|
33
33
|
|
34
|
-
#define BIGDECIMAL_VERSION "3.2.
|
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,17 +404,18 @@ 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
|
|
@@ -623,10 +530,9 @@ VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
623
530
|
static void
|
624
531
|
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
625
532
|
{
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
VpCountPrecisionAndScale(p, out_precision, out_scale);
|
533
|
+
BDVALUE v = GetBDValueMust(self);
|
534
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
535
|
+
RB_GC_GUARD(v.bigdecimal);
|
630
536
|
}
|
631
537
|
|
632
538
|
/*
|
@@ -664,8 +570,8 @@ BigDecimal_precision(VALUE self)
|
|
664
570
|
* BigDecimal("1").scale # => 0
|
665
571
|
* BigDecimal("1.1").scale # => 1
|
666
572
|
* BigDecimal("3.1415").scale # => 4
|
667
|
-
* BigDecimal("-1e20").
|
668
|
-
* BigDecimal("1e-20").
|
573
|
+
* BigDecimal("-1e20").scale # => 0
|
574
|
+
* BigDecimal("1e-20").scale # => 20
|
669
575
|
* BigDecimal("Infinity").scale # => 0
|
670
576
|
* BigDecimal("-Infinity").scale # => 0
|
671
577
|
* BigDecimal("NaN").scale # => 0
|
@@ -715,25 +621,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
715
621
|
static VALUE
|
716
622
|
BigDecimal_n_significant_digits(VALUE self)
|
717
623
|
{
|
718
|
-
|
719
|
-
|
720
|
-
Real *p;
|
721
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
722
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
624
|
+
BDVALUE v = GetBDValueMust(self);
|
625
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
723
626
|
return INT2FIX(0);
|
724
627
|
}
|
725
628
|
|
726
|
-
ssize_t n =
|
727
|
-
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);
|
728
631
|
if (n == 0) return INT2FIX(0);
|
729
632
|
|
730
633
|
DECDIG x;
|
731
634
|
int nlz = BASE_FIG;
|
732
|
-
for (x =
|
635
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
733
636
|
|
734
637
|
int ntz = 0;
|
735
|
-
for (x =
|
638
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
736
639
|
|
640
|
+
RB_GC_GUARD(v.bigdecimal);
|
737
641
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
738
642
|
return SSIZET2NUM(n_significant_digits);
|
739
643
|
}
|
@@ -755,17 +659,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
755
659
|
static VALUE
|
756
660
|
BigDecimal_hash(VALUE self)
|
757
661
|
{
|
758
|
-
|
759
|
-
|
760
|
-
st_index_t hash;
|
761
|
-
|
762
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
763
|
-
hash = (st_index_t)p->sign;
|
662
|
+
BDVALUE v = GetBDValueMust(self);
|
663
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
764
664
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
765
665
|
if(hash == 2 || hash == (st_index_t)-2) {
|
766
|
-
hash ^= rb_memhash(
|
767
|
-
hash +=
|
666
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
667
|
+
hash += v.real->exponent;
|
768
668
|
}
|
669
|
+
RB_GC_GUARD(v.bigdecimal);
|
769
670
|
return ST2FIX(hash);
|
770
671
|
}
|
771
672
|
|
@@ -784,21 +685,22 @@ BigDecimal_hash(VALUE self)
|
|
784
685
|
static VALUE
|
785
686
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
786
687
|
{
|
787
|
-
|
788
|
-
Real *vp;
|
688
|
+
BDVALUE v;
|
789
689
|
char *psz;
|
790
690
|
VALUE dummy;
|
791
691
|
volatile VALUE dump;
|
792
692
|
size_t len;
|
793
693
|
|
794
694
|
rb_scan_args(argc, argv, "01", &dummy);
|
795
|
-
|
796
|
-
dump = rb_str_new(0, VpNumOfChars(
|
695
|
+
v = GetBDValueMust(self);
|
696
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
797
697
|
psz = RSTRING_PTR(dump);
|
798
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
698
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
799
699
|
len = strlen(psz);
|
800
|
-
VpToString(
|
700
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
801
701
|
rb_str_resize(dump, strlen(psz));
|
702
|
+
|
703
|
+
RB_GC_GUARD(v.bigdecimal);
|
802
704
|
return dump;
|
803
705
|
}
|
804
706
|
|
@@ -808,27 +710,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
808
710
|
static VALUE
|
809
711
|
BigDecimal_load(VALUE self, VALUE str)
|
810
712
|
{
|
811
|
-
|
812
|
-
Real *pv;
|
713
|
+
BDVALUE v;
|
813
714
|
unsigned char *pch;
|
814
715
|
unsigned char ch;
|
815
|
-
unsigned long m=0;
|
816
716
|
|
817
717
|
pch = (unsigned char *)StringValueCStr(str);
|
818
|
-
/* First
|
718
|
+
/* First skip max prec. Don't trust the value. */
|
819
719
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
820
720
|
if(!ISDIGIT(ch)) {
|
821
721
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
822
722
|
}
|
823
|
-
m = m*10 + (unsigned long)(ch-'0');
|
824
723
|
}
|
825
|
-
|
826
|
-
|
827
|
-
m /= VpBaseFig();
|
828
|
-
if (m && pv->MaxPrec > m) {
|
829
|
-
pv->MaxPrec = m+1;
|
830
|
-
}
|
831
|
-
return VpCheckGetValue(pv);
|
724
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
725
|
+
return CheckGetValue(v);
|
832
726
|
}
|
833
727
|
|
834
728
|
static unsigned short
|
@@ -1121,22 +1015,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
1121
1015
|
static size_t
|
1122
1016
|
GetAddSubPrec(Real *a, Real *b)
|
1123
1017
|
{
|
1124
|
-
size_t mxs;
|
1125
|
-
size_t mx = a->Prec;
|
1126
|
-
SIGNED_VALUE d;
|
1127
|
-
|
1128
1018
|
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
d = a->exponent - b->exponent;
|
1133
|
-
if (d < 0) d = -d;
|
1134
|
-
mx = mx + (size_t)d;
|
1135
|
-
if (mx < mxs) {
|
1136
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
1137
|
-
}
|
1138
|
-
}
|
1139
|
-
return mx;
|
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);
|
1140
1022
|
}
|
1141
1023
|
|
1142
1024
|
static inline SIGNED_VALUE
|
@@ -1156,39 +1038,12 @@ check_int_precision(VALUE v)
|
|
1156
1038
|
return n;
|
1157
1039
|
}
|
1158
1040
|
|
1159
|
-
static
|
1160
|
-
|
1161
|
-
{
|
1162
|
-
assert(is_kind_of_BigDecimal(obj));
|
1163
|
-
assert(vp != NULL);
|
1164
|
-
|
1165
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
1166
|
-
return obj;
|
1167
|
-
|
1168
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
1169
|
-
assert(vp->obj == 0);
|
1170
|
-
|
1171
|
-
RTYPEDDATA_DATA(obj) = vp;
|
1172
|
-
vp->obj = obj;
|
1173
|
-
RB_OBJ_FREEZE(obj);
|
1174
|
-
return obj;
|
1175
|
-
}
|
1176
|
-
|
1177
|
-
VP_EXPORT Real *
|
1178
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
1179
|
-
{
|
1180
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
1181
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
1182
|
-
if (!pv)
|
1183
|
-
return NULL;
|
1184
|
-
BigDecimal_wrap_struct(obj, pv);
|
1185
|
-
return pv;
|
1186
|
-
}
|
1187
|
-
|
1188
|
-
VP_EXPORT Real *
|
1189
|
-
VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
|
1041
|
+
static NULLABLE_BDVALUE
|
1042
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
1190
1043
|
{
|
1191
|
-
|
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 };
|
1192
1047
|
}
|
1193
1048
|
|
1194
1049
|
static Real *
|
@@ -1196,7 +1051,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
1196
1051
|
{
|
1197
1052
|
assert(x != NULL);
|
1198
1053
|
|
1199
|
-
pv =
|
1054
|
+
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
1200
1055
|
pv->MaxPrec = x->MaxPrec;
|
1201
1056
|
pv->Prec = x->Prec;
|
1202
1057
|
pv->exponent = x->exponent;
|
@@ -1211,7 +1066,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
1211
1066
|
static VALUE
|
1212
1067
|
BigDecimal_IsNaN(VALUE self)
|
1213
1068
|
{
|
1214
|
-
Real *p =
|
1069
|
+
Real *p = GetSelfVpValue(self);
|
1215
1070
|
if (VpIsNaN(p)) return Qtrue;
|
1216
1071
|
return Qfalse;
|
1217
1072
|
}
|
@@ -1222,7 +1077,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
1222
1077
|
static VALUE
|
1223
1078
|
BigDecimal_IsInfinite(VALUE self)
|
1224
1079
|
{
|
1225
|
-
Real *p =
|
1080
|
+
Real *p = GetSelfVpValue(self);
|
1226
1081
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
1227
1082
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
1228
1083
|
return Qnil;
|
@@ -1232,7 +1087,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
1232
1087
|
static VALUE
|
1233
1088
|
BigDecimal_IsFinite(VALUE self)
|
1234
1089
|
{
|
1235
|
-
Real *p =
|
1090
|
+
Real *p = GetSelfVpValue(self);
|
1236
1091
|
if (VpIsNaN(p)) return Qfalse;
|
1237
1092
|
if (VpIsInf(p)) return Qfalse;
|
1238
1093
|
return Qtrue;
|
@@ -1244,6 +1099,7 @@ BigDecimal_check_num(Real *p)
|
|
1244
1099
|
VpCheckException(p, true);
|
1245
1100
|
}
|
1246
1101
|
|
1102
|
+
static VALUE BigDecimal_fix(VALUE self);
|
1247
1103
|
static VALUE BigDecimal_split(VALUE self);
|
1248
1104
|
|
1249
1105
|
/* Returns the value as an Integer.
|
@@ -1253,44 +1109,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
1253
1109
|
static VALUE
|
1254
1110
|
BigDecimal_to_i(VALUE self)
|
1255
1111
|
{
|
1256
|
-
|
1257
|
-
|
1258
|
-
Real *p;
|
1112
|
+
BDVALUE v;
|
1113
|
+
VALUE ret;
|
1259
1114
|
|
1260
|
-
|
1261
|
-
BigDecimal_check_num(
|
1115
|
+
v = GetBDValueMust(self);
|
1116
|
+
BigDecimal_check_num(v.real);
|
1262
1117
|
|
1263
|
-
|
1264
|
-
if (
|
1265
|
-
|
1266
|
-
if (e <= nf) {
|
1267
|
-
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]));
|
1268
1121
|
}
|
1269
1122
|
else {
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
ret = rb_funcall(numerator, '*', 1,
|
1286
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
1287
|
-
INT2FIX(dpower)));
|
1288
|
-
}
|
1289
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
1290
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
1291
|
-
}
|
1292
|
-
return ret;
|
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
|
+
}
|
1293
1138
|
}
|
1139
|
+
|
1140
|
+
RB_GC_GUARD(v.bigdecimal);
|
1141
|
+
return ret;
|
1294
1142
|
}
|
1295
1143
|
|
1296
1144
|
/* Returns a new Float object having approximately the same value as the
|
@@ -1300,24 +1148,26 @@ BigDecimal_to_i(VALUE self)
|
|
1300
1148
|
static VALUE
|
1301
1149
|
BigDecimal_to_f(VALUE self)
|
1302
1150
|
{
|
1303
|
-
ENTER(1);
|
1304
|
-
Real *p;
|
1305
1151
|
double d;
|
1306
1152
|
SIGNED_VALUE e;
|
1307
1153
|
char *buf;
|
1308
1154
|
volatile VALUE str;
|
1155
|
+
BDVALUE v = GetBDValueMust(self);
|
1156
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
1309
1157
|
|
1310
|
-
|
1311
|
-
if (VpVtoD(&d, &e, p) != 1)
|
1158
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
1312
1159
|
return rb_float_new(d);
|
1313
1160
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
1314
1161
|
goto overflow;
|
1315
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
1162
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
1316
1163
|
goto underflow;
|
1317
1164
|
|
1318
|
-
str = rb_str_new(0, VpNumOfChars(
|
1165
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
1319
1166
|
buf = RSTRING_PTR(str);
|
1320
|
-
VpToString(
|
1167
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
1168
|
+
|
1169
|
+
RB_GC_GUARD(v.bigdecimal);
|
1170
|
+
|
1321
1171
|
errno = 0;
|
1322
1172
|
d = strtod(buf, 0);
|
1323
1173
|
if (errno == ERANGE) {
|
@@ -1328,14 +1178,14 @@ BigDecimal_to_f(VALUE self)
|
|
1328
1178
|
|
1329
1179
|
overflow:
|
1330
1180
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
1331
|
-
if (
|
1181
|
+
if (negative)
|
1332
1182
|
return rb_float_new(VpGetDoubleNegInf());
|
1333
1183
|
else
|
1334
1184
|
return rb_float_new(VpGetDoublePosInf());
|
1335
1185
|
|
1336
1186
|
underflow:
|
1337
1187
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
1338
|
-
if (
|
1188
|
+
if (negative)
|
1339
1189
|
return rb_float_new(-0.0);
|
1340
1190
|
else
|
1341
1191
|
return rb_float_new(0.0);
|
@@ -1347,15 +1197,16 @@ underflow:
|
|
1347
1197
|
static VALUE
|
1348
1198
|
BigDecimal_to_r(VALUE self)
|
1349
1199
|
{
|
1350
|
-
|
1200
|
+
BDVALUE v;
|
1351
1201
|
ssize_t sign, power, denomi_power;
|
1352
1202
|
VALUE a, digits, numerator;
|
1353
1203
|
|
1354
|
-
|
1355
|
-
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);
|
1356
1209
|
|
1357
|
-
sign = VpGetSign(p);
|
1358
|
-
power = VpExponent10(p);
|
1359
1210
|
a = BigDecimal_split(self);
|
1360
1211
|
digits = RARRAY_AREF(a, 1);
|
1361
1212
|
denomi_power = power - RSTRING_LEN(digits);
|
@@ -1376,6 +1227,14 @@ BigDecimal_to_r(VALUE self)
|
|
1376
1227
|
}
|
1377
1228
|
}
|
1378
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
|
+
|
1379
1238
|
/* The coerce method provides support for Ruby type coercion. It is not
|
1380
1239
|
* enabled by default.
|
1381
1240
|
*
|
@@ -1393,26 +1252,9 @@ BigDecimal_to_r(VALUE self)
|
|
1393
1252
|
static VALUE
|
1394
1253
|
BigDecimal_coerce(VALUE self, VALUE other)
|
1395
1254
|
{
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
1401
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
1402
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
1403
|
-
}
|
1404
|
-
else {
|
1405
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
1406
|
-
Real* pv = DATA_PTR(self);
|
1407
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
1408
|
-
}
|
1409
|
-
else {
|
1410
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
1411
|
-
}
|
1412
|
-
obj = rb_assoc_new(b->obj, self);
|
1413
|
-
}
|
1414
|
-
|
1415
|
-
return obj;
|
1255
|
+
Real* pv = DATA_PTR(self);
|
1256
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
1257
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
1416
1258
|
}
|
1417
1259
|
|
1418
1260
|
/*
|
@@ -1432,6 +1274,15 @@ BigDecimal_uplus(VALUE self)
|
|
1432
1274
|
return self;
|
1433
1275
|
}
|
1434
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
|
+
|
1435
1286
|
/*
|
1436
1287
|
* call-seq:
|
1437
1288
|
* self + value -> bigdecimal
|
@@ -1451,42 +1302,40 @@ BigDecimal_uplus(VALUE self)
|
|
1451
1302
|
static VALUE
|
1452
1303
|
BigDecimal_add(VALUE self, VALUE r)
|
1453
1304
|
{
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1305
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
1306
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
1307
|
+
}
|
1457
1308
|
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
1464
|
-
}
|
1465
|
-
else {
|
1466
|
-
b = GetVpValue(r, 0);
|
1467
|
-
}
|
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;
|
1468
1314
|
|
1469
|
-
|
1470
|
-
|
1315
|
+
a = GetBDValueMust(self);
|
1316
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
1471
1317
|
|
1472
|
-
if (VpIsNaN(
|
1473
|
-
if (VpIsNaN(
|
1318
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
1319
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
1474
1320
|
|
1475
|
-
mx = GetAddSubPrec(a, b);
|
1321
|
+
mx = GetAddSubPrec(a.real, b.real);
|
1476
1322
|
if (mx == (size_t)-1L) {
|
1477
|
-
|
1478
|
-
|
1323
|
+
/* a or b is inf */
|
1324
|
+
c = NewZeroWrap(1, BASE_FIG);
|
1325
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
1479
1326
|
}
|
1480
1327
|
else {
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1487
|
-
}
|
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);
|
1488
1334
|
}
|
1489
|
-
|
1335
|
+
|
1336
|
+
RB_GC_GUARD(a.bigdecimal);
|
1337
|
+
RB_GC_GUARD(b.bigdecimal);
|
1338
|
+
return CheckGetValue(c);
|
1490
1339
|
}
|
1491
1340
|
|
1492
1341
|
/*
|
@@ -1507,73 +1356,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
1507
1356
|
static VALUE
|
1508
1357
|
BigDecimal_sub(VALUE self, VALUE r)
|
1509
1358
|
{
|
1510
|
-
|
1511
|
-
|
1512
|
-
size_t mx;
|
1513
|
-
|
1514
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
1515
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
1516
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
1517
|
-
}
|
1518
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
1519
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
1520
|
-
}
|
1521
|
-
else {
|
1522
|
-
b = GetVpValue(r,0);
|
1523
|
-
}
|
1524
|
-
|
1525
|
-
if (!b) return DoSomeOne(self,r,'-');
|
1526
|
-
SAVE(b);
|
1527
|
-
|
1528
|
-
if (VpIsNaN(b)) return b->obj;
|
1529
|
-
if (VpIsNaN(a)) return a->obj;
|
1530
|
-
|
1531
|
-
mx = GetAddSubPrec(a,b);
|
1532
|
-
if (mx == (size_t)-1L) {
|
1533
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
1534
|
-
VpAddSub(c, a, b, -1);
|
1535
|
-
}
|
1536
|
-
else {
|
1537
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
|
1538
|
-
if (!mx) {
|
1539
|
-
VpSetInf(c,VpGetSign(a));
|
1540
|
-
}
|
1541
|
-
else {
|
1542
|
-
VpAddSub(c, a, b, -1);
|
1543
|
-
}
|
1544
|
-
}
|
1545
|
-
return VpCheckGetValue(c);
|
1359
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
1360
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
1546
1361
|
}
|
1547
1362
|
|
1548
1363
|
static VALUE
|
1549
1364
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
1550
1365
|
{
|
1551
|
-
ENTER(5);
|
1552
1366
|
SIGNED_VALUE e;
|
1553
|
-
|
1554
|
-
|
1555
|
-
switch (TYPE(r)) {
|
1556
|
-
case T_DATA:
|
1557
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
1558
|
-
/* fall through */
|
1559
|
-
case T_FIXNUM:
|
1560
|
-
/* fall through */
|
1561
|
-
case T_BIGNUM:
|
1562
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
1563
|
-
break;
|
1564
|
-
|
1565
|
-
case T_FLOAT:
|
1566
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
1567
|
-
break;
|
1568
|
-
|
1569
|
-
case T_RATIONAL:
|
1570
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
1571
|
-
break;
|
1367
|
+
BDVALUE a = GetBDValueMust(self);
|
1368
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
1572
1369
|
|
1573
|
-
|
1574
|
-
break;
|
1575
|
-
}
|
1576
|
-
if (b == NULL) {
|
1370
|
+
if (b.real_or_null == NULL) {
|
1577
1371
|
ID f = 0;
|
1578
1372
|
|
1579
1373
|
switch (op) {
|
@@ -1602,8 +1396,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1602
1396
|
}
|
1603
1397
|
return rb_num_coerce_relop(self, r, f);
|
1604
1398
|
}
|
1605
|
-
|
1606
|
-
|
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
|
+
|
1607
1404
|
if (e == 999)
|
1608
1405
|
return (op == '*') ? Qnil : Qfalse;
|
1609
1406
|
switch (op) {
|
@@ -1643,7 +1440,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1643
1440
|
static VALUE
|
1644
1441
|
BigDecimal_zero(VALUE self)
|
1645
1442
|
{
|
1646
|
-
Real *a =
|
1443
|
+
Real *a = GetSelfVpValue(self);
|
1647
1444
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
1648
1445
|
}
|
1649
1446
|
|
@@ -1651,7 +1448,7 @@ BigDecimal_zero(VALUE self)
|
|
1651
1448
|
static VALUE
|
1652
1449
|
BigDecimal_nonzero(VALUE self)
|
1653
1450
|
{
|
1654
|
-
Real *a =
|
1451
|
+
Real *a = GetSelfVpValue(self);
|
1655
1452
|
return VpIsZero(a) ? Qnil : self;
|
1656
1453
|
}
|
1657
1454
|
|
@@ -1777,12 +1574,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
1777
1574
|
static VALUE
|
1778
1575
|
BigDecimal_neg(VALUE self)
|
1779
1576
|
{
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
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);
|
1786
1582
|
}
|
1787
1583
|
|
1788
1584
|
/*
|
@@ -1795,35 +1591,36 @@ BigDecimal_neg(VALUE self)
|
|
1795
1591
|
*
|
1796
1592
|
* See BigDecimal#mult.
|
1797
1593
|
*/
|
1798
|
-
|
1799
1594
|
static VALUE
|
1800
1595
|
BigDecimal_mult(VALUE self, VALUE r)
|
1801
1596
|
{
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1597
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
1598
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
1599
|
+
}
|
1805
1600
|
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1601
|
+
static VALUE
|
1602
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
1603
|
+
{
|
1604
|
+
BDVALUE a, b, c;
|
1605
|
+
|
1606
|
+
a = GetBDValueMust(self);
|
1607
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
1608
|
+
|
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);
|
1812
1613
|
}
|
1813
1614
|
else {
|
1814
|
-
|
1615
|
+
VpLimitRound(c.real, 0);
|
1815
1616
|
}
|
1816
1617
|
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
mx = a->Prec + b->Prec;
|
1821
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
1822
|
-
VpMult(c, a, b);
|
1823
|
-
return VpCheckGetValue(c);
|
1618
|
+
RB_GC_GUARD(a.bigdecimal);
|
1619
|
+
RB_GC_GUARD(b.bigdecimal);
|
1620
|
+
return CheckGetValue(c);
|
1824
1621
|
}
|
1825
1622
|
|
1826
|
-
static
|
1623
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
1827
1624
|
|
1828
1625
|
/* call-seq:
|
1829
1626
|
* a / b -> bigdecimal
|
@@ -1840,14 +1637,7 @@ static VALUE
|
|
1840
1637
|
BigDecimal_div(VALUE self, VALUE r)
|
1841
1638
|
/* For c = self/r: with round operation */
|
1842
1639
|
{
|
1843
|
-
if (
|
1844
|
-
!is_kind_of_BigDecimal(r) &&
|
1845
|
-
!RB_INTEGER_TYPE_P(r) &&
|
1846
|
-
!RB_TYPE_P(r, T_FLOAT) &&
|
1847
|
-
!RB_TYPE_P(r, T_RATIONAL)
|
1848
|
-
) {
|
1849
|
-
return DoSomeOne(self, r, '/');
|
1850
|
-
}
|
1640
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
1851
1641
|
return BigDecimal_div2(self, r, INT2FIX(0));
|
1852
1642
|
}
|
1853
1643
|
|
@@ -1893,114 +1683,100 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
1893
1683
|
/*
|
1894
1684
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
1895
1685
|
* div = (a.to_f/b).floor
|
1686
|
+
* In truncate mode, use truncate instead of floor.
|
1896
1687
|
*/
|
1897
|
-
static
|
1898
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
1688
|
+
static bool
|
1689
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
1899
1690
|
{
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
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;
|
1905
1695
|
|
1906
|
-
|
1907
|
-
SAVE(a);
|
1696
|
+
a = GetBDValueMust(self);
|
1908
1697
|
|
1909
|
-
|
1910
|
-
if (
|
1911
|
-
|
1912
|
-
}
|
1913
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
1914
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
1915
|
-
}
|
1916
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
1917
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
1918
|
-
}
|
1919
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
1920
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
1921
|
-
}
|
1698
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
1699
|
+
if (!b2.real_or_null) return false;
|
1700
|
+
b = bdvalue_nonnullable(b2);
|
1922
1701
|
|
1923
|
-
if (
|
1924
|
-
|
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;
|
1925
1706
|
}
|
1926
|
-
|
1927
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
1928
|
-
SAVE(b);
|
1929
|
-
|
1930
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
1931
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
1932
|
-
if (VpIsZero(b)) {
|
1707
|
+
if (VpIsZero(b.real)) {
|
1933
1708
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
1934
1709
|
}
|
1935
|
-
if (VpIsInf(a)) {
|
1936
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
1710
|
+
if (VpIsInf(a.real)) {
|
1711
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
1937
1712
|
VALUE inf = BigDecimal_positive_infinity();
|
1938
|
-
|
1713
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
1939
1714
|
}
|
1940
1715
|
else {
|
1941
1716
|
VALUE inf = BigDecimal_negative_infinity();
|
1942
|
-
|
1717
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
1943
1718
|
}
|
1944
1719
|
VALUE nan = BigDecimal_nan();
|
1945
|
-
|
1946
|
-
|
1720
|
+
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
1721
|
+
goto Done;
|
1947
1722
|
}
|
1948
|
-
if (VpIsInf(b)) {
|
1723
|
+
if (VpIsInf(b.real)) {
|
1949
1724
|
VALUE zero = BigDecimal_positive_zero();
|
1950
|
-
|
1951
|
-
*mod = a;
|
1952
|
-
|
1725
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
1726
|
+
*mod = bdvalue_nullable(a);
|
1727
|
+
goto Done;
|
1953
1728
|
}
|
1954
|
-
if (VpIsZero(a)) {
|
1729
|
+
if (VpIsZero(a.real)) {
|
1955
1730
|
VALUE zero = BigDecimal_positive_zero();
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1966
|
-
|
1967
|
-
|
1968
|
-
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
VpDivd(
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
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);
|
1980
1754
|
|
1981
|
-
if (!VpIsZero(
|
1755
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
1982
1756
|
/* result adjustment for negative case */
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
VpAddSub(
|
1988
|
-
|
1989
|
-
*
|
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);
|
1990
1767
|
}
|
1991
1768
|
else {
|
1992
|
-
*div =
|
1993
|
-
*mod =
|
1769
|
+
*div = bdvalue_nullable(dv);
|
1770
|
+
*mod = bdvalue_nullable(md);
|
1994
1771
|
}
|
1995
|
-
return Qtrue;
|
1996
1772
|
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
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;
|
2004
1780
|
}
|
2005
1781
|
|
2006
1782
|
/* call-seq:
|
@@ -2014,85 +1790,31 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
2014
1790
|
static VALUE
|
2015
1791
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
2016
1792
|
{
|
2017
|
-
|
2018
|
-
Real *div = NULL, *mod = NULL;
|
1793
|
+
NULLABLE_BDVALUE div, mod;
|
2019
1794
|
|
2020
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
2021
|
-
|
2022
|
-
return VpCheckGetValue(mod);
|
1795
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
1796
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
2023
1797
|
}
|
2024
1798
|
return DoSomeOne(self, r, '%');
|
2025
1799
|
}
|
2026
1800
|
|
1801
|
+
/* call-seq:
|
1802
|
+
* remainder(value)
|
1803
|
+
*
|
1804
|
+
* Returns the remainder from dividing by the value.
|
1805
|
+
*
|
1806
|
+
* x.remainder(y) means x-y*(x/y).truncate
|
1807
|
+
*/
|
2027
1808
|
static VALUE
|
2028
|
-
|
1809
|
+
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
2029
1810
|
{
|
2030
|
-
|
2031
|
-
size_t mx;
|
2032
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
2033
|
-
Real *f = NULL;
|
2034
|
-
|
2035
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2036
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
2037
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
2038
|
-
}
|
2039
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
2040
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
2041
|
-
}
|
2042
|
-
else {
|
2043
|
-
b = GetVpValue(r, 0);
|
2044
|
-
}
|
2045
|
-
|
2046
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
2047
|
-
SAVE(b);
|
1811
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
2048
1812
|
|
2049
|
-
if (
|
2050
|
-
|
2051
|
-
VpSetZero(*dv, 1);
|
2052
|
-
*rv = a;
|
2053
|
-
return Qnil;
|
1813
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
1814
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
2054
1815
|
}
|
2055
|
-
|
2056
|
-
|
2057
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2058
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2059
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2060
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
2061
|
-
|
2062
|
-
VpDivd(c, res, a, b);
|
2063
|
-
|
2064
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
2065
|
-
|
2066
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
2067
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
2068
|
-
|
2069
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
2070
|
-
|
2071
|
-
VpFrac(f, c);
|
2072
|
-
VpMult(rr, f, b);
|
2073
|
-
VpAddSub(ff, res, rr, 1);
|
2074
|
-
|
2075
|
-
*dv = d;
|
2076
|
-
*rv = ff;
|
2077
|
-
return Qnil;
|
2078
|
-
}
|
2079
|
-
|
2080
|
-
/* call-seq:
|
2081
|
-
* remainder(value)
|
2082
|
-
*
|
2083
|
-
* Returns the remainder from dividing by the value.
|
2084
|
-
*
|
2085
|
-
* x.remainder(y) means x-y*(x/y).truncate
|
2086
|
-
*/
|
2087
|
-
static VALUE
|
2088
|
-
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
2089
|
-
{
|
2090
|
-
VALUE f;
|
2091
|
-
Real *d, *rv = 0;
|
2092
|
-
f = BigDecimal_divremain(self, r, &d, &rv);
|
2093
|
-
if (!NIL_P(f)) return f;
|
2094
|
-
return VpCheckGetValue(rv);
|
2095
|
-
}
|
1816
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
1817
|
+
}
|
2096
1818
|
|
2097
1819
|
/* call-seq:
|
2098
1820
|
* divmod(value)
|
@@ -2119,12 +1841,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2119
1841
|
static VALUE
|
2120
1842
|
BigDecimal_divmod(VALUE self, VALUE r)
|
2121
1843
|
{
|
2122
|
-
|
2123
|
-
Real *div = NULL, *mod = NULL;
|
1844
|
+
NULLABLE_BDVALUE div, mod;
|
2124
1845
|
|
2125
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
2126
|
-
|
2127
|
-
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)));
|
2128
1848
|
}
|
2129
1849
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
2130
1850
|
}
|
@@ -2136,17 +1856,14 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
2136
1856
|
static inline VALUE
|
2137
1857
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
2138
1858
|
{
|
2139
|
-
ENTER(5);
|
2140
1859
|
SIGNED_VALUE ix;
|
2141
|
-
|
2142
|
-
Real *av = NULL, *bv = NULL, *cv = NULL;
|
2143
|
-
size_t mx, pl;
|
1860
|
+
BDVALUE av, bv, cv, res;
|
2144
1861
|
|
2145
1862
|
if (NIL_P(n)) { /* div in Float sense */
|
2146
|
-
|
2147
|
-
|
2148
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
2149
|
-
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)));
|
2150
1867
|
}
|
2151
1868
|
return DoSomeOne(self, b, rb_intern("div"));
|
2152
1869
|
}
|
@@ -2154,48 +1871,39 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2154
1871
|
/* div in BigDecimal sense */
|
2155
1872
|
ix = check_int_precision(n);
|
2156
1873
|
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
GUARD_OBJ(av, GetVpValue(self, 1));
|
2161
|
-
if (RB_FLOAT_TYPE_P(b) && ix > BIGDECIMAL_DOUBLE_FIGURES) {
|
2162
|
-
/* TODO: I want to refactor this precision control for a float value later
|
2163
|
-
* by introducing an implicit conversion function instead of
|
2164
|
-
* GetVpValueWithPrec. */
|
2165
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, BIGDECIMAL_DOUBLE_FIGURES, 1));
|
2166
|
-
}
|
2167
|
-
else {
|
2168
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, ix, 1));
|
2169
|
-
}
|
1874
|
+
av = GetBDValueMust(self);
|
1875
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
2170
1876
|
|
2171
1877
|
if (ix == 0) {
|
2172
|
-
ssize_t a_prec, b_prec;
|
2173
|
-
VpCountPrecisionAndScale(av, &a_prec, NULL);
|
2174
|
-
VpCountPrecisionAndScale(bv, &b_prec, NULL);
|
1878
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
1879
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
1880
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
2175
1881
|
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
2176
1882
|
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
2177
1883
|
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
1884
|
+
if (limit && limit < ix) ix = limit;
|
2178
1885
|
}
|
2179
1886
|
|
2180
|
-
//
|
2181
|
-
|
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);
|
2182
1891
|
|
2183
|
-
|
2184
|
-
if (mx <= av->Prec) mx = av->Prec + 1;
|
2185
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, mx * VpBaseFig()));
|
2186
|
-
VpDivd(cv, res, av, bv);
|
2187
|
-
VpSetPrecLimit(pl);
|
2188
|
-
if (!VpIsZero(res)) {
|
1892
|
+
if (!VpIsZero(res.real)) {
|
2189
1893
|
// Remainder value affects rounding result.
|
2190
|
-
// ROUND_UP cv = 0.1e0 with
|
1894
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
2191
1895
|
// 0.1e0 if remainder == 0
|
2192
1896
|
// 0.1000000001e0 if remainder != 0
|
2193
1897
|
size_t idx = roomof(ix, BASE_FIG);
|
2194
|
-
while (cv->Prec <= idx) cv->frac[cv->Prec++] = 0;
|
2195
|
-
if (cv->frac[idx] == 0 || cv->frac[idx] == HALF_BASE) cv->frac[idx]++;
|
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]++;
|
2196
1900
|
}
|
2197
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
2198
|
-
|
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);
|
2199
1907
|
}
|
2200
1908
|
|
2201
1909
|
/*
|
@@ -2271,18 +1979,7 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
2271
1979
|
static VALUE
|
2272
1980
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
2273
1981
|
{
|
2274
|
-
|
2275
|
-
Real *cv;
|
2276
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2277
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
2278
|
-
else {
|
2279
|
-
size_t pl = VpSetPrecLimit(0);
|
2280
|
-
VALUE c = BigDecimal_add(self, b);
|
2281
|
-
VpSetPrecLimit(pl);
|
2282
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2283
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2284
|
-
return VpCheckGetValue(cv);
|
2285
|
-
}
|
1982
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
2286
1983
|
}
|
2287
1984
|
|
2288
1985
|
/* call-seq:
|
@@ -2301,18 +1998,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2301
1998
|
static VALUE
|
2302
1999
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
2303
2000
|
{
|
2304
|
-
|
2305
|
-
Real *cv;
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2307
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
2308
|
-
else {
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
2310
|
-
VALUE c = BigDecimal_sub(self, b);
|
2311
|
-
VpSetPrecLimit(pl);
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2314
|
-
return VpCheckGetValue(cv);
|
2315
|
-
}
|
2001
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
2316
2002
|
}
|
2317
2003
|
|
2318
2004
|
/*
|
@@ -2344,18 +2030,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2344
2030
|
static VALUE
|
2345
2031
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
2346
2032
|
{
|
2347
|
-
|
2348
|
-
Real *cv;
|
2349
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
2350
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
2351
|
-
else {
|
2352
|
-
size_t pl = VpSetPrecLimit(0);
|
2353
|
-
VALUE c = BigDecimal_mult(self, b);
|
2354
|
-
VpSetPrecLimit(pl);
|
2355
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
2356
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
2357
|
-
return VpCheckGetValue(cv);
|
2358
|
-
}
|
2033
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
2359
2034
|
}
|
2360
2035
|
|
2361
2036
|
/*
|
@@ -2372,41 +2047,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2372
2047
|
static VALUE
|
2373
2048
|
BigDecimal_abs(VALUE self)
|
2374
2049
|
{
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2381
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2382
|
-
VpAsgn(c, a, 1);
|
2383
|
-
VpChangeSign(c, 1);
|
2384
|
-
return VpCheckGetValue(c);
|
2385
|
-
}
|
2386
|
-
|
2387
|
-
/* call-seq:
|
2388
|
-
* sqrt(n)
|
2389
|
-
*
|
2390
|
-
* Returns the square root of the value.
|
2391
|
-
*
|
2392
|
-
* Result has at least n significant digits.
|
2393
|
-
*/
|
2394
|
-
static VALUE
|
2395
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
2396
|
-
{
|
2397
|
-
ENTER(5);
|
2398
|
-
Real *c, *a;
|
2399
|
-
size_t mx, n;
|
2400
|
-
|
2401
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2402
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2403
|
-
|
2404
|
-
n = check_int_precision(nFig);
|
2405
|
-
n += VpDblFig() + VpBaseFig();
|
2406
|
-
if (mx <= n) mx = n;
|
2407
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2408
|
-
VpSqrt(c, a);
|
2409
|
-
return VpCheckGetValue(c);
|
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);
|
2410
2056
|
}
|
2411
2057
|
|
2412
2058
|
/* Return the integer part of the number, as a BigDecimal.
|
@@ -2414,15 +2060,11 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2414
2060
|
static VALUE
|
2415
2061
|
BigDecimal_fix(VALUE self)
|
2416
2062
|
{
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
2423
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2424
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
2425
|
-
return VpCheckGetValue(c);
|
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);
|
2426
2068
|
}
|
2427
2069
|
|
2428
2070
|
/* call-seq:
|
@@ -2454,13 +2096,12 @@ BigDecimal_fix(VALUE self)
|
|
2454
2096
|
static VALUE
|
2455
2097
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
2456
2098
|
{
|
2457
|
-
|
2458
|
-
Real *c, *a;
|
2099
|
+
BDVALUE c, a;
|
2459
2100
|
int iLoc = 0;
|
2460
2101
|
VALUE vLoc;
|
2461
2102
|
VALUE vRound;
|
2462
2103
|
int round_to_int = 0;
|
2463
|
-
size_t mx
|
2104
|
+
size_t mx;
|
2464
2105
|
|
2465
2106
|
unsigned short sw = VpGetRoundMode();
|
2466
2107
|
|
@@ -2491,16 +2132,46 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2491
2132
|
break;
|
2492
2133
|
}
|
2493
2134
|
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
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
|
+
|
2500
2143
|
if (round_to_int) {
|
2501
|
-
return BigDecimal_to_i(
|
2144
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
2145
|
+
}
|
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));
|
2502
2173
|
}
|
2503
|
-
return
|
2174
|
+
return CheckGetValue(c);
|
2504
2175
|
}
|
2505
2176
|
|
2506
2177
|
/* call-seq:
|
@@ -2525,28 +2196,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2525
2196
|
static VALUE
|
2526
2197
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
2527
2198
|
{
|
2528
|
-
|
2529
|
-
Real *c, *a;
|
2530
|
-
int iLoc;
|
2531
|
-
VALUE vLoc;
|
2532
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2533
|
-
|
2534
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
2535
|
-
iLoc = 0;
|
2536
|
-
}
|
2537
|
-
else {
|
2538
|
-
iLoc = NUM2INT(vLoc);
|
2539
|
-
}
|
2540
|
-
|
2541
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2542
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2543
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2544
|
-
VpSetPrecLimit(pl);
|
2545
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
2546
|
-
if (argc == 0) {
|
2547
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2548
|
-
}
|
2549
|
-
return VpCheckGetValue(c);
|
2199
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
2550
2200
|
}
|
2551
2201
|
|
2552
2202
|
/* Return the fractional part of the number, as a BigDecimal.
|
@@ -2554,15 +2204,11 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2554
2204
|
static VALUE
|
2555
2205
|
BigDecimal_frac(VALUE self)
|
2556
2206
|
{
|
2557
|
-
|
2558
|
-
|
2559
|
-
|
2560
|
-
|
2561
|
-
|
2562
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2563
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2564
|
-
VpFrac(c, a);
|
2565
|
-
return VpCheckGetValue(c);
|
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);
|
2566
2212
|
}
|
2567
2213
|
|
2568
2214
|
/* call-seq:
|
@@ -2585,31 +2231,7 @@ BigDecimal_frac(VALUE self)
|
|
2585
2231
|
static VALUE
|
2586
2232
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
2587
2233
|
{
|
2588
|
-
|
2589
|
-
Real *c, *a;
|
2590
|
-
int iLoc;
|
2591
|
-
VALUE vLoc;
|
2592
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2593
|
-
|
2594
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
2595
|
-
iLoc = 0;
|
2596
|
-
}
|
2597
|
-
else {
|
2598
|
-
iLoc = NUM2INT(vLoc);
|
2599
|
-
}
|
2600
|
-
|
2601
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2602
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2603
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2604
|
-
VpSetPrecLimit(pl);
|
2605
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
2606
|
-
#ifdef BIGDECIMAL_DEBUG
|
2607
|
-
VPrint(stderr, "floor: c=%\n", c);
|
2608
|
-
#endif
|
2609
|
-
if (argc == 0) {
|
2610
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2611
|
-
}
|
2612
|
-
return VpCheckGetValue(c);
|
2234
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
2613
2235
|
}
|
2614
2236
|
|
2615
2237
|
/* call-seq:
|
@@ -2632,27 +2254,7 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2632
2254
|
static VALUE
|
2633
2255
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
2634
2256
|
{
|
2635
|
-
|
2636
|
-
Real *c, *a;
|
2637
|
-
int iLoc;
|
2638
|
-
VALUE vLoc;
|
2639
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
2640
|
-
|
2641
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
2642
|
-
iLoc = 0;
|
2643
|
-
} else {
|
2644
|
-
iLoc = NUM2INT(vLoc);
|
2645
|
-
}
|
2646
|
-
|
2647
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
2648
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
2649
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
2650
|
-
VpSetPrecLimit(pl);
|
2651
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
2652
|
-
if (argc == 0) {
|
2653
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
2654
|
-
}
|
2655
|
-
return VpCheckGetValue(c);
|
2257
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
2656
2258
|
}
|
2657
2259
|
|
2658
2260
|
/* call-seq:
|
@@ -2673,7 +2275,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2673
2275
|
* If s contains a number, a space is inserted after each group of that many
|
2674
2276
|
* digits, starting from '.' and counting outwards.
|
2675
2277
|
*
|
2676
|
-
* If s ends with an 'E',
|
2278
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
2677
2279
|
*
|
2678
2280
|
* If s ends with an 'F', conventional floating point notation is used.
|
2679
2281
|
*
|
@@ -2691,10 +2293,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2691
2293
|
static VALUE
|
2692
2294
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
2693
2295
|
{
|
2694
|
-
ENTER(5);
|
2695
2296
|
int fmt = 0; /* 0: E format, 1: F format */
|
2696
2297
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
2697
|
-
|
2298
|
+
BDVALUE v;
|
2698
2299
|
volatile VALUE str;
|
2699
2300
|
char *psz;
|
2700
2301
|
char ch;
|
@@ -2702,7 +2303,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2702
2303
|
SIGNED_VALUE m;
|
2703
2304
|
VALUE f;
|
2704
2305
|
|
2705
|
-
|
2306
|
+
v = GetBDValueMust(self);
|
2706
2307
|
|
2707
2308
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
2708
2309
|
if (RB_TYPE_P(f, T_STRING)) {
|
@@ -2737,10 +2338,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2737
2338
|
}
|
2738
2339
|
}
|
2739
2340
|
if (fmt) {
|
2740
|
-
nc = VpNumOfChars(
|
2341
|
+
nc = VpNumOfChars(v.real, "F");
|
2741
2342
|
}
|
2742
2343
|
else {
|
2743
|
-
nc = VpNumOfChars(
|
2344
|
+
nc = VpNumOfChars(v.real, "E");
|
2744
2345
|
}
|
2745
2346
|
if (mc > 0) {
|
2746
2347
|
nc += (nc + mc - 1) / mc + 1;
|
@@ -2750,12 +2351,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2750
2351
|
psz = RSTRING_PTR(str);
|
2751
2352
|
|
2752
2353
|
if (fmt) {
|
2753
|
-
VpToFString(
|
2354
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
2754
2355
|
}
|
2755
2356
|
else {
|
2756
|
-
VpToString (
|
2357
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
2757
2358
|
}
|
2758
2359
|
rb_str_resize(str, strlen(psz));
|
2360
|
+
|
2361
|
+
RB_GC_GUARD(v.bigdecimal);
|
2759
2362
|
return str;
|
2760
2363
|
}
|
2761
2364
|
|
@@ -2786,16 +2389,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2786
2389
|
static VALUE
|
2787
2390
|
BigDecimal_split(VALUE self)
|
2788
2391
|
{
|
2789
|
-
|
2790
|
-
Real *vp;
|
2392
|
+
BDVALUE v;
|
2791
2393
|
VALUE obj,str;
|
2792
2394
|
ssize_t e, s;
|
2793
2395
|
char *psz1;
|
2794
2396
|
|
2795
|
-
|
2796
|
-
str = rb_str_new(0, VpNumOfChars(
|
2397
|
+
v = GetBDValueMust(self);
|
2398
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
2797
2399
|
psz1 = RSTRING_PTR(str);
|
2798
|
-
VpSzMantissa(
|
2400
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
2799
2401
|
s = 1;
|
2800
2402
|
if(psz1[0] == '-') {
|
2801
2403
|
size_t len = strlen(psz1 + 1);
|
@@ -2805,13 +2407,15 @@ BigDecimal_split(VALUE self)
|
|
2805
2407
|
s = -1;
|
2806
2408
|
}
|
2807
2409
|
if (psz1[0] == 'N') s = 0; /* NaN */
|
2808
|
-
e = VpExponent10(
|
2410
|
+
e = VpExponent10(v.real);
|
2809
2411
|
obj = rb_ary_new2(4);
|
2810
2412
|
rb_ary_push(obj, INT2FIX(s));
|
2811
2413
|
rb_ary_push(obj, str);
|
2812
2414
|
rb_str_resize(str, strlen(psz1));
|
2813
2415
|
rb_ary_push(obj, INT2FIX(10));
|
2814
2416
|
rb_ary_push(obj, SSIZET2NUM(e));
|
2417
|
+
|
2418
|
+
RB_GC_GUARD(v.bigdecimal);
|
2815
2419
|
return obj;
|
2816
2420
|
}
|
2817
2421
|
|
@@ -2823,7 +2427,7 @@ BigDecimal_split(VALUE self)
|
|
2823
2427
|
static VALUE
|
2824
2428
|
BigDecimal_exponent(VALUE self)
|
2825
2429
|
{
|
2826
|
-
ssize_t e = VpExponent10(
|
2430
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
2827
2431
|
return SSIZET2NUM(e);
|
2828
2432
|
}
|
2829
2433
|
|
@@ -2835,49 +2439,78 @@ BigDecimal_exponent(VALUE self)
|
|
2835
2439
|
static VALUE
|
2836
2440
|
BigDecimal_inspect(VALUE self)
|
2837
2441
|
{
|
2838
|
-
|
2839
|
-
Real *vp;
|
2442
|
+
BDVALUE v;
|
2840
2443
|
volatile VALUE str;
|
2841
2444
|
size_t nc;
|
2842
2445
|
|
2843
|
-
|
2844
|
-
nc = VpNumOfChars(
|
2446
|
+
v = GetBDValueMust(self);
|
2447
|
+
nc = VpNumOfChars(v.real, "E");
|
2845
2448
|
|
2846
2449
|
str = rb_str_new(0, nc);
|
2847
|
-
VpToString(
|
2450
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
2848
2451
|
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
2849
|
-
return str;
|
2850
|
-
}
|
2851
|
-
|
2852
|
-
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
2853
|
-
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
2854
|
-
|
2855
|
-
#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
|
2856
|
-
#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
|
2857
2452
|
|
2858
|
-
|
2859
|
-
|
2860
|
-
{
|
2861
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
2453
|
+
RB_GC_GUARD(v.bigdecimal);
|
2454
|
+
return str;
|
2862
2455
|
}
|
2863
2456
|
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
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
|
+
}
|
2875
2504
|
}
|
2876
|
-
|
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);
|
2877
2512
|
}
|
2878
2513
|
|
2879
|
-
#define is_positive(x) (!is_negative(x))
|
2880
|
-
|
2881
2514
|
inline static int
|
2882
2515
|
is_zero(VALUE x)
|
2883
2516
|
{
|
@@ -2901,344 +2534,6 @@ is_zero(VALUE x)
|
|
2901
2534
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
2902
2535
|
}
|
2903
2536
|
|
2904
|
-
inline static int
|
2905
|
-
is_one(VALUE x)
|
2906
|
-
{
|
2907
|
-
VALUE num, den;
|
2908
|
-
|
2909
|
-
switch (TYPE(x)) {
|
2910
|
-
case T_FIXNUM:
|
2911
|
-
return FIX2LONG(x) == 1;
|
2912
|
-
|
2913
|
-
case T_BIGNUM:
|
2914
|
-
return Qfalse;
|
2915
|
-
|
2916
|
-
case T_RATIONAL:
|
2917
|
-
num = rb_rational_num(x);
|
2918
|
-
den = rb_rational_den(x);
|
2919
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
2920
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
2921
|
-
|
2922
|
-
default:
|
2923
|
-
break;
|
2924
|
-
}
|
2925
|
-
|
2926
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
2927
|
-
}
|
2928
|
-
|
2929
|
-
inline static int
|
2930
|
-
is_even(VALUE x)
|
2931
|
-
{
|
2932
|
-
switch (TYPE(x)) {
|
2933
|
-
case T_FIXNUM:
|
2934
|
-
return (FIX2LONG(x) % 2) == 0;
|
2935
|
-
|
2936
|
-
case T_BIGNUM:
|
2937
|
-
{
|
2938
|
-
unsigned long l;
|
2939
|
-
rb_big_pack(x, &l, 1);
|
2940
|
-
return l % 2 == 0;
|
2941
|
-
}
|
2942
|
-
|
2943
|
-
default:
|
2944
|
-
break;
|
2945
|
-
}
|
2946
|
-
|
2947
|
-
return 0;
|
2948
|
-
}
|
2949
|
-
|
2950
|
-
static VALUE
|
2951
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
2952
|
-
{
|
2953
|
-
VALUE log_x, multiplied, y;
|
2954
|
-
volatile VALUE obj = exp->obj;
|
2955
|
-
|
2956
|
-
if (VpIsZero(exp)) {
|
2957
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
2958
|
-
}
|
2959
|
-
|
2960
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
2961
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
2962
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
2963
|
-
RB_GC_GUARD(obj);
|
2964
|
-
|
2965
|
-
return y;
|
2966
|
-
}
|
2967
|
-
|
2968
|
-
/* call-seq:
|
2969
|
-
* power(n)
|
2970
|
-
* power(n, prec)
|
2971
|
-
*
|
2972
|
-
* Returns the value raised to the power of n.
|
2973
|
-
*
|
2974
|
-
* Note that n must be an Integer.
|
2975
|
-
*
|
2976
|
-
* Also available as the operator **.
|
2977
|
-
*/
|
2978
|
-
static VALUE
|
2979
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
2980
|
-
{
|
2981
|
-
ENTER(5);
|
2982
|
-
VALUE vexp, prec;
|
2983
|
-
Real* exp = NULL;
|
2984
|
-
Real *x, *y;
|
2985
|
-
ssize_t mp, ma, n;
|
2986
|
-
SIGNED_VALUE int_exp;
|
2987
|
-
double d;
|
2988
|
-
|
2989
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
2990
|
-
|
2991
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
2992
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
2993
|
-
|
2994
|
-
if (VpIsNaN(x)) {
|
2995
|
-
y = NewZeroWrapLimited(1, n);
|
2996
|
-
VpSetNaN(y);
|
2997
|
-
RB_GC_GUARD(y->obj);
|
2998
|
-
return VpCheckGetValue(y);
|
2999
|
-
}
|
3000
|
-
|
3001
|
-
retry:
|
3002
|
-
switch (TYPE(vexp)) {
|
3003
|
-
case T_FIXNUM:
|
3004
|
-
break;
|
3005
|
-
|
3006
|
-
case T_BIGNUM:
|
3007
|
-
break;
|
3008
|
-
|
3009
|
-
case T_FLOAT:
|
3010
|
-
d = RFLOAT_VALUE(vexp);
|
3011
|
-
if (d == round(d)) {
|
3012
|
-
if (FIXABLE(d)) {
|
3013
|
-
vexp = LONG2FIX((long)d);
|
3014
|
-
}
|
3015
|
-
else {
|
3016
|
-
vexp = rb_dbl2big(d);
|
3017
|
-
}
|
3018
|
-
goto retry;
|
3019
|
-
}
|
3020
|
-
if (NIL_P(prec)) {
|
3021
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
3022
|
-
}
|
3023
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
3024
|
-
break;
|
3025
|
-
|
3026
|
-
case T_RATIONAL:
|
3027
|
-
if (is_zero(rb_rational_num(vexp))) {
|
3028
|
-
if (is_positive(vexp)) {
|
3029
|
-
vexp = INT2FIX(0);
|
3030
|
-
goto retry;
|
3031
|
-
}
|
3032
|
-
}
|
3033
|
-
else if (is_one(rb_rational_den(vexp))) {
|
3034
|
-
vexp = rb_rational_num(vexp);
|
3035
|
-
goto retry;
|
3036
|
-
}
|
3037
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
3038
|
-
if (NIL_P(prec)) {
|
3039
|
-
n += n;
|
3040
|
-
}
|
3041
|
-
break;
|
3042
|
-
|
3043
|
-
case T_DATA:
|
3044
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
3045
|
-
VALUE zero = INT2FIX(0);
|
3046
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
3047
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
3048
|
-
vexp = BigDecimal_to_i(vexp);
|
3049
|
-
goto retry;
|
3050
|
-
}
|
3051
|
-
if (NIL_P(prec)) {
|
3052
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
3053
|
-
n += y->Prec*VpBaseFig();
|
3054
|
-
}
|
3055
|
-
exp = DATA_PTR(vexp);
|
3056
|
-
break;
|
3057
|
-
}
|
3058
|
-
/* fall through */
|
3059
|
-
default:
|
3060
|
-
rb_raise(rb_eTypeError,
|
3061
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
3062
|
-
RB_OBJ_CLASSNAME(vexp));
|
3063
|
-
}
|
3064
|
-
|
3065
|
-
if (VpIsZero(x)) {
|
3066
|
-
if (is_negative(vexp)) {
|
3067
|
-
y = NewZeroWrapNolimit(1, n);
|
3068
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3069
|
-
if (is_integer(vexp)) {
|
3070
|
-
if (is_even(vexp)) {
|
3071
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
3072
|
-
VpSetPosInf(y);
|
3073
|
-
}
|
3074
|
-
else {
|
3075
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
3076
|
-
VpSetNegInf(y);
|
3077
|
-
}
|
3078
|
-
}
|
3079
|
-
else {
|
3080
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
3081
|
-
VpSetPosInf(y);
|
3082
|
-
}
|
3083
|
-
}
|
3084
|
-
else {
|
3085
|
-
/* (+0) ** (-num) -> Infinity */
|
3086
|
-
VpSetPosInf(y);
|
3087
|
-
}
|
3088
|
-
RB_GC_GUARD(y->obj);
|
3089
|
-
return VpCheckGetValue(y);
|
3090
|
-
}
|
3091
|
-
else if (is_zero(vexp)) {
|
3092
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3093
|
-
}
|
3094
|
-
else {
|
3095
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3096
|
-
}
|
3097
|
-
}
|
3098
|
-
|
3099
|
-
if (is_zero(vexp)) {
|
3100
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3101
|
-
}
|
3102
|
-
else if (is_one(vexp)) {
|
3103
|
-
return self;
|
3104
|
-
}
|
3105
|
-
|
3106
|
-
if (VpIsInf(x)) {
|
3107
|
-
if (is_negative(vexp)) {
|
3108
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3109
|
-
if (is_integer(vexp)) {
|
3110
|
-
if (is_even(vexp)) {
|
3111
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
3112
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3113
|
-
}
|
3114
|
-
else {
|
3115
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
3116
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3117
|
-
}
|
3118
|
-
}
|
3119
|
-
else {
|
3120
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
3121
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3122
|
-
}
|
3123
|
-
}
|
3124
|
-
else {
|
3125
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3126
|
-
}
|
3127
|
-
}
|
3128
|
-
else {
|
3129
|
-
y = NewZeroWrapLimited(1, n);
|
3130
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
3131
|
-
if (is_integer(vexp)) {
|
3132
|
-
if (is_even(vexp)) {
|
3133
|
-
VpSetPosInf(y);
|
3134
|
-
}
|
3135
|
-
else {
|
3136
|
-
VpSetNegInf(y);
|
3137
|
-
}
|
3138
|
-
}
|
3139
|
-
else {
|
3140
|
-
/* TODO: support complex */
|
3141
|
-
rb_raise(rb_eMathDomainError,
|
3142
|
-
"a non-integral exponent for a negative base");
|
3143
|
-
}
|
3144
|
-
}
|
3145
|
-
else {
|
3146
|
-
VpSetPosInf(y);
|
3147
|
-
}
|
3148
|
-
return VpCheckGetValue(y);
|
3149
|
-
}
|
3150
|
-
}
|
3151
|
-
|
3152
|
-
if (exp != NULL) {
|
3153
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
3154
|
-
}
|
3155
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
3156
|
-
VALUE abs_value = BigDecimal_abs(self);
|
3157
|
-
if (is_one(abs_value)) {
|
3158
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
3159
|
-
}
|
3160
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
3161
|
-
if (is_negative(vexp)) {
|
3162
|
-
y = NewZeroWrapLimited(1, n);
|
3163
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
3164
|
-
return VpCheckGetValue(y);
|
3165
|
-
}
|
3166
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
3167
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3168
|
-
}
|
3169
|
-
else {
|
3170
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3171
|
-
}
|
3172
|
-
}
|
3173
|
-
else {
|
3174
|
-
if (is_positive(vexp)) {
|
3175
|
-
y = NewZeroWrapLimited(1, n);
|
3176
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
3177
|
-
return VpCheckGetValue(y);
|
3178
|
-
}
|
3179
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
3180
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
3181
|
-
}
|
3182
|
-
else {
|
3183
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
3184
|
-
}
|
3185
|
-
}
|
3186
|
-
}
|
3187
|
-
|
3188
|
-
int_exp = FIX2LONG(vexp);
|
3189
|
-
ma = int_exp;
|
3190
|
-
if (ma < 0) ma = -ma;
|
3191
|
-
if (ma == 0) ma = 1;
|
3192
|
-
|
3193
|
-
if (VpIsDef(x)) {
|
3194
|
-
mp = x->Prec * (VpBaseFig() + 1);
|
3195
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
3196
|
-
}
|
3197
|
-
else {
|
3198
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
3199
|
-
}
|
3200
|
-
VpPowerByInt(y, x, int_exp);
|
3201
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
3202
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
3203
|
-
}
|
3204
|
-
return VpCheckGetValue(y);
|
3205
|
-
}
|
3206
|
-
|
3207
|
-
/* call-seq:
|
3208
|
-
* self ** other -> bigdecimal
|
3209
|
-
*
|
3210
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
3211
|
-
*
|
3212
|
-
* b = BigDecimal('3.14')
|
3213
|
-
* b ** 2 # => 0.98596e1
|
3214
|
-
* b ** 2.0 # => 0.98596e1
|
3215
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
3216
|
-
*
|
3217
|
-
* Related: BigDecimal#power.
|
3218
|
-
*
|
3219
|
-
*/
|
3220
|
-
static VALUE
|
3221
|
-
BigDecimal_power_op(VALUE self, VALUE exp)
|
3222
|
-
{
|
3223
|
-
return BigDecimal_power(1, &exp, self);
|
3224
|
-
}
|
3225
|
-
|
3226
|
-
/* :nodoc:
|
3227
|
-
*
|
3228
|
-
* private method for dup and clone the provided BigDecimal +other+
|
3229
|
-
*/
|
3230
|
-
static VALUE
|
3231
|
-
BigDecimal_initialize_copy(VALUE self, VALUE other)
|
3232
|
-
{
|
3233
|
-
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
|
3234
|
-
Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
|
3235
|
-
|
3236
|
-
if (self != other) {
|
3237
|
-
DATA_PTR(self) = VpCopy(pv, x);
|
3238
|
-
}
|
3239
|
-
return self;
|
3240
|
-
}
|
3241
|
-
|
3242
2537
|
/* :nodoc: */
|
3243
2538
|
static VALUE
|
3244
2539
|
BigDecimal_clone(VALUE self)
|
@@ -3277,20 +2572,17 @@ check_exception(VALUE bd)
|
|
3277
2572
|
|
3278
2573
|
Real *vp;
|
3279
2574
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
3280
|
-
|
2575
|
+
VpCheckException(vp, false);
|
3281
2576
|
|
3282
2577
|
return bd;
|
3283
2578
|
}
|
3284
2579
|
|
3285
2580
|
static VALUE
|
3286
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
2581
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
3287
2582
|
{
|
3288
|
-
VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
3289
|
-
|
3290
2583
|
Real *vp;
|
3291
2584
|
if (uval == 0) {
|
3292
2585
|
vp = rbd_allocate_struct(1);
|
3293
|
-
vp->MaxPrec = 1;
|
3294
2586
|
vp->Prec = 1;
|
3295
2587
|
vp->exponent = 1;
|
3296
2588
|
VpSetZero(vp, 1);
|
@@ -3298,7 +2590,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
3298
2590
|
}
|
3299
2591
|
else if (uval < BASE) {
|
3300
2592
|
vp = rbd_allocate_struct(1);
|
3301
|
-
vp->MaxPrec = 1;
|
3302
2593
|
vp->Prec = 1;
|
3303
2594
|
vp->exponent = 1;
|
3304
2595
|
VpSetSign(vp, 1);
|
@@ -3324,21 +2615,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
3324
2615
|
|
3325
2616
|
const size_t exp = len + ntz;
|
3326
2617
|
vp = rbd_allocate_struct(len);
|
3327
|
-
vp->MaxPrec = len;
|
3328
2618
|
vp->Prec = len;
|
3329
2619
|
vp->exponent = exp;
|
3330
2620
|
VpSetSign(vp, 1);
|
3331
2621
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
3332
2622
|
}
|
3333
2623
|
|
3334
|
-
return BigDecimal_wrap_struct(
|
2624
|
+
return BigDecimal_wrap_struct(rb_cBigDecimal, vp);
|
3335
2625
|
}
|
3336
2626
|
|
3337
2627
|
static VALUE
|
3338
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
2628
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
3339
2629
|
{
|
3340
2630
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
3341
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
2631
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
3342
2632
|
if (ival < 0) {
|
3343
2633
|
Real *vp;
|
3344
2634
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
@@ -3348,7 +2638,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
|
|
3348
2638
|
}
|
3349
2639
|
|
3350
2640
|
static VALUE
|
3351
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
2641
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
3352
2642
|
{
|
3353
2643
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
3354
2644
|
|
@@ -3360,40 +2650,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
3360
2650
|
}
|
3361
2651
|
if (size <= sizeof(long)) {
|
3362
2652
|
if (sign < 0) {
|
3363
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
2653
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
3364
2654
|
}
|
3365
2655
|
else {
|
3366
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
2656
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
3367
2657
|
}
|
3368
2658
|
}
|
3369
2659
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
3370
2660
|
else if (size <= sizeof(LONG_LONG)) {
|
3371
2661
|
if (sign < 0) {
|
3372
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
2662
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
3373
2663
|
}
|
3374
2664
|
else {
|
3375
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
2665
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
3376
2666
|
}
|
3377
2667
|
}
|
3378
2668
|
#endif
|
3379
2669
|
else {
|
3380
2670
|
VALUE str = rb_big2str(val, 10);
|
3381
|
-
|
3382
|
-
|
2671
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
2672
|
+
RSTRING_PTR(str),
|
2673
|
+
rb_cBigDecimal,
|
2674
|
+
true,
|
2675
|
+
true
|
2676
|
+
));
|
3383
2677
|
RB_GC_GUARD(str);
|
3384
|
-
return
|
2678
|
+
return CheckGetValue(v);
|
3385
2679
|
}
|
3386
2680
|
}
|
3387
2681
|
|
3388
2682
|
static VALUE
|
3389
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
2683
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
3390
2684
|
{
|
3391
2685
|
assert(RB_INTEGER_TYPE_P(val));
|
3392
2686
|
if (FIXNUM_P(val)) {
|
3393
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
2687
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
3394
2688
|
}
|
3395
2689
|
else {
|
3396
|
-
return rb_big_convert_to_BigDecimal(val
|
2690
|
+
return rb_big_convert_to_BigDecimal(val);
|
3397
2691
|
}
|
3398
2692
|
}
|
3399
2693
|
|
@@ -3428,11 +2722,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3428
2722
|
}
|
3429
2723
|
|
3430
2724
|
if (digs == SIZE_MAX) {
|
3431
|
-
|
3432
|
-
return Qnil;
|
3433
|
-
rb_raise(rb_eArgError,
|
3434
|
-
"can't omit precision for a %"PRIsVALUE".",
|
3435
|
-
CLASS_OF(val));
|
2725
|
+
digs = 0;
|
3436
2726
|
}
|
3437
2727
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
3438
2728
|
if (!raise_exception)
|
@@ -3547,7 +2837,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3547
2837
|
exp = -exp;
|
3548
2838
|
}
|
3549
2839
|
|
3550
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
2840
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
3551
2841
|
Real *vp;
|
3552
2842
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
3553
2843
|
assert(vp->Prec == prec);
|
@@ -3570,28 +2860,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3570
2860
|
CLASS_OF(val));
|
3571
2861
|
}
|
3572
2862
|
|
3573
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
2863
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
3574
2864
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
3575
2865
|
return d;
|
3576
2866
|
}
|
3577
2867
|
|
3578
2868
|
static VALUE
|
3579
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
2869
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
3580
2870
|
{
|
3581
|
-
|
3582
|
-
|
3583
|
-
|
3584
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
3585
|
-
if (!vp)
|
3586
|
-
return Qnil;
|
3587
|
-
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));
|
3588
2874
|
}
|
3589
2875
|
|
3590
2876
|
static inline VALUE
|
3591
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
2877
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
3592
2878
|
{
|
3593
2879
|
const char *c_str = StringValueCStr(val);
|
3594
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
2880
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
3595
2881
|
}
|
3596
2882
|
|
3597
2883
|
static VALUE
|
@@ -3621,15 +2907,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3621
2907
|
|
3622
2908
|
Real *vp;
|
3623
2909
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
3624
|
-
|
3625
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
3626
2910
|
vp = VpCopy(NULL, vp);
|
2911
|
+
RB_GC_GUARD(val);
|
2912
|
+
|
2913
|
+
VALUE copy = BigDecimal_wrap_struct(rb_cBigDecimal, vp);
|
3627
2914
|
/* TODO: rounding */
|
3628
|
-
|
3629
|
-
return VpCheckGetValue(vp);
|
2915
|
+
return check_exception(copy);
|
3630
2916
|
}
|
3631
2917
|
else if (RB_INTEGER_TYPE_P(val)) {
|
3632
|
-
return rb_inum_convert_to_BigDecimal(val
|
2918
|
+
return rb_inum_convert_to_BigDecimal(val);
|
3633
2919
|
}
|
3634
2920
|
else if (RB_FLOAT_TYPE_P(val)) {
|
3635
2921
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
@@ -3647,7 +2933,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3647
2933
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
3648
2934
|
}
|
3649
2935
|
else if (RB_TYPE_P(val, T_STRING)) {
|
3650
|
-
return rb_str_convert_to_BigDecimal(val,
|
2936
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
3651
2937
|
}
|
3652
2938
|
|
3653
2939
|
/* TODO: chheck to_d */
|
@@ -3661,7 +2947,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3661
2947
|
}
|
3662
2948
|
return Qnil;
|
3663
2949
|
}
|
3664
|
-
return rb_str_convert_to_BigDecimal(str,
|
2950
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
3665
2951
|
}
|
3666
2952
|
|
3667
2953
|
/* call-seq:
|
@@ -3682,12 +2968,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
3682
2968
|
*
|
3683
2969
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
3684
2970
|
*
|
3685
|
-
* # 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.
|
3686
2972
|
* BigDecimal(2) # => 0.2e1
|
3687
2973
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
3688
2974
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
3689
|
-
* #
|
3690
|
-
*
|
2975
|
+
* BigDecimal(2.0) # => 0.2e1
|
2976
|
+
* # Rational value requires ndigits.
|
3691
2977
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
3692
2978
|
*
|
3693
2979
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
@@ -3751,11 +3037,11 @@ static VALUE
|
|
3751
3037
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
3752
3038
|
{
|
3753
3039
|
char const *c_str = StringValueCStr(str);
|
3754
|
-
|
3755
|
-
if (
|
3040
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
3041
|
+
if (v.bigdecimal_or_nil == Qnil)
|
3756
3042
|
return Qnil;
|
3757
3043
|
else
|
3758
|
-
return
|
3044
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
3759
3045
|
}
|
3760
3046
|
|
3761
3047
|
/*
|
@@ -3810,7 +3096,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
3810
3096
|
static VALUE
|
3811
3097
|
BigDecimal_sign(VALUE self)
|
3812
3098
|
{ /* sign */
|
3813
|
-
int s =
|
3099
|
+
int s = GetSelfVpValue(self)->sign;
|
3814
3100
|
return INT2FIX(s);
|
3815
3101
|
}
|
3816
3102
|
|
@@ -3882,310 +3168,15 @@ BigDecimal_save_rounding_mode(VALUE self)
|
|
3882
3168
|
* puts BigDecimal.limit
|
3883
3169
|
*
|
3884
3170
|
*/
|
3885
|
-
static VALUE
|
3886
|
-
BigDecimal_save_limit(VALUE self)
|
3887
|
-
{
|
3888
|
-
size_t const limit = VpGetPrecLimit();
|
3889
|
-
int state;
|
3890
|
-
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
3891
|
-
VpSetPrecLimit(limit);
|
3892
|
-
if (state) rb_jump_tag(state);
|
3893
|
-
return ret;
|
3894
|
-
}
|
3895
|
-
|
3896
|
-
/* call-seq:
|
3897
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
3898
|
-
*
|
3899
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
3900
|
-
* power of +decimal+, to the specified number of digits of precision.
|
3901
|
-
*
|
3902
|
-
* If +decimal+ is infinity, returns Infinity.
|
3903
|
-
*
|
3904
|
-
* If +decimal+ is NaN, returns NaN.
|
3905
|
-
*/
|
3906
|
-
static VALUE
|
3907
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
3908
|
-
{
|
3909
|
-
ssize_t prec, n, i;
|
3910
|
-
Real* vx = NULL;
|
3911
|
-
VALUE one, d, y;
|
3912
|
-
int negative = 0;
|
3913
|
-
int infinite = 0;
|
3914
|
-
int nan = 0;
|
3915
|
-
double flo;
|
3916
|
-
|
3917
|
-
prec = NUM2SSIZET(vprec);
|
3918
|
-
if (prec <= 0) {
|
3919
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
3920
|
-
}
|
3921
|
-
|
3922
|
-
/* TODO: the following switch statement is almost same as one in the
|
3923
|
-
* BigDecimalCmp function. */
|
3924
|
-
switch (TYPE(x)) {
|
3925
|
-
case T_DATA:
|
3926
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
3927
|
-
vx = DATA_PTR(x);
|
3928
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
3929
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
3930
|
-
nan = VpIsNaN(vx);
|
3931
|
-
break;
|
3932
|
-
|
3933
|
-
case T_FIXNUM:
|
3934
|
-
/* fall through */
|
3935
|
-
case T_BIGNUM:
|
3936
|
-
vx = GetVpValue(x, 0);
|
3937
|
-
break;
|
3938
|
-
|
3939
|
-
case T_FLOAT:
|
3940
|
-
flo = RFLOAT_VALUE(x);
|
3941
|
-
negative = flo < 0;
|
3942
|
-
infinite = isinf(flo);
|
3943
|
-
nan = isnan(flo);
|
3944
|
-
if (!infinite && !nan) {
|
3945
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
3946
|
-
}
|
3947
|
-
break;
|
3948
|
-
|
3949
|
-
case T_RATIONAL:
|
3950
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
3951
|
-
break;
|
3952
|
-
|
3953
|
-
default:
|
3954
|
-
break;
|
3955
|
-
}
|
3956
|
-
if (infinite) {
|
3957
|
-
if (negative) {
|
3958
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
3959
|
-
}
|
3960
|
-
else {
|
3961
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
3962
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
3963
|
-
RB_GC_GUARD(vy->obj);
|
3964
|
-
return VpCheckGetValue(vy);
|
3965
|
-
}
|
3966
|
-
}
|
3967
|
-
else if (nan) {
|
3968
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
3969
|
-
VpSetNaN(vy);
|
3970
|
-
RB_GC_GUARD(vy->obj);
|
3971
|
-
return VpCheckGetValue(vy);
|
3972
|
-
}
|
3973
|
-
else if (vx == NULL) {
|
3974
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
3975
|
-
}
|
3976
|
-
x = vx->obj;
|
3977
|
-
|
3978
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
3979
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
3980
|
-
if (negative) {
|
3981
|
-
VALUE x_zero = INT2NUM(1);
|
3982
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
3983
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
3984
|
-
vx = DATA_PTR(x);
|
3985
|
-
VpSetSign(vx, 1);
|
3986
|
-
}
|
3987
|
-
|
3988
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
3989
|
-
y = one;
|
3990
|
-
d = y;
|
3991
|
-
i = 1;
|
3992
|
-
|
3993
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
3994
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
3995
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
3996
|
-
ssize_t m = n - vabs(ey - ed);
|
3997
|
-
|
3998
|
-
rb_thread_check_ints();
|
3999
|
-
|
4000
|
-
if (m <= 0) {
|
4001
|
-
break;
|
4002
|
-
}
|
4003
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
4004
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
4005
|
-
}
|
4006
|
-
|
4007
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
4008
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
4009
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
4010
|
-
++i; /* i <- i + 1 */
|
4011
|
-
}
|
4012
|
-
|
4013
|
-
if (negative) {
|
4014
|
-
return BigDecimal_div2(one, y, vprec);
|
4015
|
-
}
|
4016
|
-
else {
|
4017
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
4018
|
-
return BigDecimal_round(1, &vprec, y);
|
4019
|
-
}
|
4020
|
-
|
4021
|
-
RB_GC_GUARD(one);
|
4022
|
-
RB_GC_GUARD(x);
|
4023
|
-
RB_GC_GUARD(y);
|
4024
|
-
RB_GC_GUARD(d);
|
4025
|
-
}
|
4026
|
-
|
4027
|
-
/* call-seq:
|
4028
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
4029
|
-
*
|
4030
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
4031
|
-
* digits of precision, +numeric+.
|
4032
|
-
*
|
4033
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
4034
|
-
*
|
4035
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
4036
|
-
*
|
4037
|
-
* If +decimal+ is NaN, returns NaN.
|
4038
|
-
*/
|
4039
|
-
static VALUE
|
4040
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
4041
|
-
{
|
4042
|
-
ssize_t prec, n, i;
|
4043
|
-
SIGNED_VALUE expo;
|
4044
|
-
Real* vx = NULL;
|
4045
|
-
VALUE vn, one, two, w, x2, y, d;
|
4046
|
-
int zero = 0;
|
4047
|
-
int negative = 0;
|
4048
|
-
int infinite = 0;
|
4049
|
-
int nan = 0;
|
4050
|
-
double flo;
|
4051
|
-
long fix;
|
4052
|
-
|
4053
|
-
if (!is_integer(vprec)) {
|
4054
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
4055
|
-
}
|
4056
|
-
|
4057
|
-
prec = NUM2SSIZET(vprec);
|
4058
|
-
if (prec <= 0) {
|
4059
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
4060
|
-
}
|
4061
|
-
|
4062
|
-
/* TODO: the following switch statement is almost same as one in the
|
4063
|
-
* BigDecimalCmp function. */
|
4064
|
-
switch (TYPE(x)) {
|
4065
|
-
case T_DATA:
|
4066
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
4067
|
-
vx = DATA_PTR(x);
|
4068
|
-
zero = VpIsZero(vx);
|
4069
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
4070
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
4071
|
-
nan = VpIsNaN(vx);
|
4072
|
-
break;
|
4073
|
-
|
4074
|
-
case T_FIXNUM:
|
4075
|
-
fix = FIX2LONG(x);
|
4076
|
-
zero = fix == 0;
|
4077
|
-
negative = fix < 0;
|
4078
|
-
goto get_vp_value;
|
4079
|
-
|
4080
|
-
case T_BIGNUM:
|
4081
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
4082
|
-
zero = i == 0;
|
4083
|
-
negative = i < 0;
|
4084
|
-
get_vp_value:
|
4085
|
-
if (zero || negative) break;
|
4086
|
-
vx = GetVpValue(x, 0);
|
4087
|
-
break;
|
4088
|
-
|
4089
|
-
case T_FLOAT:
|
4090
|
-
flo = RFLOAT_VALUE(x);
|
4091
|
-
zero = flo == 0;
|
4092
|
-
negative = flo < 0;
|
4093
|
-
infinite = isinf(flo);
|
4094
|
-
nan = isnan(flo);
|
4095
|
-
if (!zero && !negative && !infinite && !nan) {
|
4096
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
4097
|
-
}
|
4098
|
-
break;
|
4099
|
-
|
4100
|
-
case T_RATIONAL:
|
4101
|
-
zero = RRATIONAL_ZERO_P(x);
|
4102
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
4103
|
-
if (zero || negative) break;
|
4104
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
4105
|
-
break;
|
4106
|
-
|
4107
|
-
case T_COMPLEX:
|
4108
|
-
rb_raise(rb_eMathDomainError,
|
4109
|
-
"Complex argument for BigMath.log");
|
4110
|
-
|
4111
|
-
default:
|
4112
|
-
break;
|
4113
|
-
}
|
4114
|
-
if (infinite && !negative) {
|
4115
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
4116
|
-
RB_GC_GUARD(vy->obj);
|
4117
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
4118
|
-
return VpCheckGetValue(vy);
|
4119
|
-
}
|
4120
|
-
else if (nan) {
|
4121
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
4122
|
-
RB_GC_GUARD(vy->obj);
|
4123
|
-
VpSetNaN(vy);
|
4124
|
-
return VpCheckGetValue(vy);
|
4125
|
-
}
|
4126
|
-
else if (zero || negative) {
|
4127
|
-
rb_raise(rb_eMathDomainError,
|
4128
|
-
"Zero or negative argument for log");
|
4129
|
-
}
|
4130
|
-
else if (vx == NULL) {
|
4131
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
4132
|
-
}
|
4133
|
-
x = VpCheckGetValue(vx);
|
4134
|
-
|
4135
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
4136
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
4137
|
-
|
4138
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
4139
|
-
vn = SSIZET2NUM(n);
|
4140
|
-
expo = VpExponent10(vx);
|
4141
|
-
if (expo < 0 || expo >= 3) {
|
4142
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
4143
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
4144
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
4145
|
-
}
|
4146
|
-
else {
|
4147
|
-
expo = 0;
|
4148
|
-
}
|
4149
|
-
w = BigDecimal_sub(x, one);
|
4150
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
4151
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
4152
|
-
y = x;
|
4153
|
-
d = y;
|
4154
|
-
i = 1;
|
4155
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
4156
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
4157
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
4158
|
-
ssize_t m = n - vabs(ey - ed);
|
4159
|
-
if (m <= 0) {
|
4160
|
-
break;
|
4161
|
-
}
|
4162
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
4163
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
4164
|
-
}
|
4165
|
-
|
4166
|
-
x = BigDecimal_mult2(x2, x, vn);
|
4167
|
-
i += 2;
|
4168
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
4169
|
-
y = BigDecimal_add(y, d);
|
4170
|
-
}
|
4171
|
-
|
4172
|
-
y = BigDecimal_mult(y, two);
|
4173
|
-
if (expo != 0) {
|
4174
|
-
VALUE log10, vexpo, dy;
|
4175
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
4176
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
4177
|
-
dy = BigDecimal_mult(log10, vexpo);
|
4178
|
-
y = BigDecimal_add(y, dy);
|
4179
|
-
}
|
4180
|
-
|
4181
|
-
RB_GC_GUARD(one);
|
4182
|
-
RB_GC_GUARD(two);
|
4183
|
-
RB_GC_GUARD(vn);
|
4184
|
-
RB_GC_GUARD(x2);
|
4185
|
-
RB_GC_GUARD(y);
|
4186
|
-
RB_GC_GUARD(d);
|
4187
|
-
|
4188
|
-
return y;
|
3171
|
+
static VALUE
|
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;
|
4189
3180
|
}
|
4190
3181
|
|
4191
3182
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
@@ -4239,6 +3230,34 @@ BigDecimal_literal(const char *str)
|
|
4239
3230
|
|
4240
3231
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
4241
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
|
+
|
4242
3261
|
/* Document-class: BigDecimal
|
4243
3262
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
4244
3263
|
*
|
@@ -4355,14 +3374,16 @@ BigDecimal_literal(const char *str)
|
|
4355
3374
|
*
|
4356
3375
|
* When you require +bigdecimal/util+, the #to_d method will be
|
4357
3376
|
* available on BigDecimal and the native Integer, Float, Rational,
|
4358
|
-
* and
|
3377
|
+
* String, Complex, and NilClass classes:
|
4359
3378
|
*
|
4360
3379
|
* require 'bigdecimal/util'
|
4361
3380
|
*
|
4362
|
-
* 42.to_d
|
4363
|
-
* 0.5.to_d
|
4364
|
-
* (2/3r).to_d(3)
|
4365
|
-
* "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
|
4366
3387
|
*
|
4367
3388
|
* == Methods for Working with \JSON
|
4368
3389
|
*
|
@@ -4436,7 +3457,7 @@ Init_bigdecimal(void)
|
|
4436
3457
|
* guarantee that two groups could always be multiplied together without
|
4437
3458
|
* overflow.)
|
4438
3459
|
*/
|
4439
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
3460
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
4440
3461
|
|
4441
3462
|
/* Exceptions */
|
4442
3463
|
|
@@ -4578,14 +3599,11 @@ Init_bigdecimal(void)
|
|
4578
3599
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
4579
3600
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
4580
3601
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
4581
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
4582
3602
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
4583
3603
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
4584
3604
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
4585
3605
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
4586
3606
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
4587
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
4588
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
4589
3607
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
4590
3608
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
4591
3609
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
@@ -4604,11 +3622,13 @@ Init_bigdecimal(void)
|
|
4604
3622
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
4605
3623
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
4606
3624
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
3625
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
4607
3626
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
4608
3627
|
|
4609
|
-
|
4610
|
-
|
4611
|
-
|
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 */
|
4612
3632
|
|
4613
3633
|
#define ROUNDING_MODE(i, name, value) \
|
4614
3634
|
id_##name = rb_intern_const(#name); \
|
@@ -4648,19 +3668,9 @@ Init_bigdecimal(void)
|
|
4648
3668
|
*/
|
4649
3669
|
#ifdef BIGDECIMAL_DEBUG
|
4650
3670
|
static int gfDebug = 1; /* Debug switch */
|
4651
|
-
#if 0
|
4652
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
4653
|
-
#endif
|
4654
3671
|
#endif /* BIGDECIMAL_DEBUG */
|
4655
3672
|
|
4656
3673
|
static Real *VpConstOne; /* constant 1.0 */
|
4657
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
4658
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
4659
|
-
/* used in VpSqrt() */
|
4660
|
-
|
4661
|
-
/* ETC */
|
4662
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
4663
|
-
#define StrCmp(x,y) strcmp(x,y)
|
4664
3674
|
|
4665
3675
|
enum op_sw {
|
4666
3676
|
OP_SW_ADD = 1, /* + */
|
@@ -4670,11 +3680,9 @@ enum op_sw {
|
|
4670
3680
|
};
|
4671
3681
|
|
4672
3682
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
4673
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
4674
3683
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
4675
3684
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
4676
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);
|
4677
|
-
static int VpNmlz(Real *a);
|
4678
3686
|
static void VpFormatSt(char *psz, size_t fFmt);
|
4679
3687
|
static int VpRdup(Real *m, size_t ind_m);
|
4680
3688
|
|
@@ -4733,10 +3741,10 @@ VpCheckException(Real *p, bool always)
|
|
4733
3741
|
}
|
4734
3742
|
|
4735
3743
|
static VALUE
|
4736
|
-
|
3744
|
+
CheckGetValue(BDVALUE v)
|
4737
3745
|
{
|
4738
|
-
VpCheckException(
|
4739
|
-
return
|
3746
|
+
VpCheckException(v.real, false);
|
3747
|
+
return v.bigdecimal;
|
4740
3748
|
}
|
4741
3749
|
|
4742
3750
|
/*
|
@@ -4768,12 +3776,10 @@ VpGetPrecLimit(void)
|
|
4768
3776
|
return NUM2SIZET(vlimit);
|
4769
3777
|
}
|
4770
3778
|
|
4771
|
-
VP_EXPORT
|
3779
|
+
VP_EXPORT void
|
4772
3780
|
VpSetPrecLimit(size_t n)
|
4773
3781
|
{
|
4774
|
-
size_t const s = VpGetPrecLimit();
|
4775
3782
|
bigdecimal_set_thread_local_precision_limit(n);
|
4776
|
-
return s;
|
4777
3783
|
}
|
4778
3784
|
|
4779
3785
|
/*
|
@@ -4888,15 +3894,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
4888
3894
|
return nzero;
|
4889
3895
|
}
|
4890
3896
|
|
4891
|
-
#if 0 /* unused */
|
4892
|
-
VP_EXPORT int
|
4893
|
-
VpIsNegDoubleZero(double v)
|
4894
|
-
{
|
4895
|
-
double z = VpGetDoubleNegZero();
|
4896
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
4897
|
-
}
|
4898
|
-
#endif
|
4899
|
-
|
4900
3897
|
VP_EXPORT int
|
4901
3898
|
VpException(unsigned short f, const char *str,int always)
|
4902
3899
|
{
|
@@ -5048,7 +4045,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
5048
4045
|
case 'E':
|
5049
4046
|
/* fall through */
|
5050
4047
|
default:
|
5051
|
-
nc = BASE_FIG*
|
4048
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
5052
4049
|
}
|
5053
4050
|
return nc;
|
5054
4051
|
}
|
@@ -5074,28 +4071,13 @@ VpInit(DECDIG BaseVal)
|
|
5074
4071
|
VpGetDoubleNegZero();
|
5075
4072
|
|
5076
4073
|
/* Const 1.0 */
|
5077
|
-
VpConstOne =
|
5078
|
-
|
5079
|
-
/* Const 0.5 */
|
5080
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
5081
|
-
VpConstPt5->exponent = 0;
|
5082
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
4074
|
+
VpConstOne = NewZero(1, 1);
|
4075
|
+
VpSetOne(VpConstOne);
|
5083
4076
|
|
5084
4077
|
#ifdef BIGDECIMAL_DEBUG
|
5085
4078
|
gnAlloc = 0;
|
5086
4079
|
#endif /* BIGDECIMAL_DEBUG */
|
5087
4080
|
|
5088
|
-
#ifdef BIGDECIMAL_DEBUG
|
5089
|
-
if (gfDebug) {
|
5090
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
5091
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
5092
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
5093
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
5094
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
5095
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
5096
|
-
}
|
5097
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5098
|
-
|
5099
4081
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
5100
4082
|
}
|
5101
4083
|
|
@@ -5111,24 +4093,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
5111
4093
|
{
|
5112
4094
|
SIGNED_VALUE e = a->exponent;
|
5113
4095
|
SIGNED_VALUE m = e+n;
|
5114
|
-
|
5115
|
-
|
5116
|
-
|
5117
|
-
|
5118
|
-
|
5119
|
-
|
5120
|
-
|
5121
|
-
|
5122
|
-
if (eb - mb > 0) goto overflow;
|
5123
|
-
}
|
5124
|
-
}
|
5125
|
-
else if (n < 0) {
|
5126
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
5127
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
5128
|
-
goto underflow;
|
5129
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
5130
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
5131
|
-
if (mb - eb > 0) goto underflow;
|
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;
|
5132
4104
|
}
|
5133
4105
|
a->exponent = m;
|
5134
4106
|
return 1;
|
@@ -5169,7 +4141,6 @@ bigdecimal_parse_special_string(const char *str)
|
|
5169
4141
|
while (*p && ISSPACE(*p)) ++p;
|
5170
4142
|
if (*p == '\0') {
|
5171
4143
|
Real *vp = rbd_allocate_struct(1);
|
5172
|
-
vp->MaxPrec = 1;
|
5173
4144
|
switch (table[i].sign) {
|
5174
4145
|
default:
|
5175
4146
|
UNREACHABLE; break;
|
@@ -5234,38 +4205,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
5234
4205
|
/*
|
5235
4206
|
* Allocates variable.
|
5236
4207
|
* [Input]
|
5237
|
-
*
|
5238
|
-
* The mx will be the number of significant digits can to be stored.
|
5239
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
5240
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
5241
|
-
* so that the full precision specified by szVal is allocated.
|
4208
|
+
* szVal ... The value assigned(char).
|
5242
4209
|
*
|
5243
4210
|
* [Returns]
|
5244
4211
|
* Pointer to the newly allocated variable, or
|
5245
4212
|
* NULL be returned if memory allocation is failed,or any error.
|
5246
4213
|
*/
|
5247
4214
|
VP_EXPORT Real *
|
5248
|
-
VpAlloc(
|
4215
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
5249
4216
|
{
|
5250
4217
|
const char *orig_szVal = szVal;
|
5251
4218
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
5252
|
-
size_t len;
|
5253
4219
|
char v, *psz;
|
5254
4220
|
int sign=1;
|
5255
4221
|
Real *vp = NULL;
|
5256
4222
|
VALUE buf;
|
5257
4223
|
|
5258
|
-
if (szVal == NULL) {
|
5259
|
-
return_zero:
|
5260
|
-
/* necessary to be able to store */
|
5261
|
-
/* at least mx digits. */
|
5262
|
-
/* szVal==NULL ==> allocate zero value. */
|
5263
|
-
vp = rbd_allocate_struct(mx);
|
5264
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
5265
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
5266
|
-
return vp;
|
5267
|
-
}
|
5268
|
-
|
5269
4224
|
/* Skipping leading spaces */
|
5270
4225
|
while (ISSPACE(*szVal)) szVal++;
|
5271
4226
|
|
@@ -5274,14 +4229,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5274
4229
|
return vp;
|
5275
4230
|
}
|
5276
4231
|
|
5277
|
-
/*
|
5278
|
-
|
5279
|
-
|
5280
|
-
|
5281
|
-
|
5282
|
-
len = rbd_calculate_internal_digits(mx, false);
|
5283
|
-
++szVal;
|
5284
|
-
}
|
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;
|
5285
4237
|
|
5286
4238
|
/* Scanning digits */
|
5287
4239
|
|
@@ -5428,7 +4380,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5428
4380
|
VALUE str;
|
5429
4381
|
invalid_value:
|
5430
4382
|
if (!strict_p) {
|
5431
|
-
|
4383
|
+
return NewZero(1, 1);
|
5432
4384
|
}
|
5433
4385
|
if (!exc) {
|
5434
4386
|
return NULL;
|
@@ -5439,11 +4391,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
5439
4391
|
|
5440
4392
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
5441
4393
|
/* units for szVal[] */
|
5442
|
-
|
5443
|
-
nalloc = Max(nalloc, len);
|
5444
|
-
len = nalloc;
|
5445
|
-
vp = rbd_allocate_struct(len);
|
5446
|
-
vp->MaxPrec = len; /* set max precision */
|
4394
|
+
vp = rbd_allocate_struct(nalloc);
|
5447
4395
|
VpSetZero(vp, sign);
|
5448
4396
|
protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
|
5449
4397
|
rb_str_resize(buf, 0);
|
@@ -5483,7 +4431,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
5483
4431
|
c->Prec = n;
|
5484
4432
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
5485
4433
|
/* Needs round ? */
|
5486
|
-
if (isw != 10) {
|
4434
|
+
if (isw != 10 && isw != -10) {
|
5487
4435
|
/* Not in ActiveRound */
|
5488
4436
|
if(c->Prec < a->Prec) {
|
5489
4437
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
@@ -5509,19 +4457,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
5509
4457
|
VP_EXPORT size_t
|
5510
4458
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
5511
4459
|
{
|
5512
|
-
short sw, isw;
|
4460
|
+
short sw, isw, sign;
|
5513
4461
|
Real *a_ptr, *b_ptr;
|
5514
4462
|
size_t n, na, nb, i;
|
5515
4463
|
DECDIG mrv;
|
5516
4464
|
|
5517
|
-
#ifdef BIGDECIMAL_DEBUG
|
5518
|
-
if (gfDebug) {
|
5519
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
5520
|
-
VPrint(stdout, " b=% \n", b);
|
5521
|
-
printf(" operation=%d\n", operation);
|
5522
|
-
}
|
5523
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5524
|
-
|
5525
4465
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
5526
4466
|
|
5527
4467
|
/* check if a or b is zero */
|
@@ -5610,28 +4550,21 @@ end_if:
|
|
5610
4550
|
if (isw) { /* addition */
|
5611
4551
|
VpSetSign(c, 1);
|
5612
4552
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
5613
|
-
|
4553
|
+
sign = isw / 2;
|
5614
4554
|
}
|
5615
4555
|
else { /* subtraction */
|
5616
4556
|
VpSetSign(c, 1);
|
5617
4557
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
5618
|
-
|
5619
|
-
VpSetSign(c,VpGetSign(a));
|
5620
|
-
}
|
5621
|
-
else {
|
5622
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
5623
|
-
}
|
4558
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
5624
4559
|
}
|
5625
|
-
|
5626
|
-
|
5627
|
-
#ifdef BIGDECIMAL_DEBUG
|
5628
|
-
if (gfDebug) {
|
5629
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
5630
|
-
VPrint(stdout, " a=% \n", a);
|
5631
|
-
VPrint(stdout, " b=% \n", b);
|
5632
|
-
printf(" operation=%d\n", operation);
|
4560
|
+
if (VpIsInf(c)) {
|
4561
|
+
VpSetInf(c, sign);
|
5633
4562
|
}
|
5634
|
-
|
4563
|
+
else {
|
4564
|
+
VpSetSign(c, sign);
|
4565
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
4566
|
+
}
|
4567
|
+
|
5635
4568
|
return c->Prec * BASE_FIG;
|
5636
4569
|
}
|
5637
4570
|
|
@@ -5652,13 +4585,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
5652
4585
|
size_t c_pos;
|
5653
4586
|
DECDIG av, bv, carry, mrv;
|
5654
4587
|
|
5655
|
-
#ifdef BIGDECIMAL_DEBUG
|
5656
|
-
if (gfDebug) {
|
5657
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
5658
|
-
VPrint(stdout, " b = %\n", b);
|
5659
|
-
}
|
5660
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5661
|
-
|
5662
4588
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
5663
4589
|
a_pos = ap;
|
5664
4590
|
b_pos = bp;
|
@@ -5724,11 +4650,6 @@ Assign_a:
|
|
5724
4650
|
|
5725
4651
|
Exit:
|
5726
4652
|
|
5727
|
-
#ifdef BIGDECIMAL_DEBUG
|
5728
|
-
if (gfDebug) {
|
5729
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
5730
|
-
}
|
5731
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5732
4653
|
return mrv;
|
5733
4654
|
}
|
5734
4655
|
|
@@ -5747,13 +4668,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
5747
4668
|
size_t c_pos;
|
5748
4669
|
DECDIG av, bv, borrow, mrv;
|
5749
4670
|
|
5750
|
-
#ifdef BIGDECIMAL_DEBUG
|
5751
|
-
if (gfDebug) {
|
5752
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
5753
|
-
VPrint(stdout, " b = %\n", b);
|
5754
|
-
}
|
5755
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5756
|
-
|
5757
4671
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
5758
4672
|
a_pos = ap;
|
5759
4673
|
b_pos = bp;
|
@@ -5829,11 +4743,6 @@ Assign_a:
|
|
5829
4743
|
mrv = 0;
|
5830
4744
|
|
5831
4745
|
Exit:
|
5832
|
-
#ifdef BIGDECIMAL_DEBUG
|
5833
|
-
if (gfDebug) {
|
5834
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
5835
|
-
}
|
5836
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5837
4746
|
return mrv;
|
5838
4747
|
}
|
5839
4748
|
|
@@ -5964,19 +4873,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
5964
4873
|
VP_EXPORT size_t
|
5965
4874
|
VpMult(Real *c, Real *a, Real *b)
|
5966
4875
|
{
|
5967
|
-
size_t MxIndA, MxIndB, MxIndAB
|
4876
|
+
size_t MxIndA, MxIndB, MxIndAB;
|
5968
4877
|
size_t ind_c, i, ii, nc;
|
5969
4878
|
size_t ind_as, ind_ae, ind_bs;
|
5970
4879
|
DECDIG carry;
|
5971
4880
|
DECDIG_DBL s;
|
5972
|
-
Real *w;
|
5973
|
-
|
5974
|
-
#ifdef BIGDECIMAL_DEBUG
|
5975
|
-
if (gfDebug) {
|
5976
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
5977
|
-
VPrint(stdout, " b=% \n", b);
|
5978
|
-
}
|
5979
|
-
#endif /* BIGDECIMAL_DEBUG */
|
5980
4881
|
|
5981
4882
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
5982
4883
|
|
@@ -5987,39 +4888,28 @@ VpMult(Real *c, Real *a, Real *b)
|
|
5987
4888
|
}
|
5988
4889
|
|
5989
4890
|
if (VpIsOne(a)) {
|
5990
|
-
VpAsgn(c, b, VpGetSign(a));
|
4891
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
5991
4892
|
goto Exit;
|
5992
4893
|
}
|
5993
4894
|
if (VpIsOne(b)) {
|
5994
|
-
VpAsgn(c, a, VpGetSign(b));
|
4895
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
5995
4896
|
goto Exit;
|
5996
4897
|
}
|
5997
4898
|
if (b->Prec > a->Prec) {
|
5998
4899
|
/* Adjust so that digits(a)>digits(b) */
|
5999
|
-
w = a;
|
4900
|
+
Real *w = a;
|
6000
4901
|
a = b;
|
6001
4902
|
b = w;
|
6002
4903
|
}
|
6003
|
-
w = NULL;
|
6004
4904
|
MxIndA = a->Prec - 1;
|
6005
4905
|
MxIndB = b->Prec - 1;
|
6006
|
-
MxIndC = c->MaxPrec - 1;
|
6007
4906
|
MxIndAB = a->Prec + b->Prec - 1;
|
6008
4907
|
|
6009
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
6010
|
-
w = c;
|
6011
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
6012
|
-
MxIndC = MxIndAB;
|
6013
|
-
}
|
6014
|
-
|
6015
4908
|
/* set LHSV c info */
|
6016
4909
|
|
6017
4910
|
c->exponent = a->exponent; /* set exponent */
|
6018
|
-
if (!AddExponent(c, b->exponent)) {
|
6019
|
-
if (w) rbd_free_struct(c);
|
6020
|
-
return 0;
|
6021
|
-
}
|
6022
4911
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
4912
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
6023
4913
|
carry = 0;
|
6024
4914
|
nc = ind_c = MxIndAB;
|
6025
4915
|
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
@@ -6066,29 +4956,18 @@ VpMult(Real *c, Real *a, Real *b)
|
|
6066
4956
|
}
|
6067
4957
|
}
|
6068
4958
|
}
|
6069
|
-
|
6070
|
-
VpNmlz(c);
|
6071
|
-
VpAsgn(w, c, 1);
|
6072
|
-
rbd_free_struct(c);
|
6073
|
-
c = w;
|
6074
|
-
}
|
6075
|
-
else {
|
6076
|
-
VpLimitRound(c,0);
|
6077
|
-
}
|
4959
|
+
VpNmlz(c);
|
6078
4960
|
|
6079
4961
|
Exit:
|
6080
|
-
#ifdef BIGDECIMAL_DEBUG
|
6081
|
-
if (gfDebug) {
|
6082
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
6083
|
-
VPrint(stdout, " a=% \n", a);
|
6084
|
-
VPrint(stdout, " b=% \n", b);
|
6085
|
-
}
|
6086
|
-
#endif /*BIGDECIMAL_DEBUG */
|
6087
4962
|
return c->Prec*BASE_FIG;
|
6088
4963
|
}
|
6089
4964
|
|
6090
4965
|
/*
|
6091
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
|
6092
4971
|
*/
|
6093
4972
|
VP_EXPORT size_t
|
6094
4973
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
@@ -6097,16 +4976,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6097
4976
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
6098
4977
|
size_t nLoop;
|
6099
4978
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
6100
|
-
DECDIG
|
4979
|
+
DECDIG borrow1, borrow2;
|
6101
4980
|
DECDIG_DBL qb;
|
6102
4981
|
|
6103
|
-
#ifdef BIGDECIMAL_DEBUG
|
6104
|
-
if (gfDebug) {
|
6105
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
6106
|
-
VPrint(stdout, " b=% \n", b);
|
6107
|
-
}
|
6108
|
-
#endif /*BIGDECIMAL_DEBUG */
|
6109
|
-
|
6110
4982
|
VpSetNaN(r);
|
6111
4983
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
6112
4984
|
if (VpIsZero(a) && VpIsZero(b)) {
|
@@ -6123,30 +4995,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6123
4995
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
6124
4996
|
goto Exit;
|
6125
4997
|
}
|
6126
|
-
if (VpIsOne(b)) {
|
6127
|
-
/* divide by one */
|
6128
|
-
VpAsgn(c, a, VpGetSign(b));
|
6129
|
-
VpSetZero(r, VpGetSign(a));
|
6130
|
-
goto Exit;
|
6131
|
-
}
|
6132
4998
|
|
6133
4999
|
word_a = a->Prec;
|
6134
5000
|
word_b = b->Prec;
|
6135
5001
|
word_c = c->MaxPrec;
|
6136
5002
|
word_r = r->MaxPrec;
|
6137
5003
|
|
6138
|
-
if (word_a
|
5004
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
6139
5005
|
|
6140
|
-
|
6141
|
-
r->frac[
|
6142
|
-
|
6143
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
6144
|
-
++ind_r;
|
6145
|
-
}
|
6146
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
6147
|
-
|
6148
|
-
ind_c = 0;
|
6149
|
-
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
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;
|
6150
5009
|
|
6151
5010
|
/* initial procedure */
|
6152
5011
|
b1 = b1p1 = b->frac[0];
|
@@ -6161,15 +5020,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6161
5020
|
|
6162
5021
|
/* */
|
6163
5022
|
/* loop start */
|
6164
|
-
|
6165
|
-
|
6166
|
-
ind_c = 1;
|
5023
|
+
nLoop = Min(word_c, word_r);
|
5024
|
+
ind_c = 0;
|
6167
5025
|
while (ind_c < nLoop) {
|
6168
5026
|
if (r->frac[ind_c] == 0) {
|
6169
5027
|
++ind_c;
|
6170
5028
|
continue;
|
6171
5029
|
}
|
6172
|
-
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);
|
6173
5031
|
if (r1r2 == b1b2) {
|
6174
5032
|
/* The first two word digits is the same */
|
6175
5033
|
ind_b = 2;
|
@@ -6182,26 +5040,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
6182
5040
|
}
|
6183
5041
|
/* The first few word digits of r and b is the same and */
|
6184
5042
|
/* the first different word digit of w is greater than that */
|
6185
|
-
/* of b, so quotient is 1
|
6186
|
-
|
6187
|
-
ind_b = b->Prec - 1;
|
6188
|
-
ind_r = ind_c + ind_b;
|
6189
|
-
if (ind_r >= word_r) goto space_error;
|
6190
|
-
n = ind_b;
|
6191
|
-
for (i = 0; i <= n; ++i) {
|
6192
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
6193
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
6194
|
-
borrow = 1;
|
6195
|
-
}
|
6196
|
-
else {
|
6197
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
6198
|
-
borrow = 0;
|
6199
|
-
}
|
6200
|
-
--ind_r;
|
6201
|
-
--ind_b;
|
6202
|
-
}
|
5043
|
+
/* of b, so quotient is 1. */
|
5044
|
+
q = 1;
|
6203
5045
|
++c->frac[ind_c];
|
6204
|
-
|
5046
|
+
ind_r = b->Prec + ind_c - 1;
|
5047
|
+
goto sub_mult;
|
6205
5048
|
}
|
6206
5049
|
/* The first two word digits is not the same, */
|
6207
5050
|
/* then compare magnitude, and divide actually. */
|
@@ -6254,49 +5097,26 @@ sub_mult:
|
|
6254
5097
|
}
|
6255
5098
|
|
6256
5099
|
r->frac[ind_r] -= borrow2;
|
6257
|
-
carry:
|
6258
|
-
ind_r = ind_c;
|
6259
|
-
while (c->frac[ind_r] >= BASE) {
|
6260
|
-
c->frac[ind_r] -= BASE;
|
6261
|
-
--ind_r;
|
6262
|
-
++c->frac[ind_r];
|
6263
|
-
}
|
6264
5100
|
}
|
6265
5101
|
/* End of operation, now final arrangement */
|
6266
5102
|
out_side:
|
6267
5103
|
c->Prec = word_c;
|
6268
5104
|
c->exponent = a->exponent;
|
6269
|
-
|
5105
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
5106
|
+
if (!AddExponent(c, 1)) return 0;
|
6270
5107
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
6271
5108
|
|
6272
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
6273
5109
|
VpNmlz(c); /* normalize c */
|
6274
5110
|
r->Prec = word_r;
|
6275
5111
|
r->exponent = a->exponent;
|
6276
|
-
if (!AddExponent(r, 1)) return 0;
|
6277
5112
|
VpSetSign(r, VpGetSign(a));
|
6278
5113
|
VpNmlz(r); /* normalize r(remainder) */
|
6279
5114
|
goto Exit;
|
6280
5115
|
|
6281
5116
|
space_error:
|
6282
|
-
#ifdef BIGDECIMAL_DEBUG
|
6283
|
-
if (gfDebug) {
|
6284
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
6285
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
6286
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
6287
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
6288
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
6289
|
-
}
|
6290
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6291
5117
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
6292
5118
|
|
6293
5119
|
Exit:
|
6294
|
-
#ifdef BIGDECIMAL_DEBUG
|
6295
|
-
if (gfDebug) {
|
6296
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
6297
|
-
VPrint(stdout, " r=% \n", r);
|
6298
|
-
}
|
6299
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6300
5120
|
return c->Prec * BASE_FIG;
|
6301
5121
|
}
|
6302
5122
|
|
@@ -6419,13 +5239,6 @@ Exit:
|
|
6419
5239
|
if (val > 1) val = 1;
|
6420
5240
|
else if (val < -1) val = -1;
|
6421
5241
|
|
6422
|
-
#ifdef BIGDECIMAL_DEBUG
|
6423
|
-
if (gfDebug) {
|
6424
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
6425
|
-
VPrint(stdout, " b=%\n", b);
|
6426
|
-
printf(" ans=%d\n", val);
|
6427
|
-
}
|
6428
|
-
#endif /* BIGDECIMAL_DEBUG */
|
6429
5242
|
return (int)val;
|
6430
5243
|
}
|
6431
5244
|
|
@@ -6543,25 +5356,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
6543
5356
|
static void
|
6544
5357
|
VpFormatSt(char *psz, size_t fFmt)
|
6545
5358
|
{
|
6546
|
-
size_t
|
6547
|
-
char
|
5359
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
5360
|
+
char *p;
|
6548
5361
|
|
6549
5362
|
if (fFmt == 0) return;
|
6550
5363
|
|
6551
|
-
|
6552
|
-
|
6553
|
-
|
6554
|
-
|
6555
|
-
|
6556
|
-
|
6557
|
-
|
6558
|
-
|
6559
|
-
|
6560
|
-
|
6561
|
-
|
6562
|
-
|
6563
|
-
|
6564
|
-
|
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;
|
6565
5382
|
}
|
6566
5383
|
}
|
6567
5384
|
|
@@ -6843,7 +5660,7 @@ VP_EXPORT int
|
|
6843
5660
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
6844
5661
|
{
|
6845
5662
|
size_t i, j, ind_a, ma, mi, me;
|
6846
|
-
SIGNED_VALUE e
|
5663
|
+
SIGNED_VALUE e;
|
6847
5664
|
int sign, signe, exponent_overflow;
|
6848
5665
|
|
6849
5666
|
/* get exponent part */
|
@@ -6866,23 +5683,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
6866
5683
|
++me;
|
6867
5684
|
}
|
6868
5685
|
while (i < me) {
|
6869
|
-
|
6870
|
-
|
6871
|
-
|
6872
|
-
}
|
6873
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
6874
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
6875
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
6876
|
-
goto exp_overflow;
|
6877
|
-
e = e * 10 + exp_chr[i] - '0';
|
6878
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
6879
|
-
goto exp_overflow;
|
6880
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
6881
|
-
exp_overflow:
|
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)) {
|
6882
5689
|
exponent_overflow = 1;
|
6883
|
-
e = es; /* keep sign */
|
6884
5690
|
break;
|
6885
5691
|
}
|
5692
|
+
e = e * 10 + signe * dig;
|
6886
5693
|
++i;
|
6887
5694
|
}
|
6888
5695
|
}
|
@@ -6901,34 +5708,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
6901
5708
|
++mi;
|
6902
5709
|
}
|
6903
5710
|
}
|
5711
|
+
/* skip leading zeros in integer part */
|
5712
|
+
while (i < mi && int_chr[i] == '0') {
|
5713
|
+
++i;
|
5714
|
+
--ni;
|
5715
|
+
}
|
6904
5716
|
|
6905
|
-
|
6906
|
-
|
6907
|
-
|
6908
|
-
|
6909
|
-
|
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
|
+
}
|
6910
5723
|
|
6911
5724
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
6912
|
-
j =
|
6913
|
-
|
6914
|
-
|
6915
|
-
|
6916
|
-
|
6917
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
6918
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
6919
|
-
if (ef) {
|
6920
|
-
++j; /* Means to add one more preceding zero */
|
6921
|
-
++e;
|
6922
|
-
}
|
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;
|
6923
5730
|
}
|
6924
5731
|
|
6925
|
-
|
6926
|
-
|
6927
|
-
if (exponent_overflow) {
|
5732
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
6928
5733
|
int zero = 1;
|
6929
5734
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
6930
5735
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
6931
|
-
if (!zero &&
|
5736
|
+
if (!zero && e > 0) {
|
6932
5737
|
VpSetInf(a, sign);
|
6933
5738
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
6934
5739
|
}
|
@@ -6978,7 +5783,7 @@ Final:
|
|
6978
5783
|
++j;
|
6979
5784
|
}
|
6980
5785
|
a->Prec = ind_a + 1;
|
6981
|
-
a->exponent =
|
5786
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
6982
5787
|
VpSetSign(a, sign);
|
6983
5788
|
VpNmlz(a);
|
6984
5789
|
return 1;
|
@@ -7050,254 +5855,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
7050
5855
|
*d *= VpGetSign(m);
|
7051
5856
|
|
7052
5857
|
Exit:
|
7053
|
-
#ifdef BIGDECIMAL_DEBUG
|
7054
|
-
if (gfDebug) {
|
7055
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
7056
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
7057
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
7058
|
-
}
|
7059
|
-
#endif /*BIGDECIMAL_DEBUG */
|
7060
5858
|
return f;
|
7061
5859
|
}
|
7062
5860
|
|
7063
|
-
/*
|
7064
|
-
* m <- d
|
7065
|
-
*/
|
7066
|
-
VP_EXPORT void
|
7067
|
-
VpDtoV(Real *m, double d)
|
7068
|
-
{
|
7069
|
-
size_t ind_m, mm;
|
7070
|
-
SIGNED_VALUE ne;
|
7071
|
-
DECDIG i;
|
7072
|
-
double val, val2;
|
7073
|
-
|
7074
|
-
if (isnan(d)) {
|
7075
|
-
VpSetNaN(m);
|
7076
|
-
goto Exit;
|
7077
|
-
}
|
7078
|
-
if (isinf(d)) {
|
7079
|
-
if (d > 0.0) VpSetPosInf(m);
|
7080
|
-
else VpSetNegInf(m);
|
7081
|
-
goto Exit;
|
7082
|
-
}
|
7083
|
-
|
7084
|
-
if (d == 0.0) {
|
7085
|
-
VpSetZero(m, 1);
|
7086
|
-
goto Exit;
|
7087
|
-
}
|
7088
|
-
val = (d > 0.) ? d : -d;
|
7089
|
-
ne = 0;
|
7090
|
-
if (val >= 1.0) {
|
7091
|
-
while (val >= 1.0) {
|
7092
|
-
val /= (double)BASE;
|
7093
|
-
++ne;
|
7094
|
-
}
|
7095
|
-
}
|
7096
|
-
else {
|
7097
|
-
val2 = 1.0 / (double)BASE;
|
7098
|
-
while (val < val2) {
|
7099
|
-
val *= (double)BASE;
|
7100
|
-
--ne;
|
7101
|
-
}
|
7102
|
-
}
|
7103
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
7104
|
-
|
7105
|
-
mm = m->MaxPrec;
|
7106
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
7107
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
7108
|
-
val *= (double)BASE;
|
7109
|
-
i = (DECDIG)val;
|
7110
|
-
val -= (double)i;
|
7111
|
-
m->frac[ind_m] = i;
|
7112
|
-
}
|
7113
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
7114
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
7115
|
-
m->Prec = ind_m + 1;
|
7116
|
-
m->exponent = ne;
|
7117
|
-
|
7118
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
7119
|
-
(DECDIG)(val*(double)BASE));
|
7120
|
-
|
7121
|
-
Exit:
|
7122
|
-
#ifdef BIGDECIMAL_DEBUG
|
7123
|
-
if (gfDebug) {
|
7124
|
-
printf("VpDtoV d=%30.30e\n", d);
|
7125
|
-
VPrint(stdout, " m=%\n", m);
|
7126
|
-
}
|
7127
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7128
|
-
return;
|
7129
|
-
}
|
7130
|
-
|
7131
|
-
/*
|
7132
|
-
* m <- ival
|
7133
|
-
*/
|
7134
|
-
#if 0 /* unused */
|
7135
|
-
VP_EXPORT void
|
7136
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
7137
|
-
{
|
7138
|
-
size_t mm, ind_m;
|
7139
|
-
size_t val, v1, v2, v;
|
7140
|
-
int isign;
|
7141
|
-
SIGNED_VALUE ne;
|
7142
|
-
|
7143
|
-
if (ival == 0) {
|
7144
|
-
VpSetZero(m, 1);
|
7145
|
-
goto Exit;
|
7146
|
-
}
|
7147
|
-
isign = 1;
|
7148
|
-
val = ival;
|
7149
|
-
if (ival < 0) {
|
7150
|
-
isign = -1;
|
7151
|
-
val =(size_t)(-ival);
|
7152
|
-
}
|
7153
|
-
ne = 0;
|
7154
|
-
ind_m = 0;
|
7155
|
-
mm = m->MaxPrec;
|
7156
|
-
while (ind_m < mm) {
|
7157
|
-
m->frac[ind_m] = 0;
|
7158
|
-
++ind_m;
|
7159
|
-
}
|
7160
|
-
ind_m = 0;
|
7161
|
-
while (val > 0) {
|
7162
|
-
if (val) {
|
7163
|
-
v1 = val;
|
7164
|
-
v2 = 1;
|
7165
|
-
while (v1 >= BASE) {
|
7166
|
-
v1 /= BASE;
|
7167
|
-
v2 *= BASE;
|
7168
|
-
}
|
7169
|
-
val = val - v2 * v1;
|
7170
|
-
v = v1;
|
7171
|
-
}
|
7172
|
-
else {
|
7173
|
-
v = 0;
|
7174
|
-
}
|
7175
|
-
m->frac[ind_m] = v;
|
7176
|
-
++ind_m;
|
7177
|
-
++ne;
|
7178
|
-
}
|
7179
|
-
m->Prec = ind_m - 1;
|
7180
|
-
m->exponent = ne;
|
7181
|
-
VpSetSign(m, isign);
|
7182
|
-
VpNmlz(m);
|
7183
|
-
|
7184
|
-
Exit:
|
7185
|
-
#ifdef BIGDECIMAL_DEBUG
|
7186
|
-
if (gfDebug) {
|
7187
|
-
printf(" VpItoV i=%d\n", ival);
|
7188
|
-
VPrint(stdout, " m=%\n", m);
|
7189
|
-
}
|
7190
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7191
|
-
return;
|
7192
|
-
}
|
7193
|
-
#endif
|
7194
|
-
|
7195
|
-
/*
|
7196
|
-
* y = SQRT(x), y*y - x =>0
|
7197
|
-
*/
|
7198
|
-
VP_EXPORT int
|
7199
|
-
VpSqrt(Real *y, Real *x)
|
7200
|
-
{
|
7201
|
-
Real *f = NULL;
|
7202
|
-
Real *r = NULL;
|
7203
|
-
size_t y_prec;
|
7204
|
-
SIGNED_VALUE n, e;
|
7205
|
-
ssize_t nr;
|
7206
|
-
double val;
|
7207
|
-
|
7208
|
-
/* Zero or +Infinity ? */
|
7209
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
7210
|
-
VpAsgn(y,x,1);
|
7211
|
-
goto Exit;
|
7212
|
-
}
|
7213
|
-
|
7214
|
-
/* Negative ? */
|
7215
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
7216
|
-
VpSetNaN(y);
|
7217
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
7218
|
-
}
|
7219
|
-
|
7220
|
-
/* NaN ? */
|
7221
|
-
if (VpIsNaN(x)) {
|
7222
|
-
VpSetNaN(y);
|
7223
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
7224
|
-
}
|
7225
|
-
|
7226
|
-
/* One ? */
|
7227
|
-
if (VpIsOne(x)) {
|
7228
|
-
VpSetOne(y);
|
7229
|
-
goto Exit;
|
7230
|
-
}
|
7231
|
-
|
7232
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
7233
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
7234
|
-
|
7235
|
-
/* allocate temporally variables */
|
7236
|
-
/* TODO: reconsider MaxPrec of f and r */
|
7237
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
7238
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
7239
|
-
|
7240
|
-
nr = 0;
|
7241
|
-
y_prec = y->MaxPrec;
|
7242
|
-
|
7243
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
7244
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
7245
|
-
n = e / 2;
|
7246
|
-
if (e - n * 2 != 0) {
|
7247
|
-
val /= BASE;
|
7248
|
-
n = (e + 1) / 2;
|
7249
|
-
}
|
7250
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
7251
|
-
y->exponent += n;
|
7252
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
7253
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
7254
|
-
f->MaxPrec = y->MaxPrec + 1;
|
7255
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
7256
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
7257
|
-
|
7258
|
-
/*
|
7259
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
7260
|
-
*/
|
7261
|
-
do {
|
7262
|
-
y->MaxPrec *= 2;
|
7263
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
7264
|
-
f->MaxPrec = y->MaxPrec;
|
7265
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
7266
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
7267
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
7268
|
-
if (VpIsZero(f))
|
7269
|
-
goto converge;
|
7270
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
7271
|
-
VpAsgn(y, r, 1); /* y = r */
|
7272
|
-
} while (++nr < n);
|
7273
|
-
|
7274
|
-
#ifdef BIGDECIMAL_DEBUG
|
7275
|
-
if (gfDebug) {
|
7276
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
7277
|
-
}
|
7278
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7279
|
-
y->MaxPrec = y_prec;
|
7280
|
-
|
7281
|
-
converge:
|
7282
|
-
VpChangeSign(y, 1);
|
7283
|
-
#ifdef BIGDECIMAL_DEBUG
|
7284
|
-
if (gfDebug) {
|
7285
|
-
VpMult(r, y, y);
|
7286
|
-
VpAddSub(f, x, r, -1);
|
7287
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
7288
|
-
VPrint(stdout, " y =% \n", y);
|
7289
|
-
VPrint(stdout, " x =% \n", x);
|
7290
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
7291
|
-
}
|
7292
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7293
|
-
y->MaxPrec = y_prec;
|
7294
|
-
|
7295
|
-
Exit:
|
7296
|
-
rbd_free_struct(f);
|
7297
|
-
rbd_free_struct(r);
|
7298
|
-
return 1;
|
7299
|
-
}
|
7300
|
-
|
7301
5861
|
/*
|
7302
5862
|
* Round relatively from the decimal point.
|
7303
5863
|
* f: rounding mode
|
@@ -7474,7 +6034,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
7474
6034
|
DECDIG v;
|
7475
6035
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
7476
6036
|
v = y->frac[0];
|
7477
|
-
nf -=
|
6037
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
7478
6038
|
while ((v /= 10) != 0) nf--;
|
7479
6039
|
nf += (ssize_t)BASE_FIG-1;
|
7480
6040
|
return VpMidRound(y, f, nf);
|
@@ -7611,117 +6171,9 @@ VpFrac(Real *y, Real *x)
|
|
7611
6171
|
VpNmlz(y);
|
7612
6172
|
|
7613
6173
|
Exit:
|
7614
|
-
#ifdef BIGDECIMAL_DEBUG
|
7615
|
-
if (gfDebug) {
|
7616
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
7617
|
-
VPrint(stdout, " x=%\n", x);
|
7618
|
-
}
|
7619
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7620
6174
|
return;
|
7621
6175
|
}
|
7622
6176
|
|
7623
|
-
/*
|
7624
|
-
* y = x ** n
|
7625
|
-
*/
|
7626
|
-
VP_EXPORT int
|
7627
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
7628
|
-
{
|
7629
|
-
size_t s, ss;
|
7630
|
-
ssize_t sign;
|
7631
|
-
Real *w1 = NULL;
|
7632
|
-
Real *w2 = NULL;
|
7633
|
-
|
7634
|
-
if (VpIsZero(x)) {
|
7635
|
-
if (n == 0) {
|
7636
|
-
VpSetOne(y);
|
7637
|
-
goto Exit;
|
7638
|
-
}
|
7639
|
-
sign = VpGetSign(x);
|
7640
|
-
if (n < 0) {
|
7641
|
-
n = -n;
|
7642
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
7643
|
-
VpSetInf(y, sign);
|
7644
|
-
}
|
7645
|
-
else {
|
7646
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
7647
|
-
VpSetZero(y,sign);
|
7648
|
-
}
|
7649
|
-
goto Exit;
|
7650
|
-
}
|
7651
|
-
if (VpIsNaN(x)) {
|
7652
|
-
VpSetNaN(y);
|
7653
|
-
goto Exit;
|
7654
|
-
}
|
7655
|
-
if (VpIsInf(x)) {
|
7656
|
-
if (n == 0) {
|
7657
|
-
VpSetOne(y);
|
7658
|
-
goto Exit;
|
7659
|
-
}
|
7660
|
-
if (n > 0) {
|
7661
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
7662
|
-
goto Exit;
|
7663
|
-
}
|
7664
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
7665
|
-
goto Exit;
|
7666
|
-
}
|
7667
|
-
|
7668
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
7669
|
-
/* abs(x) = 1 */
|
7670
|
-
VpSetOne(y);
|
7671
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
7672
|
-
if ((n % 2) == 0) goto Exit;
|
7673
|
-
VpSetSign(y, -1);
|
7674
|
-
goto Exit;
|
7675
|
-
}
|
7676
|
-
|
7677
|
-
if (n > 0) sign = 1;
|
7678
|
-
else if (n < 0) {
|
7679
|
-
sign = -1;
|
7680
|
-
n = -n;
|
7681
|
-
}
|
7682
|
-
else {
|
7683
|
-
VpSetOne(y);
|
7684
|
-
goto Exit;
|
7685
|
-
}
|
7686
|
-
|
7687
|
-
/* Allocate working variables */
|
7688
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
7689
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
7690
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
7691
|
-
|
7692
|
-
/* calculation start */
|
7693
|
-
|
7694
|
-
VpAsgn(y, x, 1);
|
7695
|
-
--n;
|
7696
|
-
while (n > 0) {
|
7697
|
-
VpAsgn(w1, x, 1);
|
7698
|
-
s = 1;
|
7699
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
7700
|
-
VpMult(w2, w1, w1);
|
7701
|
-
VpAsgn(w1, w2, 1);
|
7702
|
-
}
|
7703
|
-
n -= (SIGNED_VALUE)ss;
|
7704
|
-
VpMult(w2, y, w1);
|
7705
|
-
VpAsgn(y, w2, 1);
|
7706
|
-
}
|
7707
|
-
if (sign < 0) {
|
7708
|
-
VpDivd(w1, w2, VpConstOne, y);
|
7709
|
-
VpAsgn(y, w1, 1);
|
7710
|
-
}
|
7711
|
-
|
7712
|
-
Exit:
|
7713
|
-
#ifdef BIGDECIMAL_DEBUG
|
7714
|
-
if (gfDebug) {
|
7715
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
7716
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
7717
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
7718
|
-
}
|
7719
|
-
#endif /* BIGDECIMAL_DEBUG */
|
7720
|
-
rbd_free_struct(w2);
|
7721
|
-
rbd_free_struct(w1);
|
7722
|
-
return 1;
|
7723
|
-
}
|
7724
|
-
|
7725
6177
|
#ifdef BIGDECIMAL_DEBUG
|
7726
6178
|
int
|
7727
6179
|
VpVarCheck(Real * v)
|