bigdecimal 4.1.0 → 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/ext/bigdecimal/bigdecimal.c +146 -229
- data/ext/bigdecimal/bigdecimal.h +6 -1
- data/ext/bigdecimal/extconf.rb +4 -0
- data/lib/bigdecimal/math.rb +5 -5
- data/lib/bigdecimal.rb +11 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 937928a0baf09e4c2e5bf45b2fa608e1aa20601cf7cd27a8ebaf679874e6196f
|
|
4
|
+
data.tar.gz: a053c6e868c7e55ad9a35262bfd645314fd908dbae5969935c44530a124cfcc4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a4a41830aab00fd3bef041c64f9f6357891706ca11004696c5d815b7582f6f4f2cbd00a606900cfe4a5bce57585d46523e25da8085c2bf18aa95bbe9afd27ec
|
|
7
|
+
data.tar.gz: fe5b587431cca8921613367e236a9844fd3c65f8f53d8b2ae16fe1ed54aac455bfff9a50783256ec2d9e0f5523bc01a3eb9ce0ffc16482cded6026cc03b8c2c0
|
data/ext/bigdecimal/bigdecimal.c
CHANGED
|
@@ -33,10 +33,12 @@
|
|
|
33
33
|
#include "div.h"
|
|
34
34
|
#include "static_assert.h"
|
|
35
35
|
|
|
36
|
-
#define BIGDECIMAL_VERSION "4.1.
|
|
36
|
+
#define BIGDECIMAL_VERSION "4.1.1"
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
#define
|
|
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
|
|
40
42
|
#define SIGNED_VALUE_MAX INTPTR_MAX
|
|
41
43
|
#define SIGNED_VALUE_MIN INTPTR_MIN
|
|
42
44
|
#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
|
|
@@ -77,11 +79,6 @@ static struct {
|
|
|
77
79
|
uint8_t mode;
|
|
78
80
|
} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
|
|
79
81
|
|
|
80
|
-
typedef struct {
|
|
81
|
-
VALUE bigdecimal_or_nil;
|
|
82
|
-
Real *real_or_null;
|
|
83
|
-
} NULLABLE_BDVALUE;
|
|
84
|
-
|
|
85
82
|
static inline BDVALUE
|
|
86
83
|
bdvalue_nonnullable(NULLABLE_BDVALUE v)
|
|
87
84
|
{
|
|
@@ -157,42 +154,6 @@ rbd_struct_size(size_t const internal_digits)
|
|
|
157
154
|
return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
static inline Real *
|
|
161
|
-
rbd_allocate_struct(size_t const internal_digits)
|
|
162
|
-
{
|
|
163
|
-
size_t const size = rbd_struct_size(internal_digits);
|
|
164
|
-
Real *real = ruby_xcalloc(1, size);
|
|
165
|
-
atomic_allocation_count_inc();
|
|
166
|
-
real->MaxPrec = internal_digits;
|
|
167
|
-
return real;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
static inline Real *
|
|
171
|
-
rbd_allocate_struct_decimal_digits(size_t const decimal_digits)
|
|
172
|
-
{
|
|
173
|
-
return rbd_allocate_struct(roomof(decimal_digits, BASE_FIG));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
static void
|
|
177
|
-
rbd_free_struct(Real *real)
|
|
178
|
-
{
|
|
179
|
-
if (real != NULL) {
|
|
180
|
-
check_allocation_count_nonzero();
|
|
181
|
-
ruby_xfree(real);
|
|
182
|
-
atomic_allocation_count_dec_nounderflow();
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero(int sign, size_t const digits));
|
|
187
|
-
#define NewZero rbd_allocate_struct_zero
|
|
188
|
-
static inline Real *
|
|
189
|
-
rbd_allocate_struct_zero(int sign, size_t const digits)
|
|
190
|
-
{
|
|
191
|
-
Real *real = rbd_allocate_struct_decimal_digits(digits);
|
|
192
|
-
VpSetZero(real, sign);
|
|
193
|
-
return real;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
157
|
/*
|
|
197
158
|
* ================== Ruby Interface part ==========================
|
|
198
159
|
*/
|
|
@@ -207,7 +168,6 @@ static void VpCheckException(Real *p, bool always);
|
|
|
207
168
|
static VALUE CheckGetValue(BDVALUE v);
|
|
208
169
|
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
|
209
170
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
|
210
|
-
static Real *VpCopy(Real *pv, Real const* const x);
|
|
211
171
|
static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
|
|
212
172
|
|
|
213
173
|
/*
|
|
@@ -222,49 +182,67 @@ static VALUE BigDecimal_negative_zero(void);
|
|
|
222
182
|
static VALUE BigDecimal_addsub_with_coerce(VALUE self, VALUE r, size_t prec, int operation);
|
|
223
183
|
static VALUE BigDecimal_mult_with_coerce(VALUE self, VALUE r, size_t prec);
|
|
224
184
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
|
230
200
|
|
|
231
201
|
static size_t
|
|
232
202
|
BigDecimal_memsize(const void *ptr)
|
|
233
203
|
{
|
|
204
|
+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
205
|
+
return 0; // Entirely embedded
|
|
206
|
+
#else
|
|
234
207
|
const Real *pv = ptr;
|
|
235
208
|
return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
239
|
-
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
240
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
241
209
|
#endif
|
|
210
|
+
}
|
|
242
211
|
|
|
243
212
|
static const rb_data_type_t BigDecimal_data_type = {
|
|
244
|
-
"BigDecimal",
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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,
|
|
249
220
|
};
|
|
250
221
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
typedef struct { VALUE _obj; } NULL_WRAPPED_VALUE;
|
|
254
|
-
static NULL_WRAPPED_VALUE
|
|
255
|
-
BigDecimal_alloc_empty_struct(VALUE klass)
|
|
222
|
+
static VALUE
|
|
223
|
+
BigDecimal_allocate(size_t const internal_digits)
|
|
256
224
|
{
|
|
257
|
-
|
|
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;
|
|
258
232
|
}
|
|
259
233
|
|
|
260
234
|
static VALUE
|
|
261
|
-
|
|
235
|
+
BigDecimal_allocate_decimal_digits(size_t const decimal_digits)
|
|
262
236
|
{
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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;
|
|
268
246
|
}
|
|
269
247
|
|
|
270
248
|
MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_t const digits));
|
|
@@ -272,9 +250,10 @@ MAYBE_UNUSED(static inline BDVALUE rbd_allocate_struct_zero_wrap(int sign, size_
|
|
|
272
250
|
static BDVALUE
|
|
273
251
|
rbd_allocate_struct_zero_wrap(int sign, size_t const digits)
|
|
274
252
|
{
|
|
275
|
-
|
|
276
|
-
Real *real =
|
|
277
|
-
|
|
253
|
+
VALUE obj = BigDecimal_allocate_decimal_digits(digits);
|
|
254
|
+
Real *real = VpPtr(obj);
|
|
255
|
+
VpSetZero(real, sign);
|
|
256
|
+
return (BDVALUE) { obj, real };
|
|
278
257
|
}
|
|
279
258
|
|
|
280
259
|
static inline int
|
|
@@ -336,8 +315,7 @@ GetBDValueWithPrecInternal(VALUE v, size_t prec, int must)
|
|
|
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:
|
|
@@ -1010,26 +988,18 @@ check_int_precision(VALUE v)
|
|
|
1010
988
|
static NULLABLE_BDVALUE
|
|
1011
989
|
CreateFromString(const char *str, VALUE klass, bool strict_p, bool raise_exception)
|
|
1012
990
|
{
|
|
1013
|
-
|
|
1014
|
-
Real *pv = VpAlloc(str, strict_p, raise_exception);
|
|
1015
|
-
if (!pv) return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
1016
|
-
return (NULLABLE_BDVALUE) { BigDecimal_wrap_struct(null_wrapped, pv), pv };
|
|
991
|
+
return VpAlloc(str, strict_p, raise_exception);
|
|
1017
992
|
}
|
|
1018
993
|
|
|
1019
|
-
|
|
1020
|
-
|
|
994
|
+
void
|
|
995
|
+
VpMemCopy(Real *pv, Real const* const x)
|
|
1021
996
|
{
|
|
1022
|
-
assert(x != NULL);
|
|
1023
|
-
|
|
1024
|
-
pv = (Real *)ruby_xrealloc(pv, rbd_struct_size(x->MaxPrec));
|
|
1025
997
|
pv->MaxPrec = x->MaxPrec;
|
|
1026
998
|
pv->Prec = x->Prec;
|
|
1027
999
|
pv->exponent = x->exponent;
|
|
1028
1000
|
pv->sign = x->sign;
|
|
1029
1001
|
pv->flag = x->flag;
|
|
1030
1002
|
MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
|
|
1031
|
-
|
|
1032
|
-
return pv;
|
|
1033
1003
|
}
|
|
1034
1004
|
|
|
1035
1005
|
/* Returns True if the value is Not a Number. */
|
|
@@ -1219,7 +1189,7 @@ GetCoercePrec(Real *a, size_t prec)
|
|
|
1219
1189
|
static VALUE
|
|
1220
1190
|
BigDecimal_coerce(VALUE self, VALUE other)
|
|
1221
1191
|
{
|
|
1222
|
-
Real* pv =
|
|
1192
|
+
Real* pv = VpPtr(self);
|
|
1223
1193
|
BDVALUE b = GetBDValueWithPrecMust(other, GetCoercePrec(pv, 0));
|
|
1224
1194
|
return rb_assoc_new(CheckGetValue(b), self);
|
|
1225
1195
|
}
|
|
@@ -1687,7 +1657,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1687
1657
|
|
|
1688
1658
|
if (VpIsNaN(a.real) || VpIsNaN(b.real) || (VpIsInf(a.real) && VpIsInf(b.real))) {
|
|
1689
1659
|
VALUE nan = BigDecimal_nan();
|
|
1690
|
-
*div = *mod = (NULLABLE_BDVALUE) { nan,
|
|
1660
|
+
*div = *mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1691
1661
|
goto Done;
|
|
1692
1662
|
}
|
|
1693
1663
|
if (VpIsZero(b.real)) {
|
|
@@ -1696,19 +1666,19 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1696
1666
|
if (VpIsInf(a.real)) {
|
|
1697
1667
|
if (VpGetSign(a.real) == VpGetSign(b.real)) {
|
|
1698
1668
|
VALUE inf = BigDecimal_positive_infinity();
|
|
1699
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1669
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1700
1670
|
}
|
|
1701
1671
|
else {
|
|
1702
1672
|
VALUE inf = BigDecimal_negative_infinity();
|
|
1703
|
-
*div = (NULLABLE_BDVALUE) { inf,
|
|
1673
|
+
*div = (NULLABLE_BDVALUE) { inf, VpPtr(inf) };
|
|
1704
1674
|
}
|
|
1705
1675
|
VALUE nan = BigDecimal_nan();
|
|
1706
|
-
*mod = (NULLABLE_BDVALUE) { nan,
|
|
1676
|
+
*mod = (NULLABLE_BDVALUE) { nan, VpPtr(nan) };
|
|
1707
1677
|
goto Done;
|
|
1708
1678
|
}
|
|
1709
1679
|
if (VpIsZero(a.real)) {
|
|
1710
1680
|
VALUE zero = BigDecimal_positive_zero();
|
|
1711
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1681
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1712
1682
|
*mod = bdvalue_nullable(a);
|
|
1713
1683
|
goto Done;
|
|
1714
1684
|
}
|
|
@@ -1722,7 +1692,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, NULLABLE_BDVALUE *div, NULLABLE_BDVALUE
|
|
|
1722
1692
|
*mod = bdvalue_nullable(b);
|
|
1723
1693
|
} else {
|
|
1724
1694
|
VALUE zero = BigDecimal_positive_zero();
|
|
1725
|
-
*div = (NULLABLE_BDVALUE) { zero,
|
|
1695
|
+
*div = (NULLABLE_BDVALUE) { zero, VpPtr(zero) };
|
|
1726
1696
|
*mod = bdvalue_nullable(a);
|
|
1727
1697
|
}
|
|
1728
1698
|
goto Done;
|
|
@@ -2566,9 +2536,7 @@ check_exception(VALUE bd)
|
|
|
2566
2536
|
{
|
|
2567
2537
|
assert(is_kind_of_BigDecimal(bd));
|
|
2568
2538
|
|
|
2569
|
-
|
|
2570
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2571
|
-
VpCheckException(vp, false);
|
|
2539
|
+
VpCheckException(VpPtr(bd), false);
|
|
2572
2540
|
|
|
2573
2541
|
return bd;
|
|
2574
2542
|
}
|
|
@@ -2576,17 +2544,19 @@ check_exception(VALUE bd)
|
|
|
2576
2544
|
static VALUE
|
|
2577
2545
|
rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
2578
2546
|
{
|
|
2579
|
-
|
|
2547
|
+
VALUE bd;
|
|
2580
2548
|
Real *vp;
|
|
2581
2549
|
if (uval == 0) {
|
|
2582
|
-
|
|
2550
|
+
bd = BigDecimal_allocate(1);
|
|
2551
|
+
vp = VpPtr(bd);
|
|
2583
2552
|
vp->Prec = 1;
|
|
2584
2553
|
vp->exponent = 1;
|
|
2585
2554
|
VpSetZero(vp, 1);
|
|
2586
2555
|
vp->frac[0] = 0;
|
|
2587
2556
|
}
|
|
2588
2557
|
else if (uval < BASE) {
|
|
2589
|
-
|
|
2558
|
+
bd = BigDecimal_allocate(1);
|
|
2559
|
+
vp = VpPtr(bd);
|
|
2590
2560
|
vp->Prec = 1;
|
|
2591
2561
|
vp->exponent = 1;
|
|
2592
2562
|
VpSetSign(vp, 1);
|
|
@@ -2611,14 +2581,15 @@ rb_uint64_convert_to_BigDecimal(uint64_t uval)
|
|
|
2611
2581
|
}
|
|
2612
2582
|
|
|
2613
2583
|
const size_t exp = len + ntz;
|
|
2614
|
-
|
|
2584
|
+
bd = BigDecimal_allocate(len);
|
|
2585
|
+
vp = VpPtr(bd);
|
|
2615
2586
|
vp->Prec = len;
|
|
2616
2587
|
vp->exponent = exp;
|
|
2617
2588
|
VpSetSign(vp, 1);
|
|
2618
2589
|
MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
|
|
2619
2590
|
}
|
|
2620
2591
|
|
|
2621
|
-
return
|
|
2592
|
+
return bd;
|
|
2622
2593
|
}
|
|
2623
2594
|
|
|
2624
2595
|
static VALUE
|
|
@@ -2627,8 +2598,7 @@ rb_int64_convert_to_BigDecimal(int64_t ival)
|
|
|
2627
2598
|
const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
|
|
2628
2599
|
VALUE bd = rb_uint64_convert_to_BigDecimal(uval);
|
|
2629
2600
|
if (ival < 0) {
|
|
2630
|
-
Real *vp;
|
|
2631
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2601
|
+
Real *vp = VpPtr(bd);
|
|
2632
2602
|
VpSetSign(vp, -1);
|
|
2633
2603
|
}
|
|
2634
2604
|
return bd;
|
|
@@ -2835,8 +2805,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2835
2805
|
}
|
|
2836
2806
|
|
|
2837
2807
|
VALUE bd = rb_inum_convert_to_BigDecimal(inum);
|
|
2838
|
-
Real *vp;
|
|
2839
|
-
TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
|
|
2808
|
+
Real *vp = VpPtr(bd);
|
|
2840
2809
|
assert(vp->Prec == prec);
|
|
2841
2810
|
vp->exponent = exp;
|
|
2842
2811
|
|
|
@@ -2902,13 +2871,15 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
|
|
|
2902
2871
|
if (digs == SIZE_MAX)
|
|
2903
2872
|
return check_exception(val);
|
|
2904
2873
|
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
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
|
+
|
|
2909
2881
|
RB_GC_GUARD(val);
|
|
2910
2882
|
|
|
2911
|
-
VALUE copy = BigDecimal_wrap_struct(null_wrapped, vp);
|
|
2912
2883
|
/* TODO: rounding */
|
|
2913
2884
|
return check_exception(copy);
|
|
2914
2885
|
}
|
|
@@ -3707,7 +3678,7 @@ Init_bigdecimal(void)
|
|
|
3707
3678
|
static int gfDebug = 1; /* Debug switch */
|
|
3708
3679
|
#endif /* BIGDECIMAL_DEBUG */
|
|
3709
3680
|
|
|
3710
|
-
static
|
|
3681
|
+
static VALUE VpConstOne; /* constant 1.0 */
|
|
3711
3682
|
|
|
3712
3683
|
enum op_sw {
|
|
3713
3684
|
OP_SW_ADD = 1, /* + */
|
|
@@ -4108,8 +4079,9 @@ VpInit(DECDIG BaseVal)
|
|
|
4108
4079
|
VpGetDoubleNegZero();
|
|
4109
4080
|
|
|
4110
4081
|
/* Const 1.0 */
|
|
4111
|
-
VpConstOne
|
|
4112
|
-
|
|
4082
|
+
rb_global_variable(&VpConstOne);
|
|
4083
|
+
VpConstOne = NewZeroWrap(1, 1).bigdecimal;
|
|
4084
|
+
VpSetOne(VpPtr(VpConstOne));
|
|
4113
4085
|
|
|
4114
4086
|
#ifdef BIGDECIMAL_DEBUG
|
|
4115
4087
|
gnAlloc = 0;
|
|
@@ -4121,7 +4093,7 @@ VpInit(DECDIG BaseVal)
|
|
|
4121
4093
|
VP_EXPORT Real *
|
|
4122
4094
|
VpOne(void)
|
|
4123
4095
|
{
|
|
4124
|
-
return VpConstOne;
|
|
4096
|
+
return VpPtr(VpConstOne);
|
|
4125
4097
|
}
|
|
4126
4098
|
|
|
4127
4099
|
/* If exponent overflows,then raise exception or returns 0 */
|
|
@@ -4152,7 +4124,7 @@ overflow:
|
|
|
4152
4124
|
return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
|
|
4153
4125
|
}
|
|
4154
4126
|
|
|
4155
|
-
|
|
4127
|
+
NULLABLE_BDVALUE
|
|
4156
4128
|
bigdecimal_parse_special_string(const char *str)
|
|
4157
4129
|
{
|
|
4158
4130
|
static const struct {
|
|
@@ -4177,66 +4149,27 @@ bigdecimal_parse_special_string(const char *str)
|
|
|
4177
4149
|
p = str + table[i].len;
|
|
4178
4150
|
while (*p && ISSPACE(*p)) ++p;
|
|
4179
4151
|
if (*p == '\0') {
|
|
4180
|
-
|
|
4152
|
+
VALUE obj = BigDecimal_allocate(1);
|
|
4153
|
+
Real *vp = VpPtr(obj);
|
|
4181
4154
|
switch (table[i].sign) {
|
|
4182
4155
|
default:
|
|
4183
|
-
UNREACHABLE;
|
|
4156
|
+
UNREACHABLE;
|
|
4157
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4184
4158
|
case VP_SIGN_POSITIVE_INFINITE:
|
|
4185
4159
|
VpSetPosInf(vp);
|
|
4186
|
-
|
|
4160
|
+
break;
|
|
4187
4161
|
case VP_SIGN_NEGATIVE_INFINITE:
|
|
4188
4162
|
VpSetNegInf(vp);
|
|
4189
|
-
|
|
4163
|
+
break;
|
|
4190
4164
|
case VP_SIGN_NaN:
|
|
4191
4165
|
VpSetNaN(vp);
|
|
4192
|
-
|
|
4166
|
+
break;
|
|
4193
4167
|
}
|
|
4168
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4194
4169
|
}
|
|
4195
4170
|
}
|
|
4196
4171
|
|
|
4197
|
-
return NULL;
|
|
4198
|
-
}
|
|
4199
|
-
|
|
4200
|
-
struct VpCtoV_args {
|
|
4201
|
-
Real *a;
|
|
4202
|
-
const char *int_chr;
|
|
4203
|
-
size_t ni;
|
|
4204
|
-
const char *frac;
|
|
4205
|
-
size_t nf;
|
|
4206
|
-
const char *exp_chr;
|
|
4207
|
-
size_t ne;
|
|
4208
|
-
};
|
|
4209
|
-
|
|
4210
|
-
static VALUE
|
|
4211
|
-
call_VpCtoV(VALUE arg)
|
|
4212
|
-
{
|
|
4213
|
-
struct VpCtoV_args *x = (struct VpCtoV_args *)arg;
|
|
4214
|
-
return (VALUE)VpCtoV(x->a, x->int_chr, x->ni, x->frac, x->nf, x->exp_chr, x->ne);
|
|
4215
|
-
}
|
|
4216
|
-
|
|
4217
|
-
static int
|
|
4218
|
-
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)
|
|
4219
|
-
{
|
|
4220
|
-
struct VpCtoV_args args;
|
|
4221
|
-
int state = 0;
|
|
4222
|
-
|
|
4223
|
-
args.a = a;
|
|
4224
|
-
args.int_chr = int_chr;
|
|
4225
|
-
args.ni = ni;
|
|
4226
|
-
args.frac = frac;
|
|
4227
|
-
args.nf = nf;
|
|
4228
|
-
args.exp_chr = exp_chr;
|
|
4229
|
-
args.ne = ne;
|
|
4230
|
-
|
|
4231
|
-
VALUE result = rb_protect(call_VpCtoV, (VALUE)&args, &state);
|
|
4232
|
-
if (state) {
|
|
4233
|
-
if (free_on_error) {
|
|
4234
|
-
rbd_free_struct(a);
|
|
4235
|
-
}
|
|
4236
|
-
rb_jump_tag(state);
|
|
4237
|
-
}
|
|
4238
|
-
|
|
4239
|
-
return (int)result;
|
|
4172
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4240
4173
|
}
|
|
4241
4174
|
|
|
4242
4175
|
/*
|
|
@@ -4245,25 +4178,25 @@ protected_VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size
|
|
|
4245
4178
|
* szVal ... The value assigned(char).
|
|
4246
4179
|
*
|
|
4247
4180
|
* [Returns]
|
|
4248
|
-
*
|
|
4249
|
-
*
|
|
4181
|
+
* NULLABLE_BDVALUE to the newly allocated variable.
|
|
4182
|
+
* Null is returned if memory allocation failed, or any error occured.
|
|
4250
4183
|
*/
|
|
4251
|
-
VP_EXPORT
|
|
4184
|
+
VP_EXPORT NULLABLE_BDVALUE
|
|
4252
4185
|
VpAlloc(const char *szVal, int strict_p, int exc)
|
|
4253
4186
|
{
|
|
4254
4187
|
const char *orig_szVal = szVal;
|
|
4255
4188
|
size_t i, j, ni, ipf, nf, ipe, ne, exp_seen, nalloc;
|
|
4256
4189
|
char v, *psz;
|
|
4257
4190
|
int sign=1;
|
|
4258
|
-
Real *vp = NULL;
|
|
4259
4191
|
VALUE buf;
|
|
4260
4192
|
|
|
4261
4193
|
/* Skipping leading spaces */
|
|
4262
4194
|
while (ISSPACE(*szVal)) szVal++;
|
|
4263
4195
|
|
|
4264
4196
|
/* Check on Inf & NaN */
|
|
4265
|
-
|
|
4266
|
-
|
|
4197
|
+
NULLABLE_BDVALUE special_bd = bigdecimal_parse_special_string(szVal);
|
|
4198
|
+
if (special_bd.real_or_null != NULL) {
|
|
4199
|
+
return special_bd;
|
|
4267
4200
|
}
|
|
4268
4201
|
|
|
4269
4202
|
/* Skip leading `#`.
|
|
@@ -4417,10 +4350,11 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4417
4350
|
VALUE str;
|
|
4418
4351
|
invalid_value:
|
|
4419
4352
|
if (!strict_p) {
|
|
4420
|
-
|
|
4353
|
+
BDVALUE res = rbd_allocate_struct_zero_wrap(1, 1);
|
|
4354
|
+
return (NULLABLE_BDVALUE) { res.bigdecimal, res.real };
|
|
4421
4355
|
}
|
|
4422
4356
|
if (!exc) {
|
|
4423
|
-
return NULL;
|
|
4357
|
+
return (NULLABLE_BDVALUE) { Qnil, NULL };
|
|
4424
4358
|
}
|
|
4425
4359
|
str = rb_str_new2(orig_szVal);
|
|
4426
4360
|
rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
|
|
@@ -4428,11 +4362,12 @@ VpAlloc(const char *szVal, int strict_p, int exc)
|
|
|
4428
4362
|
|
|
4429
4363
|
nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
|
|
4430
4364
|
/* units for szVal[] */
|
|
4431
|
-
|
|
4365
|
+
VALUE obj = BigDecimal_allocate(nalloc);
|
|
4366
|
+
Real *vp = VpPtr(obj);
|
|
4432
4367
|
VpSetZero(vp, sign);
|
|
4433
|
-
|
|
4368
|
+
VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
|
|
4434
4369
|
rb_str_resize(buf, 0);
|
|
4435
|
-
return vp;
|
|
4370
|
+
return (NULLABLE_BDVALUE) { obj, vp };
|
|
4436
4371
|
}
|
|
4437
4372
|
|
|
4438
4373
|
/*
|
|
@@ -4904,17 +4839,12 @@ VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos,
|
|
|
4904
4839
|
* a0 a1 .... an * b0
|
|
4905
4840
|
* +_____________________________
|
|
4906
4841
|
* c0 c1 c2 ...... cl
|
|
4907
|
-
* nc <---|
|
|
4908
|
-
* MaxAB |--------------------|
|
|
4909
4842
|
*/
|
|
4910
4843
|
VP_EXPORT size_t
|
|
4911
4844
|
VpMult(Real *c, Real *a, Real *b)
|
|
4912
4845
|
{
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
size_t ind_as, ind_ae, ind_bs;
|
|
4916
|
-
DECDIG carry;
|
|
4917
|
-
DECDIG_DBL s;
|
|
4846
|
+
ssize_t a_batch_max, b_batch_max;
|
|
4847
|
+
DECDIG_DBL batch[VPMULT_BATCH_SIZE * 2 - 1];
|
|
4918
4848
|
|
|
4919
4849
|
if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
|
|
4920
4850
|
|
|
@@ -4938,9 +4868,6 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
4938
4868
|
a = b;
|
|
4939
4869
|
b = w;
|
|
4940
4870
|
}
|
|
4941
|
-
MxIndA = a->Prec - 1;
|
|
4942
|
-
MxIndB = b->Prec - 1;
|
|
4943
|
-
MxIndAB = a->Prec + b->Prec - 1;
|
|
4944
4871
|
|
|
4945
4872
|
/* set LHSV c info */
|
|
4946
4873
|
|
|
@@ -4954,51 +4881,41 @@ VpMult(Real *c, Real *a, Real *b)
|
|
|
4954
4881
|
goto Cleanup;
|
|
4955
4882
|
}
|
|
4956
4883
|
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
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
|
+
}
|
|
4903
|
+
}
|
|
4977
4904
|
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
carry += (DECDIG)s;
|
|
4986
|
-
c->frac[ind_c] -= (DECDIG)(s * BASE);
|
|
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);
|
|
4987
4912
|
}
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
c->frac[ii] -= (carry * BASE);
|
|
4995
|
-
}
|
|
4996
|
-
else {
|
|
4997
|
-
break;
|
|
4998
|
-
}
|
|
4999
|
-
}
|
|
5000
|
-
}
|
|
5001
|
-
}
|
|
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
|
+
}
|
|
5002
4919
|
}
|
|
5003
4920
|
|
|
5004
4921
|
Cleanup:
|
data/ext/bigdecimal/bigdecimal.h
CHANGED
|
@@ -168,6 +168,11 @@ typedef struct {
|
|
|
168
168
|
Real *real;
|
|
169
169
|
} BDVALUE;
|
|
170
170
|
|
|
171
|
+
typedef struct {
|
|
172
|
+
VALUE bigdecimal_or_nil;
|
|
173
|
+
Real *real_or_null;
|
|
174
|
+
} NULLABLE_BDVALUE;
|
|
175
|
+
|
|
171
176
|
/*
|
|
172
177
|
* ------------------
|
|
173
178
|
* EXPORTables.
|
|
@@ -194,7 +199,7 @@ VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
|
|
|
194
199
|
VP_EXPORT int VpException(unsigned short f,const char *str,int always);
|
|
195
200
|
VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
|
|
196
201
|
VP_EXPORT size_t VpInit(DECDIG BaseVal);
|
|
197
|
-
VP_EXPORT
|
|
202
|
+
VP_EXPORT NULLABLE_BDVALUE VpAlloc(const char *szVal, int strict_p, int exc);
|
|
198
203
|
VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
|
|
199
204
|
VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
|
|
200
205
|
VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
|
data/ext/bigdecimal/extconf.rb
CHANGED
|
@@ -46,6 +46,10 @@ have_func("rb_opts_exception_p", "ruby.h")
|
|
|
46
46
|
have_func("rb_category_warn", "ruby.h")
|
|
47
47
|
have_const("RB_WARN_CATEGORY_DEPRECATED", "ruby.h")
|
|
48
48
|
|
|
49
|
+
if RUBY_ENGINE == "ruby"
|
|
50
|
+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
|
|
51
|
+
end
|
|
52
|
+
|
|
49
53
|
if File.file?(File.expand_path('../lib/bigdecimal.rb', __FILE__))
|
|
50
54
|
bigdecimal_rb = "$(srcdir)/lib/bigdecimal.rb"
|
|
51
55
|
else
|
data/lib/bigdecimal/math.rb
CHANGED
|
@@ -144,7 +144,7 @@ module BigMath
|
|
|
144
144
|
x = -x if neg = x < 0
|
|
145
145
|
ex = x.exponent / 3
|
|
146
146
|
x = x._decimal_shift(-3 * ex)
|
|
147
|
-
y = BigDecimal(Math.cbrt(x
|
|
147
|
+
y = BigDecimal(Math.cbrt(BigDecimal::Internal.fast_to_f(x)), 0)
|
|
148
148
|
BigDecimal::Internal.newton_loop(prec + BigDecimal::Internal::EXTRA_PREC) do |p|
|
|
149
149
|
y = (2 * y + x.div(y, p).div(y, p)).div(3, p)
|
|
150
150
|
end
|
|
@@ -304,7 +304,7 @@ module BigMath
|
|
|
304
304
|
|
|
305
305
|
# Solve tan(y) - x = 0 with Newton's method
|
|
306
306
|
# Repeat: y -= (tan(y) - x) * cos(y)**2
|
|
307
|
-
y = BigDecimal(Math.atan(x
|
|
307
|
+
y = BigDecimal(Math.atan(BigDecimal::Internal.fast_to_f(x)), 0)
|
|
308
308
|
BigDecimal::Internal.newton_loop(n) do |p|
|
|
309
309
|
s = sin(y, p)
|
|
310
310
|
c = (1 - s * s).sqrt(p)
|
|
@@ -605,7 +605,7 @@ module BigMath
|
|
|
605
605
|
return BigDecimal(1) if x > 5000000000 # erf(5000000000) > 1 - 1e-10000000000000000000
|
|
606
606
|
|
|
607
607
|
if x > 8
|
|
608
|
-
xf = x
|
|
608
|
+
xf = BigDecimal::Internal.fast_to_f(x)
|
|
609
609
|
log10_erfc = -xf ** 2 / Math.log(10) - Math.log10(xf * Math::PI ** 0.5)
|
|
610
610
|
erfc_prec = [prec + log10_erfc.ceil, 1].max
|
|
611
611
|
erfc = _erfc_asymptotic(x, erfc_prec)
|
|
@@ -647,7 +647,7 @@ module BigMath
|
|
|
647
647
|
# erfc(x) = 1 - erf(x) < exp(-x**2)/x/sqrt(pi)
|
|
648
648
|
# Precision of erf(x) needs about log10(exp(-x**2)/x/sqrt(pi)) extra digits
|
|
649
649
|
log10 = 2.302585092994046
|
|
650
|
-
xf = x
|
|
650
|
+
xf = BigDecimal::Internal.fast_to_f(x)
|
|
651
651
|
high_prec = prec + BigDecimal::Internal::EXTRA_PREC + ((xf**2 + Math.log(xf) + Math.log(Math::PI)/2) / log10).ceil
|
|
652
652
|
BigDecimal(1).sub(erf(x, high_prec), prec)
|
|
653
653
|
end
|
|
@@ -698,7 +698,7 @@ module BigMath
|
|
|
698
698
|
# sqrt(2)/2 + k*log(k) - k - 2*k*log(x) < -prec*log(10)
|
|
699
699
|
# and the left side is minimized when k = x**2.
|
|
700
700
|
prec += BigDecimal::Internal::EXTRA_PREC
|
|
701
|
-
xf = x
|
|
701
|
+
xf = BigDecimal::Internal.fast_to_f(x)
|
|
702
702
|
kmax = (1..(xf ** 2).floor).bsearch do |k|
|
|
703
703
|
Math.log(2) / 2 + k * Math.log(k) - k - 2 * k * Math.log(xf) < -prec * Math.log(10)
|
|
704
704
|
end
|
data/lib/bigdecimal.rb
CHANGED
|
@@ -76,9 +76,18 @@ class BigDecimal
|
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
# Fast and rough conversion to float for mathematical calculations.
|
|
80
|
+
# Bigdecimal#to_f is slow when n_significant_digits is large.
|
|
81
|
+
# This is because to_f internally converts BigDecimal to String
|
|
82
|
+
# to get the exact nearest float representation.
|
|
83
|
+
# TODO: Remove this workaround when BigDecimal#to_f is optimized.
|
|
84
|
+
def self.fast_to_f(x) # :nodoc:
|
|
85
|
+
x.n_significant_digits < 40 ? x.to_f : x.mult(1, 20).to_f
|
|
86
|
+
end
|
|
87
|
+
|
|
79
88
|
# Calculates Math.log(x.to_f) considering large or small exponent
|
|
80
89
|
def self.float_log(x) # :nodoc:
|
|
81
|
-
Math.log(x._decimal_shift(-x.exponent)
|
|
90
|
+
Math.log(fast_to_f(x._decimal_shift(-x.exponent))) + x.exponent * Math.log(10)
|
|
82
91
|
end
|
|
83
92
|
|
|
84
93
|
# Calculating Taylor series sum using binary splitting method
|
|
@@ -268,7 +277,7 @@ class BigDecimal
|
|
|
268
277
|
|
|
269
278
|
ex = exponent / 2
|
|
270
279
|
x = _decimal_shift(-2 * ex)
|
|
271
|
-
y = BigDecimal(Math.sqrt(x
|
|
280
|
+
y = BigDecimal(Math.sqrt(BigDecimal::Internal.fast_to_f(x)), 0)
|
|
272
281
|
Internal.newton_loop(prec + BigDecimal::Internal::EXTRA_PREC) do |p|
|
|
273
282
|
y = y.add(x.div(y, p), p).div(2, p)
|
|
274
283
|
end
|