bigdecimal 1.3.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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);