bigdecimal 3.2.3 → 4.1.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/bigdecimal.gemspec +6 -1
- data/ext/bigdecimal/bigdecimal.c +248 -280
- 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.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 +828 -135
- data/lib/bigdecimal/newton.rb +2 -0
- data/lib/bigdecimal/util.rb +16 -15
- data/lib/bigdecimal.rb +165 -98
- 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.1"
|
|
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,38 +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
222
|
static VALUE
|
|
256
|
-
|
|
223
|
+
BigDecimal_allocate(size_t const internal_digits)
|
|
257
224
|
{
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static VALUE
|
|
235
|
+
BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
|
|
236
|
+
{
|
|
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;
|
|
261
246
|
}
|
|
262
247
|
|
|
263
248
|
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
@@ -265,8 +250,10 @@ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_
|
|
|
265
250
|
static BDVALUE
|
|
266
251
|
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
267
252
|
{
|
|
268
|
-
|
|
269
|
-
|
|
253
|
+
VALUE obj = BigDecimal_allocate_decimal_digits(digits);
|
|
254
|
+
Real *real = VpPtr(obj);
|
|
255
|
+
VpSetZero(real, sign);
|
|
256
|
+
return (BDVALUE) { obj, real };
|
|
270
257
|
}
|
|
271
258
|
|
|
272
259
|
static inline int
|
|
@@ -324,20 +311,11 @@ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
|
324
311
|
break;
|
|
325
312
|
}
|
|
326
313
|
|
|
327
|
-
#ifdef ENABLE_NUMERIC_STRING
|
|
328
|
-
case T_STRING: {
|
|
329
|
-
const char *c_str = StringValueCStr(v);
|
|
330
|
-
v = rb_cstr_convert_to_BigDecimal(c_str, must);
|
|
331
|
-
break;
|
|
332
|
-
}
|
|
333
|
-
#endif /* ENABLE_NUMERIC_STRING */
|
|
334
|
-
|
|
335
314
|
default:
|
|
336
315
|
goto SomeOneMayDoIt;
|
|
337
316
|
}
|
|
338
317
|
|
|
339
|
-
Real *vp;
|
|
340
|
-
TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
|
|
318
|
+
Real *vp = VpPtr(v);
|
|
341
319
|
return (NULLABLE_BDVALUE) { v, vp };
|
|
342
320
|
|
|
343
321
|
SomeOneMayDoIt:
|
|
@@ -388,37 +366,6 @@ BigDecimal_double_fig(VALUE self)
|
|
|
388
366
|
return INT2FIX(BIGDECIMAL_DOUBLE_FIGURES);
|
|
389
367
|
}
|
|
390
368
|
|
|
391
|
-
/* call-seq:
|
|
392
|
-
* precs -> array
|
|
393
|
-
*
|
|
394
|
-
* Returns an Array of two Integer values that represent platform-dependent
|
|
395
|
-
* internal storage properties.
|
|
396
|
-
*
|
|
397
|
-
* This method is deprecated and will be removed in the future.
|
|
398
|
-
* Instead, use BigDecimal#n_significant_digits for obtaining the number of
|
|
399
|
-
* significant digits in scientific notation, and BigDecimal#precision for
|
|
400
|
-
* obtaining the number of digits in decimal notation.
|
|
401
|
-
*
|
|
402
|
-
*/
|
|
403
|
-
|
|
404
|
-
static VALUE
|
|
405
|
-
BigDecimal_prec(VALUE self)
|
|
406
|
-
{
|
|
407
|
-
BDVALUE v;
|
|
408
|
-
VALUE obj;
|
|
409
|
-
|
|
410
|
-
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
|
|
411
|
-
"BigDecimal#precs is deprecated and will be removed in the future; "
|
|
412
|
-
"use BigDecimal#precision instead.");
|
|
413
|
-
|
|
414
|
-
v = GetBDValueMust(self);
|
|
415
|
-
obj = rb_assoc_new(SIZET2NUM(v.real->Prec*VpBaseFig()),
|
|
416
|
-
SIZET2NUM(v.real->MaxPrec*VpBaseFig()));
|
|
417
|
-
|
|
418
|
-
RB_GC_GUARD(v.bigdecimal);
|
|
419
|
-
return obj;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
369
|
static void
|
|
423
370
|
VpCountPrecisionAndScale(Real *p, ssize_t *out_precision, ssize_t *out_scale)
|
|
424
371
|
{
|
|
@@ -1015,7 +962,7 @@ BigDecimal_mode(int argc, VALUE *argv, VALUE self)
|
|
|
1015
962
|
static size_t
|
|
1016
963
|
GetAddSubPrec(Real *a, Real *b)
|
|
1017
964
|
{
|
|
1018
|
-
if (
|
|
965
|
+
if (VpIsZero(a) || VpIsZero(b)) return Max(a->Prec, b->Prec);
|
|
1019
966
|
ssize_t min_a = a->exponent - a->Prec;
|
|
1020
967
|
ssize_t min_b = b->exponent - b->Prec;
|
|
1021
968
|
return Max(a->exponent, b->exponent) - Min(min_a, min_b);
|
|
@@ -1041,25 +988,18 @@ check_int_precision(VALUE v)
|
|
|
1041
988
|
static NULLABLE_BDVALUE
|
|
1042
989
|
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1043
990
|
{
|
|
1044
|
-
|
|
1045
|
-
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1046
|
-
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(klass, pv), pv };
|
|
991
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1047
992
|
}
|
|
1048
993
|
|
|
1049
|
-
|
|
1050
|
-
|
|
994
|
+
void
|
|
995
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1051
996
|
{
|
|
1052
|
-
assert(x != NULL);
|
|
1053
|
-
|
|
1054
|
-
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1055
997
|
pv->MaxPrec = x->MaxPrec;
|
|
1056
998
|
pv->Prec = x->Prec;
|
|
1057
999
|
pv->exponent = x->exponent;
|
|
1058
1000
|
pv->sign = x->sign;
|
|
1059
1001
|
pv->flag = x->flag;
|
|
1060
1002
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1061
|
-
|
|
1062
|
-
return pv;
|
|
1063
1003
|
}
|
|
1064
1004
|
|
|
1065
1005
|
/* Returns True if the value is Not a Number. */
|
|
@@ -1099,9 +1039,6 @@ BigDecimal_check_num(Real *p)
|
|
|
1099
1039
|
VpCheckException(p, true);
|
|
1100
1040
|
}
|
|
1101
1041
|
|
|
1102
|
-
static VALUE BigDecimal_fix(VALUE self);
|
|
1103
|
-
static VALUE BigDecimal_split(VALUE self);
|
|
1104
|
-
|
|
1105
1042
|
/* Returns the value as an Integer.
|
|
1106
1043
|
*
|
|
1107
1044
|
* If the BigDecimal is infinity or NaN, raises FloatDomainError.
|
|
@@ -1252,7 +1189,7 @@ GetCoercePrec(Real *a, size_t prec)
|
|
|
1252
1189
|
static VALUE
|
|
1253
1190
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1254
1191
|
{
|
|
1255
|
-
Real* pv =
|
|
1192
|
+
Real* pv = VpPtr(self);
|
|
1256
1193
|
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1257
1194
|
return rb_assoc_new(CheckGetValue(b), self);
|
|
1258
1195
|
}
|
|
@@ -1318,13 +1255,32 @@ BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation)
|
|
|
1318
1255
|
if (VpIsNaN(a.real)) return CheckGetValue(a);
|
|
1319
1256
|
if (VpIsNaN(b.real)) return CheckGetValue(b);
|
|
1320
1257
|
|
|
1321
|
-
|
|
1322
|
-
if (mx == (size_t)-1L) {
|
|
1323
|
-
/* a or b is inf */
|
|
1258
|
+
if (VpIsInf(a.real) || VpIsInf(b.real)) {
|
|
1324
1259
|
c = NewZeroWrap(1, BASE_FIG);
|
|
1325
1260
|
VpAddSub(c.real, a.real, b.real, operation);
|
|
1326
1261
|
}
|
|
1327
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);
|
|
1328
1284
|
c = NewZeroWrap(1, (mx + 1) * BASE_FIG);
|
|
1329
1285
|
size_t pl = VpGetPrecLimit();
|
|
1330
1286
|
if (prec) VpSetPrecLimit(prec);
|
|
@@ -1701,7 +1657,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1701
1657
|
|
|
1702
1658
|
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1703
1659
|
VALUE nan = BigDecimal_nan();
|
|
1704
|
-
*div = *mod = (NULLABLE_BDVALUE) { nan,
|
|
1660
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1705
1661
|
goto Done;
|
|
1706
1662
|
}
|
|
1707
1663
|
if (VpIsZero(b.real)) {
|
|
@@ -1710,25 +1666,35 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1710
1666
|
if (VpIsInf(a.real)) {
|
|
1711
1667
|
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1712
1668
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1713
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1669
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1714
1670
|
}
|
|
1715
1671
|
else {
|
|
1716
1672
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1717
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1718
1674
|
}
|
|
1719
1675
|
VALUE nan = BigDecimal_nan();
|
|
1720
|
-
*mod = (NULLABLE_BDVALUE) { nan,
|
|
1676
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1721
1677
|
goto Done;
|
|
1722
1678
|
}
|
|
1723
|
-
if (
|
|
1679
|
+
if (VpIsZero(a.real)) {
|
|
1724
1680
|
VALUE zero = BigDecimal_positive_zero();
|
|
1725
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1681
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1726
1682
|
*mod = bdvalue_nullable(a);
|
|
1727
1683
|
goto Done;
|
|
1728
1684
|
}
|
|
1729
|
-
if (
|
|
1730
|
-
|
|
1731
|
-
|
|
1685
|
+
if (VpIsInf(b.real)) {
|
|
1686
|
+
if (!truncate && VpGetSign(a.real) * VpGetSign(b.real) < 0) {
|
|
1687
|
+
BDVALUE minus_one = NewZeroWrap(1, BASE_FIG);
|
|
1688
|
+
VpSetOne(minus_one.real);
|
|
1689
|
+
VpSetSign(minus_one.real, -1);
|
|
1690
|
+
RB_GC_GUARD(minus_one.bigdecimal);
|
|
1691
|
+
*div = bdvalue_nullable(minus_one);
|
|
1692
|
+
*mod = bdvalue_nullable(b);
|
|
1693
|
+
} else {
|
|
1694
|
+
VALUE zero = BigDecimal_positive_zero();
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1696
|
+
*mod = bdvalue_nullable(a);
|
|
1697
|
+
}
|
|
1732
1698
|
goto Done;
|
|
1733
1699
|
}
|
|
1734
1700
|
|
|
@@ -1844,7 +1810,7 @@ BigDecimal_divmod(VALUE self, VALUE r)
|
|
|
1844
1810
|
NULLABLE_BDVALUE div, mod;
|
|
1845
1811
|
|
|
1846
1812
|
if (BigDecimal_DoDivmod(self, r, &div, &mod, false)) {
|
|
1847
|
-
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)));
|
|
1848
1814
|
}
|
|
1849
1815
|
return DoSomeOne(self,r,rb_intern("divmod"));
|
|
1850
1816
|
}
|
|
@@ -2484,7 +2450,7 @@ BigDecimal_decimal_shift(VALUE self, VALUE v)
|
|
|
2484
2450
|
prec = a.real->Prec + shiftDown;
|
|
2485
2451
|
c = NewZeroWrap(1, prec * BASE_FIG);
|
|
2486
2452
|
if (shift == 0) {
|
|
2487
|
-
VpAsgn(c.real, a.real,
|
|
2453
|
+
VpAsgn(c.real, a.real, 10);
|
|
2488
2454
|
} else if (shiftDown) {
|
|
2489
2455
|
DECDIG carry = 0;
|
|
2490
2456
|
exponentShift++;
|
|
@@ -2570,9 +2536,7 @@ check_exception(VALUE bd)
|
|
|
2570
2536
|
{
|
|
2571
2537
|
assert(is_kind_of_BigDecimal(bd));
|
|
2572
2538
|
|
|
2573
|
-
|
|
2574
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2575
|
-
VpCheckException(vp, false);
|
|
2539
|
+
VpCheckException(VpPtr(bd), false);
|
|
2576
2540
|
|
|
2577
2541
|
return bd;
|
|
2578
2542
|
}
|
|
@@ -2580,16 +2544,19 @@ check_exception(VALUE bd)
|
|
|
2580
2544
|
static VALUE
|
|
2581
2545
|
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
2582
2546
|
{
|
|
2547
|
+
VALUE bd;
|
|
2583
2548
|
Real *vp;
|
|
2584
2549
|
if (uval == 0) {
|
|
2585
|
-
|
|
2550
|
+
bd = BigDecimal_allocate(1);
|
|
2551
|
+
vp = VpPtr(bd);
|
|
2586
2552
|
vp->Prec = 1;
|
|
2587
2553
|
vp->exponent = 1;
|
|
2588
2554
|
VpSetZero(vp, 1);
|
|
2589
2555
|
vp->frac[0] = 0;
|
|
2590
2556
|
}
|
|
2591
2557
|
else if (uval < BASE) {
|
|
2592
|
-
|
|
2558
|
+
bd = BigDecimal_allocate(1);
|
|
2559
|
+
vp = VpPtr(bd);
|
|
2593
2560
|
vp->Prec = 1;
|
|
2594
2561
|
vp->exponent = 1;
|
|
2595
2562
|
VpSetSign(vp, 1);
|
|
@@ -2614,14 +2581,15 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
|
2614
2581
|
}
|
|
2615
2582
|
|
|
2616
2583
|
const size_t exp = len + ntz;
|
|
2617
|
-
|
|
2584
|
+
bd = BigDecimal_allocate(len);
|
|
2585
|
+
vp = VpPtr(bd);
|
|
2618
2586
|
vp->Prec = len;
|
|
2619
2587
|
vp->exponent = exp;
|
|
2620
2588
|
VpSetSign(vp, 1);
|
|
2621
2589
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
2622
2590
|
}
|
|
2623
2591
|
|
|
2624
|
-
return
|
|
2592
|
+
return bd;
|
|
2625
2593
|
}
|
|
2626
2594
|
|
|
2627
2595
|
static VALUE
|
|
@@ -2630,8 +2598,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
|
2630
2598
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
2631
2599
|
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
2632
2600
|
if (ival < 0) {
|
|
2633
|
-
Real *vp;
|
|
2634
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2601
|
+
Real *vp = VpPtr(bd);
|
|
2635
2602
|
VpSetSign(vp, -1);
|
|
2636
2603
|
}
|
|
2637
2604
|
return bd;
|
|
@@ -2838,8 +2805,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2838
2805
|
}
|
|
2839
2806
|
|
|
2840
2807
|
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2841
|
-
Real *vp;
|
|
2842
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2808
|
+
Real *vp = VpPtr(bd);
|
|
2843
2809
|
assert(vp->Prec == prec);
|
|
2844
2810
|
vp->exponent = exp;
|
|
2845
2811
|
|
|
@@ -2905,12 +2871,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2905
2871
|
if (digs == SIZE_MAX)
|
|
2906
2872
|
return check_exception(val);
|
|
2907
2873
|
|
|
2908
|
-
Real *vp;
|
|
2909
|
-
|
|
2910
|
-
|
|
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
|
+
|
|
2911
2881
|
RB_GC_GUARD(val);
|
|
2912
2882
|
|
|
2913
|
-
VALUE copy = BigDecimal_wrap_struct(rb_cBigDecimal, vp);
|
|
2914
2883
|
/* TODO: rounding */
|
|
2915
2884
|
return check_exception(copy);
|
|
2916
2885
|
}
|
|
@@ -3232,19 +3201,39 @@ BigDecimal_literal(const char *str)
|
|
|
3232
3201
|
|
|
3233
3202
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3234
3203
|
VALUE
|
|
3235
|
-
|
|
3236
|
-
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;
|
|
3237
3206
|
size_t cn = NUM2INT(cprec);
|
|
3238
3207
|
a = GetBDValueMust(self);
|
|
3239
3208
|
b = GetBDValueMust(r);
|
|
3240
3209
|
c = NewZeroWrap(1, cn * BASE_FIG);
|
|
3241
3210
|
d = NewZeroWrap(1, VPDIVD_REM_PREC(a.real, b.real, c.real) * BASE_FIG);
|
|
3242
|
-
|
|
3211
|
+
vpdivd_func(c.real, d.real, a.real, b.real);
|
|
3243
3212
|
RB_GC_GUARD(a.bigdecimal);
|
|
3244
3213
|
RB_GC_GUARD(b.bigdecimal);
|
|
3245
3214
|
return rb_assoc_new(c.bigdecimal, d.bigdecimal);
|
|
3246
3215
|
}
|
|
3247
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
|
+
|
|
3248
3237
|
VALUE
|
|
3249
3238
|
BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
3250
3239
|
BDVALUE a,b,c;
|
|
@@ -3256,6 +3245,23 @@ BigDecimal_vpmult(VALUE self, VALUE v) {
|
|
|
3256
3245
|
RB_GC_GUARD(b.bigdecimal);
|
|
3257
3246
|
return c.bigdecimal;
|
|
3258
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
|
+
|
|
3259
3265
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3260
3266
|
|
|
3261
3267
|
/* Document-class: BigDecimal
|
|
@@ -3568,7 +3574,6 @@ Init_bigdecimal(void)
|
|
|
3568
3574
|
rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_LITERAL(NAN, NaN));
|
|
3569
3575
|
|
|
3570
3576
|
/* instance methods */
|
|
3571
|
-
rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
|
|
3572
3577
|
rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
|
|
3573
3578
|
rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
|
|
3574
3579
|
rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
|
|
@@ -3627,7 +3632,10 @@ Init_bigdecimal(void)
|
|
|
3627
3632
|
|
|
3628
3633
|
#ifdef BIGDECIMAL_USE_VP_TEST_METHODS
|
|
3629
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);
|
|
3630
3637
|
rb_define_method(rb_cBigDecimal, "vpmult", BigDecimal_vpmult, 1);
|
|
3638
|
+
rb_define_method(rb_cBigDecimal, "nttmult", BigDecimal_nttmult, 1);
|
|
3631
3639
|
#endif /* BIGDECIMAL_USE_VP_TEST_METHODS */
|
|
3632
3640
|
|
|
3633
3641
|
#define ROUNDING_MODE(i, name, value) \
|
|
@@ -3670,7 +3678,7 @@ Init_bigdecimal(void)
|
|
|
3670
3678
|
static int gfDebug = 1; /* Debug switch */
|
|
3671
3679
|
#endif /* BIGDECIMAL_DEBUG */
|
|
3672
3680
|
|
|
3673
|
-
static
|
|
3681
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
3674
3682
|
|
|
3675
3683
|
enum op_sw {
|
|
3676
3684
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4071,8 +4079,9 @@ VpInit(DECDIG BaseVal)
|
|
|
4071
4079
|
VpGetDoubleNegZero();
|
|
4072
4080
|
|
|
4073
4081
|
/* Const 1.0 */
|
|
4074
|
-
VpConstOne
|
|
4075
|
-
|
|
4082
|
+
rb_global_variable(&VpConstOne);
|
|
4083
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4084
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
4076
4085
|
|
|
4077
4086
|
#ifdef BIGDECIMAL_DEBUG
|
|
4078
4087
|
gnAlloc = 0;
|
|
@@ -4084,7 +4093,7 @@ VpInit(DECDIG BaseVal)
|
|
|
4084
4093
|
VP_EXPORT Real *
|
|
4085
4094
|
VpOne(void)
|
|
4086
4095
|
{
|
|
4087
|
-
return VpConstOne;
|
|
4096
|
+
return VpPtr(VpConstOne);
|
|
4088
4097
|
}
|
|
4089
4098
|
|
|
4090
4099
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -4115,7 +4124,7 @@ overflow:
|
|
|
4115
4124
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
4116
4125
|
}
|
|
4117
4126
|
|
|
4118
|
-
|
|
4127
|
+
NULLABLE_BDVALUE
|
|
4119
4128
|
bigdecimal_parse_special_string(const char *str)
|
|
4120
4129
|
{
|
|
4121
4130
|
static const struct {
|
|
@@ -4140,66 +4149,27 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
4140
4149
|
p = str + table[i].len;
|
|
4141
4150
|
while (*p && ISSPACE(*p)) ++p;
|
|
4142
4151
|
if (*p == '\0') {
|
|
4143
|
-
|
|
4152
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4153
|
+
Real *vp = VpPtr(obj);
|
|
4144
4154
|
switch (table[i].sign) {
|
|
4145
4155
|
default:
|
|
4146
|
-
UNREACHABLE;
|
|
4156
|
+
UNREACHABLE;
|
|
4157
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4147
4158
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
4148
4159
|
VpSetPosInf(vp);
|
|
4149
|
-
|
|
4160
|
+
break;
|
|
4150
4161
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
4151
4162
|
VpSetNegInf(vp);
|
|
4152
|
-
|
|
4163
|
+
break;
|
|
4153
4164
|
case VP_SIGN_NaN:
|
|
4154
4165
|
VpSetNaN(vp);
|
|
4155
|
-
|
|
4166
|
+
break;
|
|
4156
4167
|
}
|
|
4168
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4157
4169
|
}
|
|
4158
4170
|
}
|
|
4159
4171
|
|
|
4160
|
-
return NULL;
|
|
4161
|
-
}
|
|
4162
|
-
|
|
4163
|
-
struct VpCtoV_args {
|
|
4164
|
-
Real *a;
|
|
4165
|
-
const char *int_chr;
|
|
4166
|
-
size_t ni;
|
|
4167
|
-
const char *frac;
|
|
4168
|
-
size_t nf;
|
|
4169
|
-
const char *exp_chr;
|
|
4170
|
-
size_t ne;
|
|
4171
|
-
};
|
|
4172
|
-
|
|
4173
|
-
static VALUE
|
|
4174
|
-
call_VpCtoV(VALUE arg)
|
|
4175
|
-
{
|
|
4176
|
-
struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
|
|
4177
|
-
return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
|
|
4178
|
-
}
|
|
4179
|
-
|
|
4180
|
-
static int
|
|
4181
|
-
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)
|
|
4182
|
-
{
|
|
4183
|
-
struct VpCtoV_args args;
|
|
4184
|
-
int state = 0;
|
|
4185
|
-
|
|
4186
|
-
args.a = a;
|
|
4187
|
-
args.int_chr = int_chr;
|
|
4188
|
-
args.ni = ni;
|
|
4189
|
-
args.frac = frac;
|
|
4190
|
-
args.nf = nf;
|
|
4191
|
-
args.exp_chr = exp_chr;
|
|
4192
|
-
args.ne = ne;
|
|
4193
|
-
|
|
4194
|
-
VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
|
|
4195
|
-
if (state) {
|
|
4196
|
-
if (free_on_error) {
|
|
4197
|
-
rbd_free_struct(a);
|
|
4198
|
-
}
|
|
4199
|
-
rb_jump_tag(state);
|
|
4200
|
-
}
|
|
4201
|
-
|
|
4202
|
-
return (int)result;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4203
4173
|
}
|
|
4204
4174
|
|
|
4205
4175
|
/*
|
|
@@ -4208,25 +4178,25 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
4208
4178
|
* szVal ... The value assigned(char).
|
|
4209
4179
|
*
|
|
4210
4180
|
* [Returns]
|
|
4211
|
-
*
|
|
4212
|
-
*
|
|
4181
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4182
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
4213
4183
|
*/
|
|
4214
|
-
VP_EXPORT
|
|
4184
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4215
4185
|
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
4216
4186
|
{
|
|
4217
4187
|
const char *orig_szVal = szVal;
|
|
4218
4188
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
4219
4189
|
char v, *psz;
|
|
4220
4190
|
int sign=1;
|
|
4221
|
-
Real *vp = NULL;
|
|
4222
4191
|
VALUE buf;
|
|
4223
4192
|
|
|
4224
4193
|
/* Skipping leading spaces */
|
|
4225
4194
|
while (ISSPACE(*szVal)) szVal++;
|
|
4226
4195
|
|
|
4227
4196
|
/* Check on Inf & NaN */
|
|
4228
|
-
|
|
4229
|
-
|
|
4197
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4198
|
+
if (special_bd.real_or_null != NULL) {
|
|
4199
|
+
return special_bd;
|
|
4230
4200
|
}
|
|
4231
4201
|
|
|
4232
4202
|
/* Skip leading `#`.
|
|
@@ -4380,10 +4350,11 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4380
4350
|
VALUE str;
|
|
4381
4351
|
invalid_value:
|
|
4382
4352
|
if (!strict_p) {
|
|
4383
|
-
|
|
4353
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4354
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
4384
4355
|
}
|
|
4385
4356
|
if (!exc) {
|
|
4386
|
-
return NULL;
|
|
4357
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4387
4358
|
}
|
|
4388
4359
|
str = rb_str_new2(orig_szVal);
|
|
4389
4360
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -4391,11 +4362,12 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4391
4362
|
|
|
4392
4363
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
4393
4364
|
/* units for szVal[] */
|
|
4394
|
-
|
|
4365
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4366
|
+
Real *vp = VpPtr(obj);
|
|
4395
4367
|
VpSetZero(vp, sign);
|
|
4396
|
-
|
|
4368
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
4397
4369
|
rb_str_resize(buf, 0);
|
|
4398
|
-
return vp;
|
|
4370
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4399
4371
|
}
|
|
4400
4372
|
|
|
4401
4373
|
/*
|
|
@@ -4867,17 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
4867
4839
|
* a0 a1 .... an * b0
|
|
4868
4840
|
* +_____________________________
|
|
4869
4841
|
* c0 c1 c2 ...... cl
|
|
4870
|
-
* nc <---|
|
|
4871
|
-
* MaxAB |--------------------|
|
|
4872
4842
|
*/
|
|
4873
4843
|
VP_EXPORT size_t
|
|
4874
4844
|
VpMult(Real *c, Real *a, Real *b)
|
|
4875
4845
|
{
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
4879
|
-
DECDIG carry;
|
|
4880
|
-
DECDIG_DBL s;
|
|
4846
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4847
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
4881
4848
|
|
|
4882
4849
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
4883
4850
|
|
|
@@ -4901,61 +4868,57 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
4901
4868
|
a = b;
|
|
4902
4869
|
b = w;
|
|
4903
4870
|
}
|
|
4904
|
-
MxIndA = a->Prec - 1;
|
|
4905
|
-
MxIndB = b->Prec - 1;
|
|
4906
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
4907
4871
|
|
|
4908
4872
|
/* set LHSV c info */
|
|
4909
4873
|
|
|
4910
4874
|
c->exponent = a->exponent; /* set exponent */
|
|
4911
4875
|
VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
|
|
4912
4876
|
if (!AddExponent(c, b->exponent)) return 0;
|
|
4913
|
-
carry = 0;
|
|
4914
|
-
nc = ind_c = MxIndAB;
|
|
4915
|
-
memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
|
|
4916
|
-
c->Prec = nc + 1; /* set precision */
|
|
4917
|
-
for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
|
|
4918
|
-
if (nc < MxIndB) { /* The left triangle of the Fig. */
|
|
4919
|
-
ind_as = MxIndA - nc;
|
|
4920
|
-
ind_ae = MxIndA;
|
|
4921
|
-
ind_bs = MxIndB;
|
|
4922
|
-
}
|
|
4923
|
-
else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
|
|
4924
|
-
ind_as = MxIndA - nc;
|
|
4925
|
-
ind_ae = MxIndA - (nc - MxIndB);
|
|
4926
|
-
ind_bs = MxIndB;
|
|
4927
|
-
}
|
|
4928
|
-
else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
|
|
4929
|
-
ind_as = 0;
|
|
4930
|
-
ind_ae = MxIndAB - nc - 1;
|
|
4931
|
-
ind_bs = MxIndB - (nc - MxIndA);
|
|
4932
|
-
}
|
|
4933
4877
|
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
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
|
+
}
|
|
4943
4903
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
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
|
+
}
|
|
4958
4919
|
}
|
|
4920
|
+
|
|
4921
|
+
Cleanup:
|
|
4959
4922
|
VpNmlz(c);
|
|
4960
4923
|
|
|
4961
4924
|
Exit:
|
|
@@ -5003,6 +4966,11 @@ VpDivd(Real *c, Real *r, Real *a, Real *b)
|
|
|
5003
4966
|
|
|
5004
4967
|
if (word_a > word_r || word_b + word_c - 2 >= word_r) goto space_error;
|
|
5005
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
|
+
|
|
5006
4974
|
for (i = 0; i < word_a; ++i) r->frac[i] = a->frac[i];
|
|
5007
4975
|
for (i = word_a; i < word_r; ++i) r->frac[i] = 0;
|
|
5008
4976
|
for (i = 0; i < word_c; ++i) c->frac[i] = 0;
|
|
@@ -6141,7 +6109,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6141
6109
|
size_t my, ind_y, ind_x;
|
|
6142
6110
|
|
|
6143
6111
|
if (!VpHasVal(x)) {
|
|
6144
|
-
VpAsgn(y, x,
|
|
6112
|
+
VpAsgn(y, x, 10);
|
|
6145
6113
|
goto Exit;
|
|
6146
6114
|
}
|
|
6147
6115
|
|
|
@@ -6150,7 +6118,7 @@ VpFrac(Real *y, Real *x)
|
|
|
6150
6118
|
goto Exit;
|
|
6151
6119
|
}
|
|
6152
6120
|
else if (x->exponent <= 0) {
|
|
6153
|
-
VpAsgn(y, x,
|
|
6121
|
+
VpAsgn(y, x, 10);
|
|
6154
6122
|
goto Exit;
|
|
6155
6123
|
}
|
|
6156
6124
|
|