bigdecimal 1.3.5 → 3.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 73213efa446db0aae9dc184b48255acbd670ac6dc1fff31c8e6361bba7288103
4
- data.tar.gz: e092ee3be9410d2b888690e5c88b1c7f4e66307f2b01592512ef33f9cfb6ab00
3
+ metadata.gz: 1b3519c64aa42c80e19107fc6d5d78d81385d7d71b9c09abef67c4e4c6a0bcef
4
+ data.tar.gz: 4ab9cb50f0a24014262635c07ecb42e6891326b49de50f262550e22d00c586ed
5
5
  SHA512:
6
- metadata.gz: d314519b706ac6ddb2e8c71723138109ba09d1f399c150b0b1095ff5081b1fd5b96aef5ff4e896ba802b6a6dcb6f220dd41f058cb5796d469b3096b885d7459f
7
- data.tar.gz: daadfc6a6d520ac15847cd57c75407b87a4884055f6ad24f42ad96194aa530d0461303a6c305790aaeea8ea98f93cca4be81e7143bcc27617061711ae22a914a
6
+ metadata.gz: 8e4aa6023012625b46f68a9e58d79a5ea0aa2c579ddb4245e0753a01118d62bd75fa5a708535346ab295619aa2ad9974a929189a83a00d56321c295a1ec8498c
7
+ data.tar.gz: 5717f808a7a56ae06b5060a3752fcaf3a9b47dca9dceb8e6822e603ec20f0296b711df04d1454a309ac6720d4af60e9b4e58f3477133f7a66e20eab75207a70e
data/bigdecimal.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- bigdecimal_version = '1.3.5'
3
+ bigdecimal_version = '3.0.0'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "bigdecimal"
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.summary = "Arbitrary-precision decimal floating-point number library."
12
12
  s.description = "This library provides arbitrary-precision decimal floating-point number class."
13
13
  s.homepage = "https://github.com/ruby/bigdecimal"
14
- s.license = "ruby"
14
+ s.license = "Ruby"
15
15
 
16
16
  s.require_paths = %w[lib]
17
17
  s.extensions = %w[ext/bigdecimal/extconf.rb]
@@ -19,8 +19,7 @@ Gem::Specification.new do |s|
19
19
  bigdecimal.gemspec
20
20
  ext/bigdecimal/bigdecimal.c
21
21
  ext/bigdecimal/bigdecimal.h
22
- ext/bigdecimal/depend
23
- ext/bigdecimal/extconf.rb
22
+ lib/bigdecimal.rb
24
23
  lib/bigdecimal/jacobian.rb
25
24
  lib/bigdecimal/ludcmp.rb
26
25
  lib/bigdecimal/math.rb
@@ -31,9 +30,10 @@ Gem::Specification.new do |s|
31
30
  sample/pi.rb
32
31
  ]
33
32
 
34
- s.add_development_dependency "rake", "~> 10.0"
33
+ s.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
34
+
35
+ s.add_development_dependency "rake", ">= 12.3.3"
35
36
  s.add_development_dependency "rake-compiler", ">= 0.9"
36
- s.add_development_dependency "rake-compiler-dock", ">= 0.6.1"
37
37
  s.add_development_dependency "minitest", "< 5.0.0"
38
38
  s.add_development_dependency "pry"
39
39
  end
@@ -14,6 +14,7 @@
14
14
  #include "ruby/util.h"
15
15
 
16
16
  #ifndef BIGDECIMAL_DEBUG
17
+ # undef NDEBUG
17
18
  # define NDEBUG
18
19
  #endif
19
20
  #include <assert.h>
@@ -24,7 +25,6 @@
24
25
  #include <string.h>
25
26
  #include <errno.h>
26
27
  #include <math.h>
27
- #include "math.h"
28
28
 
29
29
  #ifdef HAVE_IEEEFP_H
30
30
  #include <ieeefp.h>
@@ -77,7 +77,7 @@ static ID id_half;
77
77
  #define BASE1 (BASE/10)
78
78
 
79
79
  #ifndef DBLE_FIG
80
- #define DBLE_FIG (DBL_DIG+1) /* figure of double */
80
+ #define DBLE_FIG rmpd_double_figures() /* figure of double */
81
81
  #endif
82
82
 
83
83
  #ifndef RRATIONAL_ZERO_P
@@ -127,6 +127,30 @@ rb_rational_den(VALUE rat)
127
127
  }
128
128
  #endif
129
129
 
130
+ #ifndef HAVE_RB_COMPLEX_REAL
131
+ static inline VALUE
132
+ rb_complex_real(VALUE cmp)
133
+ {
134
+ #ifdef HAVE_TYPE_STRUCT_RCOMPLEX
135
+ return RCOMPLEX(cmp)->real;
136
+ #else
137
+ return rb_funcall(cmp, rb_intern("real"), 0);
138
+ #endif
139
+ }
140
+ #endif
141
+
142
+ #ifndef HAVE_RB_COMPLEX_IMAG
143
+ static inline VALUE
144
+ rb_complex_imag(VALUE cmp)
145
+ {
146
+ #ifdef HAVE_TYPE_STRUCT_RCOMPLEX
147
+ return RCOMPLEX(cmp)->imag;
148
+ #else
149
+ return rb_funcall(cmp, rb_intern("imag"), 0);
150
+ #endif
151
+ }
152
+ #endif
153
+
130
154
  #define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0)
131
155
  #define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0)
132
156
 
@@ -135,24 +159,6 @@ rb_rational_den(VALUE rat)
135
159
  */
136
160
  #define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
137
161
 
138
- /*
139
- * Returns the BigDecimal version number.
140
- */
141
- static VALUE
142
- BigDecimal_version(VALUE self)
143
- {
144
- /*
145
- * 1.0.0: Ruby 1.8.0
146
- * 1.0.1: Ruby 1.8.1
147
- * 1.1.0: Ruby 1.9.3
148
- */
149
- #ifndef RUBY_BIGDECIMAL_VERSION
150
- # error RUBY_BIGDECIMAL_VERSION is not defined
151
- #endif
152
- rb_warning("BigDecimal.ver is deprecated; use BigDecimal::VERSION instead.");
153
- return rb_str_new2(RUBY_BIGDECIMAL_VERSION);
154
- }
155
-
156
162
  /*
157
163
  * VP routines used in BigDecimal part
158
164
  */
@@ -183,11 +189,16 @@ BigDecimal_memsize(const void *ptr)
183
189
  return (sizeof(*pv) + pv->MaxPrec * sizeof(BDIGIT));
184
190
  }
185
191
 
192
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
193
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
194
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
195
+ #endif
196
+
186
197
  static const rb_data_type_t BigDecimal_data_type = {
187
198
  "BigDecimal",
188
199
  { 0, BigDecimal_delete, BigDecimal_memsize, },
189
200
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
190
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
201
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
191
202
  #endif
192
203
  };
193
204
 
