bigdecimal 3.1.9 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/bigdecimal/bigdecimal.c +763 -2347
- data/ext/bigdecimal/bigdecimal.h +4 -25
- data/ext/bigdecimal/bits.h +3 -0
- data/ext/bigdecimal/extconf.rb +3 -7
- data/ext/bigdecimal/missing.h +1 -93
- data/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math.rb +789 -73
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +15 -14
- data/lib/bigdecimal.rb +355 -0
- metadata +3 -3
data/ext/bigdecimal/bigdecimal.c
CHANGED
|
@@ -31,16 +31,23 @@
|
|
|
31
31
|
#include "bits.h"
|
|
32
32
|
#include "static_assert.h"
|
|
33
33
|
|
|
34
|
-
#define BIGDECIMAL_VERSION "
|
|
34
|
+
#define BIGDECIMAL_VERSION "4.0.1"
|
|
35
35
|
|
|
36
36
|
/* #define ENABLE_NUMERIC_STRING */
|
|
37
37
|
|
|
38
38
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
|
39
39
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
|
40
40
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
41
|
+
#define ADD_OVERFLOW_SIGNED_VALUE_P(a, b) ADD_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
42
|
+
|
|
43
|
+
/* max_value = 0.9999_9999_9999E[exponent], exponent <= SIGNED_VALUE_MAX */
|
|
44
|
+
#define VP_EXPONENT_MAX (SIGNED_VALUE_MAX / BASE_FIG)
|
|
45
|
+
/* min_value = 0.0001_0000_0000E[exponent], exponent-(BASE_FIG-1) >= SIGNED_VALUE_MIN */
|
|
46
|
+
#define VP_EXPONENT_MIN ((SIGNED_VALUE_MIN + BASE_FIG - 1) / BASE_FIG)
|
|
47
|
+
#define EXPONENT_MAX (VP_EXPONENT_MAX * BASE_FIG)
|
|
48
|
+
#define EXPONENT_MIN (VP_EXPONENT_MIN * BASE_FIG - (BASE_FIG - 1))
|
|
41
49
|
|
|
42
50
|
VALUE rb_cBigDecimal;
|
|
43
|
-
VALUE rb_mBigMath;
|
|
44
51
|
|
|
45
52
|
static ID id_BigDecimal_exception_mode;
|
|
46
53
|
static ID id_BigDecimal_rounding_mode;
|
|
@@ -68,15 +75,28 @@ static struct {
|
|
|
68
75
|
uint8_t mode;
|
|
69
76
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
typedef struct {
|
|
79
|
+
VALUE bigdecimal;
|
|
80
|
+
Real *real;
|
|
81
|
+
} BDVALUE;
|
|
82
|
+
|
|
83
|
+
typedef struct {
|
|
84
|
+
VALUE bigdecimal_or_nil;
|
|
85
|
+
Real *real_or_null;
|
|
86
|
+
} NULLABLE_BDVALUE;
|
|
87
|
+
|
|
88
|
+
static inline BDVALUE
|
|
89
|
+
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
90
|
+
{
|
|
91
|
+
assert(v.real_or_null != NULL);
|
|
92
|
+
return (BDVALUE) { v.bigdecimal_or_nil, v.real_or_null };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static inline NULLABLE_BDVALUE
|
|
96
|
+
bdvalue_nullable(BDVALUE v)
|
|
97
|
+
{
|
|
98
|
+
return (NULLABLE_BDVALUE) { v.bigdecimal, v.real };
|
|
99
|
+
}
|
|
80
100
|
|
|
81
101
|
#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
|
|
82
102
|
#define BASE BIGDECIMAL_BASE
|
|
@@ -84,31 +104,6 @@ static struct {
|
|
|
84
104
|
#define HALF_BASE (BASE/2)
|
|
85
105
|
#define BASE1 (BASE/10)
|
|
86
106
|
|
|
87
|
-
#define LOG10_2 0.3010299956639812
|
|
88
|
-
|
|
89
|
-
#ifndef RRATIONAL_ZERO_P
|
|
90
|
-
# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
|
|
91
|
-
FIX2LONG(rb_rational_num(x)) == 0)
|
|
92
|
-
#endif
|
|
93
|
-
|
|
94
|
-
#ifndef RRATIONAL_NEGATIVE_P
|
|
95
|
-
# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
|
|
96
|
-
#endif
|
|
97
|
-
|
|
98
|
-
#ifndef DECIMAL_SIZE_OF_BITS
|
|
99
|
-
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
|
|
100
|
-
/* an approximation of ceil(n * log10(2)), upto 65536 at least */
|
|
101
|
-
#endif
|
|
102
|
-
|
|
103
|
-
#ifdef PRIsVALUE
|
|
104
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
|
105
|
-
# define RB_OBJ_STRING(obj) (obj)
|
|
106
|
-
#else
|
|
107
|
-
# define PRIsVALUE "s"
|
|
108
|
-
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
|
109
|
-
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
|
110
|
-
#endif
|
|
111
|
-
|
|
112
107
|
#ifndef MAYBE_UNUSED
|
|
113
108
|
# define MAYBE_UNUSED(x) x
|
|
114
109
|
#endif
|
|
@@ -145,6 +140,17 @@ check_allocation_count_nonzero(void)
|
|
|
145
140
|
# define check_allocation_count_nonzero() /* nothing */
|
|
146
141
|
#endif /* BIGDECIMAL_DEBUG */
|
|
147
142
|
|
|
143
|
+
/* VpMult VpDivd helpers */
|
|
144
|
+
#define VPMULT_RESULT_PREC(a, b) (a->Prec + b->Prec)
|
|
145
|
+
/* To calculate VpDivd with n-digits precision, quotient needs n+2*BASE_FIG-1 digits space */
|
|
146
|
+
/* In the worst precision case 0001_1111_1111 / 9999 = 0000_0001_1112, there are 2*BASE_FIG-1 leading zeros */
|
|
147
|
+
#define VPDIVD_QUO_DIGITS(required_digits) ((required_digits) + 2 * BASE_FIG - 1)
|
|
148
|
+
/* Required r.MaxPrec for calculating VpDivd(c, r, a, b) */
|
|
149
|
+
#define VPDIVD_REM_PREC(a, b, c) Max(a->Prec, b->Prec + c->MaxPrec - 1)
|
|
150
|
+
|
|
151
|
+
static NULLABLE_BDVALUE
|
|
152
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception);
|
|
153
|
+
|
|
148
154
|
PUREFUNC(static inline size_t rbd_struct_size(size_t const));
|
|
149
155
|
|
|
150
156
|
static inline size_t
|
|
@@ -164,44 +170,10 @@ rbd_allocate_struct(size_t const internal_digits)
|
|
|
164
170
|
return real;
|
|
165
171
|
}
|
|
166
172
|
|
|
167
|
-
static size_t
|
|
168
|
-
rbd_calculate_internal_digits(size_t const digits, bool limit_precision)
|
|
169
|
-
{
|
|
170
|
-
size_t const len = roomof(digits, BASE_FIG);
|
|
171
|
-
if (limit_precision) {
|
|
172
|
-
size_t const prec_limit = VpGetPrecLimit();
|
|
173
|
-
if (prec_limit > 0) {
|
|
174
|
-
/* NOTE: 2 more digits for rounding and division */
|
|
175
|
-
size_t const max_len = roomof(prec_limit, BASE_FIG) + 2;
|
|
176
|
-
if (len > max_len)
|
|
177
|
-
return max_len;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return len;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
173
|
static inline Real *
|
|
185
|
-
rbd_allocate_struct_decimal_digits(size_t const decimal_digits
|
|
186
|
-
{
|
|
187
|
-
size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision);
|
|
188
|
-
return rbd_allocate_struct(internal_digits);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp);
|
|
192
|
-
|
|
193
|
-
static Real *
|
|
194
|
-
rbd_reallocate_struct(Real *real, size_t const internal_digits)
|
|
174
|
+
rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
|
|
195
175
|
{
|
|
196
|
-
|
|
197
|
-
VALUE obj = real ? real->obj : 0;
|
|
198
|
-
Real *new_real = (Real *)ruby_xrealloc(real, size);
|
|
199
|
-
new_real->MaxPrec = internal_digits;
|
|
200
|
-
if (obj) {
|
|
201
|
-
new_real->obj = 0;
|
|
202
|
-
BigDecimal_wrap_struct(obj, new_real);
|
|
203
|
-
}
|
|
204
|
-
return new_real;
|
|
176
|
+
return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
|
|
205
177
|
}
|
|
206
178
|
|
|
207
179
|
static void
|
|
@@ -214,58 +186,16 @@ rbd_free_struct(Real *real)
|
|
|
214
186
|
}
|
|
215
187
|
}
|
|
216
188
|
|
|
189
|
+
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
|
|
217
190
|
#define NewZero rbd_allocate_struct_zero
|
|
218
|
-
static Real *
|
|
219
|
-
rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision)
|
|
220
|
-
{
|
|
221
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
|
|
222
|
-
VpSetZero(real, sign);
|
|
223
|
-
return real;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits));
|
|
227
|
-
#define NewZeroLimited rbd_allocate_struct_zero_limited
|
|
228
|
-
static inline Real *
|
|
229
|
-
rbd_allocate_struct_zero_limited(int sign, size_t const digits)
|
|
230
|
-
{
|
|
231
|
-
return rbd_allocate_struct_zero(sign, digits, true);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits));
|
|
235
|
-
#define NewZeroNolimit rbd_allocate_struct_zero_nolimit
|
|
236
191
|
static inline Real *
|
|
237
|
-
|
|
238
|
-
{
|
|
239
|
-
return rbd_allocate_struct_zero(sign, digits, false);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
#define NewOne rbd_allocate_struct_one
|
|
243
|
-
static Real *
|
|
244
|
-
rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision)
|
|
192
|
+
rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
245
193
|
{
|
|
246
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits
|
|
247
|
-
|
|
248
|
-
if (sign < 0)
|
|
249
|
-
VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
|
|
194
|
+
Real *real = rbd_allocate_struct_decimal_digits(digits);
|
|
195
|
+
VpSetZero(real, sign);
|
|
250
196
|
return real;
|
|
251
197
|
}
|
|
252
198
|
|
|
253
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits));
|
|
254
|
-
#define NewOneLimited rbd_allocate_struct_one_limited
|
|
255
|
-
static inline Real *
|
|
256
|
-
rbd_allocate_struct_one_limited(int sign, size_t const digits)
|
|
257
|
-
{
|
|
258
|
-
return rbd_allocate_struct_one(sign, digits, true);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits));
|
|
262
|
-
#define NewOneNolimit rbd_allocate_struct_one_nolimit
|
|
263
|
-
static inline Real *
|
|
264
|
-
rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
|
265
|
-
{
|
|
266
|
-
return rbd_allocate_struct_one(sign, digits, false);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
199
|
/*
|
|
270
200
|
* ================== Ruby Interface part ==========================
|
|
271
201
|
*/
|
|
@@ -277,7 +207,8 @@ rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
|
|
|
277
207
|
static unsigned short VpGetException(void);
|
|
278
208
|
static void VpSetException(unsigned short f);
|
|
279
209
|
static void VpCheckException(Real *p, bool always);
|
|
280
|
-
static
|
|
210
|
+
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
211
|
+
static VALUE CheckGetValue(BDVALUE v);
|
|
281
212
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
282
213
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
283
214
|
static Real *VpCopy(Real *pv, Real const* const x);
|
|
@@ -292,6 +223,8 @@ static VALUE BigDecimal_positive_infinity(void);
|
|
|
292
223
|
static VALUE BigDecimal_negative_infinity(void);
|
|
293
224
|
static VALUE BigDecimal_positive_zero(void);
|
|
294
225
|
static VALUE BigDecimal_negative_zero(void);
|
|
226
|
+
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
227
|
+
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
295
228
|
|
|
296
229
|
static void
|
|
297
230
|
BigDecimal_delete(void *pv)
|
|
@@ -319,58 +252,33 @@ static const rb_data_type_t BigDecimal_data_type = {
|
|
|
319
252
|
#endif
|
|
320
253
|
};
|
|
321
254
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
{
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
328
|
-
BigDecimal_wrap_struct(obj, real);
|
|
329
|
-
}
|
|
330
|
-
return real;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
|
|
334
|
-
#define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
|
|
335
|
-
static inline Real *
|
|
336
|
-
rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
|
|
337
|
-
{
|
|
338
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
|
|
342
|
-
#define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
|
|
343
|
-
static inline Real *
|
|
344
|
-
rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
|
|
345
|
-
{
|
|
346
|
-
return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
static Real *
|
|
350
|
-
rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
|
|
255
|
+
// TypedData_Wrap_Struct may fail if there is no memory, or GC.add_stress_to_class(BigDecimal) is set.
|
|
256
|
+
// We need to first allocate empty struct, allocate Real struct, and then set the data pointer.
|
|
257
|
+
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
|
258
|
+
static NULL_WRAPPED_VALUE
|
|
259
|
+
BigDecimal_alloc_empty_struct(VALUE klass)
|
|
351
260
|
{
|
|
352
|
-
|
|
353
|
-
if (real != NULL) {
|
|
354
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
355
|
-
BigDecimal_wrap_struct(obj, real);
|
|
356
|
-
}
|
|
357
|
-
return real;
|
|
261
|
+
return (NULL_WRAPPED_VALUE) { TypedData_Wrap_Struct(klass, &BigDecimal_data_type, NULL) };
|
|
358
262
|
}
|
|
359
263
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
static inline Real *
|
|
363
|
-
rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
|
|
264
|
+
static VALUE
|
|
265
|
+
BigDecimal_wrap_struct(NULL_WRAPPED_VALUE v, Real *real)
|
|
364
266
|
{
|
|
365
|
-
|
|
267
|
+
VALUE obj = v._obj;
|
|
268
|
+
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
269
|
+
RTYPEDDATA_DATA(obj) = real;
|
|
270
|
+
RB_OBJ_FREEZE(obj);
|
|
271
|
+
return obj;
|
|
366
272
|
}
|
|
367
273
|
|
|
368
|
-
MAYBE_UNUSED(static inline
|
|
369
|
-
#define
|
|
370
|
-
static
|
|
371
|
-
|
|
274
|
+
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
275
|
+
#define NewZeroWrap rbd_allocate_struct_zero_wrap
|
|
276
|
+
static BDVALUE
|
|
277
|
+
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
372
278
|
{
|
|
373
|
-
|
|
279
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
280
|
+
Real *real = rbd_allocate_struct_zero(sign, digits);
|
|
281
|
+
return (BDVALUE) { BigDecimal_wrap_struct(null_wrapped, real), real };
|
|
374
282
|
}
|
|
375
283
|
|
|
376
284
|
static inline int
|
|
@@ -398,24 +306,22 @@ cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
|
|
|
398
306
|
}
|
|
399
307
|
|
|
400
308
|
static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
|
|
401
|
-
static VALUE rb_inum_convert_to_BigDecimal(VALUE val
|
|
309
|
+
static VALUE rb_inum_convert_to_BigDecimal(VALUE val);
|
|
402
310
|
static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
403
311
|
static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
404
|
-
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
312
|
+
static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception);
|
|
405
313
|
static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
|
|
406
314
|
|
|
407
|
-
static
|
|
408
|
-
|
|
315
|
+
static NULLABLE_BDVALUE
|
|
316
|
+
GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
409
317
|
{
|
|
410
|
-
const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
|
|
411
|
-
|
|
412
318
|
switch(TYPE(v)) {
|
|
413
319
|
case T_FLOAT:
|
|
414
|
-
v = rb_float_convert_to_BigDecimal(v,
|
|
320
|
+
v = rb_float_convert_to_BigDecimal(v, 0, true);
|
|
415
321
|
break;
|
|
416
322
|
|
|
417
323
|
case T_RATIONAL:
|
|
418
|
-
v = rb_rational_convert_to_BigDecimal(v,
|
|
324
|
+
v = rb_rational_convert_to_BigDecimal(v, prec, true);
|
|
419
325
|
break;
|
|
420
326
|
|
|
421
327
|
case T_DATA:
|
|
@@ -424,47 +330,59 @@ GetVpValueWithPrec(VALUE v, long prec, int must)
|
|
|
424
330
|
}
|
|
425
331
|
break;
|
|
426
332
|
|
|
427
|
-
case T_FIXNUM:
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
|
|
333
|
+
case T_FIXNUM:
|
|
334
|
+
case T_BIGNUM: {
|
|
335
|
+
v = rb_inum_convert_to_BigDecimal(v);
|
|
431
336
|
break;
|
|
432
337
|
}
|
|
433
338
|
|
|
434
339
|
#ifdef ENABLE_NUMERIC_STRING
|
|
435
340
|
case T_STRING: {
|
|
436
341
|
const char *c_str = StringValueCStr(v);
|
|
437
|
-
v = rb_cstr_convert_to_BigDecimal(c_str,
|
|
342
|
+
v = rb_cstr_convert_to_BigDecimal(c_str, must);
|
|
438
343
|
break;
|
|
439
344
|
}
|
|
440
345
|
#endif /* ENABLE_NUMERIC_STRING */
|
|
441
346
|
|
|
442
|
-
case T_BIGNUM: {
|
|
443
|
-
VALUE bg = rb_big2str(v, 10);
|
|
444
|
-
v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
|
|
445
|
-
RB_GC_GUARD(bg);
|
|
446
|
-
break;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
347
|
default:
|
|
450
348
|
goto SomeOneMayDoIt;
|
|
451
349
|
}
|
|
452
350
|
|
|
453
351
|
Real *vp;
|
|
454
352
|
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
|
455
|
-
return vp;
|
|
353
|
+
return (NULLABLE_BDVALUE) { v, vp };
|
|
456
354
|
|
|
457
355
|
SomeOneMayDoIt:
|
|
458
356
|
if (must) {
|
|
459
357
|
cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
|
|
460
358
|
}
|
|
461
|
-
return NULL; /* NULL means to coerce */
|
|
359
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL }; /* NULL means to coerce */
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
static inline NULLABLE_BDVALUE
|
|
363
|
+
GetBDValueWithPrec(VALUE v, size_t prec)
|
|
364
|
+
{
|
|
365
|
+
return GetBDValueWithPrecInternal(v, prec, 0);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
static inline BDVALUE
|
|
370
|
+
GetBDValueWithPrecMust(VALUE v, size_t prec)
|
|
371
|
+
{
|
|
372
|
+
return bdvalue_nonnullable(GetBDValueWithPrecInternal(v, prec, 1));
|
|
462
373
|
}
|
|
463
374
|
|
|
375
|
+
// self must be a receiver of BigDecimal instance method or a gc guarded BigDecimal object.
|
|
464
376
|
static inline Real*
|
|
465
|
-
|
|
377
|
+
GetSelfVpValue(VALUE self)
|
|
378
|
+
{
|
|
379
|
+
return GetBDValueWithPrecMust(self, 0).real;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
static inline BDVALUE
|
|
383
|
+
GetBDValueMust(VALUE v)
|
|
466
384
|
{
|
|
467
|
-
return
|
|
385
|
+
return GetBDValueWithPrecMust(v, 0);
|
|
468
386
|
}
|
|
469
387
|
|
|
470
388
|
/* call-seq:
|
|
@@ -479,49 +397,14 @@ GetVpValue(VALUE v, int must)
|
|
|
479
397
|
static inline VALUE
|
|
480
398
|
BigDecimal_double_fig(VALUE self)
|
|
481
399
|
{
|
|
482
|
-
return INT2FIX(
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/* call-seq:
|
|
486
|
-
* precs -> array
|
|
487
|
-
*
|
|
488
|
-
* Returns an Array of two Integer values that represent platform-dependent
|
|
489
|
-
* internal storage properties.
|
|
490
|
-
*
|
|
491
|
-
* This method is deprecated and will be removed in the future.
|
|
492
|
-
* Instead, use BigDecimal#n_significant_digits for obtaining the number of
|
|
493
|
-
* significant digits in scientific notation, and BigDecimal#precision for
|
|
494
|
-
* obtaining the number of digits in decimal notation.
|
|
495
|
-
*
|
|
496
|
-
*/
|
|
497
|
-
|
|
498
|
-
static VALUE
|
|
499
|
-
BigDecimal_prec(VALUE self)
|
|
500
|
-
{
|
|
501
|
-
ENTER(1);
|
|
502
|
-
Real *p;
|
|
503
|
-
VALUE obj;
|
|
504
|
-
|
|
505
|
-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
|
|
506
|
-
"BigDecimal#precs is deprecated and will be removed in the future; "
|
|
507
|
-
"use BigDecimal#precision instead.");
|
|
508
|
-
|
|
509
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
510
|
-
obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
|
|
511
|
-
SIZET2NUM(p->MaxPrec*VpBaseFig()));
|
|
512
|
-
return obj;
|
|
400
|
+
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
513
401
|
}
|
|
514
402
|
|
|
515
403
|
static void
|
|
516
|
-
|
|
404
|
+
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
517
405
|
{
|
|
518
|
-
ENTER(1);
|
|
519
|
-
|
|
520
406
|
if (out_precision == NULL && out_scale == NULL)
|
|
521
407
|
return;
|
|
522
|
-
|
|
523
|
-
Real *p;
|
|
524
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
525
408
|
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
526
409
|
zero:
|
|
527
410
|
if (out_precision) *out_precision = 0;
|
|
@@ -625,6 +508,14 @@ BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t
|
|
|
625
508
|
}
|
|
626
509
|
}
|
|
627
510
|
|
|
511
|
+
static void
|
|
512
|
+
BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
|
|
513
|
+
{
|
|
514
|
+
BDVALUE v = GetBDValueMust(self);
|
|
515
|
+
VpCountPrecisionAndScale(v.real, out_precision, out_scale);
|
|
516
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
517
|
+
}
|
|
518
|
+
|
|
628
519
|
/*
|
|
629
520
|
* call-seq:
|
|
630
521
|
* precision -> integer
|
|
@@ -660,8 +551,8 @@ BigDecimal_precision(VALUE self)
|
|
|
660
551
|
* BigDecimal("1").scale # => 0
|
|
661
552
|
* BigDecimal("1.1").scale # => 1
|
|
662
553
|
* BigDecimal("3.1415").scale # => 4
|
|
663
|
-
* BigDecimal("-1e20").
|
|
664
|
-
* BigDecimal("1e-20").
|
|
554
|
+
* BigDecimal("-1e20").scale # => 0
|
|
555
|
+
* BigDecimal("1e-20").scale # => 20
|
|
665
556
|
* BigDecimal("Infinity").scale # => 0
|
|
666
557
|
* BigDecimal("-Infinity").scale # => 0
|
|
667
558
|
* BigDecimal("NaN").scale # => 0
|
|
@@ -711,25 +602,23 @@ BigDecimal_precision_scale(VALUE self)
|
|
|
711
602
|
static VALUE
|
|
712
603
|
BigDecimal_n_significant_digits(VALUE self)
|
|
713
604
|
{
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
Real *p;
|
|
717
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
718
|
-
if (VpIsZero(p) || !VpIsDef(p)) {
|
|
605
|
+
BDVALUE v = GetBDValueMust(self);
|
|
606
|
+
if (VpIsZero(v.real) || !VpIsDef(v.real)) {
|
|
719
607
|
return INT2FIX(0);
|
|
720
608
|
}
|
|
721
609
|
|
|
722
|
-
ssize_t n =
|
|
723
|
-
for (n =
|
|
610
|
+
ssize_t n = v.real->Prec; /* The length of frac without trailing zeros. */
|
|
611
|
+
for (n = v.real->Prec; n > 0 && v.real->frac[n-1] == 0; --n);
|
|
724
612
|
if (n == 0) return INT2FIX(0);
|
|
725
613
|
|
|
726
614
|
DECDIG x;
|
|
727
615
|
int nlz = BASE_FIG;
|
|
728
|
-
for (x =
|
|
616
|
+
for (x = v.real->frac[0]; x > 0; x /= 10) --nlz;
|
|
729
617
|
|
|
730
618
|
int ntz = 0;
|
|
731
|
-
for (x =
|
|
619
|
+
for (x = v.real->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
|
|
732
620
|
|
|
621
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
733
622
|
ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
|
|
734
623
|
return SSIZET2NUM(n_significant_digits);
|
|
735
624
|
}
|
|
@@ -751,17 +640,14 @@ BigDecimal_n_significant_digits(VALUE self)
|
|
|
751
640
|
static VALUE
|
|
752
641
|
BigDecimal_hash(VALUE self)
|
|
753
642
|
{
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
st_index_t hash;
|
|
757
|
-
|
|
758
|
-
GUARD_OBJ(p, GetVpValue(self, 1));
|
|
759
|
-
hash = (st_index_t)p->sign;
|
|
643
|
+
BDVALUE v = GetBDValueMust(self);
|
|
644
|
+
st_index_t hash = (st_index_t)v.real->sign;
|
|
760
645
|
/* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
|
|
761
646
|
if(hash == 2 || hash == (st_index_t)-2) {
|
|
762
|
-
hash ^= rb_memhash(
|
|
763
|
-
hash +=
|
|
647
|
+
hash ^= rb_memhash(v.real->frac, sizeof(DECDIG)*v.real->Prec);
|
|
648
|
+
hash += v.real->exponent;
|
|
764
649
|
}
|
|
650
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
765
651
|
return ST2FIX(hash);
|
|
766
652
|
}
|
|
767
653
|
|
|
@@ -780,21 +666,22 @@ BigDecimal_hash(VALUE self)
|
|
|
780
666
|
static VALUE
|
|
781
667
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
782
668
|
{
|
|
783
|
-
|
|
784
|
-
Real *vp;
|
|
669
|
+
BDVALUE v;
|
|
785
670
|
char *psz;
|
|
786
671
|
VALUE dummy;
|
|
787
672
|
volatile VALUE dump;
|
|
788
673
|
size_t len;
|
|
789
674
|
|
|
790
675
|
rb_scan_args(argc, argv, "01", &dummy);
|
|
791
|
-
|
|
792
|
-
dump = rb_str_new(0, VpNumOfChars(
|
|
676
|
+
v = GetBDValueMust(self);
|
|
677
|
+
dump = rb_str_new(0, VpNumOfChars(v.real, "E")+50);
|
|
793
678
|
psz = RSTRING_PTR(dump);
|
|
794
|
-
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":",
|
|
679
|
+
snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", v.real->Prec*VpBaseFig());
|
|
795
680
|
len = strlen(psz);
|
|
796
|
-
VpToString(
|
|
681
|
+
VpToString(v.real, psz+len, RSTRING_LEN(dump)-len, 0, 0);
|
|
797
682
|
rb_str_resize(dump, strlen(psz));
|
|
683
|
+
|
|
684
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
798
685
|
return dump;
|
|
799
686
|
}
|
|
800
687
|
|
|
@@ -804,27 +691,19 @@ BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
|
|
804
691
|
static VALUE
|
|
805
692
|
BigDecimal_load(VALUE self, VALUE str)
|
|
806
693
|
{
|
|
807
|
-
|
|
808
|
-
Real *pv;
|
|
694
|
+
BDVALUE v;
|
|
809
695
|
unsigned char *pch;
|
|
810
696
|
unsigned char ch;
|
|
811
|
-
unsigned long m=0;
|
|
812
697
|
|
|
813
698
|
pch = (unsigned char *)StringValueCStr(str);
|
|
814
|
-
/* First
|
|
699
|
+
/* First skip max prec. Don't trust the value. */
|
|
815
700
|
while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
|
|
816
701
|
if(!ISDIGIT(ch)) {
|
|
817
702
|
rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
|
|
818
703
|
}
|
|
819
|
-
m = m*10 + (unsigned long)(ch-'0');
|
|
820
704
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
m /= VpBaseFig();
|
|
824
|
-
if (m && pv->MaxPrec > m) {
|
|
825
|
-
pv->MaxPrec = m+1;
|
|
826
|
-
}
|
|
827
|
-
return VpCheckGetValue(pv);
|
|
705
|
+
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
706
|
+
return CheckGetValue(v);
|
|
828
707
|
}
|
|
829
708
|
|
|
830
709
|
static unsigned short
|
|
@@ -1117,22 +996,10 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1117
996
|
static size_t
|
|
1118
997
|
GetAddSubPrec(Real *a, Real *b)
|
|
1119
998
|
{
|
|
1120
|
-
size_t mxs;
|
|
1121
|
-
size_t mx = a->Prec;
|
|
1122
|
-
SIGNED_VALUE d;
|
|
1123
|
-
|
|
1124
999
|
if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
d = a->exponent - b->exponent;
|
|
1129
|
-
if (d < 0) d = -d;
|
|
1130
|
-
mx = mx + (size_t)d;
|
|
1131
|
-
if (mx < mxs) {
|
|
1132
|
-
return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
return mx;
|
|
1000
|
+
ssize_t min_a = a->exponent - a->Prec;
|
|
1001
|
+
ssize_t min_b = b->exponent - b->Prec;
|
|
1002
|
+
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
1136
1003
|
}
|
|
1137
1004
|
|
|
1138
1005
|
static inline SIGNED_VALUE
|
|
@@ -1152,39 +1019,13 @@ check_int_precision(VALUE v)
|
|
|
1152
1019
|
return n;
|
|
1153
1020
|
}
|
|
1154
1021
|
|
|
1155
|
-
static
|
|
1156
|
-
|
|
1157
|
-
{
|
|
1158
|
-
assert(is_kind_of_BigDecimal(obj));
|
|
1159
|
-
assert(vp != NULL);
|
|
1160
|
-
|
|
1161
|
-
if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
|
|
1162
|
-
return obj;
|
|
1163
|
-
|
|
1164
|
-
assert(RTYPEDDATA_DATA(obj) == NULL);
|
|
1165
|
-
assert(vp->obj == 0);
|
|
1166
|
-
|
|
1167
|
-
RTYPEDDATA_DATA(obj) = vp;
|
|
1168
|
-
vp->obj = obj;
|
|
1169
|
-
RB_OBJ_FREEZE(obj);
|
|
1170
|
-
return obj;
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
VP_EXPORT Real *
|
|
1174
|
-
VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1175
|
-
{
|
|
1176
|
-
VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
|
|
1177
|
-
Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
|
|
1178
|
-
if (!pv)
|
|
1179
|
-
return NULL;
|
|
1180
|
-
BigDecimal_wrap_struct(obj, pv);
|
|
1181
|
-
return pv;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
VP_EXPORT Real *
|
|
1185
|
-
VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
|
|
1022
|
+
static NULLABLE_BDVALUE
|
|
1023
|
+
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1186
1024
|
{
|
|
1187
|
-
|
|
1025
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(klass);
|
|
1026
|
+
Real *pv = VpAlloc(str, strict_p, raise_exception);
|
|
1027
|
+
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1028
|
+
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
|
|
1188
1029
|
}
|
|
1189
1030
|
|
|
1190
1031
|
static Real *
|
|
@@ -1192,7 +1033,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1192
1033
|
{
|
|
1193
1034
|
assert(x != NULL);
|
|
1194
1035
|
|
|
1195
|
-
pv =
|
|
1036
|
+
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1196
1037
|
pv->MaxPrec = x->MaxPrec;
|
|
1197
1038
|
pv->Prec = x->Prec;
|
|
1198
1039
|
pv->exponent = x->exponent;
|
|
@@ -1207,7 +1048,7 @@ VpCopy(Real *pv, Real const* const x)
|
|
|
1207
1048
|
static VALUE
|
|
1208
1049
|
BigDecimal_IsNaN(VALUE self)
|
|
1209
1050
|
{
|
|
1210
|
-
Real *p =
|
|
1051
|
+
Real *p = GetSelfVpValue(self);
|
|
1211
1052
|
if (VpIsNaN(p)) return Qtrue;
|
|
1212
1053
|
return Qfalse;
|
|
1213
1054
|
}
|
|
@@ -1218,7 +1059,7 @@ BigDecimal_IsNaN(VALUE self)
|
|
|
1218
1059
|
static VALUE
|
|
1219
1060
|
BigDecimal_IsInfinite(VALUE self)
|
|
1220
1061
|
{
|
|
1221
|
-
Real *p =
|
|
1062
|
+
Real *p = GetSelfVpValue(self);
|
|
1222
1063
|
if (VpIsPosInf(p)) return INT2FIX(1);
|
|
1223
1064
|
if (VpIsNegInf(p)) return INT2FIX(-1);
|
|
1224
1065
|
return Qnil;
|
|
@@ -1228,7 +1069,7 @@ BigDecimal_IsInfinite(VALUE self)
|
|
|
1228
1069
|
static VALUE
|
|
1229
1070
|
BigDecimal_IsFinite(VALUE self)
|
|
1230
1071
|
{
|
|
1231
|
-
Real *p =
|
|
1072
|
+
Real *p = GetSelfVpValue(self);
|
|
1232
1073
|
if (VpIsNaN(p)) return Qfalse;
|
|
1233
1074
|
if (VpIsInf(p)) return Qfalse;
|
|
1234
1075
|
return Qtrue;
|
|
@@ -1240,6 +1081,7 @@ BigDecimal_check_num(Real *p)
|
|
|
1240
1081
|
VpCheckException(p, true);
|
|
1241
1082
|
}
|
|
1242
1083
|
|
|
1084
|
+
static VALUE BigDecimal_fix(VALUE self);
|
|
1243
1085
|
static VALUE BigDecimal_split(VALUE self);
|
|
1244
1086
|
|
|
1245
1087
|
/* Returns the value as an Integer.
|
|
@@ -1249,44 +1091,36 @@ static VALUE BigDecimal_split(VALUE self);
|
|
|
1249
1091
|
static VALUE
|
|
1250
1092
|
BigDecimal_to_i(VALUE self)
|
|
1251
1093
|
{
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
Real *p;
|
|
1094
|
+
BDVALUE v;
|
|
1095
|
+
VALUE ret;
|
|
1255
1096
|
|
|
1256
|
-
|
|
1257
|
-
BigDecimal_check_num(
|
|
1097
|
+
v = GetBDValueMust(self);
|
|
1098
|
+
BigDecimal_check_num(v.real);
|
|
1258
1099
|
|
|
1259
|
-
|
|
1260
|
-
if (
|
|
1261
|
-
|
|
1262
|
-
if (e <= nf) {
|
|
1263
|
-
return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
|
|
1100
|
+
if (v.real->exponent <= 0) return INT2FIX(0);
|
|
1101
|
+
if (v.real->exponent == 1) {
|
|
1102
|
+
ret = LONG2NUM((long)(VpGetSign(v.real) * (DECDIG_DBL_SIGNED)v.real->frac[0]));
|
|
1264
1103
|
}
|
|
1265
1104
|
else {
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
ret = rb_funcall(numerator, '*', 1,
|
|
1282
|
-
rb_funcall(INT2FIX(10), rb_intern("**"), 1,
|
|
1283
|
-
INT2FIX(dpower)));
|
|
1284
|
-
}
|
|
1285
|
-
if (RB_TYPE_P(ret, T_FLOAT)) {
|
|
1286
|
-
rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1287
|
-
}
|
|
1288
|
-
return ret;
|
|
1105
|
+
VALUE fix = (ssize_t)v.real->Prec > v.real->exponent ? BigDecimal_fix(self) : self;
|
|
1106
|
+
VALUE digits = RARRAY_AREF(BigDecimal_split(fix), 1);
|
|
1107
|
+
ssize_t dpower = VpExponent10(v.real) - (ssize_t)RSTRING_LEN(digits);
|
|
1108
|
+
ret = rb_funcall(digits, rb_intern("to_i"), 0);
|
|
1109
|
+
|
|
1110
|
+
if (BIGDECIMAL_NEGATIVE_P(v.real)) {
|
|
1111
|
+
ret = rb_funcall(ret, '*', 1, INT2FIX(-1));
|
|
1112
|
+
}
|
|
1113
|
+
if (dpower) {
|
|
1114
|
+
VALUE pow10 = rb_funcall(INT2FIX(10), rb_intern("**"), 1, SSIZET2NUM(dpower));
|
|
1115
|
+
// In Ruby < 3.4, int**int may return Float::INFINITY
|
|
1116
|
+
if (RB_TYPE_P(pow10, T_FLOAT)) rb_raise(rb_eFloatDomainError, "Infinity");
|
|
1117
|
+
|
|
1118
|
+
ret = rb_funcall(ret, '*', 1, pow10);
|
|
1119
|
+
}
|
|
1289
1120
|
}
|
|
1121
|
+
|
|
1122
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1123
|
+
return ret;
|
|
1290
1124
|
}
|
|
1291
1125
|
|
|
1292
1126
|
/* Returns a new Float object having approximately the same value as the
|
|
@@ -1296,24 +1130,26 @@ BigDecimal_to_i(VALUE self)
|
|
|
1296
1130
|
static VALUE
|
|
1297
1131
|
BigDecimal_to_f(VALUE self)
|
|
1298
1132
|
{
|
|
1299
|
-
ENTER(1);
|
|
1300
|
-
Real *p;
|
|
1301
1133
|
double d;
|
|
1302
1134
|
SIGNED_VALUE e;
|
|
1303
1135
|
char *buf;
|
|
1304
1136
|
volatile VALUE str;
|
|
1137
|
+
BDVALUE v = GetBDValueMust(self);
|
|
1138
|
+
bool negative = BIGDECIMAL_NEGATIVE_P(v.real);
|
|
1305
1139
|
|
|
1306
|
-
|
|
1307
|
-
if (VpVtoD(&d, &e, p) != 1)
|
|
1140
|
+
if (VpVtoD(&d, &e, v.real) != 1)
|
|
1308
1141
|
return rb_float_new(d);
|
|
1309
1142
|
if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
|
|
1310
1143
|
goto overflow;
|
|
1311
|
-
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-
|
|
1144
|
+
if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-DBL_DIG))
|
|
1312
1145
|
goto underflow;
|
|
1313
1146
|
|
|
1314
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
1147
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
1315
1148
|
buf = RSTRING_PTR(str);
|
|
1316
|
-
VpToString(
|
|
1149
|
+
VpToString(v.real, buf, RSTRING_LEN(str), 0, 0);
|
|
1150
|
+
|
|
1151
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1152
|
+
|
|
1317
1153
|
errno = 0;
|
|
1318
1154
|
d = strtod(buf, 0);
|
|
1319
1155
|
if (errno == ERANGE) {
|
|
@@ -1324,14 +1160,14 @@ BigDecimal_to_f(VALUE self)
|
|
|
1324
1160
|
|
|
1325
1161
|
overflow:
|
|
1326
1162
|
VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
|
|
1327
|
-
if (
|
|
1163
|
+
if (negative)
|
|
1328
1164
|
return rb_float_new(VpGetDoubleNegInf());
|
|
1329
1165
|
else
|
|
1330
1166
|
return rb_float_new(VpGetDoublePosInf());
|
|
1331
1167
|
|
|
1332
1168
|
underflow:
|
|
1333
1169
|
VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
|
|
1334
|
-
if (
|
|
1170
|
+
if (negative)
|
|
1335
1171
|
return rb_float_new(-0.0);
|
|
1336
1172
|
else
|
|
1337
1173
|
return rb_float_new(0.0);
|
|
@@ -1343,15 +1179,16 @@ underflow:
|
|
|
1343
1179
|
static VALUE
|
|
1344
1180
|
BigDecimal_to_r(VALUE self)
|
|
1345
1181
|
{
|
|
1346
|
-
|
|
1182
|
+
BDVALUE v;
|
|
1347
1183
|
ssize_t sign, power, denomi_power;
|
|
1348
1184
|
VALUE a, digits, numerator;
|
|
1349
1185
|
|
|
1350
|
-
|
|
1351
|
-
BigDecimal_check_num(
|
|
1186
|
+
v = GetBDValueMust(self);
|
|
1187
|
+
BigDecimal_check_num(v.real);
|
|
1188
|
+
sign = VpGetSign(v.real);
|
|
1189
|
+
power = VpExponent10(v.real);
|
|
1190
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
1352
1191
|
|
|
1353
|
-
sign = VpGetSign(p);
|
|
1354
|
-
power = VpExponent10(p);
|
|
1355
1192
|
a = BigDecimal_split(self);
|
|
1356
1193
|
digits = RARRAY_AREF(a, 1);
|
|
1357
1194
|
denomi_power = power - RSTRING_LEN(digits);
|
|
@@ -1372,6 +1209,14 @@ BigDecimal_to_r(VALUE self)
|
|
|
1372
1209
|
}
|
|
1373
1210
|
}
|
|
1374
1211
|
|
|
1212
|
+
static size_t
|
|
1213
|
+
GetCoercePrec(Real *a, size_t prec)
|
|
1214
|
+
{
|
|
1215
|
+
if (prec == 0) prec = a->Prec * BASE_FIG;
|
|
1216
|
+
if (prec < 2 * BIGDECIMAL_DOUBLE_FIGURES) prec = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1217
|
+
return prec;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1375
1220
|
/* The coerce method provides support for Ruby type coercion. It is not
|
|
1376
1221
|
* enabled by default.
|
|
1377
1222
|
*
|
|
@@ -1389,26 +1234,9 @@ BigDecimal_to_r(VALUE self)
|
|
|
1389
1234
|
static VALUE
|
|
1390
1235
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1391
1236
|
{
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (RB_TYPE_P(other, T_FLOAT)) {
|
|
1397
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
|
|
1398
|
-
obj = rb_assoc_new(VpCheckGetValue(b), self);
|
|
1399
|
-
}
|
|
1400
|
-
else {
|
|
1401
|
-
if (RB_TYPE_P(other, T_RATIONAL)) {
|
|
1402
|
-
Real* pv = DATA_PTR(self);
|
|
1403
|
-
GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
|
|
1404
|
-
}
|
|
1405
|
-
else {
|
|
1406
|
-
GUARD_OBJ(b, GetVpValue(other, 1));
|
|
1407
|
-
}
|
|
1408
|
-
obj = rb_assoc_new(b->obj, self);
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
return obj;
|
|
1237
|
+
Real* pv = DATA_PTR(self);
|
|
1238
|
+
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1239
|
+
return rb_assoc_new(CheckGetValue(b), self);
|
|
1412
1240
|
}
|
|
1413
1241
|
|
|
1414
1242
|
/*
|
|
@@ -1428,6 +1256,15 @@ BigDecimal_uplus(VALUE self)
|
|
|
1428
1256
|
return self;
|
|
1429
1257
|
}
|
|
1430
1258
|
|
|
1259
|
+
static bool
|
|
1260
|
+
is_coerceable_to_BigDecimal(VALUE r)
|
|
1261
|
+
{
|
|
1262
|
+
return is_kind_of_BigDecimal(r) ||
|
|
1263
|
+
RB_INTEGER_TYPE_P(r) ||
|
|
1264
|
+
RB_TYPE_P(r, T_FLOAT) ||
|
|
1265
|
+
RB_TYPE_P(r, T_RATIONAL);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1431
1268
|
/*
|
|
1432
1269
|
* call-seq:
|
|
1433
1270
|
* self + value -> bigdecimal
|
|
@@ -1447,45 +1284,44 @@ BigDecimal_uplus(VALUE self)
|
|
|
1447
1284
|
static VALUE
|
|
1448
1285
|
BigDecimal_add(VALUE self, VALUE r)
|
|
1449
1286
|
{
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1287
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '+');
|
|
1288
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, +1);
|
|
1289
|
+
}
|
|
1453
1290
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1460
|
-
}
|
|
1461
|
-
else {
|
|
1462
|
-
b = GetVpValue(r, 0);
|
|
1463
|
-
}
|
|
1291
|
+
static VALUE
|
|
1292
|
+
BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
1293
|
+
{
|
|
1294
|
+
BDVALUE a, b, c;
|
|
1295
|
+
size_t mx;
|
|
1464
1296
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1297
|
+
a = GetBDValueMust(self);
|
|
1298
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1467
1299
|
|
|
1468
|
-
if (VpIsNaN(
|
|
1469
|
-
if (VpIsNaN(
|
|
1300
|
+
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1301
|
+
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1470
1302
|
|
|
1471
|
-
mx = GetAddSubPrec(a, b);
|
|
1303
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1472
1304
|
if (mx == (size_t)-1L) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1305
|
+
/* a or b is inf */
|
|
1306
|
+
c = NewZeroWrap(1, BASE_FIG);
|
|
1307
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1475
1308
|
}
|
|
1476
1309
|
else {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1310
|
+
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1311
|
+
size_t pl = VpGetPrecLimit();
|
|
1312
|
+
if (prec) VpSetPrecLimit(prec);
|
|
1313
|
+
// Let VpAddSub round the result
|
|
1314
|
+
VpAddSub(c.real, a.real, b.real, operation);
|
|
1315
|
+
if (prec) VpSetPrecLimit(pl);
|
|
1484
1316
|
}
|
|
1485
|
-
|
|
1317
|
+
|
|
1318
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1319
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1320
|
+
return CheckGetValue(c);
|
|
1486
1321
|
}
|
|
1487
1322
|
|
|
1488
|
-
/*
|
|
1323
|
+
/*
|
|
1324
|
+
* call-seq:
|
|
1489
1325
|
* self - value -> bigdecimal
|
|
1490
1326
|
*
|
|
1491
1327
|
* Returns the \BigDecimal difference of +self+ and +value+:
|
|
@@ -1502,73 +1338,18 @@ BigDecimal_add(VALUE self, VALUE r)
|
|
|
1502
1338
|
static VALUE
|
|
1503
1339
|
BigDecimal_sub(VALUE self, VALUE r)
|
|
1504
1340
|
{
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
size_t mx;
|
|
1508
|
-
|
|
1509
|
-
GUARD_OBJ(a, GetVpValue(self,1));
|
|
1510
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1511
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1512
|
-
}
|
|
1513
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1514
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1515
|
-
}
|
|
1516
|
-
else {
|
|
1517
|
-
b = GetVpValue(r,0);
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
if (!b) return DoSomeOne(self,r,'-');
|
|
1521
|
-
SAVE(b);
|
|
1522
|
-
|
|
1523
|
-
if (VpIsNaN(b)) return b->obj;
|
|
1524
|
-
if (VpIsNaN(a)) return a->obj;
|
|
1525
|
-
|
|
1526
|
-
mx = GetAddSubPrec(a,b);
|
|
1527
|
-
if (mx == (size_t)-1L) {
|
|
1528
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
|
|
1529
|
-
VpAddSub(c, a, b, -1);
|
|
1530
|
-
}
|
|
1531
|
-
else {
|
|
1532
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
|
|
1533
|
-
if (!mx) {
|
|
1534
|
-
VpSetInf(c,VpGetSign(a));
|
|
1535
|
-
}
|
|
1536
|
-
else {
|
|
1537
|
-
VpAddSub(c, a, b, -1);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
return VpCheckGetValue(c);
|
|
1341
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '-');
|
|
1342
|
+
return BigDecimal_addsub_with_coerce(self, r, 0, -1);
|
|
1541
1343
|
}
|
|
1542
1344
|
|
|
1543
1345
|
static VALUE
|
|
1544
1346
|
BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
1545
1347
|
{
|
|
1546
|
-
ENTER(5);
|
|
1547
1348
|
SIGNED_VALUE e;
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
switch (TYPE(r)) {
|
|
1551
|
-
case T_DATA:
|
|
1552
|
-
if (!is_kind_of_BigDecimal(r)) break;
|
|
1553
|
-
/* fall through */
|
|
1554
|
-
case T_FIXNUM:
|
|
1555
|
-
/* fall through */
|
|
1556
|
-
case T_BIGNUM:
|
|
1557
|
-
GUARD_OBJ(b, GetVpValue(r, 0));
|
|
1558
|
-
break;
|
|
1559
|
-
|
|
1560
|
-
case T_FLOAT:
|
|
1561
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
|
|
1562
|
-
break;
|
|
1563
|
-
|
|
1564
|
-
case T_RATIONAL:
|
|
1565
|
-
GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
|
|
1566
|
-
break;
|
|
1349
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1350
|
+
NULLABLE_BDVALUE b = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1567
1351
|
|
|
1568
|
-
|
|
1569
|
-
break;
|
|
1570
|
-
}
|
|
1571
|
-
if (b == NULL) {
|
|
1352
|
+
if (b.real_or_null == NULL) {
|
|
1572
1353
|
ID f = 0;
|
|
1573
1354
|
|
|
1574
1355
|
switch (op) {
|
|
@@ -1597,8 +1378,11 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1597
1378
|
}
|
|
1598
1379
|
return rb_num_coerce_relop(self, r, f);
|
|
1599
1380
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1381
|
+
e = VpComp(a.real, b.real_or_null);
|
|
1382
|
+
|
|
1383
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1384
|
+
RB_GC_GUARD(b.bigdecimal_or_nil);
|
|
1385
|
+
|
|
1602
1386
|
if (e == 999)
|
|
1603
1387
|
return (op == '*') ? Qnil : Qfalse;
|
|
1604
1388
|
switch (op) {
|
|
@@ -1638,7 +1422,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
|
|
|
1638
1422
|
static VALUE
|
|
1639
1423
|
BigDecimal_zero(VALUE self)
|
|
1640
1424
|
{
|
|
1641
|
-
Real *a =
|
|
1425
|
+
Real *a = GetSelfVpValue(self);
|
|
1642
1426
|
return VpIsZero(a) ? Qtrue : Qfalse;
|
|
1643
1427
|
}
|
|
1644
1428
|
|
|
@@ -1646,7 +1430,7 @@ BigDecimal_zero(VALUE self)
|
|
|
1646
1430
|
static VALUE
|
|
1647
1431
|
BigDecimal_nonzero(VALUE self)
|
|
1648
1432
|
{
|
|
1649
|
-
Real *a =
|
|
1433
|
+
Real *a = GetSelfVpValue(self);
|
|
1650
1434
|
return VpIsZero(a) ? Qnil : self;
|
|
1651
1435
|
}
|
|
1652
1436
|
|
|
@@ -1772,12 +1556,11 @@ BigDecimal_ge(VALUE self, VALUE r)
|
|
|
1772
1556
|
static VALUE
|
|
1773
1557
|
BigDecimal_neg(VALUE self)
|
|
1774
1558
|
{
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
return VpCheckGetValue(c);
|
|
1559
|
+
BDVALUE a = GetBDValueMust(self);
|
|
1560
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
1561
|
+
VpAsgn(c.real, a.real, -10);
|
|
1562
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1563
|
+
return CheckGetValue(c);
|
|
1781
1564
|
}
|
|
1782
1565
|
|
|
1783
1566
|
/*
|
|
@@ -1790,84 +1573,36 @@ BigDecimal_neg(VALUE self)
|
|
|
1790
1573
|
*
|
|
1791
1574
|
* See BigDecimal#mult.
|
|
1792
1575
|
*/
|
|
1793
|
-
|
|
1794
1576
|
static VALUE
|
|
1795
1577
|
BigDecimal_mult(VALUE self, VALUE r)
|
|
1796
1578
|
{
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
size_t mx;
|
|
1800
|
-
|
|
1801
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
1802
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1803
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
1804
|
-
}
|
|
1805
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1806
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
1807
|
-
}
|
|
1808
|
-
else {
|
|
1809
|
-
b = GetVpValue(r,0);
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
if (!b) return DoSomeOne(self, r, '*');
|
|
1813
|
-
SAVE(b);
|
|
1814
|
-
|
|
1815
|
-
mx = a->Prec + b->Prec;
|
|
1816
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
|
|
1817
|
-
VpMult(c, a, b);
|
|
1818
|
-
return VpCheckGetValue(c);
|
|
1579
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '*');
|
|
1580
|
+
return BigDecimal_mult_with_coerce(self, r, 0);
|
|
1819
1581
|
}
|
|
1820
1582
|
|
|
1821
1583
|
static VALUE
|
|
1822
|
-
|
|
1823
|
-
/* For c = self.div(r): with round operation */
|
|
1584
|
+
BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec)
|
|
1824
1585
|
{
|
|
1825
|
-
|
|
1826
|
-
Real *a, *b;
|
|
1827
|
-
ssize_t a_prec, b_prec;
|
|
1828
|
-
size_t mx;
|
|
1586
|
+
BDVALUE a, b, c;
|
|
1829
1587
|
|
|
1830
|
-
|
|
1831
|
-
|
|
1588
|
+
a = GetBDValueMust(self);
|
|
1589
|
+
b = GetBDValueWithPrecMust(r, GetCoercePrec(a.real, prec));
|
|
1832
1590
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1591
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
1592
|
+
VpMult(c.real, a.real, b.real);
|
|
1593
|
+
if (prec) {
|
|
1594
|
+
VpLeftRound(c.real, VpGetRoundMode(), prec);
|
|
1836
1595
|
}
|
|
1837
|
-
else
|
|
1838
|
-
|
|
1839
|
-
}
|
|
1840
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1841
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1842
|
-
}
|
|
1843
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1844
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
|
-
if (!is_kind_of_BigDecimal(rr)) {
|
|
1848
|
-
return DoSomeOne(self, r, '/');
|
|
1596
|
+
else {
|
|
1597
|
+
VpLimitRound(c.real, 0);
|
|
1849
1598
|
}
|
|
1850
1599
|
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
|
|
1856
|
-
BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
|
|
1857
|
-
mx = (a_prec > b_prec) ? a_prec : b_prec;
|
|
1858
|
-
mx *= 2;
|
|
1859
|
-
|
|
1860
|
-
if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
|
|
1861
|
-
mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
|
|
1862
|
-
|
|
1863
|
-
GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
|
|
1864
|
-
GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
|
|
1865
|
-
VpDivd(*c, *res, a, b);
|
|
1866
|
-
|
|
1867
|
-
return Qnil;
|
|
1600
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1601
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1602
|
+
return CheckGetValue(c);
|
|
1868
1603
|
}
|
|
1869
1604
|
|
|
1870
|
-
static
|
|
1605
|
+
static bool BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate);
|
|
1871
1606
|
|
|
1872
1607
|
/* call-seq:
|
|
1873
1608
|
* a / b -> bigdecimal
|
|
@@ -1884,20 +1619,8 @@ static VALUE
|
|
|
1884
1619
|
BigDecimal_div(VALUE self, VALUE r)
|
|
1885
1620
|
/* For c = self/r: with round operation */
|
|
1886
1621
|
{
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
r = BigDecimal_divide(self, r, &c, &res, &div);
|
|
1890
|
-
if (!NIL_P(r)) return r; /* coerced by other */
|
|
1891
|
-
SAVE(c); SAVE(res); SAVE(div);
|
|
1892
|
-
/* a/b = c + r/b */
|
|
1893
|
-
/* c xxxxx
|
|
1894
|
-
r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
|
|
1895
|
-
*/
|
|
1896
|
-
/* Round */
|
|
1897
|
-
if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
|
|
1898
|
-
VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
|
|
1899
|
-
}
|
|
1900
|
-
return VpCheckGetValue(c);
|
|
1622
|
+
if (!is_coerceable_to_BigDecimal(r)) return DoSomeOne(self, r, '/');
|
|
1623
|
+
return BigDecimal_div2(self, r, INT2FIX(0));
|
|
1901
1624
|
}
|
|
1902
1625
|
|
|
1903
1626
|
static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
|
|
@@ -1942,119 +1665,115 @@ BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
|
|
1942
1665
|
/*
|
|
1943
1666
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
|
1944
1667
|
* div = (a.to_f/b).floor
|
|
1668
|
+
* In truncate mode, use truncate instead of floor.
|
|
1945
1669
|
*/
|
|
1946
|
-
static
|
|
1947
|
-
BigDecimal_DoDivmod(VALUE self, VALUE r,
|
|
1670
|
+
static bool
|
|
1671
|
+
BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE *mod, bool truncate)
|
|
1948
1672
|
{
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
size_t mx;
|
|
1673
|
+
BDVALUE a, b, dv, md, res;
|
|
1674
|
+
NULLABLE_BDVALUE b2;
|
|
1675
|
+
ssize_t a_exponent, b_exponent;
|
|
1676
|
+
size_t mx, rx, pl;
|
|
1954
1677
|
|
|
1955
|
-
|
|
1956
|
-
SAVE(a);
|
|
1678
|
+
a = GetBDValueMust(self);
|
|
1957
1679
|
|
|
1958
|
-
|
|
1959
|
-
if (
|
|
1960
|
-
|
|
1961
|
-
}
|
|
1962
|
-
else if (RB_INTEGER_TYPE_P(r)) {
|
|
1963
|
-
rr = rb_inum_convert_to_BigDecimal(r, 0, true);
|
|
1964
|
-
}
|
|
1965
|
-
else if (RB_TYPE_P(r, T_FLOAT)) {
|
|
1966
|
-
rr = rb_float_convert_to_BigDecimal(r, 0, true);
|
|
1967
|
-
}
|
|
1968
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
1969
|
-
rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
|
|
1970
|
-
}
|
|
1680
|
+
b2 = GetBDValueWithPrec(r, GetCoercePrec(a.real, 0));
|
|
1681
|
+
if (!b2.real_or_null) return false;
|
|
1682
|
+
b = bdvalue_nonnullable(b2);
|
|
1971
1683
|
|
|
1972
|
-
if (
|
|
1973
|
-
|
|
1684
|
+
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1685
|
+
VALUE nan = BigDecimal_nan();
|
|
1686
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1687
|
+
goto Done;
|
|
1974
1688
|
}
|
|
1975
|
-
|
|
1976
|
-
TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
|
|
1977
|
-
SAVE(b);
|
|
1978
|
-
|
|
1979
|
-
if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
|
|
1980
|
-
if (VpIsInf(a) && VpIsInf(b)) goto NaN;
|
|
1981
|
-
if (VpIsZero(b)) {
|
|
1689
|
+
if (VpIsZero(b.real)) {
|
|
1982
1690
|
rb_raise(rb_eZeroDivError, "divided by 0");
|
|
1983
1691
|
}
|
|
1984
|
-
if (VpIsInf(a)) {
|
|
1985
|
-
if (VpGetSign(a) == VpGetSign(b)) {
|
|
1692
|
+
if (VpIsInf(a.real)) {
|
|
1693
|
+
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1986
1694
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1987
|
-
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1988
1696
|
}
|
|
1989
1697
|
else {
|
|
1990
1698
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1991
|
-
|
|
1699
|
+
*div = (NULLABLE_BDVALUE) { inf, DATA_PTR(inf) };
|
|
1992
1700
|
}
|
|
1993
1701
|
VALUE nan = BigDecimal_nan();
|
|
1994
|
-
|
|
1995
|
-
|
|
1702
|
+
*mod = (NULLABLE_BDVALUE) { nan, DATA_PTR(nan) };
|
|
1703
|
+
goto Done;
|
|
1996
1704
|
}
|
|
1997
|
-
if (
|
|
1705
|
+
if (VpIsZero(a.real)) {
|
|
1998
1706
|
VALUE zero = BigDecimal_positive_zero();
|
|
1999
|
-
|
|
2000
|
-
*mod = a;
|
|
2001
|
-
|
|
2002
|
-
}
|
|
2003
|
-
if (
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
1707
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1708
|
+
*mod = bdvalue_nullable(a);
|
|
1709
|
+
goto Done;
|
|
1710
|
+
}
|
|
1711
|
+
if (VpIsInf(b.real)) {
|
|
1712
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
|
1713
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
|
1714
|
+
VpSetOne(minus_one.real);
|
|
1715
|
+
VpSetSign(minus_one.real, -1);
|
|
1716
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
|
1717
|
+
*div = bdvalue_nullable(minus_one);
|
|
1718
|
+
*mod = bdvalue_nullable(b);
|
|
1719
|
+
} else {
|
|
1720
|
+
VALUE zero = BigDecimal_positive_zero();
|
|
1721
|
+
*div = (NULLABLE_BDVALUE) { zero, DATA_PTR(zero) };
|
|
1722
|
+
*mod = bdvalue_nullable(a);
|
|
1723
|
+
}
|
|
1724
|
+
goto Done;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
a_exponent = VpExponent10(a.real);
|
|
1728
|
+
b_exponent = VpExponent10(b.real);
|
|
1729
|
+
mx = a_exponent > b_exponent ? a_exponent - b_exponent + 1 : 1;
|
|
1730
|
+
dv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(mx));
|
|
1731
|
+
|
|
1732
|
+
/* res is reused for VpDivd remainder and VpMult result */
|
|
1733
|
+
rx = VPDIVD_REM_PREC(a.real, b.real, dv.real);
|
|
1734
|
+
mx = VPMULT_RESULT_PREC(dv.real, b.real);
|
|
1735
|
+
res = NewZeroWrap(1, Max(rx, mx) * BASE_FIG);
|
|
1736
|
+
/* AddSub needs one more prec */
|
|
1737
|
+
md = NewZeroWrap(1, (res.real->MaxPrec + 1) * BASE_FIG);
|
|
1738
|
+
|
|
1739
|
+
VpDivd(dv.real, res.real, a.real, b.real);
|
|
1740
|
+
VpMidRound(dv.real, VP_ROUND_DOWN, 0);
|
|
1741
|
+
VpMult(res.real, dv.real, b.real);
|
|
1742
|
+
pl = VpGetPrecLimit();
|
|
1743
|
+
VpSetPrecLimit(0);
|
|
1744
|
+
VpAddSub(md.real, a.real, res.real, -1);
|
|
1745
|
+
VpSetPrecLimit(pl);
|
|
2029
1746
|
|
|
2030
|
-
if (!VpIsZero(
|
|
1747
|
+
if (!truncate && !VpIsZero(md.real) && (VpGetSign(a.real) * VpGetSign(b.real) < 0)) {
|
|
2031
1748
|
/* result adjustment for negative case */
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
VpAddSub(
|
|
2037
|
-
|
|
2038
|
-
*
|
|
1749
|
+
BDVALUE dv2 = NewZeroWrap(1, (dv.real->MaxPrec + 1) * BASE_FIG);
|
|
1750
|
+
BDVALUE md2 = NewZeroWrap(1, (GetAddSubPrec(md.real, b.real) + 1) * BASE_FIG);
|
|
1751
|
+
VpSetPrecLimit(0);
|
|
1752
|
+
VpAddSub(dv2.real, dv.real, VpOne(), -1);
|
|
1753
|
+
VpAddSub(md2.real, md.real, b.real, 1);
|
|
1754
|
+
VpSetPrecLimit(pl);
|
|
1755
|
+
*div = bdvalue_nullable(dv2);
|
|
1756
|
+
*mod = bdvalue_nullable(md2);
|
|
1757
|
+
RB_GC_GUARD(dv2.bigdecimal);
|
|
1758
|
+
RB_GC_GUARD(md2.bigdecimal);
|
|
2039
1759
|
}
|
|
2040
1760
|
else {
|
|
2041
|
-
*div =
|
|
2042
|
-
*mod =
|
|
1761
|
+
*div = bdvalue_nullable(dv);
|
|
1762
|
+
*mod = bdvalue_nullable(md);
|
|
2043
1763
|
}
|
|
2044
|
-
return Qtrue;
|
|
2045
1764
|
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
return
|
|
1765
|
+
Done:
|
|
1766
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
1767
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
1768
|
+
RB_GC_GUARD(dv.bigdecimal);
|
|
1769
|
+
RB_GC_GUARD(md.bigdecimal);
|
|
1770
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1771
|
+
return true;
|
|
2053
1772
|
}
|
|
2054
1773
|
|
|
2055
1774
|
/* call-seq:
|
|
2056
|
-
*
|
|
2057
|
-
*
|
|
1775
|
+
* a % b
|
|
1776
|
+
* a.modulo(b)
|
|
2058
1777
|
*
|
|
2059
1778
|
* Returns the modulus from dividing by b.
|
|
2060
1779
|
*
|
|
@@ -2063,71 +1782,16 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
|
|
|
2063
1782
|
static VALUE
|
|
2064
1783
|
BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
|
|
2065
1784
|
{
|
|
2066
|
-
|
|
2067
|
-
Real *div = NULL, *mod = NULL;
|
|
1785
|
+
NULLABLE_BDVALUE div, mod;
|
|
2068
1786
|
|
|
2069
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2070
|
-
|
|
2071
|
-
return VpCheckGetValue(mod);
|
|
1787
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1788
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
2072
1789
|
}
|
|
2073
1790
|
return DoSomeOne(self, r, '%');
|
|
2074
1791
|
}
|
|
2075
1792
|
|
|
2076
|
-
static VALUE
|
|
2077
|
-
BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
2078
|
-
{
|
|
2079
|
-
ENTER(10);
|
|
2080
|
-
size_t mx;
|
|
2081
|
-
Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
|
|
2082
|
-
Real *f = NULL;
|
|
2083
|
-
|
|
2084
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2085
|
-
if (RB_TYPE_P(r, T_FLOAT)) {
|
|
2086
|
-
b = GetVpValueWithPrec(r, 0, 1);
|
|
2087
|
-
}
|
|
2088
|
-
else if (RB_TYPE_P(r, T_RATIONAL)) {
|
|
2089
|
-
b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
|
|
2090
|
-
}
|
|
2091
|
-
else {
|
|
2092
|
-
b = GetVpValue(r, 0);
|
|
2093
|
-
}
|
|
2094
|
-
|
|
2095
|
-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2096
|
-
SAVE(b);
|
|
2097
|
-
|
|
2098
|
-
if (VpIsPosInf(b) || VpIsNegInf(b)) {
|
|
2099
|
-
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
|
|
2100
|
-
VpSetZero(*dv, 1);
|
|
2101
|
-
*rv = a;
|
|
2102
|
-
return Qnil;
|
|
2103
|
-
}
|
|
2104
|
-
|
|
2105
|
-
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
|
|
2106
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2107
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2108
|
-
GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2109
|
-
GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
|
|
2110
|
-
|
|
2111
|
-
VpDivd(c, res, a, b);
|
|
2112
|
-
|
|
2113
|
-
mx = c->Prec *(VpBaseFig() + 1);
|
|
2114
|
-
|
|
2115
|
-
GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
|
|
2116
|
-
GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
|
|
2117
|
-
|
|
2118
|
-
VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2119
|
-
|
|
2120
|
-
VpFrac(f, c);
|
|
2121
|
-
VpMult(rr, f, b);
|
|
2122
|
-
VpAddSub(ff, res, rr, 1);
|
|
2123
|
-
|
|
2124
|
-
*dv = d;
|
|
2125
|
-
*rv = ff;
|
|
2126
|
-
return Qnil;
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
1793
|
/* call-seq:
|
|
2130
|
-
*
|
|
1794
|
+
* remainder(value)
|
|
2131
1795
|
*
|
|
2132
1796
|
* Returns the remainder from dividing by the value.
|
|
2133
1797
|
*
|
|
@@ -2136,15 +1800,16 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
|
|
|
2136
1800
|
static VALUE
|
|
2137
1801
|
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
2138
1802
|
{
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
1803
|
+
NULLABLE_BDVALUE div, mod = { Qnil, NULL };
|
|
1804
|
+
|
|
1805
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, true)) {
|
|
1806
|
+
return CheckGetValue(bdvalue_nonnullable(mod));
|
|
1807
|
+
}
|
|
1808
|
+
return DoSomeOne(self, r, rb_intern("remainder"));
|
|
2144
1809
|
}
|
|
2145
1810
|
|
|
2146
1811
|
/* call-seq:
|
|
2147
|
-
*
|
|
1812
|
+
* divmod(value)
|
|
2148
1813
|
*
|
|
2149
1814
|
* Divides by the specified value, and returns the quotient and modulus
|
|
2150
1815
|
* as BigDecimal numbers. The quotient is rounded towards negative infinity.
|
|
@@ -2168,12 +1833,10 @@ BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
|
|
|
2168
1833
|
static VALUE
|
|
2169
1834
|
BigDecimal_divmod(VALUE self, VALUE r)
|
|
2170
1835
|
{
|
|
2171
|
-
|
|
2172
|
-
Real *div = NULL, *mod = NULL;
|
|
1836
|
+
NULLABLE_BDVALUE div, mod;
|
|
2173
1837
|
|
|
2174
|
-
if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
|
|
2175
|
-
|
|
2176
|
-
return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
|
|
1838
|
+
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1839
|
+
return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
2177
1840
|
}
|
|
2178
1841
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
2179
1842
|
}
|
|
@@ -2185,47 +1848,54 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
2185
1848
|
static inline VALUE
|
|
2186
1849
|
BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|
2187
1850
|
{
|
|
2188
|
-
ENTER(5);
|
|
2189
1851
|
SIGNED_VALUE ix;
|
|
1852
|
+
BDVALUE av, bv, cv, res;
|
|
2190
1853
|
|
|
2191
1854
|
if (NIL_P(n)) { /* div in Float sense */
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
|
|
2195
|
-
return BigDecimal_to_i(
|
|
1855
|
+
NULLABLE_BDVALUE div;
|
|
1856
|
+
NULLABLE_BDVALUE mod;
|
|
1857
|
+
if (BigDecimal_DoDivmod(self, b, &div, &mod, false)) {
|
|
1858
|
+
return BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div)));
|
|
2196
1859
|
}
|
|
2197
1860
|
return DoSomeOne(self, b, rb_intern("div"));
|
|
2198
1861
|
}
|
|
2199
1862
|
|
|
2200
1863
|
/* div in BigDecimal sense */
|
|
2201
1864
|
ix = check_int_precision(n);
|
|
1865
|
+
|
|
1866
|
+
av = GetBDValueMust(self);
|
|
1867
|
+
bv = GetBDValueWithPrecMust(b, GetCoercePrec(av.real, ix));
|
|
1868
|
+
|
|
2202
1869
|
if (ix == 0) {
|
|
2203
|
-
|
|
1870
|
+
ssize_t a_prec, b_prec, limit = VpGetPrecLimit();
|
|
1871
|
+
VpCountPrecisionAndScale(av.real, &a_prec, NULL);
|
|
1872
|
+
VpCountPrecisionAndScale(bv.real, &b_prec, NULL);
|
|
1873
|
+
ix = ((a_prec > b_prec) ? a_prec : b_prec) + BIGDECIMAL_DOUBLE_FIGURES;
|
|
1874
|
+
if (2 * BIGDECIMAL_DOUBLE_FIGURES > ix)
|
|
1875
|
+
ix = 2 * BIGDECIMAL_DOUBLE_FIGURES;
|
|
1876
|
+
if (limit && limit < ix) ix = limit;
|
|
2204
1877
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2220
|
-
GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
|
|
2221
|
-
mx = av->Prec + bv->Prec + 2;
|
|
2222
|
-
if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
|
|
2223
|
-
GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
|
|
2224
|
-
VpDivd(cv, res, av, bv);
|
|
2225
|
-
VpSetPrecLimit(pl);
|
|
2226
|
-
VpLeftRound(cv, VpGetRoundMode(), ix);
|
|
2227
|
-
return VpCheckGetValue(cv);
|
|
1878
|
+
|
|
1879
|
+
// Needs to calculate 1 extra digit for rounding.
|
|
1880
|
+
cv = NewZeroWrap(1, VPDIVD_QUO_DIGITS(ix + 1));
|
|
1881
|
+
res = NewZeroWrap(1, VPDIVD_REM_PREC(av.real, bv.real, cv.real) * BASE_FIG);
|
|
1882
|
+
VpDivd(cv.real, res.real, av.real, bv.real);
|
|
1883
|
+
|
|
1884
|
+
if (!VpIsZero(res.real)) {
|
|
1885
|
+
// Remainder value affects rounding result.
|
|
1886
|
+
// ROUND_UP cv = 0.1e0 with idx=10 will be:
|
|
1887
|
+
// 0.1e0 if remainder == 0
|
|
1888
|
+
// 0.1000000001e0 if remainder != 0
|
|
1889
|
+
size_t idx = roomof(ix, BASE_FIG);
|
|
1890
|
+
while (cv.real->Prec <= idx) cv.real->frac[cv.real->Prec++] = 0;
|
|
1891
|
+
if (cv.real->frac[idx] == 0 || cv.real->frac[idx] == HALF_BASE) cv.real->frac[idx]++;
|
|
2228
1892
|
}
|
|
1893
|
+
VpLeftRound(cv.real, VpGetRoundMode(), ix);
|
|
1894
|
+
|
|
1895
|
+
RB_GC_GUARD(av.bigdecimal);
|
|
1896
|
+
RB_GC_GUARD(bv.bigdecimal);
|
|
1897
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1898
|
+
return CheckGetValue(cv);
|
|
2229
1899
|
}
|
|
2230
1900
|
|
|
2231
1901
|
/*
|
|
@@ -2301,22 +1971,11 @@ BigDecimal_div3(int argc, VALUE *argv, VALUE self)
|
|
|
2301
1971
|
static VALUE
|
|
2302
1972
|
BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
2303
1973
|
{
|
|
2304
|
-
|
|
2305
|
-
Real *cv;
|
|
2306
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2307
|
-
if (mx == 0) return BigDecimal_add(self, b);
|
|
2308
|
-
else {
|
|
2309
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2310
|
-
VALUE c = BigDecimal_add(self, b);
|
|
2311
|
-
VpSetPrecLimit(pl);
|
|
2312
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2313
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2314
|
-
return VpCheckGetValue(cv);
|
|
2315
|
-
}
|
|
1974
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), +1);
|
|
2316
1975
|
}
|
|
2317
1976
|
|
|
2318
1977
|
/* call-seq:
|
|
2319
|
-
*
|
|
1978
|
+
* sub(value, digits) -> bigdecimal
|
|
2320
1979
|
*
|
|
2321
1980
|
* Subtract the specified value.
|
|
2322
1981
|
*
|
|
@@ -2331,18 +1990,7 @@ BigDecimal_add2(VALUE self, VALUE b, VALUE n)
|
|
|
2331
1990
|
static VALUE
|
|
2332
1991
|
BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
2333
1992
|
{
|
|
2334
|
-
|
|
2335
|
-
Real *cv;
|
|
2336
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2337
|
-
if (mx == 0) return BigDecimal_sub(self, b);
|
|
2338
|
-
else {
|
|
2339
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2340
|
-
VALUE c = BigDecimal_sub(self, b);
|
|
2341
|
-
VpSetPrecLimit(pl);
|
|
2342
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2343
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2344
|
-
return VpCheckGetValue(cv);
|
|
2345
|
-
}
|
|
1993
|
+
return BigDecimal_addsub_with_coerce(self, b, check_int_precision(n), -1);
|
|
2346
1994
|
}
|
|
2347
1995
|
|
|
2348
1996
|
/*
|
|
@@ -2374,18 +2022,7 @@ BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
|
|
|
2374
2022
|
static VALUE
|
|
2375
2023
|
BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
2376
2024
|
{
|
|
2377
|
-
|
|
2378
|
-
Real *cv;
|
|
2379
|
-
SIGNED_VALUE mx = check_int_precision(n);
|
|
2380
|
-
if (mx == 0) return BigDecimal_mult(self, b);
|
|
2381
|
-
else {
|
|
2382
|
-
size_t pl = VpSetPrecLimit(0);
|
|
2383
|
-
VALUE c = BigDecimal_mult(self, b);
|
|
2384
|
-
VpSetPrecLimit(pl);
|
|
2385
|
-
GUARD_OBJ(cv, GetVpValue(c, 1));
|
|
2386
|
-
VpLeftRound(cv, VpGetRoundMode(), mx);
|
|
2387
|
-
return VpCheckGetValue(cv);
|
|
2388
|
-
}
|
|
2025
|
+
return BigDecimal_mult_with_coerce(self, b, check_int_precision(n));
|
|
2389
2026
|
}
|
|
2390
2027
|
|
|
2391
2028
|
/*
|
|
@@ -2402,41 +2039,12 @@ BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
|
|
|
2402
2039
|
static VALUE
|
|
2403
2040
|
BigDecimal_abs(VALUE self)
|
|
2404
2041
|
{
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2412
|
-
VpAsgn(c, a, 1);
|
|
2413
|
-
VpChangeSign(c, 1);
|
|
2414
|
-
return VpCheckGetValue(c);
|
|
2415
|
-
}
|
|
2416
|
-
|
|
2417
|
-
/* call-seq:
|
|
2418
|
-
* sqrt(n)
|
|
2419
|
-
*
|
|
2420
|
-
* Returns the square root of the value.
|
|
2421
|
-
*
|
|
2422
|
-
* Result has at least n significant digits.
|
|
2423
|
-
*/
|
|
2424
|
-
static VALUE
|
|
2425
|
-
BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
2426
|
-
{
|
|
2427
|
-
ENTER(5);
|
|
2428
|
-
Real *c, *a;
|
|
2429
|
-
size_t mx, n;
|
|
2430
|
-
|
|
2431
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2432
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2433
|
-
|
|
2434
|
-
n = check_int_precision(nFig);
|
|
2435
|
-
n += VpDblFig() + VpBaseFig();
|
|
2436
|
-
if (mx <= n) mx = n;
|
|
2437
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2438
|
-
VpSqrt(c, a);
|
|
2439
|
-
return VpCheckGetValue(c);
|
|
2042
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2043
|
+
BDVALUE c = NewZeroWrap(1, a.real->Prec * BASE_FIG);
|
|
2044
|
+
VpAsgn(c.real, a.real, 10);
|
|
2045
|
+
VpChangeSign(c.real, 1);
|
|
2046
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2047
|
+
return CheckGetValue(c);
|
|
2440
2048
|
}
|
|
2441
2049
|
|
|
2442
2050
|
/* Return the integer part of the number, as a BigDecimal.
|
|
@@ -2444,19 +2052,15 @@ BigDecimal_sqrt(VALUE self, VALUE nFig)
|
|
|
2444
2052
|
static VALUE
|
|
2445
2053
|
BigDecimal_fix(VALUE self)
|
|
2446
2054
|
{
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
mx = a->Prec *(VpBaseFig() + 1);
|
|
2453
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2454
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2455
|
-
return VpCheckGetValue(c);
|
|
2055
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2056
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2057
|
+
VpActiveRound(c.real, a.real, VP_ROUND_DOWN, 0); /* 0: round off */
|
|
2058
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2059
|
+
return CheckGetValue(c);
|
|
2456
2060
|
}
|
|
2457
2061
|
|
|
2458
2062
|
/* call-seq:
|
|
2459
|
-
*
|
|
2063
|
+
* round(n, mode)
|
|
2460
2064
|
*
|
|
2461
2065
|
* Round to the nearest integer (by default), returning the result as a
|
|
2462
2066
|
* BigDecimal if n is specified and positive, or as an Integer if it isn't.
|
|
@@ -2484,13 +2088,12 @@ BigDecimal_fix(VALUE self)
|
|
|
2484
2088
|
static VALUE
|
|
2485
2089
|
BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
2486
2090
|
{
|
|
2487
|
-
|
|
2488
|
-
Real *c, *a;
|
|
2091
|
+
BDVALUE c, a;
|
|
2489
2092
|
int iLoc = 0;
|
|
2490
2093
|
VALUE vLoc;
|
|
2491
2094
|
VALUE vRound;
|
|
2492
2095
|
int round_to_int = 0;
|
|
2493
|
-
size_t mx
|
|
2096
|
+
size_t mx;
|
|
2494
2097
|
|
|
2495
2098
|
unsigned short sw = VpGetRoundMode();
|
|
2496
2099
|
|
|
@@ -2521,20 +2124,50 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2521
2124
|
break;
|
|
2522
2125
|
}
|
|
2523
2126
|
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2127
|
+
a = GetBDValueMust(self);
|
|
2128
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2129
|
+
c = NewZeroWrap(1, mx);
|
|
2130
|
+
|
|
2131
|
+
VpActiveRound(c.real, a.real, sw, iLoc);
|
|
2132
|
+
|
|
2133
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2134
|
+
|
|
2530
2135
|
if (round_to_int) {
|
|
2531
|
-
return BigDecimal_to_i(
|
|
2136
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2532
2137
|
}
|
|
2533
|
-
return
|
|
2138
|
+
return CheckGetValue(c);
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
static VALUE
|
|
2142
|
+
BigDecimal_truncate_floor_ceil(int argc, VALUE *argv, VALUE self, unsigned short rounding_mode)
|
|
2143
|
+
{
|
|
2144
|
+
BDVALUE c, a;
|
|
2145
|
+
int iLoc;
|
|
2146
|
+
VALUE vLoc;
|
|
2147
|
+
size_t mx;
|
|
2148
|
+
|
|
2149
|
+
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2150
|
+
iLoc = 0;
|
|
2151
|
+
}
|
|
2152
|
+
else {
|
|
2153
|
+
iLoc = NUM2INT(vLoc);
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
a = GetBDValueMust(self);
|
|
2157
|
+
mx = (a.real->Prec + 1) * BASE_FIG;
|
|
2158
|
+
c = NewZeroWrap(1, mx);
|
|
2159
|
+
VpActiveRound(c.real, a.real, rounding_mode, iLoc);
|
|
2160
|
+
|
|
2161
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2162
|
+
|
|
2163
|
+
if (argc == 0) {
|
|
2164
|
+
return BigDecimal_to_i(CheckGetValue(c));
|
|
2165
|
+
}
|
|
2166
|
+
return CheckGetValue(c);
|
|
2534
2167
|
}
|
|
2535
2168
|
|
|
2536
2169
|
/* call-seq:
|
|
2537
|
-
*
|
|
2170
|
+
* truncate(n)
|
|
2538
2171
|
*
|
|
2539
2172
|
* Truncate to the nearest integer (by default), returning the result as a
|
|
2540
2173
|
* BigDecimal.
|
|
@@ -2555,28 +2188,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
|
|
|
2555
2188
|
static VALUE
|
|
2556
2189
|
BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
2557
2190
|
{
|
|
2558
|
-
|
|
2559
|
-
Real *c, *a;
|
|
2560
|
-
int iLoc;
|
|
2561
|
-
VALUE vLoc;
|
|
2562
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2563
|
-
|
|
2564
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2565
|
-
iLoc = 0;
|
|
2566
|
-
}
|
|
2567
|
-
else {
|
|
2568
|
-
iLoc = NUM2INT(vLoc);
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2572
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2573
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2574
|
-
VpSetPrecLimit(pl);
|
|
2575
|
-
VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
|
|
2576
|
-
if (argc == 0) {
|
|
2577
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2578
|
-
}
|
|
2579
|
-
return VpCheckGetValue(c);
|
|
2191
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_DOWN);
|
|
2580
2192
|
}
|
|
2581
2193
|
|
|
2582
2194
|
/* Return the fractional part of the number, as a BigDecimal.
|
|
@@ -2584,19 +2196,15 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
|
|
|
2584
2196
|
static VALUE
|
|
2585
2197
|
BigDecimal_frac(VALUE self)
|
|
2586
2198
|
{
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2593
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2594
|
-
VpFrac(c, a);
|
|
2595
|
-
return VpCheckGetValue(c);
|
|
2199
|
+
BDVALUE a = GetBDValueMust(self);
|
|
2200
|
+
BDVALUE c = NewZeroWrap(1, (a.real->Prec + 1) * BASE_FIG);
|
|
2201
|
+
VpFrac(c.real, a.real);
|
|
2202
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2203
|
+
return CheckGetValue(c);
|
|
2596
2204
|
}
|
|
2597
2205
|
|
|
2598
2206
|
/* call-seq:
|
|
2599
|
-
*
|
|
2207
|
+
* floor(n)
|
|
2600
2208
|
*
|
|
2601
2209
|
* Return the largest integer less than or equal to the value, as a BigDecimal.
|
|
2602
2210
|
*
|
|
@@ -2615,35 +2223,11 @@ BigDecimal_frac(VALUE self)
|
|
|
2615
2223
|
static VALUE
|
|
2616
2224
|
BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
2617
2225
|
{
|
|
2618
|
-
|
|
2619
|
-
Real *c, *a;
|
|
2620
|
-
int iLoc;
|
|
2621
|
-
VALUE vLoc;
|
|
2622
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2623
|
-
|
|
2624
|
-
if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
|
|
2625
|
-
iLoc = 0;
|
|
2626
|
-
}
|
|
2627
|
-
else {
|
|
2628
|
-
iLoc = NUM2INT(vLoc);
|
|
2629
|
-
}
|
|
2630
|
-
|
|
2631
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2632
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2633
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2634
|
-
VpSetPrecLimit(pl);
|
|
2635
|
-
VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
|
|
2636
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
2637
|
-
VPrint(stderr, "floor: c=%\n", c);
|
|
2638
|
-
#endif
|
|
2639
|
-
if (argc == 0) {
|
|
2640
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2641
|
-
}
|
|
2642
|
-
return VpCheckGetValue(c);
|
|
2226
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_FLOOR);
|
|
2643
2227
|
}
|
|
2644
2228
|
|
|
2645
2229
|
/* call-seq:
|
|
2646
|
-
*
|
|
2230
|
+
* ceil(n)
|
|
2647
2231
|
*
|
|
2648
2232
|
* Return the smallest integer greater than or equal to the value, as a BigDecimal.
|
|
2649
2233
|
*
|
|
@@ -2662,31 +2246,11 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self)
|
|
|
2662
2246
|
static VALUE
|
|
2663
2247
|
BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
2664
2248
|
{
|
|
2665
|
-
|
|
2666
|
-
Real *c, *a;
|
|
2667
|
-
int iLoc;
|
|
2668
|
-
VALUE vLoc;
|
|
2669
|
-
size_t mx, pl = VpSetPrecLimit(0);
|
|
2670
|
-
|
|
2671
|
-
if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
|
|
2672
|
-
iLoc = 0;
|
|
2673
|
-
} else {
|
|
2674
|
-
iLoc = NUM2INT(vLoc);
|
|
2675
|
-
}
|
|
2676
|
-
|
|
2677
|
-
GUARD_OBJ(a, GetVpValue(self, 1));
|
|
2678
|
-
mx = a->Prec * (VpBaseFig() + 1);
|
|
2679
|
-
GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
|
|
2680
|
-
VpSetPrecLimit(pl);
|
|
2681
|
-
VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
|
|
2682
|
-
if (argc == 0) {
|
|
2683
|
-
return BigDecimal_to_i(VpCheckGetValue(c));
|
|
2684
|
-
}
|
|
2685
|
-
return VpCheckGetValue(c);
|
|
2249
|
+
return BigDecimal_truncate_floor_ceil(argc, argv, self, VP_ROUND_CEIL);
|
|
2686
2250
|
}
|
|
2687
2251
|
|
|
2688
2252
|
/* call-seq:
|
|
2689
|
-
*
|
|
2253
|
+
* to_s(s)
|
|
2690
2254
|
*
|
|
2691
2255
|
* Converts the value to a string.
|
|
2692
2256
|
*
|
|
@@ -2703,7 +2267,7 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2703
2267
|
* If s contains a number, a space is inserted after each group of that many
|
|
2704
2268
|
* digits, starting from '.' and counting outwards.
|
|
2705
2269
|
*
|
|
2706
|
-
* If s ends with an 'E',
|
|
2270
|
+
* If s ends with an 'E', scientific notation (0.xxxxEnn) is used.
|
|
2707
2271
|
*
|
|
2708
2272
|
* If s ends with an 'F', conventional floating point notation is used.
|
|
2709
2273
|
*
|
|
@@ -2721,10 +2285,9 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
|
|
|
2721
2285
|
static VALUE
|
|
2722
2286
|
BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
2723
2287
|
{
|
|
2724
|
-
ENTER(5);
|
|
2725
2288
|
int fmt = 0; /* 0: E format, 1: F format */
|
|
2726
2289
|
int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
2727
|
-
|
|
2290
|
+
BDVALUE v;
|
|
2728
2291
|
volatile VALUE str;
|
|
2729
2292
|
char *psz;
|
|
2730
2293
|
char ch;
|
|
@@ -2732,7 +2295,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2732
2295
|
SIGNED_VALUE m;
|
|
2733
2296
|
VALUE f;
|
|
2734
2297
|
|
|
2735
|
-
|
|
2298
|
+
v = GetBDValueMust(self);
|
|
2736
2299
|
|
|
2737
2300
|
if (rb_scan_args(argc, argv, "01", &f) == 1) {
|
|
2738
2301
|
if (RB_TYPE_P(f, T_STRING)) {
|
|
@@ -2767,10 +2330,10 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2767
2330
|
}
|
|
2768
2331
|
}
|
|
2769
2332
|
if (fmt) {
|
|
2770
|
-
nc = VpNumOfChars(
|
|
2333
|
+
nc = VpNumOfChars(v.real, "F");
|
|
2771
2334
|
}
|
|
2772
2335
|
else {
|
|
2773
|
-
nc = VpNumOfChars(
|
|
2336
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2774
2337
|
}
|
|
2775
2338
|
if (mc > 0) {
|
|
2776
2339
|
nc += (nc + mc - 1) / mc + 1;
|
|
@@ -2780,12 +2343,14 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2780
2343
|
psz = RSTRING_PTR(str);
|
|
2781
2344
|
|
|
2782
2345
|
if (fmt) {
|
|
2783
|
-
VpToFString(
|
|
2346
|
+
VpToFString(v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2784
2347
|
}
|
|
2785
2348
|
else {
|
|
2786
|
-
VpToString (
|
|
2349
|
+
VpToString (v.real, psz, RSTRING_LEN(str), mc, fPlus);
|
|
2787
2350
|
}
|
|
2788
2351
|
rb_str_resize(str, strlen(psz));
|
|
2352
|
+
|
|
2353
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2789
2354
|
return str;
|
|
2790
2355
|
}
|
|
2791
2356
|
|
|
@@ -2816,16 +2381,15 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|
|
2816
2381
|
static VALUE
|
|
2817
2382
|
BigDecimal_split(VALUE self)
|
|
2818
2383
|
{
|
|
2819
|
-
|
|
2820
|
-
Real *vp;
|
|
2384
|
+
BDVALUE v;
|
|
2821
2385
|
VALUE obj,str;
|
|
2822
2386
|
ssize_t e, s;
|
|
2823
2387
|
char *psz1;
|
|
2824
2388
|
|
|
2825
|
-
|
|
2826
|
-
str = rb_str_new(0, VpNumOfChars(
|
|
2389
|
+
v = GetBDValueMust(self);
|
|
2390
|
+
str = rb_str_new(0, VpNumOfChars(v.real, "E"));
|
|
2827
2391
|
psz1 = RSTRING_PTR(str);
|
|
2828
|
-
VpSzMantissa(
|
|
2392
|
+
VpSzMantissa(v.real, psz1, RSTRING_LEN(str));
|
|
2829
2393
|
s = 1;
|
|
2830
2394
|
if(psz1[0] == '-') {
|
|
2831
2395
|
size_t len = strlen(psz1 + 1);
|
|
@@ -2835,13 +2399,15 @@ BigDecimal_split(VALUE self)
|
|
|
2835
2399
|
s = -1;
|
|
2836
2400
|
}
|
|
2837
2401
|
if (psz1[0] == 'N') s = 0; /* NaN */
|
|
2838
|
-
e = VpExponent10(
|
|
2402
|
+
e = VpExponent10(v.real);
|
|
2839
2403
|
obj = rb_ary_new2(4);
|
|
2840
2404
|
rb_ary_push(obj, INT2FIX(s));
|
|
2841
2405
|
rb_ary_push(obj, str);
|
|
2842
2406
|
rb_str_resize(str, strlen(psz1));
|
|
2843
2407
|
rb_ary_push(obj, INT2FIX(10));
|
|
2844
2408
|
rb_ary_push(obj, SSIZET2NUM(e));
|
|
2409
|
+
|
|
2410
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2845
2411
|
return obj;
|
|
2846
2412
|
}
|
|
2847
2413
|
|
|
@@ -2853,7 +2419,7 @@ BigDecimal_split(VALUE self)
|
|
|
2853
2419
|
static VALUE
|
|
2854
2420
|
BigDecimal_exponent(VALUE self)
|
|
2855
2421
|
{
|
|
2856
|
-
ssize_t e = VpExponent10(
|
|
2422
|
+
ssize_t e = VpExponent10(GetSelfVpValue(self));
|
|
2857
2423
|
return SSIZET2NUM(e);
|
|
2858
2424
|
}
|
|
2859
2425
|
|
|
@@ -2865,49 +2431,78 @@ BigDecimal_exponent(VALUE self)
|
|
|
2865
2431
|
static VALUE
|
|
2866
2432
|
BigDecimal_inspect(VALUE self)
|
|
2867
2433
|
{
|
|
2868
|
-
|
|
2869
|
-
Real *vp;
|
|
2434
|
+
BDVALUE v;
|
|
2870
2435
|
volatile VALUE str;
|
|
2871
2436
|
size_t nc;
|
|
2872
2437
|
|
|
2873
|
-
|
|
2874
|
-
nc = VpNumOfChars(
|
|
2438
|
+
v = GetBDValueMust(self);
|
|
2439
|
+
nc = VpNumOfChars(v.real, "E");
|
|
2875
2440
|
|
|
2876
2441
|
str = rb_str_new(0, nc);
|
|
2877
|
-
VpToString(
|
|
2442
|
+
VpToString(v.real, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
|
|
2878
2443
|
rb_str_resize(str, strlen(RSTRING_PTR(str)));
|
|
2879
|
-
return str;
|
|
2880
|
-
}
|
|
2881
|
-
|
|
2882
|
-
static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
|
|
2883
|
-
static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
|
|
2884
2444
|
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
inline static int
|
|
2889
|
-
is_integer(VALUE x)
|
|
2890
|
-
{
|
|
2891
|
-
return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
|
|
2445
|
+
RB_GC_GUARD(v.bigdecimal);
|
|
2446
|
+
return str;
|
|
2892
2447
|
}
|
|
2893
2448
|
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2449
|
+
/* Returns self * 10**v without changing the precision.
|
|
2450
|
+
* This method is currently for internal use.
|
|
2451
|
+
*
|
|
2452
|
+
* BigDecimal("0.123e10")._decimal_shift(20) #=> "0.123e30"
|
|
2453
|
+
* BigDecimal("0.123e10")._decimal_shift(-20) #=> "0.123e-10"
|
|
2454
|
+
*/
|
|
2455
|
+
static VALUE
|
|
2456
|
+
BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
2457
|
+
{
|
|
2458
|
+
BDVALUE a, c;
|
|
2459
|
+
ssize_t shift, exponentShift;
|
|
2460
|
+
bool shiftDown;
|
|
2461
|
+
size_t prec;
|
|
2462
|
+
DECDIG ex, iex;
|
|
2463
|
+
|
|
2464
|
+
a = GetBDValueMust(self);
|
|
2465
|
+
shift = NUM2SSIZET(rb_to_int(v));
|
|
2466
|
+
|
|
2467
|
+
if (VpIsZero(a.real) || VpIsNaN(a.real) || VpIsInf(a.real) || shift == 0) return CheckGetValue(a);
|
|
2468
|
+
|
|
2469
|
+
exponentShift = shift > 0 ? shift / BASE_FIG : (shift + 1) / BASE_FIG - 1;
|
|
2470
|
+
shift -= exponentShift * BASE_FIG;
|
|
2471
|
+
ex = 1;
|
|
2472
|
+
for (int i = 0; i < shift; i++) ex *= 10;
|
|
2473
|
+
shiftDown = a.real->frac[0] * (DECDIG_DBL)ex >= BASE;
|
|
2474
|
+
iex = BASE / ex;
|
|
2475
|
+
|
|
2476
|
+
prec = a.real->Prec + shiftDown;
|
|
2477
|
+
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2478
|
+
if (shift == 0) {
|
|
2479
|
+
VpAsgn(c.real, a.real, 10);
|
|
2480
|
+
} else if (shiftDown) {
|
|
2481
|
+
DECDIG carry = 0;
|
|
2482
|
+
exponentShift++;
|
|
2483
|
+
for (size_t i = 0; i < a.real->Prec; i++) {
|
|
2484
|
+
DECDIG v = a.real->frac[i];
|
|
2485
|
+
c.real->frac[i] = carry * ex + v / iex;
|
|
2486
|
+
carry = v % iex;
|
|
2487
|
+
}
|
|
2488
|
+
c.real->frac[a.real->Prec] = carry * ex;
|
|
2489
|
+
} else {
|
|
2490
|
+
DECDIG carry = 0;
|
|
2491
|
+
for (ssize_t i = a.real->Prec - 1; i >= 0; i--) {
|
|
2492
|
+
DECDIG v = a.real->frac[i];
|
|
2493
|
+
c.real->frac[i] = v % iex * ex + carry;
|
|
2494
|
+
carry = v / iex;
|
|
2495
|
+
}
|
|
2905
2496
|
}
|
|
2906
|
-
|
|
2497
|
+
while (c.real->frac[prec - 1] == 0) prec--;
|
|
2498
|
+
c.real->Prec = prec;
|
|
2499
|
+
c.real->sign = a.real->sign;
|
|
2500
|
+
c.real->exponent = a.real->exponent;
|
|
2501
|
+
AddExponent(c.real, exponentShift);
|
|
2502
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
2503
|
+
return CheckGetValue(c);
|
|
2907
2504
|
}
|
|
2908
2505
|
|
|
2909
|
-
#define is_positive(x) (!is_negative(x))
|
|
2910
|
-
|
|
2911
2506
|
inline static int
|
|
2912
2507
|
is_zero(VALUE x)
|
|
2913
2508
|
{
|
|
@@ -2931,344 +2526,6 @@ is_zero(VALUE x)
|
|
|
2931
2526
|
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
|
|
2932
2527
|
}
|
|
2933
2528
|
|
|
2934
|
-
inline static int
|
|
2935
|
-
is_one(VALUE x)
|
|
2936
|
-
{
|
|
2937
|
-
VALUE num, den;
|
|
2938
|
-
|
|
2939
|
-
switch (TYPE(x)) {
|
|
2940
|
-
case T_FIXNUM:
|
|
2941
|
-
return FIX2LONG(x) == 1;
|
|
2942
|
-
|
|
2943
|
-
case T_BIGNUM:
|
|
2944
|
-
return Qfalse;
|
|
2945
|
-
|
|
2946
|
-
case T_RATIONAL:
|
|
2947
|
-
num = rb_rational_num(x);
|
|
2948
|
-
den = rb_rational_den(x);
|
|
2949
|
-
return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
|
|
2950
|
-
FIXNUM_P(num) && FIX2LONG(num) == 1;
|
|
2951
|
-
|
|
2952
|
-
default:
|
|
2953
|
-
break;
|
|
2954
|
-
}
|
|
2955
|
-
|
|
2956
|
-
return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
|
|
2957
|
-
}
|
|
2958
|
-
|
|
2959
|
-
inline static int
|
|
2960
|
-
is_even(VALUE x)
|
|
2961
|
-
{
|
|
2962
|
-
switch (TYPE(x)) {
|
|
2963
|
-
case T_FIXNUM:
|
|
2964
|
-
return (FIX2LONG(x) % 2) == 0;
|
|
2965
|
-
|
|
2966
|
-
case T_BIGNUM:
|
|
2967
|
-
{
|
|
2968
|
-
unsigned long l;
|
|
2969
|
-
rb_big_pack(x, &l, 1);
|
|
2970
|
-
return l % 2 == 0;
|
|
2971
|
-
}
|
|
2972
|
-
|
|
2973
|
-
default:
|
|
2974
|
-
break;
|
|
2975
|
-
}
|
|
2976
|
-
|
|
2977
|
-
return 0;
|
|
2978
|
-
}
|
|
2979
|
-
|
|
2980
|
-
static VALUE
|
|
2981
|
-
bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
|
|
2982
|
-
{
|
|
2983
|
-
VALUE log_x, multiplied, y;
|
|
2984
|
-
volatile VALUE obj = exp->obj;
|
|
2985
|
-
|
|
2986
|
-
if (VpIsZero(exp)) {
|
|
2987
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
2988
|
-
}
|
|
2989
|
-
|
|
2990
|
-
log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
|
|
2991
|
-
multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
|
|
2992
|
-
y = BigMath_exp(multiplied, SSIZET2NUM(n));
|
|
2993
|
-
RB_GC_GUARD(obj);
|
|
2994
|
-
|
|
2995
|
-
return y;
|
|
2996
|
-
}
|
|
2997
|
-
|
|
2998
|
-
/* call-seq:
|
|
2999
|
-
* power(n)
|
|
3000
|
-
* power(n, prec)
|
|
3001
|
-
*
|
|
3002
|
-
* Returns the value raised to the power of n.
|
|
3003
|
-
*
|
|
3004
|
-
* Note that n must be an Integer.
|
|
3005
|
-
*
|
|
3006
|
-
* Also available as the operator **.
|
|
3007
|
-
*/
|
|
3008
|
-
static VALUE
|
|
3009
|
-
BigDecimal_power(int argc, VALUE*argv, VALUE self)
|
|
3010
|
-
{
|
|
3011
|
-
ENTER(5);
|
|
3012
|
-
VALUE vexp, prec;
|
|
3013
|
-
Real* exp = NULL;
|
|
3014
|
-
Real *x, *y;
|
|
3015
|
-
ssize_t mp, ma, n;
|
|
3016
|
-
SIGNED_VALUE int_exp;
|
|
3017
|
-
double d;
|
|
3018
|
-
|
|
3019
|
-
rb_scan_args(argc, argv, "11", &vexp, &prec);
|
|
3020
|
-
|
|
3021
|
-
GUARD_OBJ(x, GetVpValue(self, 1));
|
|
3022
|
-
n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
|
|
3023
|
-
|
|
3024
|
-
if (VpIsNaN(x)) {
|
|
3025
|
-
y = NewZeroWrapLimited(1, n);
|
|
3026
|
-
VpSetNaN(y);
|
|
3027
|
-
RB_GC_GUARD(y->obj);
|
|
3028
|
-
return VpCheckGetValue(y);
|
|
3029
|
-
}
|
|
3030
|
-
|
|
3031
|
-
retry:
|
|
3032
|
-
switch (TYPE(vexp)) {
|
|
3033
|
-
case T_FIXNUM:
|
|
3034
|
-
break;
|
|
3035
|
-
|
|
3036
|
-
case T_BIGNUM:
|
|
3037
|
-
break;
|
|
3038
|
-
|
|
3039
|
-
case T_FLOAT:
|
|
3040
|
-
d = RFLOAT_VALUE(vexp);
|
|
3041
|
-
if (d == round(d)) {
|
|
3042
|
-
if (FIXABLE(d)) {
|
|
3043
|
-
vexp = LONG2FIX((long)d);
|
|
3044
|
-
}
|
|
3045
|
-
else {
|
|
3046
|
-
vexp = rb_dbl2big(d);
|
|
3047
|
-
}
|
|
3048
|
-
goto retry;
|
|
3049
|
-
}
|
|
3050
|
-
if (NIL_P(prec)) {
|
|
3051
|
-
n += BIGDECIMAL_DOUBLE_FIGURES;
|
|
3052
|
-
}
|
|
3053
|
-
exp = GetVpValueWithPrec(vexp, 0, 1);
|
|
3054
|
-
break;
|
|
3055
|
-
|
|
3056
|
-
case T_RATIONAL:
|
|
3057
|
-
if (is_zero(rb_rational_num(vexp))) {
|
|
3058
|
-
if (is_positive(vexp)) {
|
|
3059
|
-
vexp = INT2FIX(0);
|
|
3060
|
-
goto retry;
|
|
3061
|
-
}
|
|
3062
|
-
}
|
|
3063
|
-
else if (is_one(rb_rational_den(vexp))) {
|
|
3064
|
-
vexp = rb_rational_num(vexp);
|
|
3065
|
-
goto retry;
|
|
3066
|
-
}
|
|
3067
|
-
exp = GetVpValueWithPrec(vexp, n, 1);
|
|
3068
|
-
if (NIL_P(prec)) {
|
|
3069
|
-
n += n;
|
|
3070
|
-
}
|
|
3071
|
-
break;
|
|
3072
|
-
|
|
3073
|
-
case T_DATA:
|
|
3074
|
-
if (is_kind_of_BigDecimal(vexp)) {
|
|
3075
|
-
VALUE zero = INT2FIX(0);
|
|
3076
|
-
VALUE rounded = BigDecimal_round(1, &zero, vexp);
|
|
3077
|
-
if (RTEST(BigDecimal_eq(vexp, rounded))) {
|
|
3078
|
-
vexp = BigDecimal_to_i(vexp);
|
|
3079
|
-
goto retry;
|
|
3080
|
-
}
|
|
3081
|
-
if (NIL_P(prec)) {
|
|
3082
|
-
GUARD_OBJ(y, GetVpValue(vexp, 1));
|
|
3083
|
-
n += y->Prec*VpBaseFig();
|
|
3084
|
-
}
|
|
3085
|
-
exp = DATA_PTR(vexp);
|
|
3086
|
-
break;
|
|
3087
|
-
}
|
|
3088
|
-
/* fall through */
|
|
3089
|
-
default:
|
|
3090
|
-
rb_raise(rb_eTypeError,
|
|
3091
|
-
"wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
|
|
3092
|
-
RB_OBJ_CLASSNAME(vexp));
|
|
3093
|
-
}
|
|
3094
|
-
|
|
3095
|
-
if (VpIsZero(x)) {
|
|
3096
|
-
if (is_negative(vexp)) {
|
|
3097
|
-
y = NewZeroWrapNolimit(1, n);
|
|
3098
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3099
|
-
if (is_integer(vexp)) {
|
|
3100
|
-
if (is_even(vexp)) {
|
|
3101
|
-
/* (-0) ** (-even_integer) -> Infinity */
|
|
3102
|
-
VpSetPosInf(y);
|
|
3103
|
-
}
|
|
3104
|
-
else {
|
|
3105
|
-
/* (-0) ** (-odd_integer) -> -Infinity */
|
|
3106
|
-
VpSetNegInf(y);
|
|
3107
|
-
}
|
|
3108
|
-
}
|
|
3109
|
-
else {
|
|
3110
|
-
/* (-0) ** (-non_integer) -> Infinity */
|
|
3111
|
-
VpSetPosInf(y);
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
else {
|
|
3115
|
-
/* (+0) ** (-num) -> Infinity */
|
|
3116
|
-
VpSetPosInf(y);
|
|
3117
|
-
}
|
|
3118
|
-
RB_GC_GUARD(y->obj);
|
|
3119
|
-
return VpCheckGetValue(y);
|
|
3120
|
-
}
|
|
3121
|
-
else if (is_zero(vexp)) {
|
|
3122
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3123
|
-
}
|
|
3124
|
-
else {
|
|
3125
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3126
|
-
}
|
|
3127
|
-
}
|
|
3128
|
-
|
|
3129
|
-
if (is_zero(vexp)) {
|
|
3130
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3131
|
-
}
|
|
3132
|
-
else if (is_one(vexp)) {
|
|
3133
|
-
return self;
|
|
3134
|
-
}
|
|
3135
|
-
|
|
3136
|
-
if (VpIsInf(x)) {
|
|
3137
|
-
if (is_negative(vexp)) {
|
|
3138
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3139
|
-
if (is_integer(vexp)) {
|
|
3140
|
-
if (is_even(vexp)) {
|
|
3141
|
-
/* (-Infinity) ** (-even_integer) -> +0 */
|
|
3142
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3143
|
-
}
|
|
3144
|
-
else {
|
|
3145
|
-
/* (-Infinity) ** (-odd_integer) -> -0 */
|
|
3146
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3147
|
-
}
|
|
3148
|
-
}
|
|
3149
|
-
else {
|
|
3150
|
-
/* (-Infinity) ** (-non_integer) -> -0 */
|
|
3151
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3152
|
-
}
|
|
3153
|
-
}
|
|
3154
|
-
else {
|
|
3155
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3156
|
-
}
|
|
3157
|
-
}
|
|
3158
|
-
else {
|
|
3159
|
-
y = NewZeroWrapLimited(1, n);
|
|
3160
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
3161
|
-
if (is_integer(vexp)) {
|
|
3162
|
-
if (is_even(vexp)) {
|
|
3163
|
-
VpSetPosInf(y);
|
|
3164
|
-
}
|
|
3165
|
-
else {
|
|
3166
|
-
VpSetNegInf(y);
|
|
3167
|
-
}
|
|
3168
|
-
}
|
|
3169
|
-
else {
|
|
3170
|
-
/* TODO: support complex */
|
|
3171
|
-
rb_raise(rb_eMathDomainError,
|
|
3172
|
-
"a non-integral exponent for a negative base");
|
|
3173
|
-
}
|
|
3174
|
-
}
|
|
3175
|
-
else {
|
|
3176
|
-
VpSetPosInf(y);
|
|
3177
|
-
}
|
|
3178
|
-
return VpCheckGetValue(y);
|
|
3179
|
-
}
|
|
3180
|
-
}
|
|
3181
|
-
|
|
3182
|
-
if (exp != NULL) {
|
|
3183
|
-
return bigdecimal_power_by_bigdecimal(x, exp, n);
|
|
3184
|
-
}
|
|
3185
|
-
else if (RB_TYPE_P(vexp, T_BIGNUM)) {
|
|
3186
|
-
VALUE abs_value = BigDecimal_abs(self);
|
|
3187
|
-
if (is_one(abs_value)) {
|
|
3188
|
-
return VpCheckGetValue(NewOneWrapLimited(1, n));
|
|
3189
|
-
}
|
|
3190
|
-
else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
|
|
3191
|
-
if (is_negative(vexp)) {
|
|
3192
|
-
y = NewZeroWrapLimited(1, n);
|
|
3193
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3194
|
-
return VpCheckGetValue(y);
|
|
3195
|
-
}
|
|
3196
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3197
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3198
|
-
}
|
|
3199
|
-
else {
|
|
3200
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3201
|
-
}
|
|
3202
|
-
}
|
|
3203
|
-
else {
|
|
3204
|
-
if (is_positive(vexp)) {
|
|
3205
|
-
y = NewZeroWrapLimited(1, n);
|
|
3206
|
-
VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
|
|
3207
|
-
return VpCheckGetValue(y);
|
|
3208
|
-
}
|
|
3209
|
-
else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
|
|
3210
|
-
return VpCheckGetValue(NewZeroWrapLimited(-1, n));
|
|
3211
|
-
}
|
|
3212
|
-
else {
|
|
3213
|
-
return VpCheckGetValue(NewZeroWrapLimited(1, n));
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
3216
|
-
}
|
|
3217
|
-
|
|
3218
|
-
int_exp = FIX2LONG(vexp);
|
|
3219
|
-
ma = int_exp;
|
|
3220
|
-
if (ma < 0) ma = -ma;
|
|
3221
|
-
if (ma == 0) ma = 1;
|
|
3222
|
-
|
|
3223
|
-
if (VpIsDef(x)) {
|
|
3224
|
-
mp = x->Prec * (VpBaseFig() + 1);
|
|
3225
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
|
|
3226
|
-
}
|
|
3227
|
-
else {
|
|
3228
|
-
GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
|
|
3229
|
-
}
|
|
3230
|
-
VpPowerByInt(y, x, int_exp);
|
|
3231
|
-
if (!NIL_P(prec) && VpIsDef(y)) {
|
|
3232
|
-
VpMidRound(y, VpGetRoundMode(), n);
|
|
3233
|
-
}
|
|
3234
|
-
return VpCheckGetValue(y);
|
|
3235
|
-
}
|
|
3236
|
-
|
|
3237
|
-
/* call-seq:
|
|
3238
|
-
* self ** other -> bigdecimal
|
|
3239
|
-
*
|
|
3240
|
-
* Returns the \BigDecimal value of +self+ raised to power +other+:
|
|
3241
|
-
*
|
|
3242
|
-
* b = BigDecimal('3.14')
|
|
3243
|
-
* b ** 2 # => 0.98596e1
|
|
3244
|
-
* b ** 2.0 # => 0.98596e1
|
|
3245
|
-
* b ** Rational(2, 1) # => 0.98596e1
|
|
3246
|
-
*
|
|
3247
|
-
* Related: BigDecimal#power.
|
|
3248
|
-
*
|
|
3249
|
-
*/
|
|
3250
|
-
static VALUE
|
|
3251
|
-
BigDecimal_power_op(VALUE self, VALUE exp)
|
|
3252
|
-
{
|
|
3253
|
-
return BigDecimal_power(1, &exp, self);
|
|
3254
|
-
}
|
|
3255
|
-
|
|
3256
|
-
/* :nodoc:
|
|
3257
|
-
*
|
|
3258
|
-
* private method for dup and clone the provided BigDecimal +other+
|
|
3259
|
-
*/
|
|
3260
|
-
static VALUE
|
|
3261
|
-
BigDecimal_initialize_copy(VALUE self, VALUE other)
|
|
3262
|
-
{
|
|
3263
|
-
Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
|
|
3264
|
-
Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
|
|
3265
|
-
|
|
3266
|
-
if (self != other) {
|
|
3267
|
-
DATA_PTR(self) = VpCopy(pv, x);
|
|
3268
|
-
}
|
|
3269
|
-
return self;
|
|
3270
|
-
}
|
|
3271
|
-
|
|
3272
2529
|
/* :nodoc: */
|
|
3273
2530
|
static VALUE
|
|
3274
2531
|
BigDecimal_clone(VALUE self)
|
|
@@ -3307,20 +2564,18 @@ check_exception(VALUE bd)
|
|
|
3307
2564
|
|
|
3308
2565
|
Real *vp;
|
|
3309
2566
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3310
|
-
|
|
2567
|
+
VpCheckException(vp, false);
|
|
3311
2568
|
|
|
3312
2569
|
return bd;
|
|
3313
2570
|
}
|
|
3314
2571
|
|
|
3315
2572
|
static VALUE
|
|
3316
|
-
rb_uint64_convert_to_BigDecimal(uint64_t uval
|
|
2573
|
+
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
3317
2574
|
{
|
|
3318
|
-
|
|
3319
|
-
|
|
2575
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3320
2576
|
Real *vp;
|
|
3321
2577
|
if (uval == 0) {
|
|
3322
2578
|
vp = rbd_allocate_struct(1);
|
|
3323
|
-
vp->MaxPrec = 1;
|
|
3324
2579
|
vp->Prec = 1;
|
|
3325
2580
|
vp->exponent = 1;
|
|
3326
2581
|
VpSetZero(vp, 1);
|
|
@@ -3328,7 +2583,6 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3328
2583
|
}
|
|
3329
2584
|
else if (uval < BASE) {
|
|
3330
2585
|
vp = rbd_allocate_struct(1);
|
|
3331
|
-
vp->MaxPrec = 1;
|
|
3332
2586
|
vp->Prec = 1;
|
|
3333
2587
|
vp->exponent = 1;
|
|
3334
2588
|
VpSetSign(vp, 1);
|
|
@@ -3354,21 +2608,20 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int r
|
|
|
3354
2608
|
|
|
3355
2609
|
const size_t exp = len + ntz;
|
|
3356
2610
|
vp = rbd_allocate_struct(len);
|
|
3357
|
-
vp->MaxPrec = len;
|
|
3358
2611
|
vp->Prec = len;
|
|
3359
2612
|
vp->exponent = exp;
|
|
3360
2613
|
VpSetSign(vp, 1);
|
|
3361
2614
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
3362
2615
|
}
|
|
3363
2616
|
|
|
3364
|
-
return BigDecimal_wrap_struct(
|
|
2617
|
+
return BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3365
2618
|
}
|
|
3366
2619
|
|
|
3367
2620
|
static VALUE
|
|
3368
|
-
rb_int64_convert_to_BigDecimal(int64_t ival
|
|
2621
|
+
rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
3369
2622
|
{
|
|
3370
2623
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
3371
|
-
VALUE bd = rb_uint64_convert_to_BigDecimal(uval
|
|
2624
|
+
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
3372
2625
|
if (ival < 0) {
|
|
3373
2626
|
Real *vp;
|
|
3374
2627
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
@@ -3378,7 +2631,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
|
|
|
3378
2631
|
}
|
|
3379
2632
|
|
|
3380
2633
|
static VALUE
|
|
3381
|
-
rb_big_convert_to_BigDecimal(VALUE val
|
|
2634
|
+
rb_big_convert_to_BigDecimal(VALUE val)
|
|
3382
2635
|
{
|
|
3383
2636
|
assert(RB_TYPE_P(val, T_BIGNUM));
|
|
3384
2637
|
|
|
@@ -3390,40 +2643,44 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
|
|
|
3390
2643
|
}
|
|
3391
2644
|
if (size <= sizeof(long)) {
|
|
3392
2645
|
if (sign < 0) {
|
|
3393
|
-
return rb_int64_convert_to_BigDecimal(NUM2LONG(val)
|
|
2646
|
+
return rb_int64_convert_to_BigDecimal(NUM2LONG(val));
|
|
3394
2647
|
}
|
|
3395
2648
|
else {
|
|
3396
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val)
|
|
2649
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val));
|
|
3397
2650
|
}
|
|
3398
2651
|
}
|
|
3399
2652
|
#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
|
|
3400
2653
|
else if (size <= sizeof(LONG_LONG)) {
|
|
3401
2654
|
if (sign < 0) {
|
|
3402
|
-
return rb_int64_convert_to_BigDecimal(NUM2LL(val)
|
|
2655
|
+
return rb_int64_convert_to_BigDecimal(NUM2LL(val));
|
|
3403
2656
|
}
|
|
3404
2657
|
else {
|
|
3405
|
-
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val)
|
|
2658
|
+
return rb_uint64_convert_to_BigDecimal(NUM2ULL(val));
|
|
3406
2659
|
}
|
|
3407
2660
|
}
|
|
3408
2661
|
#endif
|
|
3409
2662
|
else {
|
|
3410
2663
|
VALUE str = rb_big2str(val, 10);
|
|
3411
|
-
|
|
3412
|
-
|
|
2664
|
+
BDVALUE v = bdvalue_nonnullable(CreateFromString(
|
|
2665
|
+
RSTRING_PTR(str),
|
|
2666
|
+
rb_cBigDecimal,
|
|
2667
|
+
true,
|
|
2668
|
+
true
|
|
2669
|
+
));
|
|
3413
2670
|
RB_GC_GUARD(str);
|
|
3414
|
-
return
|
|
2671
|
+
return CheckGetValue(v);
|
|
3415
2672
|
}
|
|
3416
2673
|
}
|
|
3417
2674
|
|
|
3418
2675
|
static VALUE
|
|
3419
|
-
rb_inum_convert_to_BigDecimal(VALUE val
|
|
2676
|
+
rb_inum_convert_to_BigDecimal(VALUE val)
|
|
3420
2677
|
{
|
|
3421
2678
|
assert(RB_INTEGER_TYPE_P(val));
|
|
3422
2679
|
if (FIXNUM_P(val)) {
|
|
3423
|
-
return rb_int64_convert_to_BigDecimal(FIX2LONG(val)
|
|
2680
|
+
return rb_int64_convert_to_BigDecimal(FIX2LONG(val));
|
|
3424
2681
|
}
|
|
3425
2682
|
else {
|
|
3426
|
-
return rb_big_convert_to_BigDecimal(val
|
|
2683
|
+
return rb_big_convert_to_BigDecimal(val);
|
|
3427
2684
|
}
|
|
3428
2685
|
}
|
|
3429
2686
|
|
|
@@ -3458,11 +2715,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3458
2715
|
}
|
|
3459
2716
|
|
|
3460
2717
|
if (digs == SIZE_MAX) {
|
|
3461
|
-
|
|
3462
|
-
return Qnil;
|
|
3463
|
-
rb_raise(rb_eArgError,
|
|
3464
|
-
"can't omit precision for a %"PRIsVALUE".",
|
|
3465
|
-
CLASS_OF(val));
|
|
2718
|
+
digs = 0;
|
|
3466
2719
|
}
|
|
3467
2720
|
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
|
|
3468
2721
|
if (!raise_exception)
|
|
@@ -3577,7 +2830,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3577
2830
|
exp = -exp;
|
|
3578
2831
|
}
|
|
3579
2832
|
|
|
3580
|
-
VALUE bd = rb_inum_convert_to_BigDecimal(inum
|
|
2833
|
+
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
3581
2834
|
Real *vp;
|
|
3582
2835
|
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
3583
2836
|
assert(vp->Prec == prec);
|
|
@@ -3600,28 +2853,24 @@ rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3600
2853
|
CLASS_OF(val));
|
|
3601
2854
|
}
|
|
3602
2855
|
|
|
3603
|
-
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val)
|
|
2856
|
+
VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val));
|
|
3604
2857
|
VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
|
|
3605
2858
|
return d;
|
|
3606
2859
|
}
|
|
3607
2860
|
|
|
3608
2861
|
static VALUE
|
|
3609
|
-
rb_cstr_convert_to_BigDecimal(const char *c_str,
|
|
2862
|
+
rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
3610
2863
|
{
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
|
|
3615
|
-
if (!vp)
|
|
3616
|
-
return Qnil;
|
|
3617
|
-
return VpCheckGetValue(vp);
|
|
2864
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, rb_cBigDecimal, true, raise_exception);
|
|
2865
|
+
if (v.bigdecimal_or_nil == Qnil) return Qnil;
|
|
2866
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3618
2867
|
}
|
|
3619
2868
|
|
|
3620
2869
|
static inline VALUE
|
|
3621
|
-
rb_str_convert_to_BigDecimal(VALUE val,
|
|
2870
|
+
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
3622
2871
|
{
|
|
3623
2872
|
const char *c_str = StringValueCStr(val);
|
|
3624
|
-
return rb_cstr_convert_to_BigDecimal(c_str,
|
|
2873
|
+
return rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
3625
2874
|
}
|
|
3626
2875
|
|
|
3627
2876
|
static VALUE
|
|
@@ -3649,17 +2898,18 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3649
2898
|
if (digs == SIZE_MAX)
|
|
3650
2899
|
return check_exception(val);
|
|
3651
2900
|
|
|
2901
|
+
NULL_WRAPPED_VALUE null_wrapped = BigDecimal_alloc_empty_struct(rb_cBigDecimal);
|
|
3652
2902
|
Real *vp;
|
|
3653
2903
|
TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
|
|
3654
|
-
|
|
3655
|
-
VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
|
|
3656
2904
|
vp = VpCopy(NULL, vp);
|
|
2905
|
+
RB_GC_GUARD(val);
|
|
2906
|
+
|
|
2907
|
+
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
3657
2908
|
/* TODO: rounding */
|
|
3658
|
-
|
|
3659
|
-
return VpCheckGetValue(vp);
|
|
2909
|
+
return check_exception(copy);
|
|
3660
2910
|
}
|
|
3661
2911
|
else if (RB_INTEGER_TYPE_P(val)) {
|
|
3662
|
-
return rb_inum_convert_to_BigDecimal(val
|
|
2912
|
+
return rb_inum_convert_to_BigDecimal(val);
|
|
3663
2913
|
}
|
|
3664
2914
|
else if (RB_FLOAT_TYPE_P(val)) {
|
|
3665
2915
|
return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
|
|
@@ -3677,7 +2927,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3677
2927
|
return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
|
|
3678
2928
|
}
|
|
3679
2929
|
else if (RB_TYPE_P(val, T_STRING)) {
|
|
3680
|
-
return rb_str_convert_to_BigDecimal(val,
|
|
2930
|
+
return rb_str_convert_to_BigDecimal(val, raise_exception);
|
|
3681
2931
|
}
|
|
3682
2932
|
|
|
3683
2933
|
/* TODO: chheck to_d */
|
|
@@ -3691,7 +2941,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3691
2941
|
}
|
|
3692
2942
|
return Qnil;
|
|
3693
2943
|
}
|
|
3694
|
-
return rb_str_convert_to_BigDecimal(str,
|
|
2944
|
+
return rb_str_convert_to_BigDecimal(str, raise_exception);
|
|
3695
2945
|
}
|
|
3696
2946
|
|
|
3697
2947
|
/* call-seq:
|
|
@@ -3712,12 +2962,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
3712
2962
|
*
|
|
3713
2963
|
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
|
|
3714
2964
|
*
|
|
3715
|
-
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
|
|
2965
|
+
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
|
|
3716
2966
|
* BigDecimal(2) # => 0.2e1
|
|
3717
2967
|
* BigDecimal(Complex(2, 0)) # => 0.2e1
|
|
3718
2968
|
* BigDecimal(BigDecimal(2)) # => 0.2e1
|
|
3719
|
-
* #
|
|
3720
|
-
*
|
|
2969
|
+
* BigDecimal(2.0) # => 0.2e1
|
|
2970
|
+
* # Rational value requires ndigits.
|
|
3721
2971
|
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
|
|
3722
2972
|
*
|
|
3723
2973
|
* - String: converted by parsing if it contains an integer or floating-point literal;
|
|
@@ -3781,15 +3031,16 @@ static VALUE
|
|
|
3781
3031
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3782
3032
|
{
|
|
3783
3033
|
char const *c_str = StringValueCStr(str);
|
|
3784
|
-
|
|
3785
|
-
if (
|
|
3034
|
+
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3035
|
+
if (v.bigdecimal_or_nil == Qnil)
|
|
3786
3036
|
return Qnil;
|
|
3787
3037
|
else
|
|
3788
|
-
return
|
|
3038
|
+
return CheckGetValue(bdvalue_nonnullable(v));
|
|
3789
3039
|
}
|
|
3790
3040
|
|
|
3791
|
-
/*
|
|
3792
|
-
*
|
|
3041
|
+
/*
|
|
3042
|
+
* call-seq:
|
|
3043
|
+
* BigDecimal.limit(digits)
|
|
3793
3044
|
*
|
|
3794
3045
|
* Limit the number of significant digits in newly created BigDecimal
|
|
3795
3046
|
* numbers to the specified value. Rounding is performed as necessary,
|
|
@@ -3839,7 +3090,7 @@ BigDecimal_limit(int argc, VALUE *argv, VALUE self)
|
|
|
3839
3090
|
static VALUE
|
|
3840
3091
|
BigDecimal_sign(VALUE self)
|
|
3841
3092
|
{ /* sign */
|
|
3842
|
-
int s =
|
|
3093
|
+
int s = GetSelfVpValue(self)->sign;
|
|
3843
3094
|
return INT2FIX(s);
|
|
3844
3095
|
}
|
|
3845
3096
|
|
|
@@ -3911,310 +3162,15 @@ BigDecimal_save_rounding_mode(VALUE self)
|
|
|
3911
3162
|
* puts BigDecimal.limit
|
|
3912
3163
|
*
|
|
3913
3164
|
*/
|
|
3914
|
-
static VALUE
|
|
3915
|
-
BigDecimal_save_limit(VALUE self)
|
|
3916
|
-
{
|
|
3917
|
-
size_t const limit = VpGetPrecLimit();
|
|
3918
|
-
int state;
|
|
3919
|
-
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3920
|
-
VpSetPrecLimit(limit);
|
|
3921
|
-
if (state) rb_jump_tag(state);
|
|
3922
|
-
return ret;
|
|
3923
|
-
}
|
|
3924
|
-
|
|
3925
|
-
/* call-seq:
|
|
3926
|
-
* BigMath.exp(decimal, numeric) -> BigDecimal
|
|
3927
|
-
*
|
|
3928
|
-
* Computes the value of e (the base of natural logarithms) raised to the
|
|
3929
|
-
* power of +decimal+, to the specified number of digits of precision.
|
|
3930
|
-
*
|
|
3931
|
-
* If +decimal+ is infinity, returns Infinity.
|
|
3932
|
-
*
|
|
3933
|
-
* If +decimal+ is NaN, returns NaN.
|
|
3934
|
-
*/
|
|
3935
|
-
static VALUE
|
|
3936
|
-
BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
|
|
3937
|
-
{
|
|
3938
|
-
ssize_t prec, n, i;
|
|
3939
|
-
Real* vx = NULL;
|
|
3940
|
-
VALUE one, d, y;
|
|
3941
|
-
int negative = 0;
|
|
3942
|
-
int infinite = 0;
|
|
3943
|
-
int nan = 0;
|
|
3944
|
-
double flo;
|
|
3945
|
-
|
|
3946
|
-
prec = NUM2SSIZET(vprec);
|
|
3947
|
-
if (prec <= 0) {
|
|
3948
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
3949
|
-
}
|
|
3950
|
-
|
|
3951
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
3952
|
-
* BigDecimalCmp function. */
|
|
3953
|
-
switch (TYPE(x)) {
|
|
3954
|
-
case T_DATA:
|
|
3955
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
3956
|
-
vx = DATA_PTR(x);
|
|
3957
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
3958
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
3959
|
-
nan = VpIsNaN(vx);
|
|
3960
|
-
break;
|
|
3961
|
-
|
|
3962
|
-
case T_FIXNUM:
|
|
3963
|
-
/* fall through */
|
|
3964
|
-
case T_BIGNUM:
|
|
3965
|
-
vx = GetVpValue(x, 0);
|
|
3966
|
-
break;
|
|
3967
|
-
|
|
3968
|
-
case T_FLOAT:
|
|
3969
|
-
flo = RFLOAT_VALUE(x);
|
|
3970
|
-
negative = flo < 0;
|
|
3971
|
-
infinite = isinf(flo);
|
|
3972
|
-
nan = isnan(flo);
|
|
3973
|
-
if (!infinite && !nan) {
|
|
3974
|
-
vx = GetVpValueWithPrec(x, 0, 0);
|
|
3975
|
-
}
|
|
3976
|
-
break;
|
|
3977
|
-
|
|
3978
|
-
case T_RATIONAL:
|
|
3979
|
-
vx = GetVpValueWithPrec(x, prec, 0);
|
|
3980
|
-
break;
|
|
3981
|
-
|
|
3982
|
-
default:
|
|
3983
|
-
break;
|
|
3984
|
-
}
|
|
3985
|
-
if (infinite) {
|
|
3986
|
-
if (negative) {
|
|
3987
|
-
return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
|
|
3988
|
-
}
|
|
3989
|
-
else {
|
|
3990
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3991
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
3992
|
-
RB_GC_GUARD(vy->obj);
|
|
3993
|
-
return VpCheckGetValue(vy);
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3996
|
-
else if (nan) {
|
|
3997
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
3998
|
-
VpSetNaN(vy);
|
|
3999
|
-
RB_GC_GUARD(vy->obj);
|
|
4000
|
-
return VpCheckGetValue(vy);
|
|
4001
|
-
}
|
|
4002
|
-
else if (vx == NULL) {
|
|
4003
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4004
|
-
}
|
|
4005
|
-
x = vx->obj;
|
|
4006
|
-
|
|
4007
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4008
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4009
|
-
if (negative) {
|
|
4010
|
-
VALUE x_zero = INT2NUM(1);
|
|
4011
|
-
VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
|
|
4012
|
-
x = BigDecimal_initialize_copy(x_copy, x);
|
|
4013
|
-
vx = DATA_PTR(x);
|
|
4014
|
-
VpSetSign(vx, 1);
|
|
4015
|
-
}
|
|
4016
|
-
|
|
4017
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4018
|
-
y = one;
|
|
4019
|
-
d = y;
|
|
4020
|
-
i = 1;
|
|
4021
|
-
|
|
4022
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4023
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4024
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4025
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4026
|
-
|
|
4027
|
-
rb_thread_check_ints();
|
|
4028
|
-
|
|
4029
|
-
if (m <= 0) {
|
|
4030
|
-
break;
|
|
4031
|
-
}
|
|
4032
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4033
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4034
|
-
}
|
|
4035
|
-
|
|
4036
|
-
d = BigDecimal_mult(d, x); /* d <- d * x */
|
|
4037
|
-
d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
|
|
4038
|
-
y = BigDecimal_add(y, d); /* y <- y + d */
|
|
4039
|
-
++i; /* i <- i + 1 */
|
|
4040
|
-
}
|
|
4041
|
-
|
|
4042
|
-
if (negative) {
|
|
4043
|
-
return BigDecimal_div2(one, y, vprec);
|
|
4044
|
-
}
|
|
4045
|
-
else {
|
|
4046
|
-
vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
|
|
4047
|
-
return BigDecimal_round(1, &vprec, y);
|
|
4048
|
-
}
|
|
4049
|
-
|
|
4050
|
-
RB_GC_GUARD(one);
|
|
4051
|
-
RB_GC_GUARD(x);
|
|
4052
|
-
RB_GC_GUARD(y);
|
|
4053
|
-
RB_GC_GUARD(d);
|
|
4054
|
-
}
|
|
4055
|
-
|
|
4056
|
-
/* call-seq:
|
|
4057
|
-
* BigMath.log(decimal, numeric) -> BigDecimal
|
|
4058
|
-
*
|
|
4059
|
-
* Computes the natural logarithm of +decimal+ to the specified number of
|
|
4060
|
-
* digits of precision, +numeric+.
|
|
4061
|
-
*
|
|
4062
|
-
* If +decimal+ is zero or negative, raises Math::DomainError.
|
|
4063
|
-
*
|
|
4064
|
-
* If +decimal+ is positive infinity, returns Infinity.
|
|
4065
|
-
*
|
|
4066
|
-
* If +decimal+ is NaN, returns NaN.
|
|
4067
|
-
*/
|
|
4068
|
-
static VALUE
|
|
4069
|
-
BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
|
|
4070
|
-
{
|
|
4071
|
-
ssize_t prec, n, i;
|
|
4072
|
-
SIGNED_VALUE expo;
|
|
4073
|
-
Real* vx = NULL;
|
|
4074
|
-
VALUE vn, one, two, w, x2, y, d;
|
|
4075
|
-
int zero = 0;
|
|
4076
|
-
int negative = 0;
|
|
4077
|
-
int infinite = 0;
|
|
4078
|
-
int nan = 0;
|
|
4079
|
-
double flo;
|
|
4080
|
-
long fix;
|
|
4081
|
-
|
|
4082
|
-
if (!is_integer(vprec)) {
|
|
4083
|
-
rb_raise(rb_eArgError, "precision must be an Integer");
|
|
4084
|
-
}
|
|
4085
|
-
|
|
4086
|
-
prec = NUM2SSIZET(vprec);
|
|
4087
|
-
if (prec <= 0) {
|
|
4088
|
-
rb_raise(rb_eArgError, "Zero or negative precision for exp");
|
|
4089
|
-
}
|
|
4090
|
-
|
|
4091
|
-
/* TODO: the following switch statement is almost same as one in the
|
|
4092
|
-
* BigDecimalCmp function. */
|
|
4093
|
-
switch (TYPE(x)) {
|
|
4094
|
-
case T_DATA:
|
|
4095
|
-
if (!is_kind_of_BigDecimal(x)) break;
|
|
4096
|
-
vx = DATA_PTR(x);
|
|
4097
|
-
zero = VpIsZero(vx);
|
|
4098
|
-
negative = BIGDECIMAL_NEGATIVE_P(vx);
|
|
4099
|
-
infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
|
|
4100
|
-
nan = VpIsNaN(vx);
|
|
4101
|
-
break;
|
|
4102
|
-
|
|
4103
|
-
case T_FIXNUM:
|
|
4104
|
-
fix = FIX2LONG(x);
|
|
4105
|
-
zero = fix == 0;
|
|
4106
|
-
negative = fix < 0;
|
|
4107
|
-
goto get_vp_value;
|
|
4108
|
-
|
|
4109
|
-
case T_BIGNUM:
|
|
4110
|
-
i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
|
|
4111
|
-
zero = i == 0;
|
|
4112
|
-
negative = i < 0;
|
|
4113
|
-
get_vp_value:
|
|
4114
|
-
if (zero || negative) break;
|
|
4115
|
-
vx = GetVpValue(x, 0);
|
|
4116
|
-
break;
|
|
4117
|
-
|
|
4118
|
-
case T_FLOAT:
|
|
4119
|
-
flo = RFLOAT_VALUE(x);
|
|
4120
|
-
zero = flo == 0;
|
|
4121
|
-
negative = flo < 0;
|
|
4122
|
-
infinite = isinf(flo);
|
|
4123
|
-
nan = isnan(flo);
|
|
4124
|
-
if (!zero && !negative && !infinite && !nan) {
|
|
4125
|
-
vx = GetVpValueWithPrec(x, 0, 1);
|
|
4126
|
-
}
|
|
4127
|
-
break;
|
|
4128
|
-
|
|
4129
|
-
case T_RATIONAL:
|
|
4130
|
-
zero = RRATIONAL_ZERO_P(x);
|
|
4131
|
-
negative = RRATIONAL_NEGATIVE_P(x);
|
|
4132
|
-
if (zero || negative) break;
|
|
4133
|
-
vx = GetVpValueWithPrec(x, prec, 1);
|
|
4134
|
-
break;
|
|
4135
|
-
|
|
4136
|
-
case T_COMPLEX:
|
|
4137
|
-
rb_raise(rb_eMathDomainError,
|
|
4138
|
-
"Complex argument for BigMath.log");
|
|
4139
|
-
|
|
4140
|
-
default:
|
|
4141
|
-
break;
|
|
4142
|
-
}
|
|
4143
|
-
if (infinite && !negative) {
|
|
4144
|
-
Real *vy = NewZeroWrapNolimit(1, prec);
|
|
4145
|
-
RB_GC_GUARD(vy->obj);
|
|
4146
|
-
VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
|
|
4147
|
-
return VpCheckGetValue(vy);
|
|
4148
|
-
}
|
|
4149
|
-
else if (nan) {
|
|
4150
|
-
Real* vy = NewZeroWrapNolimit(1, prec);
|
|
4151
|
-
RB_GC_GUARD(vy->obj);
|
|
4152
|
-
VpSetNaN(vy);
|
|
4153
|
-
return VpCheckGetValue(vy);
|
|
4154
|
-
}
|
|
4155
|
-
else if (zero || negative) {
|
|
4156
|
-
rb_raise(rb_eMathDomainError,
|
|
4157
|
-
"Zero or negative argument for log");
|
|
4158
|
-
}
|
|
4159
|
-
else if (vx == NULL) {
|
|
4160
|
-
cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
|
|
4161
|
-
}
|
|
4162
|
-
x = VpCheckGetValue(vx);
|
|
4163
|
-
|
|
4164
|
-
one = VpCheckGetValue(NewOneWrapLimited(1, 1));
|
|
4165
|
-
two = VpCheckGetValue(VpCreateRbObject(1, "2", true));
|
|
4166
|
-
|
|
4167
|
-
n = prec + BIGDECIMAL_DOUBLE_FIGURES;
|
|
4168
|
-
vn = SSIZET2NUM(n);
|
|
4169
|
-
expo = VpExponent10(vx);
|
|
4170
|
-
if (expo < 0 || expo >= 3) {
|
|
4171
|
-
char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
|
|
4172
|
-
snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
|
|
4173
|
-
x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
|
|
4174
|
-
}
|
|
4175
|
-
else {
|
|
4176
|
-
expo = 0;
|
|
4177
|
-
}
|
|
4178
|
-
w = BigDecimal_sub(x, one);
|
|
4179
|
-
x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
|
|
4180
|
-
x2 = BigDecimal_mult2(x, x, vn);
|
|
4181
|
-
y = x;
|
|
4182
|
-
d = y;
|
|
4183
|
-
i = 1;
|
|
4184
|
-
while (!VpIsZero((Real*)DATA_PTR(d))) {
|
|
4185
|
-
SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
|
|
4186
|
-
SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
|
|
4187
|
-
ssize_t m = n - vabs(ey - ed);
|
|
4188
|
-
if (m <= 0) {
|
|
4189
|
-
break;
|
|
4190
|
-
}
|
|
4191
|
-
else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
|
|
4192
|
-
m = BIGDECIMAL_DOUBLE_FIGURES;
|
|
4193
|
-
}
|
|
4194
|
-
|
|
4195
|
-
x = BigDecimal_mult2(x2, x, vn);
|
|
4196
|
-
i += 2;
|
|
4197
|
-
d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
|
|
4198
|
-
y = BigDecimal_add(y, d);
|
|
4199
|
-
}
|
|
4200
|
-
|
|
4201
|
-
y = BigDecimal_mult(y, two);
|
|
4202
|
-
if (expo != 0) {
|
|
4203
|
-
VALUE log10, vexpo, dy;
|
|
4204
|
-
log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
|
|
4205
|
-
vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
|
|
4206
|
-
dy = BigDecimal_mult(log10, vexpo);
|
|
4207
|
-
y = BigDecimal_add(y, dy);
|
|
4208
|
-
}
|
|
4209
|
-
|
|
4210
|
-
RB_GC_GUARD(one);
|
|
4211
|
-
RB_GC_GUARD(two);
|
|
4212
|
-
RB_GC_GUARD(vn);
|
|
4213
|
-
RB_GC_GUARD(x2);
|
|
4214
|
-
RB_GC_GUARD(y);
|
|
4215
|
-
RB_GC_GUARD(d);
|
|
4216
|
-
|
|
4217
|
-
return y;
|
|
3165
|
+
static VALUE
|
|
3166
|
+
BigDecimal_save_limit(VALUE self)
|
|
3167
|
+
{
|
|
3168
|
+
size_t const limit = VpGetPrecLimit();
|
|
3169
|
+
int state;
|
|
3170
|
+
VALUE ret = rb_protect(rb_yield, Qnil, &state);
|
|
3171
|
+
VpSetPrecLimit(limit);
|
|
3172
|
+
if (state) rb_jump_tag(state);
|
|
3173
|
+
return ret;
|
|
4218
3174
|
}
|
|
4219
3175
|
|
|
4220
3176
|
static VALUE BIGDECIMAL_NAN = Qnil;
|
|
@@ -4268,6 +3224,34 @@ BigDecimal_literal(const char *str)
|
|
|
4268
3224
|
|
|
4269
3225
|
#define BIGDECIMAL_LITERAL(var, val) (BIGDECIMAL_ ## var = BigDecimal_literal(#val))
|
|
4270
3226
|
|
|
3227
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3228
|
+
VALUE
|
|
3229
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3230
|
+
BDVALUE a,b,c,d;
|
|
3231
|
+
size_t cn = NUM2INT(cprec);
|
|
3232
|
+
a = GetBDValueMust(self);
|
|
3233
|
+
b = GetBDValueMust(r);
|
|
3234
|
+
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3235
|
+
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3236
|
+
VpDivd(c.real, d.real, a.real, b.real);
|
|
3237
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3238
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3239
|
+
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
VALUE
|
|
3243
|
+
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3244
|
+
BDVALUE a,b,c;
|
|
3245
|
+
a = GetBDValueMust(self);
|
|
3246
|
+
b = GetBDValueMust(v);
|
|
3247
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3248
|
+
VpMult(c.real, a.real, b.real);
|
|
3249
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3250
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3251
|
+
return c.bigdecimal;
|
|
3252
|
+
}
|
|
3253
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3254
|
+
|
|
4271
3255
|
/* Document-class: BigDecimal
|
|
4272
3256
|
* BigDecimal provides arbitrary-precision floating point decimal arithmetic.
|
|
4273
3257
|
*
|
|
@@ -4384,14 +3368,16 @@ BigDecimal_literal(const char *str)
|
|
|
4384
3368
|
*
|
|
4385
3369
|
* When you require +bigdecimal/util+, the #to_d method will be
|
|
4386
3370
|
* available on BigDecimal and the native Integer, Float, Rational,
|
|
4387
|
-
* and
|
|
3371
|
+
* String, Complex, and NilClass classes:
|
|
4388
3372
|
*
|
|
4389
3373
|
* require 'bigdecimal/util'
|
|
4390
3374
|
*
|
|
4391
|
-
* 42.to_d
|
|
4392
|
-
* 0.5.to_d
|
|
4393
|
-
* (2/3r).to_d(3)
|
|
4394
|
-
* "0.5".to_d
|
|
3375
|
+
* 42.to_d # => 0.42e2
|
|
3376
|
+
* 0.5.to_d # => 0.5e0
|
|
3377
|
+
* (2/3r).to_d(3) # => 0.667e0
|
|
3378
|
+
* "0.5".to_d # => 0.5e0
|
|
3379
|
+
* Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
|
3380
|
+
* nil.to_d # => 0.0
|
|
4395
3381
|
*
|
|
4396
3382
|
* == Methods for Working with \JSON
|
|
4397
3383
|
*
|
|
@@ -4465,7 +3451,7 @@ Init_bigdecimal(void)
|
|
|
4465
3451
|
* guarantee that two groups could always be multiplied together without
|
|
4466
3452
|
* overflow.)
|
|
4467
3453
|
*/
|
|
4468
|
-
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)
|
|
3454
|
+
rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)BASE));
|
|
4469
3455
|
|
|
4470
3456
|
/* Exceptions */
|
|
4471
3457
|
|
|
@@ -4576,7 +3562,6 @@ Init_bigdecimal(void)
|
|
|
4576
3562
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
4577
3563
|
|
|
4578
3564
|
/* instance methods */
|
|
4579
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
4580
3565
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
4581
3566
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
4582
3567
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -4607,14 +3592,11 @@ Init_bigdecimal(void)
|
|
|
4607
3592
|
rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
|
|
4608
3593
|
rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
|
|
4609
3594
|
rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
|
|
4610
|
-
rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
|
|
4611
3595
|
rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
|
|
4612
3596
|
rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
|
|
4613
3597
|
rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
|
|
4614
3598
|
rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
|
|
4615
3599
|
rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
|
|
4616
|
-
rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
|
|
4617
|
-
rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
|
|
4618
3600
|
rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
|
|
4619
3601
|
rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
|
|
4620
3602
|
rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
|
|
@@ -4633,11 +3615,13 @@ Init_bigdecimal(void)
|
|
|
4633
3615
|
rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
|
|
4634
3616
|
rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
|
|
4635
3617
|
rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
|
|
3618
|
+
rb_define_method(rb_cBigDecimal, "_decimal_shift", BigDecimal_decimal_shift, 1);
|
|
4636
3619
|
rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
|
|
4637
3620
|
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
3621
|
+
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3622
|
+
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3623
|
+
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3624
|
+
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
4641
3625
|
|
|
4642
3626
|
#define ROUNDING_MODE(i, name, value) \
|
|
4643
3627
|
id_##name = rb_intern_const(#name); \
|
|
@@ -4677,19 +3661,9 @@ Init_bigdecimal(void)
|
|
|
4677
3661
|
*/
|
|
4678
3662
|
#ifdef BIGDECIMAL_DEBUG
|
|
4679
3663
|
static int gfDebug = 1; /* Debug switch */
|
|
4680
|
-
#if 0
|
|
4681
|
-
static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
|
|
4682
|
-
#endif
|
|
4683
3664
|
#endif /* BIGDECIMAL_DEBUG */
|
|
4684
3665
|
|
|
4685
3666
|
static Real *VpConstOne; /* constant 1.0 */
|
|
4686
|
-
static Real *VpConstPt5; /* constant 0.5 */
|
|
4687
|
-
#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
|
|
4688
|
-
/* used in VpSqrt() */
|
|
4689
|
-
|
|
4690
|
-
/* ETC */
|
|
4691
|
-
#define MemCmp(x,y,z) memcmp(x,y,z)
|
|
4692
|
-
#define StrCmp(x,y) strcmp(x,y)
|
|
4693
3667
|
|
|
4694
3668
|
enum op_sw {
|
|
4695
3669
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4699,11 +3673,9 @@ enum op_sw {
|
|
|
4699
3673
|
};
|
|
4700
3674
|
|
|
4701
3675
|
static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
|
|
4702
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
4703
3676
|
static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
|
|
4704
3677
|
static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
|
|
4705
3678
|
static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
|
|
4706
|
-
static int VpNmlz(Real *a);
|
|
4707
3679
|
static void VpFormatSt(char *psz, size_t fFmt);
|
|
4708
3680
|
static int VpRdup(Real *m, size_t ind_m);
|
|
4709
3681
|
|
|
@@ -4762,10 +3734,10 @@ VpCheckException(Real *p, bool always)
|
|
|
4762
3734
|
}
|
|
4763
3735
|
|
|
4764
3736
|
static VALUE
|
|
4765
|
-
|
|
3737
|
+
CheckGetValue(BDVALUE v)
|
|
4766
3738
|
{
|
|
4767
|
-
VpCheckException(
|
|
4768
|
-
return
|
|
3739
|
+
VpCheckException(v.real, false);
|
|
3740
|
+
return v.bigdecimal;
|
|
4769
3741
|
}
|
|
4770
3742
|
|
|
4771
3743
|
/*
|
|
@@ -4797,12 +3769,10 @@ VpGetPrecLimit(void)
|
|
|
4797
3769
|
return NUM2SIZET(vlimit);
|
|
4798
3770
|
}
|
|
4799
3771
|
|
|
4800
|
-
VP_EXPORT
|
|
3772
|
+
VP_EXPORT void
|
|
4801
3773
|
VpSetPrecLimit(size_t n)
|
|
4802
3774
|
{
|
|
4803
|
-
size_t const s = VpGetPrecLimit();
|
|
4804
3775
|
bigdecimal_set_thread_local_precision_limit(n);
|
|
4805
|
-
return s;
|
|
4806
3776
|
}
|
|
4807
3777
|
|
|
4808
3778
|
/*
|
|
@@ -4917,15 +3887,6 @@ VpGetDoubleNegZero(void) /* Returns the value of -0 */
|
|
|
4917
3887
|
return nzero;
|
|
4918
3888
|
}
|
|
4919
3889
|
|
|
4920
|
-
#if 0 /* unused */
|
|
4921
|
-
VP_EXPORT int
|
|
4922
|
-
VpIsNegDoubleZero(double v)
|
|
4923
|
-
{
|
|
4924
|
-
double z = VpGetDoubleNegZero();
|
|
4925
|
-
return MemCmp(&v,&z,sizeof(v))==0;
|
|
4926
|
-
}
|
|
4927
|
-
#endif
|
|
4928
|
-
|
|
4929
3890
|
VP_EXPORT int
|
|
4930
3891
|
VpException(unsigned short f, const char *str,int always)
|
|
4931
3892
|
{
|
|
@@ -5077,7 +4038,7 @@ VpNumOfChars(Real *vp,const char *pszFmt)
|
|
|
5077
4038
|
case 'E':
|
|
5078
4039
|
/* fall through */
|
|
5079
4040
|
default:
|
|
5080
|
-
nc = BASE_FIG*
|
|
4041
|
+
nc = BASE_FIG * vp->Prec + 25; /* "-0."(3) + digits_chars + "e-"(2) + 64bit_exponent_chars(19) + null(1) */
|
|
5081
4042
|
}
|
|
5082
4043
|
return nc;
|
|
5083
4044
|
}
|
|
@@ -5103,28 +4064,13 @@ VpInit(DECDIG BaseVal)
|
|
|
5103
4064
|
VpGetDoubleNegZero();
|
|
5104
4065
|
|
|
5105
4066
|
/* Const 1.0 */
|
|
5106
|
-
VpConstOne =
|
|
5107
|
-
|
|
5108
|
-
/* Const 0.5 */
|
|
5109
|
-
VpConstPt5 = NewOneNolimit(1, 1);
|
|
5110
|
-
VpConstPt5->exponent = 0;
|
|
5111
|
-
VpConstPt5->frac[0] = 5*BASE1;
|
|
4067
|
+
VpConstOne = NewZero(1, 1);
|
|
4068
|
+
VpSetOne(VpConstOne);
|
|
5112
4069
|
|
|
5113
4070
|
#ifdef BIGDECIMAL_DEBUG
|
|
5114
4071
|
gnAlloc = 0;
|
|
5115
4072
|
#endif /* BIGDECIMAL_DEBUG */
|
|
5116
4073
|
|
|
5117
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5118
|
-
if (gfDebug) {
|
|
5119
|
-
printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
|
|
5120
|
-
printf("\tBASE = %"PRIuDECDIG"\n", BASE);
|
|
5121
|
-
printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
|
|
5122
|
-
printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
|
|
5123
|
-
printf("\tBASE_FIG = %u\n", BASE_FIG);
|
|
5124
|
-
printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
5125
|
-
}
|
|
5126
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5127
|
-
|
|
5128
4074
|
return BIGDECIMAL_DOUBLE_FIGURES;
|
|
5129
4075
|
}
|
|
5130
4076
|
|
|
@@ -5140,24 +4086,14 @@ AddExponent(Real *a, SIGNED_VALUE n)
|
|
|
5140
4086
|
{
|
|
5141
4087
|
SIGNED_VALUE e = a->exponent;
|
|
5142
4088
|
SIGNED_VALUE m = e+n;
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
if (eb - mb > 0) goto overflow;
|
|
5152
|
-
}
|
|
5153
|
-
}
|
|
5154
|
-
else if (n < 0) {
|
|
5155
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
|
|
5156
|
-
MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
5157
|
-
goto underflow;
|
|
5158
|
-
mb = m*(SIGNED_VALUE)BASE_FIG;
|
|
5159
|
-
eb = e*(SIGNED_VALUE)BASE_FIG;
|
|
5160
|
-
if (mb - eb > 0) goto underflow;
|
|
4089
|
+
if (e > 0 && n > 0) {
|
|
4090
|
+
if (n > VP_EXPONENT_MAX - e) goto overflow;
|
|
4091
|
+
} else if (e < 0 && n < 0) {
|
|
4092
|
+
if (n < VP_EXPONENT_MIN - e) goto underflow;
|
|
4093
|
+
} else if (m > VP_EXPONENT_MAX) {
|
|
4094
|
+
goto overflow;
|
|
4095
|
+
} else if (m < VP_EXPONENT_MIN) {
|
|
4096
|
+
goto underflow;
|
|
5161
4097
|
}
|
|
5162
4098
|
a->exponent = m;
|
|
5163
4099
|
return 1;
|
|
@@ -5198,7 +4134,6 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
5198
4134
|
while (*p && ISSPACE(*p)) ++p;
|
|
5199
4135
|
if (*p == '\0') {
|
|
5200
4136
|
Real *vp = rbd_allocate_struct(1);
|
|
5201
|
-
vp->MaxPrec = 1;
|
|
5202
4137
|
switch (table[i].sign) {
|
|
5203
4138
|
default:
|
|
5204
4139
|
UNREACHABLE; break;
|
|
@@ -5263,38 +4198,22 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
5263
4198
|
/*
|
|
5264
4199
|
* Allocates variable.
|
|
5265
4200
|
* [Input]
|
|
5266
|
-
*
|
|
5267
|
-
* The mx will be the number of significant digits can to be stored.
|
|
5268
|
-
* szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
|
|
5269
|
-
* If szVal[0]=='#' then MaxPrec is not affected by the precision limit
|
|
5270
|
-
* so that the full precision specified by szVal is allocated.
|
|
4201
|
+
* szVal ... The value assigned(char).
|
|
5271
4202
|
*
|
|
5272
4203
|
* [Returns]
|
|
5273
4204
|
* Pointer to the newly allocated variable, or
|
|
5274
4205
|
* NULL be returned if memory allocation is failed,or any error.
|
|
5275
4206
|
*/
|
|
5276
4207
|
VP_EXPORT Real *
|
|
5277
|
-
VpAlloc(
|
|
4208
|
+
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
5278
4209
|
{
|
|
5279
4210
|
const char *orig_szVal = szVal;
|
|
5280
4211
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
5281
|
-
size_t len;
|
|
5282
4212
|
char v, *psz;
|
|
5283
4213
|
int sign=1;
|
|
5284
4214
|
Real *vp = NULL;
|
|
5285
4215
|
VALUE buf;
|
|
5286
4216
|
|
|
5287
|
-
if (szVal == NULL) {
|
|
5288
|
-
return_zero:
|
|
5289
|
-
/* necessary to be able to store */
|
|
5290
|
-
/* at least mx digits. */
|
|
5291
|
-
/* szVal==NULL ==> allocate zero value. */
|
|
5292
|
-
vp = rbd_allocate_struct(mx);
|
|
5293
|
-
vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
|
|
5294
|
-
VpSetZero(vp, 1); /* initialize vp to zero. */
|
|
5295
|
-
return vp;
|
|
5296
|
-
}
|
|
5297
|
-
|
|
5298
4217
|
/* Skipping leading spaces */
|
|
5299
4218
|
while (ISSPACE(*szVal)) szVal++;
|
|
5300
4219
|
|
|
@@ -5303,14 +4222,11 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5303
4222
|
return vp;
|
|
5304
4223
|
}
|
|
5305
4224
|
|
|
5306
|
-
/*
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
len = rbd_calculate_internal_digits(mx, false);
|
|
5312
|
-
++szVal;
|
|
5313
|
-
}
|
|
4225
|
+
/* Skip leading `#`.
|
|
4226
|
+
* It used to be a mark to indicate that an extra MaxPrec should be allocated,
|
|
4227
|
+
* but now it has no effect.
|
|
4228
|
+
*/
|
|
4229
|
+
if (*szVal == '#') ++szVal;
|
|
5314
4230
|
|
|
5315
4231
|
/* Scanning digits */
|
|
5316
4232
|
|
|
@@ -5457,7 +4373,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5457
4373
|
VALUE str;
|
|
5458
4374
|
invalid_value:
|
|
5459
4375
|
if (!strict_p) {
|
|
5460
|
-
|
|
4376
|
+
return NewZero(1, 1);
|
|
5461
4377
|
}
|
|
5462
4378
|
if (!exc) {
|
|
5463
4379
|
return NULL;
|
|
@@ -5468,11 +4384,7 @@ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
|
|
|
5468
4384
|
|
|
5469
4385
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
5470
4386
|
/* units for szVal[] */
|
|
5471
|
-
|
|
5472
|
-
nalloc = Max(nalloc, len);
|
|
5473
|
-
len = nalloc;
|
|
5474
|
-
vp = rbd_allocate_struct(len);
|
|
5475
|
-
vp->MaxPrec = len; /* set max precision */
|
|
4387
|
+
vp = rbd_allocate_struct(nalloc);
|
|
5476
4388
|
VpSetZero(vp, sign);
|
|
5477
4389
|
protected_VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne, true);
|
|
5478
4390
|
rb_str_resize(buf, 0);
|
|
@@ -5512,7 +4424,7 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5512
4424
|
c->Prec = n;
|
|
5513
4425
|
memcpy(c->frac, a->frac, n * sizeof(DECDIG));
|
|
5514
4426
|
/* Needs round ? */
|
|
5515
|
-
if (isw != 10) {
|
|
4427
|
+
if (isw != 10 && isw != -10) {
|
|
5516
4428
|
/* Not in ActiveRound */
|
|
5517
4429
|
if(c->Prec < a->Prec) {
|
|
5518
4430
|
VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
|
|
@@ -5538,19 +4450,11 @@ VpAsgn(Real *c, Real *a, int isw)
|
|
|
5538
4450
|
VP_EXPORT size_t
|
|
5539
4451
|
VpAddSub(Real *c, Real *a, Real *b, int operation)
|
|
5540
4452
|
{
|
|
5541
|
-
short sw, isw;
|
|
4453
|
+
short sw, isw, sign;
|
|
5542
4454
|
Real *a_ptr, *b_ptr;
|
|
5543
4455
|
size_t n, na, nb, i;
|
|
5544
4456
|
DECDIG mrv;
|
|
5545
4457
|
|
|
5546
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5547
|
-
if (gfDebug) {
|
|
5548
|
-
VPrint(stdout, "VpAddSub(enter) a=% \n", a);
|
|
5549
|
-
VPrint(stdout, " b=% \n", b);
|
|
5550
|
-
printf(" operation=%d\n", operation);
|
|
5551
|
-
}
|
|
5552
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5553
|
-
|
|
5554
4458
|
if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
|
|
5555
4459
|
|
|
5556
4460
|
/* check if a or b is zero */
|
|
@@ -5639,28 +4543,21 @@ end_if:
|
|
|
5639
4543
|
if (isw) { /* addition */
|
|
5640
4544
|
VpSetSign(c, 1);
|
|
5641
4545
|
mrv = VpAddAbs(a_ptr, b_ptr, c);
|
|
5642
|
-
|
|
4546
|
+
sign = isw / 2;
|
|
5643
4547
|
}
|
|
5644
4548
|
else { /* subtraction */
|
|
5645
4549
|
VpSetSign(c, 1);
|
|
5646
4550
|
mrv = VpSubAbs(a_ptr, b_ptr, c);
|
|
5647
|
-
|
|
5648
|
-
VpSetSign(c,VpGetSign(a));
|
|
5649
|
-
}
|
|
5650
|
-
else {
|
|
5651
|
-
VpSetSign(c, VpGetSign(a_ptr) * sw);
|
|
5652
|
-
}
|
|
4551
|
+
sign = a_ptr == a ? VpGetSign(a) : VpGetSign(a_ptr) * sw;
|
|
5653
4552
|
}
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5657
|
-
if (gfDebug) {
|
|
5658
|
-
VPrint(stdout, "VpAddSub(result) c=% \n", c);
|
|
5659
|
-
VPrint(stdout, " a=% \n", a);
|
|
5660
|
-
VPrint(stdout, " b=% \n", b);
|
|
5661
|
-
printf(" operation=%d\n", operation);
|
|
4553
|
+
if (VpIsInf(c)) {
|
|
4554
|
+
VpSetInf(c, sign);
|
|
5662
4555
|
}
|
|
5663
|
-
|
|
4556
|
+
else {
|
|
4557
|
+
VpSetSign(c, sign);
|
|
4558
|
+
VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
|
|
4559
|
+
}
|
|
4560
|
+
|
|
5664
4561
|
return c->Prec * BASE_FIG;
|
|
5665
4562
|
}
|
|
5666
4563
|
|
|
@@ -5681,13 +4578,6 @@ VpAddAbs(Real *a, Real *b, Real *c)
|
|
|
5681
4578
|
size_t c_pos;
|
|
5682
4579
|
DECDIG av, bv, carry, mrv;
|
|
5683
4580
|
|
|
5684
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5685
|
-
if (gfDebug) {
|
|
5686
|
-
VPrint(stdout, "VpAddAbs called: a = %\n", a);
|
|
5687
|
-
VPrint(stdout, " b = %\n", b);
|
|
5688
|
-
}
|
|
5689
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5690
|
-
|
|
5691
4581
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5692
4582
|
a_pos = ap;
|
|
5693
4583
|
b_pos = bp;
|
|
@@ -5753,11 +4643,6 @@ Assign_a:
|
|
|
5753
4643
|
|
|
5754
4644
|
Exit:
|
|
5755
4645
|
|
|
5756
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5757
|
-
if (gfDebug) {
|
|
5758
|
-
VPrint(stdout, "VpAddAbs exit: c=% \n", c);
|
|
5759
|
-
}
|
|
5760
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5761
4646
|
return mrv;
|
|
5762
4647
|
}
|
|
5763
4648
|
|
|
@@ -5776,13 +4661,6 @@ VpSubAbs(Real *a, Real *b, Real *c)
|
|
|
5776
4661
|
size_t c_pos;
|
|
5777
4662
|
DECDIG av, bv, borrow, mrv;
|
|
5778
4663
|
|
|
5779
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5780
|
-
if (gfDebug) {
|
|
5781
|
-
VPrint(stdout, "VpSubAbs called: a = %\n", a);
|
|
5782
|
-
VPrint(stdout, " b = %\n", b);
|
|
5783
|
-
}
|
|
5784
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5785
|
-
|
|
5786
4664
|
word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
|
|
5787
4665
|
a_pos = ap;
|
|
5788
4666
|
b_pos = bp;
|
|
@@ -5858,11 +4736,6 @@ Assign_a:
|
|
|
5858
4736
|
mrv = 0;
|
|
5859
4737
|
|
|
5860
4738
|
Exit:
|
|
5861
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
5862
|
-
if (gfDebug) {
|
|
5863
|
-
VPrint(stdout, "VpSubAbs exit: c=% \n", c);
|
|
5864
|
-
}
|
|
5865
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
5866
4739
|
return mrv;
|
|
5867
4740
|
}
|
|
5868
4741
|
|
|
@@ -5993,19 +4866,11 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
5993
4866
|
VP_EXPORT size_t
|
|
5994
4867
|
VpMult(Real *c, Real *a, Real *b)
|
|
5995
4868
|
{
|
|
5996
|
-
size_t MxIndA, MxIndB, MxIndAB
|
|
4869
|
+
size_t MxIndA, MxIndB, MxIndAB;
|
|
5997
4870
|
size_t ind_c, i, ii, nc;
|
|
5998
4871
|
size_t ind_as, ind_ae, ind_bs;
|
|
5999
4872
|
DECDIG carry;
|
|
6000
4873
|
DECDIG_DBL s;
|
|
6001
|
-
Real *w;
|
|
6002
|
-
|
|
6003
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6004
|
-
if (gfDebug) {
|
|
6005
|
-
VPrint(stdout, "VpMult(Enter): a=% \n", a);
|
|
6006
|
-
VPrint(stdout, " b=% \n", b);
|
|
6007
|
-
}
|
|
6008
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6009
4874
|
|
|
6010
4875
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
6011
4876
|
|
|
@@ -6016,39 +4881,28 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6016
4881
|
}
|
|
6017
4882
|
|
|
6018
4883
|
if (VpIsOne(a)) {
|
|
6019
|
-
VpAsgn(c, b, VpGetSign(a));
|
|
4884
|
+
VpAsgn(c, b, 10 * VpGetSign(a));
|
|
6020
4885
|
goto Exit;
|
|
6021
4886
|
}
|
|
6022
4887
|
if (VpIsOne(b)) {
|
|
6023
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
4888
|
+
VpAsgn(c, a, 10 * VpGetSign(b));
|
|
6024
4889
|
goto Exit;
|
|
6025
4890
|
}
|
|
6026
4891
|
if (b->Prec > a->Prec) {
|
|
6027
4892
|
/* Adjust so that digits(a)>digits(b) */
|
|
6028
|
-
w = a;
|
|
4893
|
+
Real *w = a;
|
|
6029
4894
|
a = b;
|
|
6030
4895
|
b = w;
|
|
6031
4896
|
}
|
|
6032
|
-
w = NULL;
|
|
6033
4897
|
MxIndA = a->Prec - 1;
|
|
6034
4898
|
MxIndB = b->Prec - 1;
|
|
6035
|
-
MxIndC = c->MaxPrec - 1;
|
|
6036
4899
|
MxIndAB = a->Prec + b->Prec - 1;
|
|
6037
4900
|
|
|
6038
|
-
if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
|
|
6039
|
-
w = c;
|
|
6040
|
-
c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
|
|
6041
|
-
MxIndC = MxIndAB;
|
|
6042
|
-
}
|
|
6043
|
-
|
|
6044
4901
|
/* set LHSV c info */
|
|
6045
4902
|
|
|
6046
4903
|
c->exponent = a->exponent; /* set exponent */
|
|
6047
|
-
if (!AddExponent(c, b->exponent)) {
|
|
6048
|
-
if (w) rbd_free_struct(c);
|
|
6049
|
-
return 0;
|
|
6050
|
-
}
|
|
6051
4904
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4905
|
+
if (!AddExponent(c, b->exponent)) return 0;
|
|
6052
4906
|
carry = 0;
|
|
6053
4907
|
nc = ind_c = MxIndAB;
|
|
6054
4908
|
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
|
@@ -6095,29 +4949,18 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
6095
4949
|
}
|
|
6096
4950
|
}
|
|
6097
4951
|
}
|
|
6098
|
-
|
|
6099
|
-
VpNmlz(c);
|
|
6100
|
-
VpAsgn(w, c, 1);
|
|
6101
|
-
rbd_free_struct(c);
|
|
6102
|
-
c = w;
|
|
6103
|
-
}
|
|
6104
|
-
else {
|
|
6105
|
-
VpLimitRound(c,0);
|
|
6106
|
-
}
|
|
4952
|
+
VpNmlz(c);
|
|
6107
4953
|
|
|
6108
4954
|
Exit:
|
|
6109
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6110
|
-
if (gfDebug) {
|
|
6111
|
-
VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
|
|
6112
|
-
VPrint(stdout, " a=% \n", a);
|
|
6113
|
-
VPrint(stdout, " b=% \n", b);
|
|
6114
|
-
}
|
|
6115
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6116
4955
|
return c->Prec*BASE_FIG;
|
|
6117
4956
|
}
|
|
6118
4957
|
|
|
6119
4958
|
/*
|
|
6120
4959
|
* c = a / b, remainder = r
|
|
4960
|
+
* XXXX_YYYY_ZZZZ / 0001 = XXXX_YYYY_ZZZZ
|
|
4961
|
+
* XXXX_YYYY_ZZZZ / 1111 = 000X_000Y_000Z
|
|
4962
|
+
* 00XX_XXYY_YYZZ / 1000 = 0000_0XXX_XYYY
|
|
4963
|
+
* 0001_0000_0000 / 9999 = 0000_0001_0001
|
|
6121
4964
|
*/
|
|
6122
4965
|
VP_EXPORT size_t
|
|
6123
4966
|
VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
@@ -6126,16 +4969,9 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6126
4969
|
size_t i, n, ind_a, ind_b, ind_c, ind_r;
|
|
6127
4970
|
size_t nLoop;
|
|
6128
4971
|
DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
|
|
6129
|
-
DECDIG
|
|
4972
|
+
DECDIG borrow1, borrow2;
|
|
6130
4973
|
DECDIG_DBL qb;
|
|
6131
4974
|
|
|
6132
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6133
|
-
if (gfDebug) {
|
|
6134
|
-
VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
|
|
6135
|
-
VPrint(stdout, " b=% \n", b);
|
|
6136
|
-
}
|
|
6137
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
6138
|
-
|
|
6139
4975
|
VpSetNaN(r);
|
|
6140
4976
|
if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
|
|
6141
4977
|
if (VpIsZero(a) && VpIsZero(b)) {
|
|
@@ -6152,30 +4988,17 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6152
4988
|
VpSetZero(r, VpGetSign(a) * VpGetSign(b));
|
|
6153
4989
|
goto Exit;
|
|
6154
4990
|
}
|
|
6155
|
-
if (VpIsOne(b)) {
|
|
6156
|
-
/* divide by one */
|
|
6157
|
-
VpAsgn(c, a, VpGetSign(b));
|
|
6158
|
-
VpSetZero(r, VpGetSign(a));
|
|
6159
|
-
goto Exit;
|
|
6160
|
-
}
|
|
6161
4991
|
|
|
6162
4992
|
word_a = a->Prec;
|
|
6163
4993
|
word_b = b->Prec;
|
|
6164
4994
|
word_c = c->MaxPrec;
|
|
6165
4995
|
word_r = r->MaxPrec;
|
|
6166
4996
|
|
|
6167
|
-
if (word_a >= word_r) goto space_error;
|
|
4997
|
+
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
6168
4998
|
|
|
6169
|
-
|
|
6170
|
-
r->frac[
|
|
6171
|
-
|
|
6172
|
-
r->frac[ind_r] = a->frac[ind_r - 1];
|
|
6173
|
-
++ind_r;
|
|
6174
|
-
}
|
|
6175
|
-
while (ind_r < word_r) r->frac[ind_r++] = 0;
|
|
6176
|
-
|
|
6177
|
-
ind_c = 0;
|
|
6178
|
-
while (ind_c < word_c) c->frac[ind_c++] = 0;
|
|
4999
|
+
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5000
|
+
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5001
|
+
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
6179
5002
|
|
|
6180
5003
|
/* initial procedure */
|
|
6181
5004
|
b1 = b1p1 = b->frac[0];
|
|
@@ -6190,15 +5013,14 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6190
5013
|
|
|
6191
5014
|
/* */
|
|
6192
5015
|
/* loop start */
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
ind_c = 1;
|
|
5016
|
+
nLoop = Min(word_c, word_r);
|
|
5017
|
+
ind_c = 0;
|
|
6196
5018
|
while (ind_c < nLoop) {
|
|
6197
5019
|
if (r->frac[ind_c] == 0) {
|
|
6198
5020
|
++ind_c;
|
|
6199
5021
|
continue;
|
|
6200
5022
|
}
|
|
6201
|
-
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
|
|
5023
|
+
r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + (ind_c + 1 < word_r ? r->frac[ind_c + 1] : 0);
|
|
6202
5024
|
if (r1r2 == b1b2) {
|
|
6203
5025
|
/* The first two word digits is the same */
|
|
6204
5026
|
ind_b = 2;
|
|
@@ -6211,26 +5033,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
6211
5033
|
}
|
|
6212
5034
|
/* The first few word digits of r and b is the same and */
|
|
6213
5035
|
/* the first different word digit of w is greater than that */
|
|
6214
|
-
/* of b, so quotient is 1
|
|
6215
|
-
|
|
6216
|
-
ind_b = b->Prec - 1;
|
|
6217
|
-
ind_r = ind_c + ind_b;
|
|
6218
|
-
if (ind_r >= word_r) goto space_error;
|
|
6219
|
-
n = ind_b;
|
|
6220
|
-
for (i = 0; i <= n; ++i) {
|
|
6221
|
-
if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
|
|
6222
|
-
r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
|
|
6223
|
-
borrow = 1;
|
|
6224
|
-
}
|
|
6225
|
-
else {
|
|
6226
|
-
r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
|
|
6227
|
-
borrow = 0;
|
|
6228
|
-
}
|
|
6229
|
-
--ind_r;
|
|
6230
|
-
--ind_b;
|
|
6231
|
-
}
|
|
5036
|
+
/* of b, so quotient is 1. */
|
|
5037
|
+
q = 1;
|
|
6232
5038
|
++c->frac[ind_c];
|
|
6233
|
-
|
|
5039
|
+
ind_r = b->Prec + ind_c - 1;
|
|
5040
|
+
goto sub_mult;
|
|
6234
5041
|
}
|
|
6235
5042
|
/* The first two word digits is not the same, */
|
|
6236
5043
|
/* then compare magnitude, and divide actually. */
|
|
@@ -6283,49 +5090,26 @@ sub_mult:
|
|
|
6283
5090
|
}
|
|
6284
5091
|
|
|
6285
5092
|
r->frac[ind_r] -= borrow2;
|
|
6286
|
-
carry:
|
|
6287
|
-
ind_r = ind_c;
|
|
6288
|
-
while (c->frac[ind_r] >= BASE) {
|
|
6289
|
-
c->frac[ind_r] -= BASE;
|
|
6290
|
-
--ind_r;
|
|
6291
|
-
++c->frac[ind_r];
|
|
6292
|
-
}
|
|
6293
5093
|
}
|
|
6294
5094
|
/* End of operation, now final arrangement */
|
|
6295
5095
|
out_side:
|
|
6296
5096
|
c->Prec = word_c;
|
|
6297
5097
|
c->exponent = a->exponent;
|
|
6298
|
-
|
|
5098
|
+
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
5099
|
+
if (!AddExponent(c, 1)) return 0;
|
|
6299
5100
|
if (!AddExponent(c, -(b->exponent))) return 0;
|
|
6300
5101
|
|
|
6301
|
-
VpSetSign(c, VpGetSign(a) * VpGetSign(b));
|
|
6302
5102
|
VpNmlz(c); /* normalize c */
|
|
6303
5103
|
r->Prec = word_r;
|
|
6304
5104
|
r->exponent = a->exponent;
|
|
6305
|
-
if (!AddExponent(r, 1)) return 0;
|
|
6306
5105
|
VpSetSign(r, VpGetSign(a));
|
|
6307
5106
|
VpNmlz(r); /* normalize r(remainder) */
|
|
6308
5107
|
goto Exit;
|
|
6309
5108
|
|
|
6310
5109
|
space_error:
|
|
6311
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6312
|
-
if (gfDebug) {
|
|
6313
|
-
printf(" word_a=%"PRIuSIZE"\n", word_a);
|
|
6314
|
-
printf(" word_b=%"PRIuSIZE"\n", word_b);
|
|
6315
|
-
printf(" word_c=%"PRIuSIZE"\n", word_c);
|
|
6316
|
-
printf(" word_r=%"PRIuSIZE"\n", word_r);
|
|
6317
|
-
printf(" ind_r =%"PRIuSIZE"\n", ind_r);
|
|
6318
|
-
}
|
|
6319
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6320
5110
|
rb_bug("ERROR(VpDivd): space for remainder too small.");
|
|
6321
5111
|
|
|
6322
5112
|
Exit:
|
|
6323
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6324
|
-
if (gfDebug) {
|
|
6325
|
-
VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
|
|
6326
|
-
VPrint(stdout, " r=% \n", r);
|
|
6327
|
-
}
|
|
6328
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6329
5113
|
return c->Prec * BASE_FIG;
|
|
6330
5114
|
}
|
|
6331
5115
|
|
|
@@ -6448,13 +5232,6 @@ Exit:
|
|
|
6448
5232
|
if (val > 1) val = 1;
|
|
6449
5233
|
else if (val < -1) val = -1;
|
|
6450
5234
|
|
|
6451
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
6452
|
-
if (gfDebug) {
|
|
6453
|
-
VPrint(stdout, " VpComp a=%\n", a);
|
|
6454
|
-
VPrint(stdout, " b=%\n", b);
|
|
6455
|
-
printf(" ans=%d\n", val);
|
|
6456
|
-
}
|
|
6457
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
6458
5235
|
return (int)val;
|
|
6459
5236
|
}
|
|
6460
5237
|
|
|
@@ -6572,25 +5349,29 @@ VPrint(FILE *fp, const char *cntl_chr, Real *a)
|
|
|
6572
5349
|
static void
|
|
6573
5350
|
VpFormatSt(char *psz, size_t fFmt)
|
|
6574
5351
|
{
|
|
6575
|
-
size_t
|
|
6576
|
-
char
|
|
5352
|
+
size_t iend, idig = 0, iexp = 0, nspaces;
|
|
5353
|
+
char *p;
|
|
6577
5354
|
|
|
6578
5355
|
if (fFmt == 0) return;
|
|
6579
5356
|
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
5357
|
+
iend = strlen(psz);
|
|
5358
|
+
|
|
5359
|
+
if ((p = strchr(psz, '.'))) {
|
|
5360
|
+
idig = (p - psz) + 1;
|
|
5361
|
+
}
|
|
5362
|
+
if ((p = strchr(psz, 'E')) || (p = strchr(psz, 'e'))) {
|
|
5363
|
+
iexp = p - psz;
|
|
5364
|
+
}
|
|
5365
|
+
if (idig == 0 || idig > iexp) return;
|
|
5366
|
+
|
|
5367
|
+
nspaces = (iexp - idig - 1) / fFmt;
|
|
5368
|
+
p = psz + iend + 1;
|
|
5369
|
+
for (size_t i = nspaces; i > 0; i--) {
|
|
5370
|
+
char *src = psz + idig + i * fFmt;
|
|
5371
|
+
char *dst = psz + idig + i * (fFmt + 1);
|
|
5372
|
+
memmove(dst, src, p - src);
|
|
5373
|
+
dst[-1] = ' ';
|
|
5374
|
+
p = src;
|
|
6594
5375
|
}
|
|
6595
5376
|
}
|
|
6596
5377
|
|
|
@@ -6872,7 +5653,7 @@ VP_EXPORT int
|
|
|
6872
5653
|
VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
|
|
6873
5654
|
{
|
|
6874
5655
|
size_t i, j, ind_a, ma, mi, me;
|
|
6875
|
-
SIGNED_VALUE e
|
|
5656
|
+
SIGNED_VALUE e;
|
|
6876
5657
|
int sign, signe, exponent_overflow;
|
|
6877
5658
|
|
|
6878
5659
|
/* get exponent part */
|
|
@@ -6895,23 +5676,13 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6895
5676
|
++me;
|
|
6896
5677
|
}
|
|
6897
5678
|
while (i < me) {
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
}
|
|
6902
|
-
es = e * (SIGNED_VALUE)BASE_FIG;
|
|
6903
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
6904
|
-
SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
|
|
6905
|
-
goto exp_overflow;
|
|
6906
|
-
e = e * 10 + exp_chr[i] - '0';
|
|
6907
|
-
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
|
|
6908
|
-
goto exp_overflow;
|
|
6909
|
-
if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
|
|
6910
|
-
exp_overflow:
|
|
5679
|
+
int dig = exp_chr[i] - '0';
|
|
5680
|
+
if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
|
|
5681
|
+
ADD_OVERFLOW_SIGNED_VALUE_P(e * 10, signe * dig)) {
|
|
6911
5682
|
exponent_overflow = 1;
|
|
6912
|
-
e = es; /* keep sign */
|
|
6913
5683
|
break;
|
|
6914
5684
|
}
|
|
5685
|
+
e = e * 10 + signe * dig;
|
|
6915
5686
|
++i;
|
|
6916
5687
|
}
|
|
6917
5688
|
}
|
|
@@ -6930,34 +5701,32 @@ VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, con
|
|
|
6930
5701
|
++mi;
|
|
6931
5702
|
}
|
|
6932
5703
|
}
|
|
5704
|
+
/* skip leading zeros in integer part */
|
|
5705
|
+
while (i < mi && int_chr[i] == '0') {
|
|
5706
|
+
++i;
|
|
5707
|
+
--ni;
|
|
5708
|
+
}
|
|
6933
5709
|
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
5710
|
+
/* set actual exponent size. */
|
|
5711
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)ni)) {
|
|
5712
|
+
exponent_overflow = 1;
|
|
5713
|
+
} else {
|
|
5714
|
+
e += ni;
|
|
5715
|
+
}
|
|
6939
5716
|
|
|
6940
5717
|
/* Adjust the exponent so that it is the multiple of BASE_FIG. */
|
|
6941
|
-
j =
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
ef = eb / (SIGNED_VALUE)BASE_FIG;
|
|
6947
|
-
ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
|
|
6948
|
-
if (ef) {
|
|
6949
|
-
++j; /* Means to add one more preceding zero */
|
|
6950
|
-
++e;
|
|
6951
|
-
}
|
|
5718
|
+
j = (BASE_FIG - e % BASE_FIG) % BASE_FIG;
|
|
5719
|
+
if (ADD_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)j)) {
|
|
5720
|
+
exponent_overflow = 1;
|
|
5721
|
+
} else {
|
|
5722
|
+
e += j;
|
|
6952
5723
|
}
|
|
6953
5724
|
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
if (exponent_overflow) {
|
|
5725
|
+
if (exponent_overflow || e < EXPONENT_MIN || e > EXPONENT_MAX) {
|
|
6957
5726
|
int zero = 1;
|
|
6958
5727
|
for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
|
|
6959
5728
|
for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
|
|
6960
|
-
if (!zero &&
|
|
5729
|
+
if (!zero && e > 0) {
|
|
6961
5730
|
VpSetInf(a, sign);
|
|
6962
5731
|
VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
|
|
6963
5732
|
}
|
|
@@ -7007,7 +5776,7 @@ Final:
|
|
|
7007
5776
|
++j;
|
|
7008
5777
|
}
|
|
7009
5778
|
a->Prec = ind_a + 1;
|
|
7010
|
-
a->exponent =
|
|
5779
|
+
a->exponent = e / (SIGNED_VALUE)BASE_FIG;
|
|
7011
5780
|
VpSetSign(a, sign);
|
|
7012
5781
|
VpNmlz(a);
|
|
7013
5782
|
return 1;
|
|
@@ -7079,254 +5848,9 @@ VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
|
|
|
7079
5848
|
*d *= VpGetSign(m);
|
|
7080
5849
|
|
|
7081
5850
|
Exit:
|
|
7082
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7083
|
-
if (gfDebug) {
|
|
7084
|
-
VPrint(stdout, " VpVtoD: m=%\n", m);
|
|
7085
|
-
printf(" d=%e * 10 **%ld\n", *d, *e);
|
|
7086
|
-
printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
|
|
7087
|
-
}
|
|
7088
|
-
#endif /*BIGDECIMAL_DEBUG */
|
|
7089
5851
|
return f;
|
|
7090
5852
|
}
|
|
7091
5853
|
|
|
7092
|
-
/*
|
|
7093
|
-
* m <- d
|
|
7094
|
-
*/
|
|
7095
|
-
VP_EXPORT void
|
|
7096
|
-
VpDtoV(Real *m, double d)
|
|
7097
|
-
{
|
|
7098
|
-
size_t ind_m, mm;
|
|
7099
|
-
SIGNED_VALUE ne;
|
|
7100
|
-
DECDIG i;
|
|
7101
|
-
double val, val2;
|
|
7102
|
-
|
|
7103
|
-
if (isnan(d)) {
|
|
7104
|
-
VpSetNaN(m);
|
|
7105
|
-
goto Exit;
|
|
7106
|
-
}
|
|
7107
|
-
if (isinf(d)) {
|
|
7108
|
-
if (d > 0.0) VpSetPosInf(m);
|
|
7109
|
-
else VpSetNegInf(m);
|
|
7110
|
-
goto Exit;
|
|
7111
|
-
}
|
|
7112
|
-
|
|
7113
|
-
if (d == 0.0) {
|
|
7114
|
-
VpSetZero(m, 1);
|
|
7115
|
-
goto Exit;
|
|
7116
|
-
}
|
|
7117
|
-
val = (d > 0.) ? d : -d;
|
|
7118
|
-
ne = 0;
|
|
7119
|
-
if (val >= 1.0) {
|
|
7120
|
-
while (val >= 1.0) {
|
|
7121
|
-
val /= (double)BASE;
|
|
7122
|
-
++ne;
|
|
7123
|
-
}
|
|
7124
|
-
}
|
|
7125
|
-
else {
|
|
7126
|
-
val2 = 1.0 / (double)BASE;
|
|
7127
|
-
while (val < val2) {
|
|
7128
|
-
val *= (double)BASE;
|
|
7129
|
-
--ne;
|
|
7130
|
-
}
|
|
7131
|
-
}
|
|
7132
|
-
/* Now val = 0.xxxxx*BASE**ne */
|
|
7133
|
-
|
|
7134
|
-
mm = m->MaxPrec;
|
|
7135
|
-
memset(m->frac, 0, mm * sizeof(DECDIG));
|
|
7136
|
-
for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
|
|
7137
|
-
val *= (double)BASE;
|
|
7138
|
-
i = (DECDIG)val;
|
|
7139
|
-
val -= (double)i;
|
|
7140
|
-
m->frac[ind_m] = i;
|
|
7141
|
-
}
|
|
7142
|
-
if (ind_m >= mm) ind_m = mm - 1;
|
|
7143
|
-
VpSetSign(m, (d > 0.0) ? 1 : -1);
|
|
7144
|
-
m->Prec = ind_m + 1;
|
|
7145
|
-
m->exponent = ne;
|
|
7146
|
-
|
|
7147
|
-
VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
|
|
7148
|
-
(DECDIG)(val*(double)BASE));
|
|
7149
|
-
|
|
7150
|
-
Exit:
|
|
7151
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7152
|
-
if (gfDebug) {
|
|
7153
|
-
printf("VpDtoV d=%30.30e\n", d);
|
|
7154
|
-
VPrint(stdout, " m=%\n", m);
|
|
7155
|
-
}
|
|
7156
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7157
|
-
return;
|
|
7158
|
-
}
|
|
7159
|
-
|
|
7160
|
-
/*
|
|
7161
|
-
* m <- ival
|
|
7162
|
-
*/
|
|
7163
|
-
#if 0 /* unused */
|
|
7164
|
-
VP_EXPORT void
|
|
7165
|
-
VpItoV(Real *m, SIGNED_VALUE ival)
|
|
7166
|
-
{
|
|
7167
|
-
size_t mm, ind_m;
|
|
7168
|
-
size_t val, v1, v2, v;
|
|
7169
|
-
int isign;
|
|
7170
|
-
SIGNED_VALUE ne;
|
|
7171
|
-
|
|
7172
|
-
if (ival == 0) {
|
|
7173
|
-
VpSetZero(m, 1);
|
|
7174
|
-
goto Exit;
|
|
7175
|
-
}
|
|
7176
|
-
isign = 1;
|
|
7177
|
-
val = ival;
|
|
7178
|
-
if (ival < 0) {
|
|
7179
|
-
isign = -1;
|
|
7180
|
-
val =(size_t)(-ival);
|
|
7181
|
-
}
|
|
7182
|
-
ne = 0;
|
|
7183
|
-
ind_m = 0;
|
|
7184
|
-
mm = m->MaxPrec;
|
|
7185
|
-
while (ind_m < mm) {
|
|
7186
|
-
m->frac[ind_m] = 0;
|
|
7187
|
-
++ind_m;
|
|
7188
|
-
}
|
|
7189
|
-
ind_m = 0;
|
|
7190
|
-
while (val > 0) {
|
|
7191
|
-
if (val) {
|
|
7192
|
-
v1 = val;
|
|
7193
|
-
v2 = 1;
|
|
7194
|
-
while (v1 >= BASE) {
|
|
7195
|
-
v1 /= BASE;
|
|
7196
|
-
v2 *= BASE;
|
|
7197
|
-
}
|
|
7198
|
-
val = val - v2 * v1;
|
|
7199
|
-
v = v1;
|
|
7200
|
-
}
|
|
7201
|
-
else {
|
|
7202
|
-
v = 0;
|
|
7203
|
-
}
|
|
7204
|
-
m->frac[ind_m] = v;
|
|
7205
|
-
++ind_m;
|
|
7206
|
-
++ne;
|
|
7207
|
-
}
|
|
7208
|
-
m->Prec = ind_m - 1;
|
|
7209
|
-
m->exponent = ne;
|
|
7210
|
-
VpSetSign(m, isign);
|
|
7211
|
-
VpNmlz(m);
|
|
7212
|
-
|
|
7213
|
-
Exit:
|
|
7214
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7215
|
-
if (gfDebug) {
|
|
7216
|
-
printf(" VpItoV i=%d\n", ival);
|
|
7217
|
-
VPrint(stdout, " m=%\n", m);
|
|
7218
|
-
}
|
|
7219
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7220
|
-
return;
|
|
7221
|
-
}
|
|
7222
|
-
#endif
|
|
7223
|
-
|
|
7224
|
-
/*
|
|
7225
|
-
* y = SQRT(x), y*y - x =>0
|
|
7226
|
-
*/
|
|
7227
|
-
VP_EXPORT int
|
|
7228
|
-
VpSqrt(Real *y, Real *x)
|
|
7229
|
-
{
|
|
7230
|
-
Real *f = NULL;
|
|
7231
|
-
Real *r = NULL;
|
|
7232
|
-
size_t y_prec;
|
|
7233
|
-
SIGNED_VALUE n, e;
|
|
7234
|
-
ssize_t nr;
|
|
7235
|
-
double val;
|
|
7236
|
-
|
|
7237
|
-
/* Zero or +Infinity ? */
|
|
7238
|
-
if (VpIsZero(x) || VpIsPosInf(x)) {
|
|
7239
|
-
VpAsgn(y,x,1);
|
|
7240
|
-
goto Exit;
|
|
7241
|
-
}
|
|
7242
|
-
|
|
7243
|
-
/* Negative ? */
|
|
7244
|
-
if (BIGDECIMAL_NEGATIVE_P(x)) {
|
|
7245
|
-
VpSetNaN(y);
|
|
7246
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
|
|
7247
|
-
}
|
|
7248
|
-
|
|
7249
|
-
/* NaN ? */
|
|
7250
|
-
if (VpIsNaN(x)) {
|
|
7251
|
-
VpSetNaN(y);
|
|
7252
|
-
return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
|
|
7253
|
-
}
|
|
7254
|
-
|
|
7255
|
-
/* One ? */
|
|
7256
|
-
if (VpIsOne(x)) {
|
|
7257
|
-
VpSetOne(y);
|
|
7258
|
-
goto Exit;
|
|
7259
|
-
}
|
|
7260
|
-
|
|
7261
|
-
n = (SIGNED_VALUE)y->MaxPrec;
|
|
7262
|
-
if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
|
|
7263
|
-
|
|
7264
|
-
/* allocate temporally variables */
|
|
7265
|
-
/* TODO: reconsider MaxPrec of f and r */
|
|
7266
|
-
f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
|
|
7267
|
-
r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
|
|
7268
|
-
|
|
7269
|
-
nr = 0;
|
|
7270
|
-
y_prec = y->MaxPrec;
|
|
7271
|
-
|
|
7272
|
-
VpVtoD(&val, &e, x); /* val <- x */
|
|
7273
|
-
e /= (SIGNED_VALUE)BASE_FIG;
|
|
7274
|
-
n = e / 2;
|
|
7275
|
-
if (e - n * 2 != 0) {
|
|
7276
|
-
val /= BASE;
|
|
7277
|
-
n = (e + 1) / 2;
|
|
7278
|
-
}
|
|
7279
|
-
VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
|
|
7280
|
-
y->exponent += n;
|
|
7281
|
-
n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
|
|
7282
|
-
y->MaxPrec = Min((size_t)n , y_prec);
|
|
7283
|
-
f->MaxPrec = y->MaxPrec + 1;
|
|
7284
|
-
n = (SIGNED_VALUE)(y_prec * BASE_FIG);
|
|
7285
|
-
if (n > (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
|
|
7286
|
-
|
|
7287
|
-
/*
|
|
7288
|
-
* Perform: y_{n+1} = (y_n - x/y_n) / 2
|
|
7289
|
-
*/
|
|
7290
|
-
do {
|
|
7291
|
-
y->MaxPrec *= 2;
|
|
7292
|
-
if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
|
|
7293
|
-
f->MaxPrec = y->MaxPrec;
|
|
7294
|
-
VpDivd(f, r, x, y); /* f = x/y */
|
|
7295
|
-
VpAddSub(r, f, y, -1); /* r = f - y */
|
|
7296
|
-
VpMult(f, VpConstPt5, r); /* f = 0.5*r */
|
|
7297
|
-
if (VpIsZero(f))
|
|
7298
|
-
goto converge;
|
|
7299
|
-
VpAddSub(r, f, y, 1); /* r = y + f */
|
|
7300
|
-
VpAsgn(y, r, 1); /* y = r */
|
|
7301
|
-
} while (++nr < n);
|
|
7302
|
-
|
|
7303
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7304
|
-
if (gfDebug) {
|
|
7305
|
-
printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
|
|
7306
|
-
}
|
|
7307
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7308
|
-
y->MaxPrec = y_prec;
|
|
7309
|
-
|
|
7310
|
-
converge:
|
|
7311
|
-
VpChangeSign(y, 1);
|
|
7312
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7313
|
-
if (gfDebug) {
|
|
7314
|
-
VpMult(r, y, y);
|
|
7315
|
-
VpAddSub(f, x, r, -1);
|
|
7316
|
-
printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
|
|
7317
|
-
VPrint(stdout, " y =% \n", y);
|
|
7318
|
-
VPrint(stdout, " x =% \n", x);
|
|
7319
|
-
VPrint(stdout, " x-y*y = % \n", f);
|
|
7320
|
-
}
|
|
7321
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7322
|
-
y->MaxPrec = y_prec;
|
|
7323
|
-
|
|
7324
|
-
Exit:
|
|
7325
|
-
rbd_free_struct(f);
|
|
7326
|
-
rbd_free_struct(r);
|
|
7327
|
-
return 1;
|
|
7328
|
-
}
|
|
7329
|
-
|
|
7330
5854
|
/*
|
|
7331
5855
|
* Round relatively from the decimal point.
|
|
7332
5856
|
* f: rounding mode
|
|
@@ -7503,7 +6027,7 @@ VpLeftRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
7503
6027
|
DECDIG v;
|
|
7504
6028
|
if (!VpHasVal(y)) return 0; /* Unable to round */
|
|
7505
6029
|
v = y->frac[0];
|
|
7506
|
-
nf -=
|
|
6030
|
+
nf -= y->exponent * (ssize_t)BASE_FIG;
|
|
7507
6031
|
while ((v /= 10) != 0) nf--;
|
|
7508
6032
|
nf += (ssize_t)BASE_FIG-1;
|
|
7509
6033
|
return VpMidRound(y, f, nf);
|
|
@@ -7610,7 +6134,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7610
6134
|
size_t my, ind_y, ind_x;
|
|
7611
6135
|
|
|
7612
6136
|
if (!VpHasVal(x)) {
|
|
7613
|
-
VpAsgn(y, x,
|
|
6137
|
+
VpAsgn(y, x, 10);
|
|
7614
6138
|
goto Exit;
|
|
7615
6139
|
}
|
|
7616
6140
|
|
|
@@ -7619,7 +6143,7 @@ VpFrac(Real *y, Real *x)
|
|
|
7619
6143
|
goto Exit;
|
|
7620
6144
|
}
|
|
7621
6145
|
else if (x->exponent <= 0) {
|
|
7622
|
-
VpAsgn(y, x,
|
|
6146
|
+
VpAsgn(y, x, 10);
|
|
7623
6147
|
goto Exit;
|
|
7624
6148
|
}
|
|
7625
6149
|
|
|
@@ -7640,117 +6164,9 @@ VpFrac(Real *y, Real *x)
|
|
|
7640
6164
|
VpNmlz(y);
|
|
7641
6165
|
|
|
7642
6166
|
Exit:
|
|
7643
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7644
|
-
if (gfDebug) {
|
|
7645
|
-
VPrint(stdout, "VpFrac y=%\n", y);
|
|
7646
|
-
VPrint(stdout, " x=%\n", x);
|
|
7647
|
-
}
|
|
7648
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7649
6167
|
return;
|
|
7650
6168
|
}
|
|
7651
6169
|
|
|
7652
|
-
/*
|
|
7653
|
-
* y = x ** n
|
|
7654
|
-
*/
|
|
7655
|
-
VP_EXPORT int
|
|
7656
|
-
VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
|
|
7657
|
-
{
|
|
7658
|
-
size_t s, ss;
|
|
7659
|
-
ssize_t sign;
|
|
7660
|
-
Real *w1 = NULL;
|
|
7661
|
-
Real *w2 = NULL;
|
|
7662
|
-
|
|
7663
|
-
if (VpIsZero(x)) {
|
|
7664
|
-
if (n == 0) {
|
|
7665
|
-
VpSetOne(y);
|
|
7666
|
-
goto Exit;
|
|
7667
|
-
}
|
|
7668
|
-
sign = VpGetSign(x);
|
|
7669
|
-
if (n < 0) {
|
|
7670
|
-
n = -n;
|
|
7671
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7672
|
-
VpSetInf(y, sign);
|
|
7673
|
-
}
|
|
7674
|
-
else {
|
|
7675
|
-
if (sign < 0) sign = (n % 2) ? -1 : 1;
|
|
7676
|
-
VpSetZero(y,sign);
|
|
7677
|
-
}
|
|
7678
|
-
goto Exit;
|
|
7679
|
-
}
|
|
7680
|
-
if (VpIsNaN(x)) {
|
|
7681
|
-
VpSetNaN(y);
|
|
7682
|
-
goto Exit;
|
|
7683
|
-
}
|
|
7684
|
-
if (VpIsInf(x)) {
|
|
7685
|
-
if (n == 0) {
|
|
7686
|
-
VpSetOne(y);
|
|
7687
|
-
goto Exit;
|
|
7688
|
-
}
|
|
7689
|
-
if (n > 0) {
|
|
7690
|
-
VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7691
|
-
goto Exit;
|
|
7692
|
-
}
|
|
7693
|
-
VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
|
|
7694
|
-
goto Exit;
|
|
7695
|
-
}
|
|
7696
|
-
|
|
7697
|
-
if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
|
|
7698
|
-
/* abs(x) = 1 */
|
|
7699
|
-
VpSetOne(y);
|
|
7700
|
-
if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
|
|
7701
|
-
if ((n % 2) == 0) goto Exit;
|
|
7702
|
-
VpSetSign(y, -1);
|
|
7703
|
-
goto Exit;
|
|
7704
|
-
}
|
|
7705
|
-
|
|
7706
|
-
if (n > 0) sign = 1;
|
|
7707
|
-
else if (n < 0) {
|
|
7708
|
-
sign = -1;
|
|
7709
|
-
n = -n;
|
|
7710
|
-
}
|
|
7711
|
-
else {
|
|
7712
|
-
VpSetOne(y);
|
|
7713
|
-
goto Exit;
|
|
7714
|
-
}
|
|
7715
|
-
|
|
7716
|
-
/* Allocate working variables */
|
|
7717
|
-
/* TODO: reconsider MaxPrec of w1 and w2 */
|
|
7718
|
-
w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
|
|
7719
|
-
w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
|
|
7720
|
-
|
|
7721
|
-
/* calculation start */
|
|
7722
|
-
|
|
7723
|
-
VpAsgn(y, x, 1);
|
|
7724
|
-
--n;
|
|
7725
|
-
while (n > 0) {
|
|
7726
|
-
VpAsgn(w1, x, 1);
|
|
7727
|
-
s = 1;
|
|
7728
|
-
while (ss = s, (s += s) <= (size_t)n) {
|
|
7729
|
-
VpMult(w2, w1, w1);
|
|
7730
|
-
VpAsgn(w1, w2, 1);
|
|
7731
|
-
}
|
|
7732
|
-
n -= (SIGNED_VALUE)ss;
|
|
7733
|
-
VpMult(w2, y, w1);
|
|
7734
|
-
VpAsgn(y, w2, 1);
|
|
7735
|
-
}
|
|
7736
|
-
if (sign < 0) {
|
|
7737
|
-
VpDivd(w1, w2, VpConstOne, y);
|
|
7738
|
-
VpAsgn(y, w1, 1);
|
|
7739
|
-
}
|
|
7740
|
-
|
|
7741
|
-
Exit:
|
|
7742
|
-
#ifdef BIGDECIMAL_DEBUG
|
|
7743
|
-
if (gfDebug) {
|
|
7744
|
-
VPrint(stdout, "VpPowerByInt y=%\n", y);
|
|
7745
|
-
VPrint(stdout, "VpPowerByInt x=%\n", x);
|
|
7746
|
-
printf(" n=%"PRIdVALUE"\n", n);
|
|
7747
|
-
}
|
|
7748
|
-
#endif /* BIGDECIMAL_DEBUG */
|
|
7749
|
-
rbd_free_struct(w2);
|
|
7750
|
-
rbd_free_struct(w1);
|
|
7751
|
-
return 1;
|
|
7752
|
-
}
|
|
7753
|
-
|
|
7754
6170
|
#ifdef BIGDECIMAL_DEBUG
|
|
7755
6171
|
int
|
|
7756
6172
|
VpVarCheck(Real * v)
|