bigdecimal 3.3.1 → 4.1.2
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 +6 -1
- data/ext/bigdecimal/bigdecimal.c +266 -297
- data/ext/bigdecimal/bigdecimal.h +43 -37
- data/ext/bigdecimal/div.h +192 -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.rb +760 -82
- 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 +1502 -0
- data/sig/big_decimal_util.rbs +158 -0
- data/sig/big_math.rbs +423 -0
- metadata +8 -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.2"
|
|
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)
|
|
@@ -75,16 +79,6 @@ static struct {
|
|
|
75
79
|
uint8_t mode;
|
|
76
80
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
77
81
|
|
|
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
82
|
static inline BDVALUE
|
|
89
83
|
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
90
84
|
{
|
|
@@ -160,42 +154,6 @@ rbd_struct_size(size_t const internal_digits)
|
|
|
160
154
|
return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
|
|
161
155
|
}
|
|
162
156
|
|
|
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
157
|
/*
|
|
200
158
|
* ================== Ruby Interface part ==========================
|
|
201
159
|
*/
|
|
@@ -207,11 +165,9 @@ rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
|
207
165
|
static unsigned short VpGetException(void);
|
|
208
166
|
static void VpSetException(unsigned short f);
|
|
209
167
|
static void VpCheckException(Real *p, bool always);
|
|
210
|
-
static int AddExponent(Real *a, SIGNED_VALUE n);
|
|
211
168
|
static VALUE CheckGetValue(BDVALUE v);
|
|
212
169
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
213
170
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
214
|
-
static Real *VpCopy(Real *pv, Real const* const x);
|
|
215
171
|
static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
|
|
216
172
|
|
|
217
173
|
/*
|
|
@@ -226,49 +182,67 @@ static VALUE BigDecimal_negative_zero(void);
|
|
|
226
182
|
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
227
183
|
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
228
184
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
185
|
+
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
186
|
+
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
187
|
+
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
188
|
+
#endif
|
|
189
|
+
|
|
190
|
+
#ifdef RUBY_TYPED_EMBEDDABLE
|
|
191
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
192
|
+
#else
|
|
193
|
+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
|
|
194
|
+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
|
|
195
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
196
|
+
# else
|
|
197
|
+
# define RUBY_TYPED_EMBEDDABLE 0
|
|
198
|
+
# endif
|
|
199
|
+
#endif
|
|
234
200
|
|
|
235
201
|
static size_t
|
|
236
202
|
BigDecimal_memsize(const void *ptr)
|
|
237
203
|
{
|
|
204
|
+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
205
|
+
return 0; // Entirely embedded
|
|
206
|
+
#else
|
|
238
207
|
const Real *pv = ptr;
|
|
239
208
|
return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
243
|
-
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
244
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
245
209
|
#endif
|
|
210
|
+
}
|
|
246
211
|
|
|
247
212
|
static const rb_data_type_t BigDecimal_data_type = {
|
|
248
|
-
"BigDecimal",
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
213
|
+
.wrap_struct_name = "BigDecimal",
|
|
214
|
+
.function = {
|
|
215
|
+
.dmark = 0,
|
|
216
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
217
|
+
.dsize = BigDecimal_memsize,
|
|
218
|
+
},
|
|
219
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
|
|
253
220
|
};
|
|
254
221
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
|
258
|
-
static NULL_WRAPPED_VALUE
|
|
259
|
-
BigDecimal_alloc_empty_struct(VALUE klass)
|
|
222
|
+
static VALUE
|
|
223
|
+
BigDecimal_allocate(size_t const internal_digits)
|
|
260
224
|
{
|
|
261
|
-
|
|
225
|
+
const size_t size = rbd_struct_size(internal_digits);
|
|
226
|
+
VALUE bd = rb_data_typed_object_zalloc(rb_cBigDecimal, size, &BigDecimal_data_type);
|
|
227
|
+
Real *vp;
|
|
228
|
+
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
229
|
+
vp->MaxPrec = internal_digits;
|
|
230
|
+
RB_OBJ_FREEZE(bd);
|
|
231
|
+
return bd;
|
|
262
232
|
}
|
|
263
233
|
|
|
264
234
|
static VALUE
|
|
265
|
-
|
|
235
|
+
BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
|
|
266
236
|
{
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
237
|
+
return BigDecimal_allocate(roomof(decimal_digits, BASE_FIG));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static Real *
|
|
241
|
+
VpPtr(VALUE obj)
|
|
242
|
+
{
|
|
243
|
+
Real *vp;
|
|
244
|
+
TypedData_Get_Struct(obj, Real, &BigDecimal_data_type, vp);
|
|
245
|
+
return vp;
|
|
272
246
|
}
|
|
273
247
|
|
|
274
248
|
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
@@ -276,9 +250,10 @@ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_
|
|
|
276
250
|
static BDVALUE
|
|
277
251
|
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
278
252
|
{
|
|
279
|
-
|
|
280
|
-
Real *real =
|
|
281
|
-
|
|
253
|
+
VALUE obj = BigDecimal_allocate_decimal_digits(digits);
|
|
254
|
+
Real *real = VpPtr(obj);
|
|
255
|
+
VpSetZero(real, sign);
|
|
256
|
+
return (BDVALUE) { obj, real };
|
|
282
257
|
}
|
|
283
258
|
|
|
284
259
|
static inline int
|
|
@@ -336,20 +311,11 @@ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
|
336
311
|
break;
|
|
337
312
|
}
|
|
338
313
|
|
|
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
314
|
default:
|
|
348
315
|
goto SomeOneMayDoIt;
|
|
349
316
|
}
|
|
350
317
|
|
|
351
|
-
Real *vp;
|
|
352
|
-
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
|
318
|
+
Real *vp = VpPtr(v);
|
|
353
319
|
return (NULLABLE_BDVALUE) { v, vp };
|
|
354
320
|
|
|
355
321
|
SomeOneMayDoIt:
|
|
@@ -400,37 +366,6 @@ BigDecimal_double_fig(VALUE self)
|
|
|
400
366
|
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
401
367
|
}
|
|
402
368
|
|
|
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
369
|
static void
|
|
435
370
|
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
436
371
|
{
|
|
@@ -1027,7 +962,7 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1027
962
|
static size_t
|
|
1028
963
|
GetAddSubPrec(Real *a, Real *b)
|
|
1029
964
|
{
|
|
1030
|
-
if (
|
|
965
|
+
if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
|
|
1031
966
|
ssize_t min_a = a->exponent - a->Prec;
|
|
1032
967
|
ssize_t min_b = b->exponent - b->Prec;
|
|
1033
968
|
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
@@ -1053,26 +988,18 @@ check_int_precision(VALUE v)
|
|
|
1053
988
|
static NULLABLE_BDVALUE
|
|
1054
989
|
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1055
990
|
{
|
|
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 };
|
|
991
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1060
992
|
}
|
|
1061
993
|
|
|
1062
|
-
|
|
1063
|
-
|
|
994
|
+
void
|
|
995
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1064
996
|
{
|
|
1065
|
-
assert(x != NULL);
|
|
1066
|
-
|
|
1067
|
-
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1068
997
|
pv->MaxPrec = x->MaxPrec;
|
|
1069
998
|
pv->Prec = x->Prec;
|
|
1070
999
|
pv->exponent = x->exponent;
|
|
1071
1000
|
pv->sign = x->sign;
|
|
1072
1001
|
pv->flag = x->flag;
|
|
1073
1002
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1074
|
-
|
|
1075
|
-
return pv;
|
|
1076
1003
|
}
|
|
1077
1004
|
|
|
1078
1005
|
/* Returns True if the value is Not a Number. */
|
|
@@ -1112,9 +1039,6 @@ BigDecimal_check_num(Real *p)
|
|
|
1112
1039
|
VpCheckException(p, true);
|
|
1113
1040
|
}
|
|
1114
1041
|
|
|
1115
|
-
static VALUE BigDecimal_fix(VALUE self);
|
|
1116
|
-
static VALUE BigDecimal_split(VALUE self);
|
|
1117
|
-
|
|
1118
1042
|
/* Returns the value as an Integer.
|
|
1119
1043
|
*
|
|
1120
1044
|
* If the BigDecimal is infinity or NaN, raises FloatDomainError.
|
|
@@ -1265,7 +1189,7 @@ GetCoercePrec(Real *a, size_t prec)
|
|
|
1265
1189
|
static VALUE
|
|
1266
1190
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1267
1191
|
{
|
|
1268
|
-
Real* pv =
|
|
1192
|
+
Real* pv = VpPtr(self);
|
|
1269
1193
|
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1270
1194
|
return rb_assoc_new(CheckGetValue(b), self);
|
|
1271
1195
|
}
|
|
@@ -1331,13 +1255,32 @@ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
|
1331
1255
|
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1332
1256
|
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1333
1257
|
|
|
1334
|
-
|
|
1335
|
-
if (mx == (size_t)-1L) {
|
|
1336
|
-
/* a or b is inf */
|
|
1258
|
+
if (VpIsInf(a.real) || VpIsInf(b.real)) {
|
|
1337
1259
|
c = NewZeroWrap(1, BASE_FIG);
|
|
1338
1260
|
VpAddSub(c.real, a.real, b.real, operation);
|
|
1339
1261
|
}
|
|
1340
1262
|
else {
|
|
1263
|
+
|
|
1264
|
+
// Optimization when exponent difference is large
|
|
1265
|
+
// (1.234e+1000).add(5.678e-1000, 10) == (1.234e+1000).add(0.1e+990, 10) in every rounding mode
|
|
1266
|
+
if (prec && !VpIsZero(a.real) && !VpIsZero(b.real)) {
|
|
1267
|
+
size_t precRoom = roomof(prec, BASE_FIG);
|
|
1268
|
+
if (a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1 > b.real->exponent) {
|
|
1269
|
+
BDVALUE b2 = NewZeroWrap(1, BASE_FIG);
|
|
1270
|
+
VpSetOne(b2.real)
|
|
1271
|
+
VpSetSign(b2.real, b.real->sign);
|
|
1272
|
+
b2.real->exponent = a.real->exponent - (ssize_t)Max(a.real->Prec, precRoom) - 1;
|
|
1273
|
+
b = b2;
|
|
1274
|
+
} else if (b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1 > a.real->exponent) {
|
|
1275
|
+
BDVALUE a2 = NewZeroWrap(1, BASE_FIG);
|
|
1276
|
+
VpSetOne(a2.real)
|
|
1277
|
+
VpSetSign(a2.real, a.real->sign);
|
|
1278
|
+
a2.real->exponent = b.real->exponent - (ssize_t)Max(b.real->Prec, precRoom) - 1;
|
|
1279
|
+
a = a2;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
mx = GetAddSubPrec(a.real, b.real);
|
|
1341
1284
|
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1342
1285
|
size_t pl = VpGetPrecLimit();
|
|
1343
1286
|
if (prec) VpSetPrecLimit(prec);
|
|
@@ -1714,7 +1657,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1714
1657
|
|
|
1715
1658
|
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1716
1659
|
VALUE nan = BigDecimal_nan();
|
|
1717
|
-
*div = *mod = (NULLABLE_BDVALUE) { nan,
|
|
1660
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1718
1661
|
goto Done;
|
|
1719
1662
|
}
|
|
1720
1663
|
if (VpIsZero(b.real)) {
|
|
@@ -1723,19 +1666,19 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1723
1666
|
if (VpIsInf(a.real)) {
|
|
1724
1667
|
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1725
1668
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1726
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1669
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1727
1670
|
}
|
|
1728
1671
|
else {
|
|
1729
1672
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1730
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1731
1674
|
}
|
|
1732
1675
|
VALUE nan = BigDecimal_nan();
|
|
1733
|
-
*mod = (NULLABLE_BDVALUE) { nan,
|
|
1676
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1734
1677
|
goto Done;
|
|
1735
1678
|
}
|
|
1736
1679
|
if (VpIsZero(a.real)) {
|
|
1737
1680
|
VALUE zero = BigDecimal_positive_zero();
|
|
1738
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1681
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1739
1682
|
*mod = bdvalue_nullable(a);
|
|
1740
1683
|
goto Done;
|
|
1741
1684
|
}
|
|
@@ -1749,7 +1692,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1749
1692
|
*mod = bdvalue_nullable(b);
|
|
1750
1693
|
} else {
|
|
1751
1694
|
VALUE zero = BigDecimal_positive_zero();
|
|
1752
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1753
1696
|
*mod = bdvalue_nullable(a);
|
|
1754
1697
|
}
|
|
1755
1698
|
goto Done;
|
|
@@ -1867,7 +1810,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
1867
1810
|
NULLABLE_BDVALUE div, mod;
|
|
1868
1811
|
|
|
1869
1812
|
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1870
|
-
return rb_assoc_new(CheckGetValue(bdvalue_nonnullable(div)), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
1813
|
+
return rb_assoc_new(BigDecimal_to_i(CheckGetValue(bdvalue_nonnullable(div))), CheckGetValue(bdvalue_nonnullable(mod)));
|
|
1871
1814
|
}
|
|
1872
1815
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
1873
1816
|
}
|
|
@@ -2507,7 +2450,7 @@ BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
|
2507
2450
|
prec = a.real->Prec + shiftDown;
|
|
2508
2451
|
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2509
2452
|
if (shift == 0) {
|
|
2510
|
-
VpAsgn(c.real, a.real,
|
|
2453
|
+
VpAsgn(c.real, a.real, 10);
|
|
2511
2454
|
} else if (shiftDown) {
|
|
2512
2455
|
DECDIG carry = 0;
|
|
2513
2456
|
exponentShift++;
|
|
@@ -2593,9 +2536,7 @@ check_exception(VALUE bd)
|
|
|
2593
2536
|
{
|
|
2594
2537
|
assert(is_kind_of_BigDecimal(bd));
|
|
2595
2538
|
|
|
2596
|
-
|
|
2597
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2598
|
-
VpCheckException(vp, false);
|
|
2539
|
+
VpCheckException(VpPtr(bd), false);
|
|
2599
2540
|
|
|
2600
2541
|
return bd;
|
|
2601
2542
|
}
|
|
@@ -2603,17 +2544,19 @@ check_exception(VALUE bd)
|
|
|
2603
2544
|
static VALUE
|
|
2604
2545
|
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
2605
2546
|
{
|
|
2606
|
-
|
|
2547
|
+
VALUE bd;
|
|
2607
2548
|
Real *vp;
|
|
2608
2549
|
if (uval == 0) {
|
|
2609
|
-
|
|
2550
|
+
bd = BigDecimal_allocate(1);
|
|
2551
|
+
vp = VpPtr(bd);
|
|
2610
2552
|
vp->Prec = 1;
|
|
2611
2553
|
vp->exponent = 1;
|
|
2612
2554
|
VpSetZero(vp, 1);
|
|
2613
2555
|
vp->frac[0] = 0;
|
|
2614
2556
|
}
|
|
2615
2557
|
else if (uval < BASE) {
|
|
2616
|
-
|
|
2558
|
+
bd = BigDecimal_allocate(1);
|
|
2559
|
+
vp = VpPtr(bd);
|
|
2617
2560
|
vp->Prec = 1;
|
|
2618
2561
|
vp->exponent = 1;
|
|
2619
2562
|
VpSetSign(vp, 1);
|
|
@@ -2638,14 +2581,15 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
|
2638
2581
|
}
|
|
2639
2582
|
|
|
2640
2583
|
const size_t exp = len + ntz;
|
|
2641
|
-
|
|
2584
|
+
bd = BigDecimal_allocate(len);
|
|
2585
|
+
vp = VpPtr(bd);
|
|
2642
2586
|
vp->Prec = len;
|
|
2643
2587
|
vp->exponent = exp;
|
|
2644
2588
|
VpSetSign(vp, 1);
|
|
2645
2589
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
2646
2590
|
}
|
|
2647
2591
|
|
|
2648
|
-
return
|
|
2592
|
+
return bd;
|
|
2649
2593
|
}
|
|
2650
2594
|
|
|
2651
2595
|
static VALUE
|
|
@@ -2654,8 +2598,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
|
2654
2598
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
2655
2599
|
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
2656
2600
|
if (ival < 0) {
|
|
2657
|
-
Real *vp;
|
|
2658
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2601
|
+
Real *vp = VpPtr(bd);
|
|
2659
2602
|
VpSetSign(vp, -1);
|
|
2660
2603
|
}
|
|
2661
2604
|
return bd;
|
|
@@ -2766,7 +2709,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2766
2709
|
len10 = BIGDECIMAL_DOUBLE_FIGURES;
|
|
2767
2710
|
}
|
|
2768
2711
|
memcpy(buf, p, len10);
|
|
2769
|
-
|
|
2712
|
+
free(p);
|
|
2770
2713
|
|
|
2771
2714
|
VALUE inum;
|
|
2772
2715
|
size_t RB_UNUSED_VAR(prec) = 0;
|
|
@@ -2862,8 +2805,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2862
2805
|
}
|
|
2863
2806
|
|
|
2864
2807
|
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2865
|
-
Real *vp;
|
|
2866
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2808
|
+
Real *vp = VpPtr(bd);
|
|
2867
2809
|
assert(vp->Prec == prec);
|
|
2868
2810
|
vp->exponent = exp;
|
|
2869
2811
|
|
|
@@ -2929,13 +2871,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2929
2871
|
if (digs == SIZE_MAX)
|
|
2930
2872
|
return check_exception(val);
|
|
2931
2873
|
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2874
|
+
Real *vp = VpPtr(val);
|
|
2875
|
+
|
|
2876
|
+
VALUE copy = BigDecimal_allocate(vp->MaxPrec);
|
|
2877
|
+
Real *vp_copy = VpPtr(copy);
|
|
2878
|
+
|
|
2879
|
+
VpMemCopy(vp_copy, vp);
|
|
2880
|
+
|
|
2936
2881
|
RB_GC_GUARD(val);
|
|
2937
2882
|
|
|
2938
|
-
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
2939
2883
|
/* TODO: rounding */
|
|
2940
2884
|
return check_exception(copy);
|
|
2941
2885
|
}
|
|
@@ -3257,19 +3201,39 @@ BigDecimal_literal(const char *str)
|
|
|
3257
3201
|
|
|
3258
3202
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3259
3203
|
VALUE
|
|
3260
|
-
|
|
3261
|
-
BDVALUE a,b,c,d;
|
|
3204
|
+
BigDecimal_vpdivd_generic(VALUE self, VALUE r, VALUE cprec, void (*vpdivd_func)(Real*, Real*, Real*, Real*)) {
|
|
3205
|
+
BDVALUE a, b, c, d;
|
|
3262
3206
|
size_t cn = NUM2INT(cprec);
|
|
3263
3207
|
a = GetBDValueMust(self);
|
|
3264
3208
|
b = GetBDValueMust(r);
|
|
3265
3209
|
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3266
3210
|
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3267
|
-
|
|
3211
|
+
vpdivd_func(c.real, d.real, a.real, b.real);
|
|
3268
3212
|
RB_GC_GUARD(a.bigdecimal);
|
|
3269
3213
|
RB_GC_GUARD(b.bigdecimal);
|
|
3270
3214
|
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3271
3215
|
}
|
|
3272
3216
|
|
|
3217
|
+
void
|
|
3218
|
+
VpDivdNormal(Real *c, Real *r, Real *a, Real *b) {
|
|
3219
|
+
VpDivd(c, r, a, b);
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
VALUE
|
|
3223
|
+
BigDecimal_vpdivd(VALUE self, VALUE r, VALUE cprec) {
|
|
3224
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNormal);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
VALUE
|
|
3228
|
+
BigDecimal_vpdivd_newton(VALUE self, VALUE r, VALUE cprec) {
|
|
3229
|
+
return BigDecimal_vpdivd_generic(self, r, cprec, VpDivdNewton);
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
VALUE
|
|
3233
|
+
BigDecimal_newton_raphson_inverse(VALUE self, VALUE prec) {
|
|
3234
|
+
return newton_raphson_inverse(self, NUM2SIZET(prec));
|
|
3235
|
+
}
|
|
3236
|
+
|
|
3273
3237
|
VALUE
|
|
3274
3238
|
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3275
3239
|
BDVALUE a,b,c;
|
|
@@ -3281,6 +3245,23 @@ BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
|
3281
3245
|
RB_GC_GUARD(b.bigdecimal);
|
|
3282
3246
|
return c.bigdecimal;
|
|
3283
3247
|
}
|
|
3248
|
+
|
|
3249
|
+
VALUE
|
|
3250
|
+
BigDecimal_nttmult(VALUE self, VALUE v) {
|
|
3251
|
+
BDVALUE a,b,c;
|
|
3252
|
+
a = GetBDValueMust(self);
|
|
3253
|
+
b = GetBDValueMust(v);
|
|
3254
|
+
c = NewZeroWrap(1, VPMULT_RESULT_PREC(a.real, b.real) * BASE_FIG);
|
|
3255
|
+
ntt_multiply(a.real->Prec, b.real->Prec, a.real->frac, b.real->frac, c.real->frac);
|
|
3256
|
+
VpSetSign(c.real, a.real->sign * b.real->sign);
|
|
3257
|
+
c.real->exponent = a.real->exponent + b.real->exponent;
|
|
3258
|
+
c.real->Prec = a.real->Prec + b.real->Prec;
|
|
3259
|
+
VpNmlz(c.real);
|
|
3260
|
+
RB_GC_GUARD(a.bigdecimal);
|
|
3261
|
+
RB_GC_GUARD(b.bigdecimal);
|
|
3262
|
+
return c.bigdecimal;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3284
3265
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3285
3266
|
|
|
3286
3267
|
/* Document-class: BigDecimal
|
|
@@ -3593,7 +3574,6 @@ Init_bigdecimal(void)
|
|
|
3593
3574
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
3594
3575
|
|
|
3595
3576
|
/* instance methods */
|
|
3596
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
3597
3577
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
3598
3578
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
3599
3579
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -3652,7 +3632,10 @@ Init_bigdecimal(void)
|
|
|
3652
3632
|
|
|
3653
3633
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3654
3634
|
rb_define_method(rb_cBigDecimal, "vpdivd", BigDecimal_vpdivd, 2);
|
|
3635
|
+
rb_define_method(rb_cBigDecimal, "vpdivd_newton", BigDecimal_vpdivd_newton, 2);
|
|
3636
|
+
rb_define_method(rb_cBigDecimal, "newton_raphson_inverse", BigDecimal_newton_raphson_inverse, 1);
|
|
3655
3637
|
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3638
|
+
rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
|
|
3656
3639
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3657
3640
|
|
|
3658
3641
|
#define ROUNDING_MODE(i, name, value) \
|
|
@@ -3695,7 +3678,7 @@ Init_bigdecimal(void)
|
|
|
3695
3678
|
static int gfDebug = 1; /* Debug switch */
|
|
3696
3679
|
#endif /* BIGDECIMAL_DEBUG */
|
|
3697
3680
|
|
|
3698
|
-
static
|
|
3681
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
3699
3682
|
|
|
3700
3683
|
enum op_sw {
|
|
3701
3684
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4096,8 +4079,9 @@ VpInit(DECDIG BaseVal)
|
|
|
4096
4079
|
VpGetDoubleNegZero();
|
|
4097
4080
|
|
|
4098
4081
|
/* Const 1.0 */
|
|
4099
|
-
VpConstOne
|
|
4100
|
-
|
|
4082
|
+
rb_global_variable(&VpConstOne);
|
|
4083
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4084
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
4101
4085
|
|
|
4102
4086
|
#ifdef BIGDECIMAL_DEBUG
|
|
4103
4087
|
gnAlloc = 0;
|
|
@@ -4109,7 +4093,7 @@ VpInit(DECDIG BaseVal)
|
|
|
4109
4093
|
VP_EXPORT Real *
|
|
4110
4094
|
VpOne(void)
|
|
4111
4095
|
{
|
|
4112
|
-
return VpConstOne;
|
|
4096
|
+
return VpPtr(VpConstOne);
|
|
4113
4097
|
}
|
|
4114
4098
|
|
|
4115
4099
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -4140,7 +4124,7 @@ overflow:
|
|
|
4140
4124
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
4141
4125
|
}
|
|
4142
4126
|
|
|
4143
|
-
|
|
4127
|
+
NULLABLE_BDVALUE
|
|
4144
4128
|
bigdecimal_parse_special_string(const char *str)
|
|
4145
4129
|
{
|
|
4146
4130
|
static const struct {
|
|
@@ -4165,66 +4149,27 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
4165
4149
|
p = str + table[i].len;
|
|
4166
4150
|
while (*p && ISSPACE(*p)) ++p;
|
|
4167
4151
|
if (*p == '\0') {
|
|
4168
|
-
|
|
4152
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4153
|
+
Real *vp = VpPtr(obj);
|
|
4169
4154
|
switch (table[i].sign) {
|
|
4170
4155
|
default:
|
|
4171
|
-
UNREACHABLE;
|
|
4156
|
+
UNREACHABLE;
|
|
4157
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4172
4158
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
4173
4159
|
VpSetPosInf(vp);
|
|
4174
|
-
|
|
4160
|
+
break;
|
|
4175
4161
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
4176
4162
|
VpSetNegInf(vp);
|
|
4177
|
-
|
|
4163
|
+
break;
|
|
4178
4164
|
case VP_SIGN_NaN:
|
|
4179
4165
|
VpSetNaN(vp);
|
|
4180
|
-
|
|
4166
|
+
break;
|
|
4181
4167
|
}
|
|
4168
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4182
4169
|
}
|
|
4183
4170
|
}
|
|
4184
4171
|
|
|
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;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4228
4173
|
}
|
|
4229
4174
|
|
|
4230
4175
|
/*
|
|
@@ -4233,25 +4178,25 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
4233
4178
|
* szVal ... The value assigned(char).
|
|
4234
4179
|
*
|
|
4235
4180
|
* [Returns]
|
|
4236
|
-
*
|
|
4237
|
-
*
|
|
4181
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4182
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
4238
4183
|
*/
|
|
4239
|
-
VP_EXPORT
|
|
4184
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4240
4185
|
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
4241
4186
|
{
|
|
4242
4187
|
const char *orig_szVal = szVal;
|
|
4243
4188
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
4244
4189
|
char v, *psz;
|
|
4245
4190
|
int sign=1;
|
|
4246
|
-
Real *vp = NULL;
|
|
4247
4191
|
VALUE buf;
|
|
4248
4192
|
|
|
4249
4193
|
/* Skipping leading spaces */
|
|
4250
4194
|
while (ISSPACE(*szVal)) szVal++;
|
|
4251
4195
|
|
|
4252
4196
|
/* Check on Inf & NaN */
|
|
4253
|
-
|
|
4254
|
-
|
|
4197
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4198
|
+
if (special_bd.real_or_null != NULL) {
|
|
4199
|
+
return special_bd;
|
|
4255
4200
|
}
|
|
4256
4201
|
|
|
4257
4202
|
/* Skip leading `#`.
|
|
@@ -4405,10 +4350,11 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4405
4350
|
VALUE str;
|
|
4406
4351
|
invalid_value:
|
|
4407
4352
|
if (!strict_p) {
|
|
4408
|
-
|
|
4353
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4354
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
4409
4355
|
}
|
|
4410
4356
|
if (!exc) {
|
|
4411
|
-
return NULL;
|
|
4357
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4412
4358
|
}
|
|
4413
4359
|
str = rb_str_new2(orig_szVal);
|
|
4414
4360
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -4416,11 +4362,12 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4416
4362
|
|
|
4417
4363
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
4418
4364
|
/* units for szVal[] */
|
|
4419
|
-
|
|
4365
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4366
|
+
Real *vp = VpPtr(obj);
|
|
4420
4367
|
VpSetZero(vp, sign);
|
|
4421
|
-
|
|
4368
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
4422
4369
|
rb_str_resize(buf, 0);
|
|
4423
|
-
return vp;
|
|
4370
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4424
4371
|
}
|
|
4425
4372
|
|
|
4426
4373
|
/*
|
|
@@ -4892,17 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
4892
4839
|
* a0 a1 .... an * b0
|
|
4893
4840
|
* +_____________________________
|
|
4894
4841
|
* c0 c1 c2 ...... cl
|
|
4895
|
-
* nc <---|
|
|
4896
|
-
* MaxAB |--------------------|
|
|
4897
4842
|
*/
|
|
4898
4843
|
VP_EXPORT size_t
|
|
4899
4844
|
VpMult(Real *c, Real *a, Real *b)
|
|
4900
4845
|
{
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
4904
|
-
DECDIG carry;
|
|
4905
|
-
DECDIG_DBL s;
|
|
4846
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4847
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
4906
4848
|
|
|
4907
4849
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
4908
4850
|
|
|
@@ -4926,61 +4868,57 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
4926
4868
|
a = b;
|
|
4927
4869
|
b = w;
|
|
4928
4870
|
}
|
|
4929
|
-
MxIndA = a->Prec - 1;
|
|
4930
|
-
MxIndB = b->Prec - 1;
|
|
4931
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
4932
4871
|
|
|
4933
4872
|
/* set LHSV c info */
|
|
4934
4873
|
|
|
4935
4874
|
c->exponent = a->exponent; /* set exponent */
|
|
4936
4875
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4937
4876
|
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
4877
|
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4878
|
+
if (b->Prec >= NTT_MULTIPLICATION_THRESHOLD) {
|
|
4879
|
+
ntt_multiply(a->Prec, b->Prec, a->frac, b->frac, c->frac);
|
|
4880
|
+
c->Prec = a->Prec + b->Prec;
|
|
4881
|
+
goto Cleanup;
|
|
4882
|
+
}
|
|
4883
|
+
|
|
4884
|
+
c->Prec = a->Prec + b->Prec; /* set precision */
|
|
4885
|
+
memset(c->frac, 0, c->Prec * sizeof(DECDIG)); /* Initialize c */
|
|
4886
|
+
|
|
4887
|
+
// Process VPMULT_BATCH_SIZE decdigits at a time to reduce the number of carry operations.
|
|
4888
|
+
a_batch_max = (a->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4889
|
+
b_batch_max = (b->Prec - 1) / VPMULT_BATCH_SIZE;
|
|
4890
|
+
for (ssize_t ibatch = a_batch_max; ibatch >= 0; ibatch--) {
|
|
4891
|
+
int isize = ibatch == a_batch_max ? (a->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4892
|
+
for (ssize_t jbatch = b_batch_max; jbatch >= 0; jbatch--) {
|
|
4893
|
+
int jsize = jbatch == b_batch_max ? (b->Prec - 1) % VPMULT_BATCH_SIZE + 1 : VPMULT_BATCH_SIZE;
|
|
4894
|
+
memset(batch, 0, (isize + jsize - 1) * sizeof(DECDIG_DBL));
|
|
4895
|
+
|
|
4896
|
+
// Perform multiplication without carry calculation.
|
|
4897
|
+
// BASE * BASE * VPMULT_BATCH_SIZE < 2**64 should be satisfied so that
|
|
4898
|
+
// DECDIG_DBL can hold the intermediate sum without overflow.
|
|
4899
|
+
for (int i = 0; i < isize; i++) {
|
|
4900
|
+
for (int j = 0; j < jsize; j++) {
|
|
4901
|
+
batch[i + j] += (DECDIG_DBL)a->frac[ibatch * VPMULT_BATCH_SIZE + i] * b->frac[jbatch * VPMULT_BATCH_SIZE + j];
|
|
4902
|
+
}
|
|
4968
4903
|
}
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4904
|
+
|
|
4905
|
+
// Add the batch result to c with carry calculation.
|
|
4906
|
+
DECDIG_DBL carry = 0;
|
|
4907
|
+
for (int k = isize + jsize - 2; k >= 0; k--) {
|
|
4908
|
+
size_t l = (ibatch + jbatch) * VPMULT_BATCH_SIZE + k + 1;
|
|
4909
|
+
DECDIG_DBL s = c->frac[l] + batch[k] + carry;
|
|
4910
|
+
c->frac[l] = (DECDIG)(s % BASE);
|
|
4911
|
+
carry = (DECDIG_DBL)(s / BASE);
|
|
4912
|
+
}
|
|
4913
|
+
|
|
4914
|
+
// Adding carry may exceed BASE, but it won't cause overflow of DECDIG.
|
|
4915
|
+
// Exceeded value will be resolved in the carry operation of next (ibatch + jbatch - 1) batch.
|
|
4916
|
+
// WARNING: This safety strongly relies on the current nested loop execution order.
|
|
4917
|
+
c->frac[(ibatch + jbatch) * VPMULT_BATCH_SIZE] += (DECDIG)carry;
|
|
4918
|
+
}
|
|
4983
4919
|
}
|
|
4920
|
+
|
|
4921
|
+
Cleanup:
|
|
4984
4922
|
VpNmlz(c);
|
|
4985
4923
|
|
|
4986
4924
|
Exit:
|
|
@@ -5028,6 +4966,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
5028
4966
|
|
|
5029
4967
|
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
5030
4968
|
|
|
4969
|
+
if (word_c >= NEWTON_RAPHSON_DIVISION_THRESHOLD && word_b >= NEWTON_RAPHSON_DIVISION_THRESHOLD) {
|
|
4970
|
+
VpDivdNewton(c, r, a, b);
|
|
4971
|
+
goto Exit;
|
|
4972
|
+
}
|
|
4973
|
+
|
|
5031
4974
|
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5032
4975
|
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5033
4976
|
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
@@ -5453,8 +5396,8 @@ VpSzMantissa(Real *a, char *buf, size_t buflen)
|
|
|
5453
5396
|
while (m) {
|
|
5454
5397
|
nn = e / m;
|
|
5455
5398
|
if (!ZeroSup || nn) {
|
|
5456
|
-
|
|
5457
|
-
buf
|
|
5399
|
+
*buf = (char)('0' + nn);
|
|
5400
|
+
buf++;
|
|
5458
5401
|
/* as 0.00xx will be ignored. */
|
|
5459
5402
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
5460
5403
|
}
|
|
@@ -5506,10 +5449,22 @@ VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
|
|
|
5506
5449
|
return 0;
|
|
5507
5450
|
}
|
|
5508
5451
|
|
|
5452
|
+
#define ULLTOA_BUFFER_SIZE 20
|
|
5453
|
+
static size_t Vp_ulltoa(unsigned long long number, char *buf)
|
|
5454
|
+
{
|
|
5455
|
+
static const char digits[] = "0123456789";
|
|
5456
|
+
char* tmp = buf;
|
|
5457
|
+
|
|
5458
|
+
do *tmp-- = digits[number % 10]; while (number /= 10);
|
|
5459
|
+
return buf - tmp;
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5509
5462
|
VP_EXPORT void
|
|
5510
5463
|
VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
5511
5464
|
/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
|
|
5512
5465
|
{
|
|
5466
|
+
char ulltoa_buf[ULLTOA_BUFFER_SIZE];
|
|
5467
|
+
char *ulltoa_buf_end = ulltoa_buf + ULLTOA_BUFFER_SIZE;
|
|
5513
5468
|
size_t i, n, ZeroSup;
|
|
5514
5469
|
DECDIG shift, m, e, nn;
|
|
5515
5470
|
char *p = buf;
|
|
@@ -5549,10 +5504,9 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
5549
5504
|
while (m) {
|
|
5550
5505
|
nn = e / m;
|
|
5551
5506
|
if (!ZeroSup || nn) {
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
ADVANCE(n);
|
|
5507
|
+
*p = (char)('0' + nn);
|
|
5508
|
+
ADVANCE(1);
|
|
5509
|
+
|
|
5556
5510
|
/* as 0.00xx will be ignored. */
|
|
5557
5511
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
5558
5512
|
}
|
|
@@ -5571,7 +5525,22 @@ VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
|
|
|
5571
5525
|
*(--p) = '\0';
|
|
5572
5526
|
++plen;
|
|
5573
5527
|
}
|
|
5574
|
-
|
|
5528
|
+
*p = 'e';
|
|
5529
|
+
ADVANCE(1);
|
|
5530
|
+
|
|
5531
|
+
if (ex < 0) {
|
|
5532
|
+
*p = '-';
|
|
5533
|
+
ADVANCE(1);
|
|
5534
|
+
ex = -ex;
|
|
5535
|
+
}
|
|
5536
|
+
|
|
5537
|
+
size_t ex_n = Vp_ulltoa(ex, ulltoa_buf_end - 1);
|
|
5538
|
+
if (ex_n > plen) goto overflow;
|
|
5539
|
+
MEMCPY(p, ulltoa_buf_end - ex_n, char, ex_n);
|
|
5540
|
+
ADVANCE(ex_n);
|
|
5541
|
+
*p = '\0';
|
|
5542
|
+
ADVANCE(1);
|
|
5543
|
+
|
|
5575
5544
|
if (fFmt) VpFormatSt(buf, fFmt);
|
|
5576
5545
|
|
|
5577
5546
|
overflow:
|
|
@@ -6166,7 +6135,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6166
6135
|
size_t my, ind_y, ind_x;
|
|
6167
6136
|
|
|
6168
6137
|
if (!VpHasVal(x)) {
|
|
6169
|
-
VpAsgn(y, x,
|
|
6138
|
+
VpAsgn(y, x, 10);
|
|
6170
6139
|
goto Exit;
|
|
6171
6140
|
}
|
|
6172
6141
|
|
|
@@ -6175,7 +6144,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6175
6144
|
goto Exit;
|
|
6176
6145
|
}
|
|
6177
6146
|
else if (x->exponent <= 0) {
|
|
6178
|
-
VpAsgn(y, x,
|
|
6147
|
+
VpAsgn(y, x, 10);
|
|
6179
6148
|
goto Exit;
|
|
6180
6149
|
}
|
|
6181
6150
|
|