@@ -246,7 +257,7 @@ again:
246
257
  switch(TYPE(v)) {
247
258
  case T_FLOAT:
248
259
  if (prec < 0) goto unable_to_coerce_without_prec;
249
- if (prec > DBL_DIG+1) goto SomeOneMayDoIt;
260
+ if (prec > (long)DBLE_FIG) goto SomeOneMayDoIt;
250
261
  d = RFLOAT_VALUE(v);
251
262
  if (!isfinite(d)) {
252
263
  pv = VpCreateRbObject(1, NULL);
@@ -294,7 +305,6 @@ again:
294
305
  #ifdef ENABLE_NUMERIC_STRING
295
306
  case T_STRING:
296
307
  StringValueCStr(v);
297
- rb_check_safe_obj(v);
298
308
  return VpCreateRbObject(RSTRING_LEN(v) + VpBaseFig() + 1,
299
309
  RSTRING_PTR(v));
300
310
  #endif /* ENABLE_NUMERIC_STRING */
@@ -345,11 +355,13 @@ BigDecimal_double_fig(VALUE self)
345
355
  /* call-seq:
346
356
  * big_decimal.precs -> array
347
357
  *
348
- * Returns an Array of two Integer values.
358
+ * Returns an Array of two Integer values that represent platform-dependent
359
+ * internal storage properties.
349
360
  *
350
- * The first value is the current number of significant digits in the
351
- * BigDecimal. The second value is the maximum number of significant digits
352
- * for the BigDecimal.
361
+ * This method is deprecated and will be removed in the future.
362
+ * Instead, use BigDecimal#n_significant_digits for obtaining the number of
363
+ * significant digits in scientific notation, and BigDecimal#precision for
364
+ * obtaining the number of digits in decimal notation.
353
365
  *
354
366
  * BigDecimal('5').precs #=> [9, 18]
355
367
  */
@@ -361,12 +373,109 @@ BigDecimal_prec(VALUE self)
361
373
  Real *p;
362
374
  VALUE obj;
363
375
 
376
+ rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
377
+ "BigDecimal#precs is deprecated and will be removed in the future; "
378
+ "use BigDecimal#precision instead.");
379
+
364
380
  GUARD_OBJ(p, GetVpValue(self, 1));
365
- obj = rb_assoc_new(INT2NUM(p->Prec*VpBaseFig()),
366
- INT2NUM(p->MaxPrec*VpBaseFig()));
381
+ obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
382
+ SIZET2NUM(p->MaxPrec*VpBaseFig()));
367
383
  return obj;
368
384
  }
369
385
 
386
+ /*
387
+ * call-seq:
388
+ * big_decimal.precision -> intreger
389
+ *
390
+ * Returns the number of decimal digits in this number.
391
+ *
392
+ * Example:
393
+ *
394
+ * BigDecimal("0").precision # => 0
395
+ * BigDecimal("1").precision # => 1
396
+ * BigDecimal("-1e20").precision # => 21
397
+ * BigDecimal("1e-20").precision # => 20
398
+ * BigDecimal("Infinity").precision # => 0
399
+ * BigDecimal("-Infinity").precision # => 0
400
+ * BigDecimal("NaN").precision # => 0
401
+ */
402
+ static VALUE
403
+ BigDecimal_precision(VALUE self)
404
+ {
405
+ ENTER(1);
406
+
407
+ Real *p;
408
+ GUARD_OBJ(p, GetVpValue(self, 1));
409
+
410
+ /*
411
+ * The most significant digit is frac[0], and the least significant digit is frac[Prec-1].
412
+ * When the exponent is zero, the decimal point is located just before frac[0].
413
+ * When the exponent is negative, the decimal point moves to leftward.
414
+ * Conversely, when the exponent is positive, the decimal point moves to rightward.
415
+ *
416
+ * | frac[0] frac[1] frac[2] . frac[3] frac[4] ... frac[Prec-1]
417
+ * |------------------------> exponent == 3
418
+ */
419
+
420
+ ssize_t ex = p->exponent;
421
+ ssize_t precision;
422
+ if (ex < 0) {
423
+ precision = (-ex + 1) * BASE_FIG; /* 1 is for p->frac[0] */
424
+ ex = 0;
425
+ }
426
+ else if (p->Prec > 0) {
427
+ BDIGIT x = p->frac[0];
428
+ for (precision = 0; x > 0; x /= 10) {
429
+ ++precision;
430
+ }
431
+ }
432
+
433
+ if (ex > (ssize_t)p->Prec) {
434
+ precision += (ex - 1) * BASE_FIG;
435
+ }
436
+ else if (p->Prec > 0) {
437
+ ssize_t n = (ssize_t)p->Prec - 1;
438
+ while (n > 0 && p->frac[n] == 0) --n;
439
+
440
+ precision += n * BASE_FIG;
441
+
442
+ if (ex < (ssize_t)p->Prec) {
443
+ BDIGIT x = p->frac[n];
444
+ for (; x > 0 && x % 10 == 0; x /= 10) {
445
+ --precision;
446
+ }
447
+ }
448
+ }
449
+
450
+ return SSIZET2NUM(precision);
451
+ }
452
+
453
+ static VALUE
454
+ BigDecimal_n_significant_digits(VALUE self)
455
+ {
456
+ ENTER(1);
457
+
458
+ Real *p;
459
+ GUARD_OBJ(p, GetVpValue(self, 1));
460
+
461
+ ssize_t n = p->Prec;
462
+ while (n > 0 && p->frac[n-1] == 0) --n;
463
+ if (n <= 0) {
464
+ return INT2FIX(0);
465
+ }
466
+
467
+ int nlz, ntz;
468
+
469
+ BDIGIT x = p->frac[0];
470
+ for (nlz = BASE_FIG; x > 0; x /= 10) --nlz;
471
+
472
+ x = p->frac[n-1];
473
+ for (ntz = 0; x > 0 && x % 10 == 0; x /= 10) ++ntz;
474
+
475
+ ssize_t n_digits = BASE_FIG * n - nlz - ntz;
476
+ return SSIZET2NUM(n_digits);
477
+ }
478
+
370
479
  /*
371
480
  * call-seq: hash
372
481
  *
@@ -436,7 +545,6 @@ BigDecimal_load(VALUE self, VALUE str)
436
545
  unsigned long m=0;
437
546
 
438
547
  pch = (unsigned char *)StringValueCStr(str);
439
- rb_check_safe_obj(str);
440
548
  /* First get max prec */
441
549
  while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
