bigdecimal 3.3.1 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bigdecimal.gemspec +8 -1
- data/ext/bigdecimal/bigdecimal.c +288 -303
- data/ext/bigdecimal/bigdecimal.h +48 -42
- data/ext/bigdecimal/div.h +219 -0
- data/ext/bigdecimal/extconf.rb +5 -2
- data/ext/bigdecimal/missing/dtoa.c +184 -137
- data/ext/bigdecimal/missing.h +4 -2
- data/ext/bigdecimal/ntt.h +191 -0
- data/lib/bigdecimal/jacobian.rb +2 -0
- data/lib/bigdecimal/ludcmp.rb +2 -0
- data/lib/bigdecimal/math/erf.rb +291 -0
- data/lib/bigdecimal/math/gamma.rb +513 -0
- data/lib/bigdecimal/math.rb +548 -81
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +1 -1
- data/lib/bigdecimal.rb +121 -73
- data/sample/linear.rb +73 -37
- data/sample/nlsolve.rb +47 -30
- data/sample/pi.rb +2 -7
- data/sig/big_decimal.rbs +1504 -0
- data/sig/big_decimal_util.rbs +158 -0
- data/sig/big_math.rbs +423 -0
- metadata +10 -3
data/ext/bigdecimal/bigdecimal.c
CHANGED
|
@@ -29,12 +29,16 @@
|
|
|
29
29
|
#endif
|
|
30
30
|
|
|
31
31
|
#include "bits.h"
|
|
32
|
+
#include "ntt.h"
|
|
33
|
+
#include "div.h"
|
|
32
34
|
#include "static_assert.h"
|
|
33
35
|
|
|
34
|
-
#define BIGDECIMAL_VERSION "
|
|
35
|
-
|
|
36
|
-
/* #define ENABLE_NUMERIC_STRING */
|
|
36
|
+
#define BIGDECIMAL_VERSION "4.1.3"
|
|
37
37
|
|
|
38
|
+
/* Make sure VPMULT_BATCH_SIZE*BASE*BASE does not overflow DECDIG_DBL */
|
|
39
|
+
#define VPMULT_BATCH_SIZE 16
|
|
40
|
+
#define NTT_MULTIPLICATION_THRESHOLD 450
|
|
41
|
+
#define NEWTON_RAPHSON_DIVISION_THRESHOLD 100
|
|
38
42
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
|
39
43
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
|
40
44
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
@@ -64,7 +68,6 @@ static ID id_banker;
|
|
|
64
68
|
static ID id_ceiling;
|
|
65
69
|
static ID id_ceil;
|
|
66
70
|
static ID id_floor;
|
|
67
|
-
static ID id_to_r;
|
|
68
71
|
static ID id_eq;
|
|
69
72
|
static ID id_half;
|
|
70
73
|
|
|
@@ -75,16 +78,6 @@ static struct {
|
|
|
75
78
|
uint8_t mode;
|
|
76
79
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
77
80
|
|
|
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
81
|
static inline BDVALUE
|
|
89
82
|
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
90
83
|
{
|
|
@@ -160,42 +153,6 @@ rbd_struct_size(size_t const internal_digits)
|
|
|
160
153
|
return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
|
|
161
154
|
}
|
|
162
155
|
|
|
163
|
-
static inline Real *
|
|
164
|
-
rbd_allocate_struct(size_t const internal_digits)
|
|
165
|
-
{
|
|
166
|
-
size_t const size = rbd_struct_size(internal_digits);
|
|
167
|
-
Real *real = ruby_xcalloc(1, size);
|
|
168
|
-
atomic_allocation_count_inc();
|
|
169
|
-
real->MaxPrec = internal_digits;
|
|
170
|
-
return real;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
static inline Real *
|
|
174
|
-
rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
|
|
175
|
-
{
|
|
176
|
-
return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
static void
|
|
180
|
-
rbd_free_struct(Real *real)
|
|
181
|
-
{
|
|
182
|
-
if (real != NULL) {
|
|
183
|
-
check_allocation_count_nonzero();
|
|
184
|
-
ruby_xfree(real);
|
|
185
|
-
atomic_allocation_count_dec_nounderflow();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
|
|
190
|
-
#define NewZero rbd_allocate_struct_zero
|
|
191
|
-
static inline Real *
|
|
192
|
-
rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
193
|
-
{
|
|
194
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits);
|
|
195
|
-
VpSetZero(real, sign);
|
|
196
|
-
return real;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
156
|
/*
|
|
200
157
|
* ================== Ruby Interface part ==========================
|
|
201
158
|
*/
|
|
@@ -207,11 +164,9 @@ rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
|
207
164
|
static unsigned short VpGetException(void);
|
|
208
165
|
static void VpSetException(unsigned short f);
|
|
209
166
|
static void VpCheckException(Real *p, bool always);
|
|
210
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
211
167
|
static VALUE CheckGetValue(BDVALUE v);
|
|
212
168
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
213
169
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
214
|
-
static Real *VpCopy(Real *pv, Real const* const x);
|
|
215
170
|
static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
|
|
216
171
|
|
|
217
172
|
/*
|
|
@@ -226,49 +181,71 @@ static VALUE BigDecimal_negative_zero(void);
|
|
|
226
181
|
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
227
182
|
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
228
183
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
184
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
185
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
186
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
187
|
+
#endif
|
|
188
|
+
|
|
189
|
+
#ifdef RUBY_TYPED_EMBEDDABLE
|
|
190
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
191
|
+
#else
|
|
192
|
+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
|
|
193
|
+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
|
|
194
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
195
|
+
# else
|
|
196
|
+
# define RUBY_TYPED_EMBEDDABLE 0
|
|
197
|
+
# endif
|
|
198
|
+
#endif
|
|
234
199
|
|
|
235
200
|
static size_t
|
|
236
201
|
BigDecimal_memsize(const void *ptr)
|
|
237
202
|
{
|
|
203
|
+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
204
|
+
return 0; // Entirely embedded
|
|
205
|
+
#else
|
|
238
206
|
const Real *pv = ptr;
|
|
239
207
|
return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
|
|
208
|
+
#endif
|
|
240
209
|
}
|
|
241
210
|
|
|
242
|
-
#ifndef
|
|
243
|
-
#
|
|
244
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
211
|
+
#ifndef RUBY_TYPED_THREAD_SAFE_FREE
|
|
212
|
+
#define RUBY_TYPED_THREAD_SAFE_FREE RUBY_TYPED_FREE_IMMEDIATELY
|
|
245
213
|
#endif
|
|
246
214
|
|
|
247
215
|
static const rb_data_type_t BigDecimal_data_type = {
|
|
248
|
-
"BigDecimal",
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
216
|
+
.wrap_struct_name = "BigDecimal",
|
|
217
|
+
.function = {
|
|
218
|
+
.dmark = 0,
|
|
219
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
220
|
+
.dsize = BigDecimal_memsize,
|
|
221
|
+
},
|
|
222
|
+
.flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
|
|
253
223
|
};
|
|
254
224
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
|
258
|
-
static NULL_WRAPPED_VALUE
|
|
259
|
-
BigDecimal_alloc_empty_struct(VALUE klass)
|
|
225
|
+
static VALUE
|
|
226
|
+
BigDecimal_allocate(size_t const internal_digits)
|
|
260
227
|
{
|
|
261
|
-
|
|
228
|
+
const size_t size = rbd_struct_size(internal_digits);
|
|
229
|
+
VALUE bd = rb_data_typed_object_zalloc(rb_cBigDecimal, size, &BigDecimal_data_type);
|
|
230
|
+
Real *vp;
|
|
231
|
+
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
232
|
+
vp->MaxPrec = internal_digits;
|
|
233
|
+
RB_OBJ_FREEZE(bd);
|
|
234
|
+
return bd;
|
|
262
235
|
}
|
|
263
236
|
|
|
264
237
|
static VALUE
|
|
265
|
-
|
|
238
|
+
BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
|
|
266
239
|
{
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
240
|
+
return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static Real *
|
|
244
|
+
VpPtr(VALUE obj)
|
|
245
|
+
{
|
|
246
|
+
Real *vp;
|
|
247
|
+
TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
|
|
248
|
+
return vp;
|
|
272
249
|
}
|
|
273
250
|
|
|
274
251
|
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
@@ -276,9 +253,10 @@ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_
|
|
|
276
253
|
static BDVALUE
|
|
277
254
|
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
278
255
|
{
|
|
279
|
-
|
|
280
|
-
Real *real =
|
|
281
|
-
|
|
256
|
+
VALUE obj = BigDecimal_allocate_decimal_digits(digits);
|
|
257
|
+
Real *real = VpPtr(obj);
|
|
258
|
+
VpSetZero(real, sign);
|
|
259
|
+
return (BDVALUE) { obj, real };
|
|
282
260
|
}
|
|
283
261
|
|
|
284
262
|
static inline int
|
|
@@ -336,20 +314,11 @@ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
|
336
314
|
break;
|
|
337
315
|
}
|
|
338
316
|
|
|
339
|
-
#ifdef ENABLE_NUMERIC_STRING
|
|
340
|
-
case T_STRING: {
|
|
341
|
-
const char *c_str = StringValueCStr(v);
|
|
342
|
-
v = rb_cstr_convert_to_BigDecimal(c_str, must);
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
#endif /* ENABLE_NUMERIC_STRING */
|
|
346
|
-
|
|
347
317
|
default:
|
|
348
318
|
goto SomeOneMayDoIt;
|
|
349
319
|
}
|
|
350
320
|
|
|
351
|
-
Real *vp;
|
|
352
|
-
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
|
321
|
+
Real *vp = VpPtr(v);
|
|
353
322
|
return (NULLABLE_BDVALUE) { v, vp };
|
|
354
323
|
|
|
355
324
|
SomeOneMayDoIt:
|
|
@@ -400,37 +369,6 @@ BigDecimal_double_fig(VALUE self)
|
|
|
400
369
|
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
401
370
|
}
|
|
402
371
|
|
|
403
|
-
/* call-seq:
|
|
404
|
-
* precs -> array
|
|
405
|
-
*
|
|
406
|
-
* Returns an Array of two Integer values that represent platform-dependent
|
|
407
|
-
* internal storage properties.
|
|
408
|
-
*
|
|
409
|
-
* This method is deprecated and will be removed in the future.
|
|
410
|
-
* Instead, use BigDecimal#n_significant_digits for obtaining the number of
|
|
411
|
-
* significant digits in scientific notation, and BigDecimal#precision for
|
|
412
|
-
* obtaining the number of digits in decimal notation.
|
|
413
|
-
*
|
|
414
|
-
*/
|
|
415
|
-
|
|
416
|
-
static VALUE
|
|
417
|
-
BigDecimal_prec(VALUE self)
|
|
418
|
-
{
|
|
419
|
-
BDVALUE v;
|
|
420
|
-
VALUE obj;
|
|
421
|
-
|
|
422
|
-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
|
|
423
|
-
"BigDecimal#precs is deprecated and will be removed in the future; "
|
|
424
|
-
"use BigDecimal#precision instead.");
|
|
425
|
-
|
|
426
|
-
v = GetBDValueMust(self);
|
|
427
|
-
obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
|
|
428
|
-
SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
|
|
429
|
-
|
|
430
|
-
RB_GC_GUARD(v.bigdecimal);
|
|
431
|
-
return obj;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
372
|
static void
|
|
435
373
|
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
436
374
|
{
|
|
@@ -734,6 +672,7 @@ BigDecimal_load(VALUE self, VALUE str)
|
|
|
734
672
|
}
|
|
735
673
|
}
|
|
736
674
|
v = bdvalue_nonnullable(CreateFromString((char *)pch, self, true, true));
|
|
675
|
+
RB_GC_GUARD(str);
|
|
737
676
|
return CheckGetValue(v);
|
|
738
677
|
}
|
|
739
678
|
|
|
@@ -1027,7 +966,7 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1027
966
|
static size_t
|
|
1028
967
|
GetAddSubPrec(Real *a, Real *b)
|
|
1029
968
|
{
|
|
1030
|
-
if (
|
|
969
|
+
if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
|
|
1031
970
|
ssize_t min_a = a->exponent - a->Prec;
|
|
1032
971
|
ssize_t min_b = b->exponent - b->Prec;
|
|
1033
972
|
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
@@ -1053,26 +992,18 @@ check_int_precision(VALUE v)
|
|
|
1053
992
|
static NULLABLE_BDVALUE
|
|
1054
993
|
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1055
994
|
{
|
|
1056
|
-
|
|
1057
|
-
Real *pv = VpAlloc(str, strict_p, raise_exception);
|
|
1058
|
-
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1059
|
-
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
|
|
995
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1060
996
|
}
|
|
1061
997
|
|
|
1062
|
-
|
|
1063
|
-
|
|
998
|
+
void
|
|
999
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1064
1000
|
{
|
|
1065
|
-
assert(x != NULL);
|
|
1066
|
-
|
|
1067
|
-
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1068
1001
|
pv->MaxPrec = x->MaxPrec;
|
|
1069
1002
|
pv->Prec = x->Prec;
|
|
1070
1003
|
pv->exponent = x->exponent;
|
|
1071
1004
|
pv->sign = x->sign;
|
|
1072
1005
|
pv->flag = x->flag;
|
|
1073
1006
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1074
|
-
|
|
1075
|
-
return pv;
|
|
1076
1007
|
}
|
|
1077
1008
|
|
|
1078
1009
|
/* Returns True if the value is Not a Number. */
|
|
@@ -1112,9 +1043,6 @@ BigDecimal_check_num(Real *p)
|
|
|
1112
1043
|
VpCheckException(p, true);
|
|
1113
1044
|
}
|
|
1114
1045
|
|
|
1115
|
-
static VALUE BigDecimal_fix(VALUE self);
|
|
1116
|
-
static VALUE BigDecimal_split(VALUE self);
|
|
1117
|
-
|
|
1118
1046
|
/* Returns the value as an Integer.
|
|
1119
1047
|
*
|
|
1120
1048
|
* If the BigDecimal is infinity or NaN, raises FloatDomainError.
|
|
@@ -1265,7 +1193,7 @@ GetCoercePrec(Real *a, size_t prec)
|
|
|
1265
1193
|
static VALUE
|
|
1266
1194
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1267
1195
|
{
|
|
1268
|
-
Real* pv =
|
|
1196
|
+
Real* pv = VpPtr(self);
|
|
1269
1197
|
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1270
1198
|
return rb_assoc_new(CheckGetValue(b), self);
|
|
1271
1199
|
}
|
|
@@ -1331,13 +1259,32 @@ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
|
1331
1259
|
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1332
1260
|
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1333
1261
|
|
|
1334
|
-
|
|
1335
|
-
if (mx == (size_t)-1L) {
|
|
1336
|
-
/* a or b is inf */
|
|
1262
|
+
if (VpIsInf(a.real) || VpIsInf(b.real)) {
|
|
1337
1263
|
c = NewZeroWrap(1, BASE_FIG);
|
|
1338
1264
|
VpAddSub(c.real, a.real, b.real, operation);
|
|
1339
1265
|
}
|
|
1340
1266
|
else {
|
|
1267
|
+
|
|
1268
|
+
// Optimization when exponent difference is large
|
|
1269
|
+
// (1.234e+1000).add(5.678e-1000, 10) == (1.234e+1000).add(0.1e+990, 10) in every rounding mode
|
|
1270
|
+
if (prec && !VpIsZero(a.real) && !VpIsZero(b.real)) {
|
|
1271
|
+
size_t precRoom = roomof(prec, BASE_FIG);
|
|
1272
|
+
if (a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1 > b.real->exponent) {
|
|
1273
|
+
BDVALUE b2 = NewZeroWrap(1, BASE_FIG);
|
|
1274
|
+
VpSetOne(b2.real)
|
|
1275
|
+
VpSetSign(b2.real, b.real->sign);
|
|
1276
|
+
b2.real->exponent = a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1;
|
|
1277
|
+
b = b2;
|
|
1278
|
+
} else if (b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1 > a.real->exponent) {
|
|
1279
|
+
BDVALUE a2 = NewZeroWrap(1, BASE_FIG);
|
|
1280
|
+
VpSetOne(a2.real)
|
|
1281
|
+
VpSetSign(a2.real, a.real->sign);
|
|
1282
|
+
a2.real->exponent = b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1;
|
|
1283
|
+
a = a2;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1341
1288
|
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1342
1289
|
size_t pl = VpGetPrecLimit();
|
|
1343
1290
|
if (prec) VpSetPrecLimit(prec);
|
|
@@ -1714,7 +1661,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1714
1661
|
|
|
1715
1662
|
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1716
1663
|
VALUE nan = BigDecimal_nan();
|
|
1717
|
-
*div = *mod = (NULLABLE_BDVALUE) { nan,
|
|
1664
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1718
1665
|
goto Done;
|
|
1719
1666
|
}
|
|
1720
1667
|
if (VpIsZero(b.real)) {
|
|
@@ -1723,19 +1670,19 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1723
1670
|
if (VpIsInf(a.real)) {
|
|
1724
1671
|
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1725
1672
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1726
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1727
1674
|
}
|
|
1728
1675
|
else {
|
|
1729
1676
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1730
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1677
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1731
1678
|
}
|
|
1732
1679
|
VALUE nan = BigDecimal_nan();
|
|
1733
|
-
*mod = (NULLABLE_BDVALUE) { nan,
|
|
1680
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1734
1681
|
goto Done;
|
|
1735
1682
|
}
|
|
1736
1683
|
if (VpIsZero(a.real)) {
|
|
1737
1684
|
VALUE zero = BigDecimal_positive_zero();
|
|
1738
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1685
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1739
1686
|
*mod = bdvalue_nullable(a);
|
|
1740
1687
|
goto Done;
|
|
1741
1688
|
}
|
|
@@ -1749,7 +1696,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1749
1696
|
*mod = bdvalue_nullable(b);
|
|
1750
1697
|
} else {
|
|
1751
1698
|
VALUE zero = BigDecimal_positive_zero();
|
|
1752
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1699
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1753
1700
|
*mod = bdvalue_nullable(a);
|
|
1754
1701
|
}
|
|
1755
1702
|
goto Done;
|
|
@@ -1792,13 +1739,13 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1792
1739
|
*div = bdvalue_nullable(dv);
|
|
1793
1740
|
*mod = bdvalue_nullable(md);
|
|
1794
1741
|
}
|
|
1742
|
+
RB_GC_GUARD(dv.bigdecimal);
|
|
1743
|
+
RB_GC_GUARD(md.bigdecimal);
|
|
1744
|
+
RB_GC_GUARD(res.bigdecimal);
|
|
1795
1745
|
|
|
1796
1746
|
Done:
|
|
1797
1747
|
RB_GC_GUARD(a.bigdecimal);
|
|
1798
1748
|
RB_GC_GUARD(b.bigdecimal);
|
|
1799
|
-
RB_GC_GUARD(dv.bigdecimal);
|
|
1800
|
-
RB_GC_GUARD(md.bigdecimal);
|
|
1801
|
-
RB_GC_GUARD(res.bigdecimal);
|
|
1802
1749
|
return true;
|
|
1803
1750
|
}
|
|
1804
1751
|
|
|
@@ -1867,7 +1814,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
1867
1814
|
NULLABLE_BDVALUE div, mod;
|
|
1868
1815
|
|
|
1869
1816
|
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1870
|
-
return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
1817
|
+
return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
1871
1818
|
}
|
|
1872
1819
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
1873
1820
|
}
|
|
@@ -2507,7 +2454,7 @@ BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
|
2507
2454
|
prec = a.real->Prec + shiftDown;
|
|
2508
2455
|
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2509
2456
|
if (shift == 0) {
|
|
2510
|
-
VpAsgn(c.real, a.real,
|
|
2457
|
+
VpAsgn(c.real, a.real, 10);
|
|
2511
2458
|
} else if (shiftDown) {
|
|
2512
2459
|
DECDIG carry = 0;
|
|
2513
2460
|
exponentShift++;
|
|
@@ -2593,9 +2540,7 @@ check_exception(VALUE bd)
|
|
|
2593
2540
|
{
|
|
2594
2541
|
assert(is_kind_of_BigDecimal(bd));
|
|
2595
2542
|
|
|
2596
|
-
|
|
2597
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2598
|
-
VpCheckException(vp, false);
|
|
2543
|
+
VpCheckException(VpPtr(bd), false);
|
|
2599
2544
|
|
|
2600
2545
|
return bd;
|
|
2601
2546
|
}
|
|
@@ -2603,17 +2548,19 @@ check_exception(VALUE bd)
|
|
|
2603
2548
|
static VALUE
|
|
2604
2549
|
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
2605
2550
|
{
|
|
2606
|
-
|
|
2551
|
+
VALUE bd;
|
|
2607
2552
|
Real *vp;
|
|
2608
2553
|
if (uval == 0) {
|
|
2609
|
-
|
|
2554
|
+
bd = BigDecimal_allocate(1);
|
|
2555
|
+
vp = VpPtr(bd);
|
|
2610
2556
|
vp->Prec = 1;
|
|
2611
2557
|
vp->exponent = 1;
|
|
2612
2558
|
VpSetZero(vp, 1);
|
|
2613
2559
|
vp->frac[0] = 0;
|
|
2614
2560
|
}
|
|
2615
2561
|
else if (uval < BASE) {
|
|
2616
|
-
|
|
2562
|
+
bd = BigDecimal_allocate(1);
|
|
2563
|
+
vp = VpPtr(bd);
|
|
2617
2564
|
vp->Prec = 1;
|
|
2618
2565
|
vp->exponent = 1;
|
|
2619
2566
|
VpSetSign(vp, 1);
|
|
@@ -2638,14 +2585,15 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
|
2638
2585
|
}
|
|
2639
2586
|
|
|
2640
2587
|
const size_t exp = len + ntz;
|
|
2641
|
-
|
|
2588
|
+
bd = BigDecimal_allocate(len);
|
|
2589
|
+
vp = VpPtr(bd);
|
|
2642
2590
|
vp->Prec = len;
|
|
2643
2591
|
vp->exponent = exp;
|
|
2644
2592
|
VpSetSign(vp, 1);
|
|
2645
2593
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
2646
2594
|
}
|
|
2647
2595
|
|
|
2648
|
-
return
|
|
2596
|
+
return bd;
|
|
2649
2597
|
}
|
|
2650
2598
|
|
|
2651
2599
|
static VALUE
|
|
@@ -2654,8 +2602,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
|
2654
2602
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
2655
2603
|
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
2656
2604
|
if (ival < 0) {
|
|
2657
|
-
Real *vp;
|
|
2658
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2605
|
+
Real *vp = VpPtr(bd);
|
|
2659
2606
|
VpSetSign(vp, -1);
|
|
2660
2607
|
}
|
|
2661
2608
|
return bd;
|
|
@@ -2766,7 +2713,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2766
2713
|
len10 = BIGDECIMAL_DOUBLE_FIGURES;
|
|
2767
2714
|
}
|
|
2768
2715
|
memcpy(buf, p, len10);
|
|
2769
|
-
|
|
2716
|
+
free(p);
|
|
2770
2717
|
|
|
2771
2718
|
VALUE inum;
|
|
2772
2719
|
size_t RB_UNUSED_VAR(prec) = 0;
|
|
@@ -2862,8 +2809,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2862
2809
|
}
|
|
2863
2810
|
|
|
2864
2811
|
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2865
|
-
Real *vp;
|
|
2866
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2812
|
+
Real *vp = VpPtr(bd);
|
|
2867
2813
|
assert(vp->Prec == prec);
|
|
2868
2814
|
vp->exponent = exp;
|
|
2869
2815
|
|
|
@@ -2900,8 +2846,13 @@ rb_cstr_convert_to_BigDecimal(const char *c_str, int raise_exception)
|
|
|
2900
2846
|
static inline VALUE
|
|
2901
2847
|
rb_str_convert_to_BigDecimal(VALUE val, int raise_exception)
|
|
2902
2848
|
{
|
|
2849
|
+
StringValue(val);
|
|
2850
|
+
rb_must_asciicompat(val);
|
|
2851
|
+
if (!raise_exception && memchr(RSTRING_PTR(val), '\0', RSTRING_LEN(val))) return Qnil;
|
|
2903
2852
|
const char *c_str = StringValueCStr(val);
|
|
2904
|
-
|
|
2853
|
+
VALUE bd = rb_cstr_convert_to_BigDecimal(c_str, raise_exception);
|
|
2854
|
+
RB_GC_GUARD(val);
|
|
2855
|
+
return bd;
|
|
2905
2856
|
}
|
|
2906
2857
|
|
|
2907
2858
|
static VALUE
|
|
@@ -2929,13 +2880,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2929
2880
|
if (digs == SIZE_MAX)
|
|
2930
2881
|
return check_exception(val);
|
|
2931
2882
|
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2883
|
+
Real *vp = VpPtr(val);
|
|
2884
|
+
|
|
2885
|
+
VALUE copy = BigDecimal_allocate(vp->MaxPrec);
|
|
2886
|
+
Real *vp_copy = VpPtr(copy);
|
|
2887
|
+
|
|
2888
|
+
VpMemCopy(vp_copy, vp);
|
|
2889
|
+
|
|
2936
2890
|
RB_GC_GUARD(val);
|
|
2937
2891
|
|
|
2938
|
-
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
2939
2892
|
/* TODO: rounding */
|
|
2940
2893
|
return check_exception(copy);
|
|
2941
2894
|
}
|
|
@@ -2951,7 +2904,7 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2951
2904
|
else if (RB_TYPE_P(val, T_COMPLEX)) {
|
|
2952
2905
|
VALUE im = rb_complex_imag(val);
|
|
2953
2906
|
if (!is_zero(im)) {
|
|
2954
|
-
|
|
2907
|
+
if (!raise_exception) return Qnil;
|
|
2955
2908
|
rb_raise(rb_eArgError,
|
|
2956
2909
|
"Unable to make a BigDecimal from non-zero imaginary number");
|
|
2957
2910
|
}
|
|
@@ -3061,8 +3014,15 @@ f_BigDecimal(int argc, VALUE *argv, VALUE self)
|
|
|
3061
3014
|
static VALUE
|
|
3062
3015
|
BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
|
|
3063
3016
|
{
|
|
3017
|
+
StringValue(str);
|
|
3018
|
+
rb_must_asciicompat(str);
|
|
3019
|
+
/* Like String#to_f, ignore everything after an embedded NUL */
|
|
3020
|
+
const char *p = RSTRING_PTR(str);
|
|
3021
|
+
const char *nul = memchr(p, '\0', RSTRING_LEN(str));
|
|
3022
|
+
if (nul) str = rb_str_subseq(str, 0, nul - p);
|
|
3064
3023
|
char const *c_str = StringValueCStr(str);
|
|
3065
3024
|
NULLABLE_BDVALUE v = CreateFromString(c_str, klass, false, true);
|
|
3025
|
+
RB_GC_GUARD(str);
|
|
3066
3026
|
if (v.bigdecimal_or_nil == Qnil)
|
|
3067
3027
|
return Qnil;
|
|
3068
3028
|
else
|
|
@@ -3257,19 +3217,39 @@ BigDecimal_literal(const char *str)
|
|
|
3257
3217
|
|
|
3258
3218
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3259
3219
|
VALUE
|
|
3260
|
-
|
|
3261
|
-
BDVALUE a,b,c,d;
|
|
3220
|
+
BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
|
|
3221
|
+
BDVALUE a, b, c, d;
|
|
3262
3222
|
size_t cn = NUM2INT(cprec);
|
|
3263
3223
|
a = GetBDValueMust(self);
|
|
3264
3224
|
b = GetBDValueMust(r);
|
|
3265
3225
|
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3266
3226
|
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3267
|
-
|
|
3227
|
+
vpdivd_func(c.real, d.real, a.real, b.real);
|
|
3268
3228
|
RB_GC_GUARD(a.bigdecimal);
|
|
3269
3229
|
RB_GC_GUARD(b.bigdecimal);
|
|
3270
3230
|
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3271
3231
|
}
|
|
3272
3232
|
|
|
3233
|
+
void
|
|
3234
|
+
VpDivdNormal(Real *c, Real *r, Real *a, Real *b) {
|
|
3235
|
+
VpDivd(c, r, a, b);
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
VALUE
|
|
3239
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3240
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNormal);
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
VALUE
|
|
3244
|
+
BigDecimal_vpdivd_newton(VALUE self, VALUE r, VALUE cprec) {
|
|
3245
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNewton);
|
|
3246
|
+
}
|
|
3247
|
+
|
|
3248
|
+
VALUE
|
|
3249
|
+
BigDecimal_newton_raphson_inverse(VALUE self, VALUE prec) {
|
|
3250
|
+
return newton_raphson_inverse(self, NUM2SIZET(prec));
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3273
3253
|
VALUE
|
|
3274
3254
|
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3275
3255
|
BDVALUE a,b,c;
|
|
@@ -3281,6 +3261,23 @@ BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
|
3281
3261
|
RB_GC_GUARD(b.bigdecimal);
|
|
3282
3262
|
return c.bigdecimal;
|
|
3283
3263
|
}
|
|
3264
|
+
|
|
3265
|
+
VALUE
|
|
3266
|
+
BigDecimal_nttmult(VALUE self, VALUE v) {
|
|
3267
|
+
BDVALUE a,b,c;
|
|
3268
|
+
a = GetBDValueMust(self);
|
|
3269
|
+
b = GetBDValueMust(v);
|
|
3270
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3271
|
+
ntt_multiply(a.real->Prec, b.real->Prec, a.real->frac, b.real->frac, c.real->frac);
|
|
3272
|
+
VpSetSign(c.real, a.real->sign * b.real->sign);
|
|
3273
|
+
c.real->exponent = a.real->exponent + b.real->exponent;
|
|
3274
|
+
c.real->Prec = a.real->Prec + b.real->Prec;
|
|
3275
|
+
VpNmlz(c.real);
|
|
3276
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3277
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3278
|
+
return c.bigdecimal;
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3284
3281
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3285
3282
|
|
|
3286
3283
|
/* Document-class: BigDecimal
|
|
@@ -3593,7 +3590,6 @@ Init_bigdecimal(void)
|
|
|
3593
3590
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
3594
3591
|
|
|
3595
3592
|
/* instance methods */
|
|
3596
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
3597
3593
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
3598
3594
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
3599
3595
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -3652,7 +3648,10 @@ Init_bigdecimal(void)
|
|
|
3652
3648
|
|
|
3653
3649
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3654
3650
|
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3651
|
+
rb_define_method(rb_cBigDecimal, "vpdivd_newton", BigDecimal_vpdivd_newton, 2);
|
|
3652
|
+
rb_define_method(rb_cBigDecimal, "newton_raphson_inverse", BigDecimal_newton_raphson_inverse, 1);
|
|
3655
3653
|
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3654
|
+
rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
|
|
3656
3655
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3657
3656
|
|
|
3658
3657
|
#define ROUNDING_MODE(i, name, value) \
|
|
@@ -3675,7 +3674,6 @@ Init_bigdecimal(void)
|
|
|
3675
3674
|
|
|
3676
3675
|
#undef ROUNDING_MODE
|
|
3677
3676
|
|
|
3678
|
-
id_to_r = rb_intern_const("to_r");
|
|
3679
3677
|
id_eq = rb_intern_const("==");
|
|
3680
3678
|
id_half = rb_intern_const("half");
|
|
3681
3679
|
|
|
@@ -3695,7 +3693,7 @@ Init_bigdecimal(void)
|
|
|
3695
3693
|
static int gfDebug = 1; /* Debug switch */
|
|
3696
3694
|
#endif /* BIGDECIMAL_DEBUG */
|
|
3697
3695
|
|
|
3698
|
-
static
|
|
3696
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
3699
3697
|
|
|
3700
3698
|
enum op_sw {
|
|
3701
3699
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4096,8 +4094,9 @@ VpInit(DECDIG BaseVal)
|
|
|
4096
4094
|
VpGetDoubleNegZero();
|
|
4097
4095
|
|
|
4098
4096
|
/* Const 1.0 */
|
|
4099
|
-
VpConstOne
|
|
4100
|
-
|
|
4097
|
+
rb_global_variable(&VpConstOne);
|
|
4098
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4099
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
4101
4100
|
|
|
4102
4101
|
#ifdef BIGDECIMAL_DEBUG
|
|
4103
4102
|
gnAlloc = 0;
|
|
@@ -4109,7 +4108,7 @@ VpInit(DECDIG BaseVal)
|
|
|
4109
4108
|
VP_EXPORT Real *
|
|
4110
4109
|
VpOne(void)
|
|
4111
4110
|
{
|
|
4112
|
-
return VpConstOne;
|
|
4111
|
+
return VpPtr(VpConstOne);
|
|
4113
4112
|
}
|
|
4114
4113
|
|
|
4115
4114
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -4140,7 +4139,7 @@ overflow:
|
|
|
4140
4139
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
4141
4140
|
}
|
|
4142
4141
|
|
|
4143
|
-
|
|
4142
|
+
NULLABLE_BDVALUE
|
|
4144
4143
|
bigdecimal_parse_special_string(const char *str)
|
|
4145
4144
|
{
|
|
4146
4145
|
static const struct {
|
|
@@ -4165,66 +4164,27 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
4165
4164
|
p = str + table[i].len;
|
|
4166
4165
|
while (*p && ISSPACE(*p)) ++p;
|
|
4167
4166
|
if (*p == '\0') {
|
|
4168
|
-
|
|
4167
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4168
|
+
Real *vp = VpPtr(obj);
|
|
4169
4169
|
switch (table[i].sign) {
|
|
4170
4170
|
default:
|
|
4171
|
-
UNREACHABLE;
|
|
4171
|
+
UNREACHABLE;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4172
4173
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
4173
4174
|
VpSetPosInf(vp);
|
|
4174
|
-
|
|
4175
|
+
break;
|
|
4175
4176
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
4176
4177
|
VpSetNegInf(vp);
|
|
4177
|
-
|
|
4178
|
+
break;
|
|
4178
4179
|
case VP_SIGN_NaN:
|
|
4179
4180
|
VpSetNaN(vp);
|
|
4180
|
-
|
|
4181
|
+
break;
|
|
4181
4182
|
}
|
|
4183
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4182
4184
|
}
|
|
4183
4185
|
}
|
|
4184
4186
|
|
|
4185
|
-
return NULL;
|
|
4186
|
-
}
|
|
4187
|
-
|
|
4188
|
-
struct VpCtoV_args {
|
|
4189
|
-
Real *a;
|
|
4190
|
-
const char *int_chr;
|
|
4191
|
-
size_t ni;
|
|
4192
|
-
const char *frac;
|
|
4193
|
-
size_t nf;
|
|
4194
|
-
const char *exp_chr;
|
|
4195
|
-
size_t ne;
|
|
4196
|
-
};
|
|
4197
|
-
|
|
4198
|
-
static VALUE
|
|
4199
|
-
call_VpCtoV(VALUE arg)
|
|
4200
|
-
{
|
|
4201
|
-
struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
|
|
4202
|
-
return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
|
|
4203
|
-
}
|
|
4204
|
-
|
|
4205
|
-
static int
|
|
4206
|
-
protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne, int free_on_error)
|
|
4207
|
-
{
|
|
4208
|
-
struct VpCtoV_args args;
|
|
4209
|
-
int state = 0;
|
|
4210
|
-
|
|
4211
|
-
args.a = a;
|
|
4212
|
-
args.int_chr = int_chr;
|
|
4213
|
-
args.ni = ni;
|
|
4214
|
-
args.frac = frac;
|
|
4215
|
-
args.nf = nf;
|
|
4216
|
-
args.exp_chr = exp_chr;
|
|
4217
|
-
args.ne = ne;
|
|
4218
|
-
|
|
4219
|
-
VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
|
|
4220
|
-
if (state) {
|
|
4221
|
-
if (free_on_error) {
|
|
4222
|
-
rbd_free_struct(a);
|
|
4223
|
-
}
|
|
4224
|
-
rb_jump_tag(state);
|
|
4225
|
-
}
|
|
4226
|
-
|
|
4227
|
-
return (int)result;
|
|
4187
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4228
4188
|
}
|
|
4229
4189
|
|
|
4230
4190
|
/*
|
|
@@ -4233,25 +4193,25 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
4233
4193
|
* szVal ... The value assigned(char).
|
|
4234
4194
|
*
|
|
4235
4195
|
* [Returns]
|
|
4236
|
-
*
|
|
4237
|
-
*
|
|
4196
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4197
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
4238
4198
|
*/
|
|
4239
|
-
VP_EXPORT
|
|
4199
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4240
4200
|
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
4241
4201
|
{
|
|
4242
4202
|
const char *orig_szVal = szVal;
|
|
4243
4203
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
4244
4204
|
char v, *psz;
|
|
4245
4205
|
int sign=1;
|
|
4246
|
-
Real *vp = NULL;
|
|
4247
4206
|
VALUE buf;
|
|
4248
4207
|
|
|
4249
4208
|
/* Skipping leading spaces */
|
|
4250
4209
|
while (ISSPACE(*szVal)) szVal++;
|
|
4251
4210
|
|
|
4252
4211
|
/* Check on Inf & NaN */
|
|
4253
|
-
|
|
4254
|
-
|
|
4212
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4213
|
+
if (special_bd.real_or_null != NULL) {
|
|
4214
|
+
return special_bd;
|
|
4255
4215
|
}
|
|
4256
4216
|
|
|
4257
4217
|
/* Skip leading `#`.
|
|
@@ -4405,10 +4365,11 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4405
4365
|
VALUE str;
|
|
4406
4366
|
invalid_value:
|
|
4407
4367
|
if (!strict_p) {
|
|
4408
|
-
|
|
4368
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4369
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
4409
4370
|
}
|
|
4410
4371
|
if (!exc) {
|
|
4411
|
-
return NULL;
|
|
4372
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4412
4373
|
}
|
|
4413
4374
|
str = rb_str_new2(orig_szVal);
|
|
4414
4375
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -4416,11 +4377,12 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4416
4377
|
|
|
4417
4378
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
4418
4379
|
/* units for szVal[] */
|
|
4419
|
-
|
|
4380
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4381
|
+
Real *vp = VpPtr(obj);
|
|
4420
4382
|
VpSetZero(vp, sign);
|
|
4421
|
-
|
|
4383
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
4422
4384
|
rb_str_resize(buf, 0);
|
|
4423
|
-
return vp;
|
|
4385
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4424
4386
|
}
|
|
4425
4387
|
|
|
4426
4388
|
/*
|
|
@@ -4892,17 +4854,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
4892
4854
|
* a0 a1 .... an * b0
|
|
4893
4855
|
* +_____________________________
|
|
4894
4856
|
* c0 c1 c2 ...... cl
|
|
4895
|
-
* nc <---|
|
|
4896
|
-
* MaxAB |--------------------|
|
|
4897
4857
|
*/
|
|
4898
4858
|
VP_EXPORT size_t
|
|
4899
4859
|
VpMult(Real *c, Real *a, Real *b)
|
|
4900
4860
|
{
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
4904
|
-
DECDIG carry;
|
|
4905
|
-
DECDIG_DBL s;
|
|
4861
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4862
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
4906
4863
|
|
|
4907
4864
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
4908
4865
|
|
|
@@ -4926,61 +4883,57 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
4926
4883
|
a = b;
|
|
4927
4884
|
b = w;
|
|
4928
4885
|
}
|
|
4929
|
-
MxIndA = a->Prec - 1;
|
|
4930
|
-
MxIndB = b->Prec - 1;
|
|
4931
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
4932
4886
|
|
|
4933
4887
|
/* set LHSV c info */
|
|
4934
4888
|
|
|
4935
4889
|
c->exponent = a->exponent; /* set exponent */
|
|
4936
4890
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4937
4891
|
if (!AddExponent(c, b->exponent)) return 0;
|
|
4938
|
-
carry = 0;
|
|
4939
|
-
nc = ind_c = MxIndAB;
|
|
4940
|
-
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
|
4941
|
-
c->Prec = nc + 1; /* set precision */
|
|
4942
|
-
for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
|
|
4943
|
-
if (nc < MxIndB) { /* The left triangle of the Fig. */
|
|
4944
|
-
ind_as = MxIndA - nc;
|
|
4945
|
-
ind_ae = MxIndA;
|
|
4946
|
-
ind_bs = MxIndB;
|
|
4947
|
-
}
|
|
4948
|
-
else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
|
|
4949
|
-
ind_as = MxIndA - nc;
|
|
4950
|
-
ind_ae = MxIndA - (nc - MxIndB);
|
|
4951
|
-
ind_bs = MxIndB;
|
|
4952
|
-
}
|
|
4953
|
-
else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
|
|
4954
|
-
ind_as = 0;
|
|
4955
|
-
ind_ae = MxIndAB - nc - 1;
|
|
4956
|
-
ind_bs = MxIndB - (nc - MxIndA);
|
|
4957
|
-
}
|
|
4958
4892
|
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4893
|
+
if (b->Prec >= NTT_MULTIPLICATION_THRESHOLD) {
|
|
4894
|
+
ntt_multiply(a->Prec, b->Prec, a->frac, b->frac, c->frac);
|
|
4895
|
+
c->Prec = a->Prec + b->Prec;
|
|
4896
|
+
goto Cleanup;
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4899
|
+
c->Prec = a->Prec + b->Prec; /* set precision */
|
|
4900
|
+
memset(c->frac, 0, c->Prec * sizeof(DECDIG)); /* Initialize c */
|
|
4901
|
+
|
|
4902
|
+
// Process VPMULT_BATCH_SIZE decdigits at a time to reduce the number of carry operations.
|
|
4903
|
+
a_batch_max = (a->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4904
|
+
b_batch_max = (b->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4905
|
+
for (ssize_t ibatch = a_batch_max; ibatch >= 0; ibatch--) {
|
|
4906
|
+
int isize = ibatch == a_batch_max ? (a->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4907
|
+
for (ssize_t jbatch = b_batch_max; jbatch >= 0; jbatch--) {
|
|
4908
|
+
int jsize = jbatch == b_batch_max ? (b->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4909
|
+
memset(batch, 0, (isize + jsize - 1) * sizeof(DECDIG_DBL));
|
|
4910
|
+
|
|
4911
|
+
// Perform multiplication without carry calculation.
|
|
4912
|
+
// BASE * BASE * VPMULT_BATCH_SIZE < 2**64 should be satisfied so that
|
|
4913
|
+
// DECDIG_DBL can hold the intermediate sum without overflow.
|
|
4914
|
+
for (int i = 0; i < isize; i++) {
|
|
4915
|
+
for (int j = 0; j < jsize; j++) {
|
|
4916
|
+
batch[i + j] += (DECDIG_DBL)a->frac[ibatch * VPMULT_BATCH_SIZE + i] * b->frac[jbatch * VPMULT_BATCH_SIZE + j];
|
|
4917
|
+
}
|
|
4968
4918
|
}
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4919
|
+
|
|
4920
|
+
// Add the batch result to c with carry calculation.
|
|
4921
|
+
DECDIG_DBL carry = 0;
|
|
4922
|
+
for (int k = isize + jsize - 2; k >= 0; k--) {
|
|
4923
|
+
size_t l = (ibatch + jbatch) * VPMULT_BATCH_SIZE + k + 1;
|
|
4924
|
+
DECDIG_DBL s = c->frac[l] + batch[k] + carry;
|
|
4925
|
+
c->frac[l] = (DECDIG)(s % BASE);
|
|
4926
|
+
carry = (DECDIG_DBL)(s / BASE);
|
|
4927
|
+
}
|
|
4928
|
+
|
|
4929
|
+
// Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
|
|
4930
|
+
// Exceeded value will be resolved in the carry operation of next (ibatch + jbatch - 1) batch.
|
|
4931
|
+
// WARNING: This safety strongly relies on the current nested loop execution order.
|
|
4932
|
+
c->frac[(ibatch + jbatch) * VPMULT_BATCH_SIZE] += (DECDIG)carry;
|
|
4933
|
+
}
|
|
4983
4934
|
}
|
|
4935
|
+
|
|
4936
|
+
Cleanup:
|
|
4984
4937
|
VpNmlz(c);
|
|
4985
4938
|
|
|
4986
4939
|
Exit:
|
|
@@ -5028,6 +4981,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
5028
4981
|
|
|
5029
4982
|
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
5030
4983
|
|
|
4984
|
+
if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
|
|
4985
|
+
VpDivdNewton(c, r, a, b);
|
|
4986
|
+
goto Exit;
|
|
4987
|
+
}
|
|
4988
|
+
|
|
5031
4989
|
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5032
4990
|
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5033
4991
|
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
@@ -5178,6 +5136,7 @@ VpNmlz(Real *a)
|
|
|
5178
5136
|
NoVal:
|
|
5179
5137
|
a->frac[0] = 0;
|
|
5180
5138
|
a->Prec = 1;
|
|
5139
|
+
a->exponent = 0;
|
|
5181
5140
|
return 0;
|
|
5182
5141
|
}
|
|
5183
5142
|
|
|
@@ -5453,8 +5412,8 @@ VpSzMantissa(Real *a, char *buf, size_t buflen)
|
|
|
5453
5412
|
while (m) {
|
|
5454
5413
|
nn = e / m;
|
|
5455
5414
|
if (!ZeroSup || nn) {
|
|
5456
|
-
|
|
5457
|
-
buf
|
|
5415
|
+
*buf = (char)('0' + nn);
|
|
5416
|
+
buf++;
|
|
5458
5417
|
/* as 0.00xx will be ignored. */
|
|
5459
5418
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
5460
5419
|
}
|
|
@@ -5506,10 +5465,22 @@ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
|
|
|
5506
5465
|
return 0;
|
|
5507
5466
|
}
|
|
5508
5467
|
|
|
5468
|
+
#define ULLTOA_BUFFER_SIZE 20
|
|
5469
|
+
static size_t Vp_ulltoa(unsigned long long number, char *buf)
|
|
5470
|
+
{
|
|
5471
|
+
static const char digits[] = "0123456789";
|
|
5472
|
+
char* tmp = buf;
|
|
5473
|
+
|
|
5474
|
+
do *tmp-- = digits[number % 10]; while (number /= 10);
|
|
5475
|
+
return buf - tmp;
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5509
5478
|
VP_EXPORT void
|
|
5510
5479
|
VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
5511
5480
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
5512
5481
|
{
|
|
5482
|
+
char ulltoa_buf[ULLTOA_BUFFER_SIZE];
|
|
5483
|
+
char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
|
|
5513
5484
|
size_t i, n, ZeroSup;
|
|
5514
5485
|
DECDIG shift, m, e, nn;
|
|
5515
5486
|
char *p = buf;
|
|
@@ -5549,10 +5520,9 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
5549
5520
|
while (m) {
|
|
5550
5521
|
nn = e / m;
|
|
5551
5522
|
if (!ZeroSup || nn) {
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
ADVANCE(n);
|
|
5523
|
+
*p = (char)('0' + nn);
|
|
5524
|
+
ADVANCE(1);
|
|
5525
|
+
|
|
5556
5526
|
/* as 0.00xx will be ignored. */
|
|
5557
5527
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
5558
5528
|
}
|
|
@@ -5571,7 +5541,22 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
5571
5541
|
*(--p) = '\0';
|
|
5572
5542
|
++plen;
|
|
5573
5543
|
}
|
|
5574
|
-
|
|
5544
|
+
*p = 'e';
|
|
5545
|
+
ADVANCE(1);
|
|
5546
|
+
|
|
5547
|
+
if (ex < 0) {
|
|
5548
|
+
*p = '-';
|
|
5549
|
+
ADVANCE(1);
|
|
5550
|
+
ex = -ex;
|
|
5551
|
+
}
|
|
5552
|
+
|
|
5553
|
+
size_t ex_n = Vp_ulltoa(ex, ulltoa_buf_end - 1);
|
|
5554
|
+
if (ex_n > plen) goto overflow;
|
|
5555
|
+
MEMCPY(p, ulltoa_buf_end - ex_n, char, ex_n);
|
|
5556
|
+
ADVANCE(ex_n);
|
|
5557
|
+
*p = '\0';
|
|
5558
|
+
ADVANCE(1);
|
|
5559
|
+
|
|
5575
5560
|
if (fFmt) VpFormatSt(buf, fFmt);
|
|
5576
5561
|
|
|
5577
5562
|
overflow:
|
|
@@ -6036,7 +6021,7 @@ VpMidRound(Real *y, unsigned short f, ssize_t nf)
|
|
|
6036
6021
|
y->frac[ix] = div;
|
|
6037
6022
|
VpNmlz(y);
|
|
6038
6023
|
}
|
|
6039
|
-
if (exptoadd > 0) {
|
|
6024
|
+
if (exptoadd > 0 && !VpIsZero(y)) {
|
|
6040
6025
|
y->exponent += (SIGNED_VALUE)(exptoadd / BASE_FIG);
|
|
6041
6026
|
exptoadd %= (ssize_t)BASE_FIG;
|
|
6042
6027
|
for (i = 0; i < exptoadd; i++) {
|
|
@@ -6166,7 +6151,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6166
6151
|
size_t my, ind_y, ind_x;
|
|
6167
6152
|
|
|
6168
6153
|
if (!VpHasVal(x)) {
|
|
6169
|
-
VpAsgn(y, x,
|
|
6154
|
+
VpAsgn(y, x, 10);
|
|
6170
6155
|
goto Exit;
|
|
6171
6156
|
}
|
|
6172
6157
|
|
|
@@ -6175,7 +6160,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6175
6160
|
goto Exit;
|
|
6176
6161
|
}
|
|
6177
6162
|
else if (x->exponent <= 0) {
|
|
6178
|
-
VpAsgn(y, x,
|
|
6163
|
+
VpAsgn(y, x, 10);
|
|
6179
6164
|
goto Exit;
|
|
6180
6165
|
}
|
|
6181
6166
|
|