442
550
  if(!ISDIGIT(ch)) {
@@ -664,9 +772,10 @@ VP_EXPORT Real *
664
772
  VpNewRbClass(size_t mx, const char *str, VALUE klass)
665
773
  {
666
774
  VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
667
- Real *pv = VpAlloc(mx,str);
775
+ Real *pv = VpAlloc(mx, str, 1, 1);
668
776
  RTYPEDDATA_DATA(obj) = pv;
669
777
  pv->obj = obj;
778
+ RB_OBJ_FREEZE(obj);
670
779
  return pv;
671
780
  }
672
781
 
@@ -894,7 +1003,7 @@ BigDecimal_coerce(VALUE self, VALUE other)
894
1003
  Real *b;
895
1004
 
896
1005
  if (RB_TYPE_P(other, T_FLOAT)) {
897
- GUARD_OBJ(b, GetVpValueWithPrec(other, DBL_DIG+1, 1));
1006
+ GUARD_OBJ(b, GetVpValueWithPrec(other, DBLE_FIG, 1));
898
1007
  obj = rb_assoc_new(ToValue(b), self);
899
1008
  }
900
1009
  else {
@@ -952,7 +1061,7 @@ BigDecimal_add(VALUE self, VALUE r)
952
1061
 
953
1062
  GUARD_OBJ(a, GetVpValue(self, 1));
954
1063
  if (RB_TYPE_P(r, T_FLOAT)) {
955
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1064
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
956
1065
  }
957
1066
  else if (RB_TYPE_P(r, T_RATIONAL)) {
958
1067
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1010,7 +1119,7 @@ BigDecimal_sub(VALUE self, VALUE r)
1010
1119
 
1011
1120
  GUARD_OBJ(a, GetVpValue(self,1));
1012
1121
  if (RB_TYPE_P(r, T_FLOAT)) {
1013
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1122
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1014
1123
  }
1015
1124
  else if (RB_TYPE_P(r, T_RATIONAL)) {
1016
1125
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1060,7 +1169,7 @@ BigDecimalCmp(VALUE self, VALUE r,char op)
1060
1169
  break;
1061
1170
 
1062
1171
  case T_FLOAT:
1063
- GUARD_OBJ(b, GetVpValueWithPrec(r, DBL_DIG+1, 0));
1172
+ GUARD_OBJ(b, GetVpValueWithPrec(r, DBLE_FIG, 0));
1064
1173
  break;
1065
1174
 
1066
1175
  case T_RATIONAL:
@@ -1273,7 +1382,7 @@ BigDecimal_mult(VALUE self, VALUE r)
1273
1382
 
1274
1383
  GUARD_OBJ(a, GetVpValue(self, 1));
1275
1384
  if (RB_TYPE_P(r, T_FLOAT)) {
1276
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1385
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1277
1386
  }
1278
1387
  else if (RB_TYPE_P(r, T_RATIONAL)) {
1279
1388
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1301,7 +1410,7 @@ BigDecimal_divide(Real **c, Real **res, Real **div, VALUE self, VALUE r)
1301
1410
 
1302
1411
  GUARD_OBJ(a, GetVpValue(self, 1));
1303
1412
  if (RB_TYPE_P(r, T_FLOAT)) {
1304
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1413
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1305
1414
  }
1306
1415
  else if (RB_TYPE_P(r, T_RATIONAL)) {
1307
1416
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1367,7 +1476,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
1367
1476
 
1368
1477
  GUARD_OBJ(a, GetVpValue(self, 1));
1369
1478
  if (RB_TYPE_P(r, T_FLOAT)) {
1370
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1479
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1371
1480
  }
1372
1481
  else if (RB_TYPE_P(r, T_RATIONAL)) {
1373
1482
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1468,7 +1577,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
1468
1577
 
1469
1578
  GUARD_OBJ(a, GetVpValue(self, 1));
1470
1579
  if (RB_TYPE_P(r, T_FLOAT)) {
1471
- b = GetVpValueWithPrec(r, DBL_DIG+1, 1);
1580
+ b = GetVpValueWithPrec(r, DBLE_FIG, 1);
1472
1581
  }
1473
1582
  else if (RB_TYPE_P(r, T_RATIONAL)) {
1474
1583
  b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
@@ -1773,20 +1882,23 @@ BigDecimal_fix(VALUE self)
1773
1882
  * round(n, mode)
1774
1883
  *
1775
1884
  * Round to the nearest integer (by default), returning the result as a
1776
- * BigDecimal.
1885
+ * BigDecimal if n is specified, or as an Integer if it isn't.
1777
1886
  *
1778
1887
  * BigDecimal('3.14159').round #=> 3
1779
1888
  * BigDecimal('8.7').round #=> 9
1780
1889
  * BigDecimal('-9.9').round #=> -10
1781
1890
  *
1891
+ * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
1892
+ * BigDecimal('3.14159').round.class.name #=> "Integer"
1893
+ *
1782
1894
  * If n is specified and positive, the fractional part of the result has no
1783
1895
  * more than that many digits.
1784
1896
  *
1785
1897
  * If n is specified and negative, at least that many digits to the left of the
1786
- * decimal point will be 0 in the result.
1898
+ * decimal point will be 0 in the result, and return value will be an Integer.
1787
1899
  *
1788
1900
  * BigDecimal('3.14159').round(3) #=> 3.142
1789
- * BigDecimal('13345.234').round(-2) #=> 13300.0
1901
+ * BigDecimal('13345.234').round(-2) #=> 13300
1790
1902
  *
1791
1903
  * The value of the optional mode argument can be used to determine how
1792
1904
  * rounding is performed; see BigDecimal.mode.
@@ -1799,6 +1911,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
1799
1911
  int iLoc = 0;
1800
1912
  VALUE vLoc;
1801
1913
  VALUE vRound;
1914
+ int round_to_int = 0;
1802
1915
  size_t mx, pl;
1803
1916
 
1804
1917
  unsigned short sw = VpGetRoundMode();
@@ -1806,6 +1919,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
1806
1919
  switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
1807
1920
  case 0:
1808
1921
  iLoc = 0;
1922
+ round_to_int = 1;
1809
1923
  break;
1810
1924
  case 1:
1811
1925
  if (RB_TYPE_P(vLoc, T_HASH)) {
@@ -1813,6 +1927,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
1813
1927
  }
1814
1928
  else {
1815
1929
  iLoc = NUM2INT(vLoc);
1930
+ if (iLoc < 1) round_to_int = 1;
1816
1931
  }
1817
1932
  break;
1818
1933
  case 2:
@@ -1834,7 +1949,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
1834
1949
  GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
1835
1950
  VpSetPrecLimit(pl);
1836
1951
  VpActiveRound(c, a, sw, iLoc);
1837
- if (argc == 0) {
1952
+ if (round_to_int) {
1838
1953
  return BigDecimal_to_i(ToValue(c));
1839
1954
  }
1840
1955
  return ToValue(c);
@@ -2044,7 +2159,6 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2044
2159
  if (rb_scan_args(argc, argv, "01", &f) == 1) {
2045
2160
  if (RB_TYPE_P(f, T_STRING)) {
2046
2161
  psz = StringValueCStr(f);
2047
- rb_check_safe_obj(f);
2048
2162
  if (*psz == ' ') {
2049
2163
  fPlus = 1;
2050
2164
  psz++;
@@ -2084,7 +2198,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
2084
2198
  nc += (nc + mc - 1) / mc + 1;
2085
2199
  }
2086
2200
 
2087
- str = rb_str_new(0, nc);
2201
+ str = rb_usascii_str_new(0, nc);
2088
2202
  psz = RSTRING_PTR(str);
2089
2203
 
2090
2204
  if (fmt) {
@@ -2149,7 +2263,7 @@ BigDecimal_split(VALUE self)
2149
2263
  rb_ary_push(obj, str);
2150
2264
  rb_str_resize(str, strlen(psz1));
2151
2265
  rb_ary_push(obj, INT2FIX(10));
2152
- rb_ary_push(obj, INT2NUM(e));
2266
+ rb_ary_push(obj, SSIZET2NUM(e));
2153
2267
  return obj;
2154
2268
  }
2155
2269
 
@@ -2162,18 +2276,13 @@ static VALUE
2162
2276
  BigDecimal_exponent(VALUE self)
2163
2277
  {
2164
2278
  ssize_t e = VpExponent10(GetVpValue(self, 1));
2165
- return INT2NUM(e);
2279
+ return SSIZET2NUM(e);
2166
2280
  }
2167
2281
 
2168
- /* Returns debugging information about the value as a string of comma-separated
2169
- * values in angle brackets with a leading #:
2282
+ /* Returns a string representation of self.
2170
2283
  *
2171
2284
  * BigDecimal("1234.5678").inspect
2172
2285
  * #=> "0.12345678e4"
2173
- *
2174
- * The first part is the address, the second is the value as a string, and
2175
- * the final part ss(mm) is the current number of significant digits and the
2176
- * maximum number of significant digits, respectively.
2177
2286
  */
2178
2287
  static VALUE
2179
2288
  BigDecimal_inspect(VALUE self)
@@ -2335,7 +2444,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2335
2444
  n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
2336
2445
 
2337
2446
  if (VpIsNaN(x)) {
2338
- y = VpCreateRbObject(n, "0#");
2447
+ y = VpCreateRbObject(n, "0");
2339
2448
  RB_GC_GUARD(y->obj);
2340
2449
  VpSetNaN(y);
2341
2450
  return ToValue(y);
@@ -2360,7 +2469,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2360
2469
  }
2361
2470
  goto retry;
2362
2471
  }
2363
- exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1);
2472
+ if (NIL_P(prec)) {
2473
+ n += DBLE_FIG;
2474
+ }
2475
+ exp = GetVpValueWithPrec(vexp, DBLE_FIG, 1);
2364
2476
  break;
2365
2477
 
2366
2478
  case T_RATIONAL:
@@ -2375,6 +2487,9 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2375
2487
  goto retry;
2376
2488
  }
2377
2489
  exp = GetVpValueWithPrec(vexp, n, 1);
2490
+ if (NIL_P(prec)) {
2491
+ n += n;
2492
+ }
2378
2493
  break;
2379
2494
 
2380
2495
  case T_DATA:
@@ -2385,6 +2500,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2385
2500
  vexp = BigDecimal_to_i(vexp);
2386
2501
  goto retry;
2387
2502
  }
2503
+ if (NIL_P(prec)) {
2504
+ GUARD_OBJ(y, GetVpValue(vexp, 1));
2505
+ n += y->Prec*VpBaseFig();
2506
+ }
2388
2507
  exp = DATA_PTR(vexp);
2389
2508
  break;
2390
2509
  }
@@ -2459,7 +2578,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2459
2578
  }
2460
2579
  }
2461
2580
  else {
2462
- y = VpCreateRbObject(n, "0#");
2581
+ y = VpCreateRbObject(n, "0");
2463
2582
  if (BIGDECIMAL_NEGATIVE_P(x)) {
2464
2583
  if (is_integer(vexp)) {
2465
2584
  if (is_even(vexp)) {
@@ -2492,7 +2611,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2492
2611
  }
2493
2612
  else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
2494
2613
  if (is_negative(vexp)) {
2495
- y = VpCreateRbObject(n, "0#");
2614
+ y = VpCreateRbObject(n, "0");
2496
2615
  if (is_even(vexp)) {
2497
2616
  VpSetInf(y, VpGetSign(x));
2498
2617
  }
@@ -2510,7 +2629,7 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
2510
2629
  }
2511
2630
  else {
2512
2631
  if (is_positive(vexp)) {
2513
- y = VpCreateRbObject(n, "0#");
2632
+ y = VpCreateRbObject(n, "0");
2514
2633
  if (is_even(vexp)) {
2515
2634
  VpSetInf(y, VpGetSign(x));
2516
2635
  }
@@ -2560,72 +2679,6 @@ BigDecimal_power_op(VALUE self, VALUE exp)
2560
2679
  return BigDecimal_power(1, &exp, self);
2561
2680
  }
2562
2681
 
2563
- static VALUE
2564
- BigDecimal_s_allocate(VALUE klass)
2565
- {
2566
- return VpNewRbClass(0, NULL, klass)->obj;
2567
- }
2568
-
2569
- static Real *BigDecimal_new(int argc, VALUE *argv);
2570
-
2571
- /* call-seq:
2572
- * new(initial, digits)
2573
- *
2574
- * Create a new BigDecimal object.
2575
- *
2576
- * initial:: The initial value, as an Integer, a Float, a Rational,
2577
- * a BigDecimal, or a String.
2578
- *
2579
- * If it is a String, spaces are ignored and unrecognized characters
2580
- * terminate the value.
2581
- *
2582
- * digits:: The number of significant digits, as an Integer. If omitted or 0,
2583
- * the number of significant digits is determined from the initial
2584
- * value.
2585
- *
2586
- * The actual number of significant digits used in computation is usually
2587
- * larger than the specified number.
2588
- *
2589
- * ==== Exceptions
2590
- *
2591
- * TypeError:: If the +initial+ type is neither Integer, Float,
2592
- * Rational, nor BigDecimal, this exception is raised.
2593
- *
2594
- * TypeError:: If the +digits+ is not an Integer, this exception is raised.
2595
- *
2596
- * ArgumentError:: If +initial+ is a Float, and the +digits+ is larger than
2597
- * Float::DIG + 1, this exception is raised.
2598
- *
2599
- * ArgumentError:: If the +initial+ is a Float or Rational, and the +digits+
2600
- * value is omitted, this exception is raised.
2601
- */
2602
- static VALUE
2603
- BigDecimal_s_new(int argc, VALUE *argv, VALUE self)
2604
- {
2605
- rb_warning("BigDecimal.new is deprecated; use Kernel.BigDecimal method instead.");
2606
- return rb_call_super(argc, argv);
2607
- }
2608
-
2609
- static VALUE
2610
- BigDecimal_initialize(int argc, VALUE *argv, VALUE self)
2611
- {
2612
- ENTER(1);
2613
- Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
2614
- Real *x;
2615
-
2616
- GUARD_OBJ(x, BigDecimal_new(argc, argv));
2617
- if (ToValue(x)) {
2618
- pv = VpCopy(pv, x);
2619
- }
2620
- else {
2621
- VpFree(pv);
2622
- pv = x;
2623
- }
2624
- DATA_PTR(self) = pv;
2625
- pv->obj = self;
2626
- return self;
2627
- }
2628
-
2629
2682
  /* :nodoc:
2630
2683
  *
2631
2684
  * private method for dup and clone the provided BigDecimal +other+
@@ -2648,21 +2701,75 @@ BigDecimal_clone(VALUE self)
2648
2701
  return self;
2649
2702
  }
2650
2703
 
2704
+ #ifdef HAVE_RB_OPTS_EXCEPTION_P
2705
+ int rb_opts_exception_p(VALUE opts, int default_value);
2706
+ #define opts_exception_p(opts) rb_opts_exception_p((opts), 1)
2707
+ #else
2708
+ static int
2709
+ opts_exception_p(VALUE opts)
2710
+ {
2711
+ static ID kwds[1];
2712
+ VALUE exception;
2713
+ if (!kwds[0]) {
2714
+ kwds[0] = rb_intern_const("exception");
2715
+ }
2716
+ if (!rb_get_kwargs(opts, kwds, 0, 1, &exception)) return 1;
2717
+ switch (exception) {
2718
+ case Qtrue: case Qfalse:
2719
+ break;
2720
+ default:
2721
+ rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE,
2722
+ exception);
2723
+ }
2724
+ return exception != Qfalse;
2725
+ }
2726
+ #endif
2727
+
2651
2728
  static Real *
2652
- BigDecimal_new(int argc, VALUE *argv)
2729
+ VpNewVarArg(int argc, VALUE *argv)
2653
2730
  {
2654
2731
  size_t mf;
2732
+ VALUE opts = Qnil;
2655
2733
  VALUE nFig;
2656
2734
  VALUE iniValue;
2657
2735
  double d;
2736
+ int exc;
2658
2737
 
2659
- if (rb_scan_args(argc, argv, "11", &iniValue, &nFig) == 1) {
2738
+ argc = rb_scan_args(argc, argv, "11:", &iniValue, &nFig, &opts);
2739
+ exc = opts_exception_p(opts);
2740
+
2741
+ if (argc == 1) {
2660
2742
  mf = 0;
2661
2743
  }
2662
2744
  else {
2663
- mf = GetPrecisionInt(nFig);
2745
+ /* expand GetPrecisionInt for exception suppression */
2746
+ ssize_t n = NUM2INT(nFig);
2747
+ if (n < 0) {
2748
+ if (!exc) {
2749
+ return NULL;
2750
+ }
2751
+ rb_raise(rb_eArgError, "negative precision");
2752
+ }
2753
+ mf = (size_t)n;
2754
+ }
2755
+
2756
+ if (SPECIAL_CONST_P(iniValue)) {
2757
+ switch (iniValue) {
2758
+ case Qnil:
2759
+ if (!exc) return NULL;
2760
+ rb_raise(rb_eTypeError, "can't convert nil into BigDecimal");
2761
+ case Qtrue:
2762
+ if (!exc) return NULL;
2763
+ rb_raise(rb_eTypeError, "can't convert true into BigDecimal");
2764
+ case Qfalse:
2765
+ if (!exc) return NULL;
2766
+ rb_raise(rb_eTypeError, "can't convert false into BigDecimal");
2767
+ default:
2768
+ break;
2769
+ }
2664
2770
  }
2665
2771
 
2772
+ retry:
2666
2773
  switch (TYPE(iniValue)) {
2667
2774
  case T_DATA:
2668
2775
  if (is_kind_of_BigDecimal(iniValue)) {
@@ -2682,42 +2789,120 @@ BigDecimal_new(int argc, VALUE *argv)
2682
2789
  VpDtoV(pv, d);
2683
2790
  return pv;
2684
2791
  }
2685
- if (mf > DBL_DIG+1) {
2792
+ if (mf > DBLE_FIG) {
2793
+ if (!exc) {
2794
+ return NULL;
2795
+ }
2686
2796
  rb_raise(rb_eArgError, "precision too large.");
2687
2797
  }
2688
2798
  /* fall through */
2689
2799
  case T_RATIONAL:
2690
2800
  if (NIL_P(nFig)) {
2801
+ if (!exc) {
2802
+ return NULL;
2803
+ }
2691
2804
  rb_raise(rb_eArgError,
2692
2805
  "can't omit precision for a %"PRIsVALUE".",
2693
2806
  RB_OBJ_CLASSNAME(iniValue));
2694
2807
  }
2695
2808
  return GetVpValueWithPrec(iniValue, mf, 1);
2696
2809
 
2810
+ case T_COMPLEX:
2811
+ {
2812
+ VALUE im;
2813
+ im = rb_complex_imag(iniValue);
2814
+ if (!is_zero(im)) {
2815
+ rb_raise(rb_eArgError,
2816
+ "Unable to make a BigDecimal from non-zero imaginary number");
2817
+ }
2818
+ iniValue = rb_complex_real(iniValue);
2819
+ goto retry;
2820
+ }
2821
+
2697
2822
  case T_STRING:
2698
2823
  /* fall through */
2699
2824
  default:
2700
2825
  break;
2701
2826
  }
2827
+ /* TODO: support to_d */
2828
+ if (!exc) {
2829
+ iniValue = rb_check_convert_type(iniValue, T_STRING, "String", "to_str");
2830
+ if (NIL_P(iniValue)) return NULL;
2831
+ }
2702
2832
  StringValueCStr(iniValue);
2703
- return VpAlloc(mf, RSTRING_PTR(iniValue));
2833
+ return VpAlloc(mf, RSTRING_PTR(iniValue), 1, exc);
2704
2834
  }
2705
2835
 
2706
- /* See also BigDecimal.new */
2836
+ /* call-seq:
2837
+ * BigDecimal(initial, digits, exception: true)
2838
+ *
2839
+ * Create a new BigDecimal object.
2840
+ *
2841
+ * initial:: The initial value, as an Integer, a Float, a Rational,
2842
+ * a BigDecimal, or a String.
2843
+ *
2844
+ * If it is a String, spaces are ignored and unrecognized characters
2845
+ * terminate the value.
2846
+ *
2847
+ * digits:: The number of significant digits, as an Integer. If omitted or 0,
2848
+ * the number of significant digits is determined from the initial
2849
+ * value.
2850
+ *
2851
+ * The actual number of significant digits used in computation is
2852
+ * usually larger than the specified number.
2853
+ *
2854
+ * exception:: Whether an exception should be raised on invalid arguments.
2855
+ * +true+ by default, if passed +false+, just returns +nil+
2856
+ * for invalid.
2857
+ *
2858
+ *
2859
+ * ==== Exceptions
2860
+ *
2861
+ * TypeError:: If the +initial+ type is neither Integer, Float,
2862
+ * Rational, nor BigDecimal, this exception is raised.
2863
+ *
2864
+ * TypeError:: If the +digits+ is not an Integer, this exception is raised.
2865
+ *
2866
+ * ArgumentError:: If +initial+ is a Float, and the +digits+ is larger than
2867
+ * Float::DIG + 1, this exception is raised.
2868
+ *
2869
+ * ArgumentError:: If the +initial+ is a Float or Rational, and the +digits+
2870
+ * value is omitted, this exception is raised.
2871
+ */
2707
2872
  static VALUE
2708
- BigDecimal_global_new(int argc, VALUE *argv, VALUE self)
2873
+ f_BigDecimal(int argc, VALUE *argv, VALUE self)
2709
2874
  {
2710
2875
  ENTER(1);
2711
2876
  Real *pv;
2712
2877
  VALUE obj;
2713
2878
 
2879
+ if (argc > 0 && CLASS_OF(argv[0]) == rb_cBigDecimal) {
2880
+ if (argc == 1 || (argc == 2 && RB_TYPE_P(argv[1], T_HASH))) return argv[0];
2881
+ }
2714
2882
  obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
2715
- GUARD_OBJ(pv, BigDecimal_new(argc, argv));
2883
+ pv = VpNewVarArg(argc, argv);
2884
+ if (pv == NULL) return Qnil;
2885
+ SAVE(pv);
2716
2886
  if (ToValue(pv)) pv = VpCopy(NULL, pv);
2717
2887
  RTYPEDDATA_DATA(obj) = pv;
2888
+ RB_OBJ_FREEZE(obj);
2718
2889
  return pv->obj = obj;
2719
2890
  }
2720
2891
 
2892
+ static VALUE
2893
+ BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
2894
+ {
2895
+ ENTER(1);
2896
+ char const *c_str;
2897
+ Real *pv;
2898
+
2899
+ c_str = StringValueCStr(str);
2900
+ GUARD_OBJ(pv, VpAlloc(0, c_str, 0, 1));
2901
+ pv->obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, pv);
2902
+ RB_OBJ_FREEZE(pv->obj);
2903
+ return pv->obj;
2904
+ }
2905
+
2721
2906
  /* call-seq:
2722
2907
  * BigDecimal.limit(digits)
2723
2908
  *
@@ -2734,7 +2919,7 @@ static VALUE
2734
2919
  BigDecimal_limit(int argc, VALUE *argv, VALUE self)
2735
2920
  {
2736
2921
  VALUE nFig;
2737
- VALUE nCur = INT2NUM(VpGetPrecLimit());
2922
+ VALUE nCur = SIZET2NUM(VpGetPrecLimit());
2738
2923
 
2739
2924
  if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
2740
2925
  int nf;
@@ -2899,7 +3084,7 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
2899
3084
  infinite = isinf(flo);
2900
3085
  nan = isnan(flo);
2901
3086
  if (!infinite && !nan) {
2902
- vx = GetVpValueWithPrec(x, DBL_DIG+1, 0);
3087
+ vx = GetVpValueWithPrec(x, DBLE_FIG, 0);
2903
3088
  }
2904
3089
  break;
2905
3090
 
@@ -2937,6 +3122,10 @@ BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
2937
3122
  n = prec + rmpd_double_figures();
2938
3123
  negative = BIGDECIMAL_NEGATIVE_P(vx);
2939
3124
  if (negative) {
3125
+ VALUE x_zero = INT2NUM(1);
3126
+ VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
3127
+ x = BigDecimal_initialize_copy(x_copy, x);
3128
+ vx = DATA_PTR(x);
2940
3129
  VpSetSign(vx, 1);
2941
3130
  }
2942
3131
 
@@ -3048,7 +3237,7 @@ get_vp_value:
3048
3237
  infinite = isinf(flo);
3049
3238
  nan = isnan(flo);
3050
3239
  if (!zero && !negative && !infinite && !nan) {
3051
- vx = GetVpValueWithPrec(x, DBL_DIG+1, 1);
3240
+ vx = GetVpValueWithPrec(x, DBLE_FIG, 1);
3052
3241
  }
3053
3242
  break;
3054
3243
 
@@ -3266,6 +3455,9 @@ get_vp_value:
3266
3455
  void
3267
3456
  Init_bigdecimal(void)
3268
3457
  {
3458
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
3459
+ rb_ext_ractor_safe(true);
3460
+ #endif
3269
3461
  VALUE arg;
3270
3462
 
3271
3463
  id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
@@ -3277,18 +3469,18 @@ Init_bigdecimal(void)
3277
3469
 
3278
3470
  /* Class and method registration */
3279
3471
  rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric);
3280
- rb_define_alloc_func(rb_cBigDecimal, BigDecimal_s_allocate);
3281
3472
 
3282
3473
  /* Global function */
3283
- rb_define_global_function("BigDecimal", BigDecimal_global_new, -1);
3474
+ rb_define_global_function("BigDecimal", f_BigDecimal, -1);
3284
3475
 
3285
3476
  /* Class methods */
3286
- rb_define_singleton_method(rb_cBigDecimal, "new", BigDecimal_s_new, -1);
3477
+ rb_undef_alloc_func(rb_cBigDecimal);
3478
+ rb_undef_method(CLASS_OF(rb_cBigDecimal), "new");
3479
+ rb_define_singleton_method(rb_cBigDecimal, "interpret_loosely", BigDecimal_s_interpret_loosely, 1);
3287
3480
  rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
3288
3481
  rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
3289
3482
  rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
3290
3483
  rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
3291
- rb_define_singleton_method(rb_cBigDecimal, "ver", BigDecimal_version, 0);
3292
3484
 
3293
3485
  rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
3294
3486
  rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
@@ -3408,16 +3600,16 @@ Init_bigdecimal(void)
3408
3600
 
3409
3601
  arg = rb_str_new2("+Infinity");
3410
3602
  /* Positive infinity value. */
3411
- rb_define_const(rb_cBigDecimal, "INFINITY", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
3603
+ rb_define_const(rb_cBigDecimal, "INFINITY", f_BigDecimal(1, &arg, rb_cBigDecimal));
3412
3604
  arg = rb_str_new2("NaN");
3413
3605
  /* 'Not a Number' value. */
3414
- rb_define_const(rb_cBigDecimal, "NAN", BigDecimal_global_new(1, &arg, rb_cBigDecimal));
3606
+ rb_define_const(rb_cBigDecimal, "NAN", f_BigDecimal(1, &arg, rb_cBigDecimal));
3415
3607
 
3416
3608
 
3417
3609
  /* instance methods */
3418
- rb_define_method(rb_cBigDecimal, "initialize", BigDecimal_initialize, -1);
3419
- rb_define_method(rb_cBigDecimal, "initialize_copy", BigDecimal_initialize_copy, 1);
3420
3610
  rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
3611
+ rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
3612
+ rb_define_method(rb_cBigDecimal, "n_significant_digits", BigDecimal_n_significant_digits, 0);
3421
3613
 
3422
3614
  rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
3423
3615
  rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
@@ -3534,6 +3726,9 @@ static void VpFormatSt(char *psz, size_t fFmt);
3534
3726
  static int VpRdup(Real *m, size_t ind_m);
3535
3727
 
3536
3728
  #ifdef BIGDECIMAL_DEBUG
3729
+ # ifdef HAVE_RB_EXT_RACTOR_SAFE
3730
+ # error Need to make rewiting gnAlloc atomic
3731
+ # endif
3537
3732
  static int gnAlloc = 0; /* Memory allocation counter */
3538
3733
  #endif /* BIGDECIMAL_DEBUG */
3539
3734
 
@@ -3714,13 +3909,7 @@ VpSetRoundMode(unsigned short n)
3714
3909
  * (to let the compiler know they may be changed in outside
3715
3910
  * (... but not actually..)).
3716
3911
  */
3717
- volatile const double gZero_ABCED9B1_CE73__00400511F31D = 0.0;
3718
3912
  volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
3719
- static double
3720
- Zero(void)
3721
- {
3722
- return gZero_ABCED9B1_CE73__00400511F31D;
3723
- }
3724
3913
 
3725
3914
  static double
3726
3915
  One(void)
@@ -3745,25 +3934,19 @@ One(void)
3745
3934
  VP_EXPORT double
3746
3935
  VpGetDoubleNaN(void) /* Returns the value of NaN */
3747
3936
  {
3748
- static double fNaN = 0.0;
3749
- if (fNaN == 0.0) fNaN = Zero()/Zero();
3750
- return fNaN;
3937
+ return nan("");
3751
3938
  }
3752
3939
 
3753
3940
  VP_EXPORT double
3754
3941
  VpGetDoublePosInf(void) /* Returns the value of +Infinity */
3755
3942
  {
3756
- static double fInf = 0.0;
3757
- if (fInf == 0.0) fInf = One()/Zero();
3758
- return fInf;
3943
+ return HUGE_VAL;
3759
3944
  }
3760
3945
 
3761
3946
  VP_EXPORT double
3762
3947
  VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
3763
3948
  {
3764
- static double fInf = 0.0;
3765
- if (fInf == 0.0) fInf = -(One()/Zero());
3766
- return fInf;
3949
+ return -HUGE_VAL;
3767
3950
  }
3768
3951
 
3769
3952
  VP_EXPORT double
@@ -3952,20 +4135,17 @@ VpNumOfChars(Real *vp,const char *pszFmt)
3952
4135
  * by one BDIGIT word in the computer used.
3953
4136
  *
3954
4137
  * [Returns]
3955
- * 1+DBL_DIG ... OK
4138
+ * DBLE_FIG ... OK
3956
4139
  */
3957
4140
  VP_EXPORT size_t
3958
4141
  VpInit(BDIGIT BaseVal)
3959
4142
  {
3960
4143
  /* Setup +/- Inf NaN -0 */
3961
- VpGetDoubleNaN();
3962
- VpGetDoublePosInf();
3963
- VpGetDoubleNegInf();
3964
4144
  VpGetDoubleNegZero();
3965
4145
 
3966
4146
  /* Allocates Vp constants. */
3967
- VpConstOne = VpAlloc(1UL, "1");
3968
- VpPt5 = VpAlloc(1UL, ".5");
4147
+ VpConstOne = VpAlloc(1UL, "1", 1, 1);
4148
+ VpPt5 = VpAlloc(1UL, ".5", 1, 1);
3969
4149
 
3970
4150
  #ifdef BIGDECIMAL_DEBUG
3971
4151
  gnAlloc = 0;
@@ -4029,6 +4209,52 @@ overflow:
4029
4209
  return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
4030
4210
  }
4031
4211
 
4212
+ Real *
4213
+ rmpd_parse_special_string(const char *str)
4214
+ {
4215
+ static const struct {
4216
+ const char *str;
4217
+ size_t len;
4218
+ int sign;
4219
+ } table[] = {
4220
+ { SZ_INF, sizeof(SZ_INF) - 1, VP_SIGN_POSITIVE_INFINITE },
4221
+ { SZ_PINF, sizeof(SZ_PINF) - 1, VP_SIGN_POSITIVE_INFINITE },
4222
+ { SZ_NINF, sizeof(SZ_NINF) - 1, VP_SIGN_NEGATIVE_INFINITE },
4223
+ { SZ_NaN, sizeof(SZ_NaN) - 1, VP_SIGN_NaN }
4224
+ };
4225
+ static const size_t table_length = sizeof(table) / sizeof(table[0]);
4226
+ size_t i;
4227
+
4228
+ for (i = 0; i < table_length; ++i) {
4229
+ const char *p;
4230
+ if (strncmp(str, table[i].str, table[i].len) != 0) {
4231
+ continue;
4232
+ }
4233
+
4234
+ p = str + table[i].len;
4235
+ while (*p && ISSPACE(*p)) ++p;
4236
+ if (*p == '\0') {
4237
+ Real *vp = VpAllocReal(1);
4238
+ vp->MaxPrec = 1;
4239
+ switch (table[i].sign) {
4240
+ default:
4241
+ UNREACHABLE; break;
4242
+ case VP_SIGN_POSITIVE_INFINITE:
4243
+ VpSetPosInf(vp);
4244
+ return vp;
4245
+ case VP_SIGN_NEGATIVE_INFINITE:
4246
+ VpSetNegInf(vp);
4247
+ return vp;
4248
+ case VP_SIGN_NaN:
4249
+ VpSetNaN(vp);
4250
+ return vp;
4251
+ }
4252
+ }
4253
+ }
4254
+
4255
+ return NULL;
4256
+ }
4257
+
4032
4258
  /*
4033
4259
  * Allocates variable.
4034
4260
  * [Input]
@@ -4043,10 +4269,10 @@ overflow:
4043
4269
  * NULL be returned if memory allocation is failed,or any error.
4044
4270
  */
4045
4271
  VP_EXPORT Real *
4046
- VpAlloc(size_t mx, const char *szVal)
4272
+ VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
4047
4273
  {
4048
4274
  const char *orig_szVal = szVal;
4049
- size_t i, ni, ipn, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
4275
+ size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
4050
4276
  char v, *psz;
4051
4277
  int sign=1;
4052
4278
  Real *vp = NULL;
@@ -4057,7 +4283,10 @@ VpAlloc(size_t mx, const char *szVal)
4057
4283
  if (mx == 0) ++mx;
4058
4284
 
4059
4285
  if (szVal) {
4286
+ /* Skipping leading spaces */
4060
4287
  while (ISSPACE(*szVal)) szVal++;
4288
+
4289
+ /* Processing the leading one `#` */
4061
4290
  if (*szVal != '#') {
4062
4291
  if (mf) {
4063
4292
  mf = (mf + BASE_FIG - 1) / BASE_FIG + 2; /* Needs 1 more for div */
@@ -4071,115 +4300,179 @@ VpAlloc(size_t mx, const char *szVal)
4071
4300
  }
4072
4301
  }
4073
4302
  else {
4303
+ return_zero:
4074
4304
  /* necessary to be able to store */
4075
4305
  /* at least mx digits. */
4076
4306
  /* szVal==NULL ==> allocate zero value. */
4077
4307
  vp = VpAllocReal(mx);
4078
- /* xmalloc() alway returns(or throw interruption) */
4308
+ /* xmalloc() always returns(or throw interruption) */
4079
4309
  vp->MaxPrec = mx; /* set max precision */
4080
4310
  VpSetZero(vp, 1); /* initialize vp to zero. */
4081
4311
  return vp;
4082
4312
  }
4083
4313
 
4084
- /* Skip all '_' after digit: 2006-6-30 */
4085
- ni = 0;
4314
+ /* Check on Inf & NaN */
4315
+ if ((vp = rmpd_parse_special_string(szVal)) != NULL) {
4316
+ return vp;
4317
+ }
4318
+
4319
+ /* Scanning digits */
4320
+
4321
+ /* A buffer for keeping scanned digits */
4086
4322
  buf = rb_str_tmp_new(strlen(szVal) + 1);
4087
4323
  psz = RSTRING_PTR(buf);
4088
- i = 0;
4089
- ipn = 0;
4090
- while ((psz[i] = szVal[ipn]) != 0) {
4091
- if (ISSPACE(psz[i])) {
4092
- psz[i] = 0;
4324
+
4325
+ /* cursor: i for psz, and j for szVal */
4326
+ i = j = 0;
4327
+
4328
+ /* Scanning: sign part */
4329
+ v = psz[i] = szVal[j];
4330
+ if ((v == '-') || (v == '+')) {
4331
+ sign = -(v == '-');
4332
+ ++i;
4333
+ ++j;
4334
+ }
4335
+
4336
+ /* Scanning: integer part */
4337
+ ni = 0; /* number of digits in the integer part */
4338
+ while ((v = psz[i] = szVal[j]) != '\0') {
4339
+ if (!strict_p && ISSPACE(v)) {
4340
+ v = psz[i] = '\0';
4093
4341
  break;
4094
4342
  }
4095
- if (ISDIGIT(psz[i])) ++ni;
4096
- if (psz[i] == '_') {
4343
+ if (v == '_') {
4097
4344
  if (ni > 0) {
4098
- ipn++;
4099
- continue;
4345
+ v = szVal[j+1];
4346
+ if (v == '\0' || ISSPACE(v) || ISDIGIT(v)) {
4347
+ ++j;
4348
+ continue;
4349
+ }
4350
+ if (!strict_p) {
4351
+ v = psz[i] = '\0';
4352
+ break;
4353
+ }
4100
4354
  }
4101
- psz[i] = 0;
4355
+ goto invalid_value;
4356
+ }
4357
+ if (!ISDIGIT(v)) {
4102
4358
  break;
4103
4359
  }
4360
+ ++ni;
4104
4361
  ++i;
4105
- ++ipn;
4362
+ ++j;
4106
4363
  }
4107
- szVal = psz;
4108
4364
 
4109
- /* Check on Inf & NaN */
4110
- if (StrCmp(szVal, SZ_PINF) == 0 || StrCmp(szVal, SZ_INF) == 0 ) {
4111
- vp = VpAllocReal(1);
4112
- vp->MaxPrec = 1; /* set max precision */
4113
- VpSetPosInf(vp);
4114
- return vp;
4115
- }
4116
- if (StrCmp(szVal, SZ_NINF) == 0) {
4117
- vp = VpAllocReal(1);
4118
- vp->MaxPrec = 1; /* set max precision */
4119
- VpSetNegInf(vp);
4120
- return vp;
4121
- }
4122
- if (StrCmp(szVal, SZ_NaN) == 0) {
4123
- vp = VpAllocReal(1);
4124
- vp->MaxPrec = 1; /* set max precision */
4125
- VpSetNaN(vp);
4126
- return vp;
4127
- }
4128
-
4129
- /* check on number szVal[] */
4130
- ipn = i = 0;
4131
- if (szVal[i] == '-') { sign=-1; ++i; }
4132
- else if (szVal[i] == '+') ++i;
4133
- /* Skip digits */
4134
- ni = 0; /* digits in mantissa */
4135
- while ((v = szVal[i]) != 0) {
4136
- if (!ISDIGIT(v)) break;
4137
- ++i;
4138
- ++ni;
4139
- }
4140
- nf = 0;
4141
- ipf = 0;
4142
- ipe = 0;
4143
- ne = 0;
4365
+ /* Scanning: fractional part */
4366
+ nf = 0; /* number of digits in the fractional part */
4367
+ ne = 0; /* number of digits in the exponential part */
4368
+ ipf = 0; /* index of the beginning of the fractional part */
4369
+ ipe = 0; /* index of the beginning of the exponential part */
4144
4370
  dot_seen = 0;
4145
4371
  exp_seen = 0;
4146
- if (v) {
4147
- /* other than digit nor \0 */
4148
- if (szVal[i] == '.') { /* xxx. */
4372
+
4373
+ if (v != '\0') {
4374
+ /* Scanning fractional part */
4375
+ if ((psz[i] = szVal[j]) == '.') {
4149
4376
  dot_seen = 1;
4150
4377
  ++i;
4378
+ ++j;
4151
4379
  ipf = i;
4152
- while ((v = szVal[i]) != 0) { /* get fraction part. */
4380
+ while ((v = psz[i] = szVal[j]) != '\0') {
4381
+ if (!strict_p && ISSPACE(v)) {
4382
+ v = psz[i] = '\0';
4383
+ break;
4384
+ }
4385
+ if (v == '_') {
4386
+ if (nf > 0 && ISDIGIT(szVal[j+1])) {
4387
+ ++j;
4388
+ continue;
4389
+ }
4390
+ if (!strict_p) {
4391
+ v = psz[i] = '\0';
4392
+ if (nf == 0) {
4393
+ dot_seen = 0;
4394
+ }
4395
+ break;
4396
+ }
4397
+ goto invalid_value;
4398
+ }
4153
4399
  if (!ISDIGIT(v)) break;
4154
4400
  ++i;
4401
+ ++j;
4155
4402
  ++nf;
4156
4403
  }
4157
4404
  }
4158
- ipe = 0; /* Exponent */
4159
-
4160
- switch (szVal[i]) {
4161
- case '\0':
4162
- break;
4163
- case 'e': case 'E':
4164
- case 'd': case 'D':
4165
- exp_seen = 1;
4166
- ++i;
4167
- ipe = i;
4168
- v = szVal[i];
4169
- if ((v == '-') || (v == '+')) ++i;
4170
- while ((v=szVal[i]) != 0) {
4171
- if (!ISDIGIT(v)) break;
4405
+
4406
+ /* Scanning exponential part */
4407
+ if (v != '\0') {
4408
+ switch ((psz[i] = szVal[j])) {
4409
+ case '\0':
4410
+ break;
4411
+ case 'e': case 'E':
4412
+ case 'd': case 'D':
4413
+ exp_seen = 1;
4172
4414
  ++i;
4173
- ++ne;
4174
- }
4175
- break;
4176
- default:
4177
- break;
4415
+ ++j;
4416
+ ipe = i;
4417
+ v = psz[i] = szVal[j];
4418
+ if ((v == '-') || (v == '+')) {
4419
+ ++i;
4420
+ ++j;
4421
+ }
4422
+ while ((v = psz[i] = szVal[j]) != '\0') {
4423
+ if (!strict_p && ISSPACE(v)) {
4424
+ v = psz[i] = '\0';
4425
+ break;
4426
+ }
4427
+ if (v == '_') {
4428
+ if (ne > 0 && ISDIGIT(szVal[j+1])) {
4429
+ ++j;
4430
+ continue;
4431
+ }
4432
+ if (!strict_p) {
4433
+ v = psz[i] = '\0';
4434
+ if (ne == 0) {
4435
+ exp_seen = 0;
4436
+ }
4437
+ break;
4438
+ }
4439
+ goto invalid_value;
4440
+ }
4441
+ if (!ISDIGIT(v)) break;
4442
+ ++i;
4443
+ ++j;
4444
+ ++ne;
4445
+ }
4446
+ break;
4447
+ default:
4448
+ break;
4449
+ }
4450
+ }
4451
+
4452
+ if (v != '\0') {
4453
+ /* Scanning trailing spaces */
4454
+ while (ISSPACE(szVal[j])) ++j;
4455
+
4456
+ /* Invalid character */
4457
+ if (szVal[j] && strict_p) {
4458
+ goto invalid_value;
4459
+ }
4178
4460
  }
4179
4461
  }
4180
- if (((ni == 0 || dot_seen) && nf == 0) || (exp_seen && ne == 0)) {
4181
- VALUE str = rb_str_new2(orig_szVal);
4182
- rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
4462
+
4463
+ psz[i] = '\0';
4464
+
4465
+ if (strict_p && (((ni == 0 || dot_seen) && nf == 0) || (exp_seen && ne == 0))) {
4466
+ VALUE str;
4467
+ invalid_value:
4468
+ if (!strict_p) {
4469
+ goto return_zero;
4470
+ }
4471
+ if (!exc) {
4472
+ return NULL;
4473
+ }
4474
+ str = rb_str_new2(orig_szVal);
4475
+ rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
4183
4476
  }
4184
4477
 
4185
4478
  nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
@@ -4188,10 +4481,10 @@ VpAlloc(size_t mx, const char *szVal)
4188
4481
  nalloc = Max(nalloc, mx);
4189
4482
  mx = nalloc;
4190
4483
  vp = VpAllocReal(mx);
4191
- /* xmalloc() alway returns(or throw interruption) */
4484
+ /* xmalloc() always returns(or throw interruption) */
4192
4485
  vp->MaxPrec = mx; /* set max precision */
4193
4486
  VpSetZero(vp, sign);
4194
- VpCtoV(vp, &szVal[ipn], ni, &szVal[ipf], nf, &szVal[ipe], ne);
4487
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
4195
4488
  rb_str_resize(buf, 0);
4196
4489
  return vp;
4197
4490
  }
@@ -4754,7 +5047,7 @@ VpMult(Real *c, Real *a, Real *b)
4754
5047
 
4755
5048
  if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
4756
5049
  w = c;
4757
- c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0");
5050
+ c = VpAlloc((size_t)((MxIndAB + 1) * BASE_FIG), "#0", 1, 1);
4758
5051
  MxIndC = MxIndAB;
4759
5052
  }
4760
5053
 
@@ -5922,8 +6215,8 @@ VpSqrt(Real *y, Real *x)
5922
6215
  if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
5923
6216
 
5924
6217
  /* allocate temporally variables */
5925
- f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1");
5926
- r = VpAlloc((n + n) * (BASE_FIG + 2), "#1");
6218
+ f = VpAlloc(y->MaxPrec * (BASE_FIG + 2), "#1", 1, 1);
6219
+ r = VpAlloc((n + n) * (BASE_FIG + 2), "#1", 1, 1);
5927
6220
 
5928
6221
  nr = 0;
5929
6222
  y_prec = y->MaxPrec;
@@ -6375,8 +6668,8 @@ VpPower(Real *y, Real *x, SIGNED_VALUE n)
6375
6668
 
6376
6669
  /* Allocate working variables */
6377
6670
 
6378
- w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0");
6379
- w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0");
6671
+ w1 = VpAlloc((y->MaxPrec + 2) * BASE_FIG, "#0", 1, 1);
6672
+ w2 = VpAlloc((w1->MaxPrec * 2 + 1) * BASE_FIG, "#0", 1, 1);
6380
6673
  /* calculation start */
6381
6674
 
6382
6675
  VpAsgn(y, x, 1);