bigdecimal 3.2.3-java → 3.3.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/bigdecimal/math.rb +85 -70
- data/lib/bigdecimal/util.rb +15 -14
- data/lib/bigdecimal.rb +67 -51
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b3e1def7d1cfc2c72b5aa0a460ef768973e6c704a1225663e8df144718ac23a
|
4
|
+
data.tar.gz: 41e414cf6a1348e4567ce0b06928abb2c757a3a4f5de05ebcb1d78ff54140afe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5880f8f1e8ed360116110107cf448894118a6714ecc916b3be74c056dab9e258b82620db42ace5a4b0b5833445859403e401fd2ba3a6c7d5aecaea1068986da
|
7
|
+
data.tar.gz: 33d209590eaa3132f31495884df9a5f08eae7382d349df1977c03b69d6e48c3a3bab0dee6fc5c99ead0690e5dee4f74364976d99381290b7c71f0ab4e93d7f07
|
data/lib/bigdecimal/math.rb
CHANGED
@@ -7,6 +7,7 @@ require 'bigdecimal'
|
|
7
7
|
# sqrt(x, prec)
|
8
8
|
# sin (x, prec)
|
9
9
|
# cos (x, prec)
|
10
|
+
# tan (x, prec)
|
10
11
|
# atan(x, prec)
|
11
12
|
# PI (prec)
|
12
13
|
# E (prec) == exp(1.0,prec)
|
@@ -24,8 +25,8 @@ require 'bigdecimal'
|
|
24
25
|
#
|
25
26
|
# include BigMath
|
26
27
|
#
|
27
|
-
# a = BigDecimal((PI(
|
28
|
-
# puts sin(a,100) # => 0.
|
28
|
+
# a = BigDecimal((PI(49)/2).to_s)
|
29
|
+
# puts sin(a,100) # => 0.9999999999...9999999986e0
|
29
30
|
#
|
30
31
|
module BigMath
|
31
32
|
module_function
|
@@ -36,13 +37,42 @@ module BigMath
|
|
36
37
|
# Computes the square root of +decimal+ to the specified number of digits of
|
37
38
|
# precision, +numeric+.
|
38
39
|
#
|
39
|
-
# BigMath.sqrt(BigDecimal('2'),
|
40
|
-
# #=> "0.
|
40
|
+
# BigMath.sqrt(BigDecimal('2'), 32).to_s
|
41
|
+
# #=> "0.14142135623730950488016887242097e1"
|
41
42
|
#
|
42
43
|
def sqrt(x, prec)
|
44
|
+
BigDecimal::Internal.validate_prec(prec, :sqrt)
|
45
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sqrt)
|
43
46
|
x.sqrt(prec)
|
44
47
|
end
|
45
48
|
|
49
|
+
|
50
|
+
# Returns [sign, reduced_x] where reduced_x is in -pi/2..pi/2
|
51
|
+
# and satisfies sin(x) = sign * sin(reduced_x)
|
52
|
+
# If add_half_pi is true, adds pi/2 to x before reduction.
|
53
|
+
# Precision of pi is adjusted to ensure reduced_x has the required precision.
|
54
|
+
private_class_method def _sin_periodic_reduction(x, prec, add_half_pi: false) # :nodoc:
|
55
|
+
return [1, x] if -Math::PI/2 <= x && x <= Math::PI/2 && !add_half_pi
|
56
|
+
|
57
|
+
mod_prec = prec + BigDecimal.double_fig
|
58
|
+
pi_extra_prec = [x.exponent, 0].max + BigDecimal.double_fig
|
59
|
+
while true
|
60
|
+
pi = PI(mod_prec + pi_extra_prec)
|
61
|
+
half_pi = pi / 2
|
62
|
+
div, mod = (add_half_pi ? x + pi : x + half_pi).divmod(pi)
|
63
|
+
mod -= half_pi
|
64
|
+
if mod.zero? || mod_prec + mod.exponent <= 0
|
65
|
+
# mod is too small to estimate required pi precision
|
66
|
+
mod_prec = mod_prec * 3 / 2 + BigDecimal.double_fig
|
67
|
+
elsif mod_prec + mod.exponent < prec
|
68
|
+
# Estimate required precision of pi
|
69
|
+
mod_prec = prec - mod.exponent + BigDecimal.double_fig
|
70
|
+
else
|
71
|
+
return [div % 2 == 0 ? 1 : -1, mod.mult(1, prec)]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
46
76
|
# call-seq:
|
47
77
|
# sin(decimal, numeric) -> BigDecimal
|
48
78
|
#
|
@@ -51,42 +81,33 @@ module BigMath
|
|
51
81
|
#
|
52
82
|
# If +decimal+ is Infinity or NaN, returns NaN.
|
53
83
|
#
|
54
|
-
# BigMath.sin(BigMath.PI(5)/4,
|
55
|
-
# #=> "0.
|
84
|
+
# BigMath.sin(BigMath.PI(5)/4, 32).to_s
|
85
|
+
# #=> "0.70710807985947359435812921837984e0"
|
56
86
|
#
|
57
87
|
def sin(x, prec)
|
58
|
-
|
59
|
-
|
88
|
+
BigDecimal::Internal.validate_prec(prec, :sin)
|
89
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sin)
|
90
|
+
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
60
91
|
n = prec + BigDecimal.double_fig
|
61
92
|
one = BigDecimal("1")
|
62
93
|
two = BigDecimal("2")
|
63
|
-
|
64
|
-
if x > 6
|
65
|
-
twopi = two * BigMath.PI(prec + x.exponent)
|
66
|
-
if x > 30
|
67
|
-
x %= twopi
|
68
|
-
else
|
69
|
-
x -= twopi while x > twopi
|
70
|
-
end
|
71
|
-
end
|
94
|
+
sign, x = _sin_periodic_reduction(x, n)
|
72
95
|
x1 = x
|
73
96
|
x2 = x.mult(x,n)
|
74
|
-
sign = 1
|
75
97
|
y = x
|
76
98
|
d = y
|
77
99
|
i = one
|
78
100
|
z = one
|
79
101
|
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
80
102
|
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
81
|
-
|
82
|
-
x1 = x2.mult(x1,n)
|
103
|
+
x1 = -x2.mult(x1,n)
|
83
104
|
i += two
|
84
105
|
z *= (i-one) * i
|
85
|
-
d =
|
106
|
+
d = x1.div(z,m)
|
86
107
|
y += d
|
87
108
|
end
|
88
109
|
y = BigDecimal("1") if y > 1
|
89
|
-
|
110
|
+
y.mult(sign, prec)
|
90
111
|
end
|
91
112
|
|
92
113
|
# call-seq:
|
@@ -97,41 +118,34 @@ module BigMath
|
|
97
118
|
#
|
98
119
|
# If +decimal+ is Infinity or NaN, returns NaN.
|
99
120
|
#
|
100
|
-
# BigMath.cos(BigMath.PI(
|
101
|
-
# #=> "-0.
|
121
|
+
# BigMath.cos(BigMath.PI(16), 32).to_s
|
122
|
+
# #=> "-0.99999999999999999999999999999997e0"
|
102
123
|
#
|
103
124
|
def cos(x, prec)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
x1 = x2.mult(x1,n)
|
129
|
-
i += two
|
130
|
-
z *= (i-one) * i
|
131
|
-
d = sign * x1.div(z,m)
|
132
|
-
y += d
|
133
|
-
end
|
134
|
-
y < -1 ? BigDecimal("-1") : y > 1 ? BigDecimal("1") : y
|
125
|
+
BigDecimal::Internal.validate_prec(prec, :cos)
|
126
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cos)
|
127
|
+
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
128
|
+
sign, x = _sin_periodic_reduction(x, prec + BigDecimal.double_fig, add_half_pi: true)
|
129
|
+
sign * sin(x, prec)
|
130
|
+
end
|
131
|
+
|
132
|
+
# call-seq:
|
133
|
+
# tan(decimal, numeric) -> BigDecimal
|
134
|
+
#
|
135
|
+
# Computes the tangent of +decimal+ to the specified number of digits of
|
136
|
+
# precision, +numeric+.
|
137
|
+
#
|
138
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
139
|
+
#
|
140
|
+
# BigMath.tan(BigDecimal("0.0"), 4).to_s
|
141
|
+
# #=> "0.0"
|
142
|
+
#
|
143
|
+
# BigMath.tan(BigMath.PI(24) / 4, 32).to_s
|
144
|
+
# #=> "0.99999999999999999999999830836025e0"
|
145
|
+
#
|
146
|
+
def tan(x, prec)
|
147
|
+
BigDecimal::Internal.validate_prec(prec, :tan)
|
148
|
+
sin(x, prec + BigDecimal.double_fig).div(cos(x, prec + BigDecimal.double_fig), prec)
|
135
149
|
end
|
136
150
|
|
137
151
|
# call-seq:
|
@@ -142,17 +156,18 @@ module BigMath
|
|
142
156
|
#
|
143
157
|
# If +decimal+ is NaN, returns NaN.
|
144
158
|
#
|
145
|
-
# BigMath.atan(BigDecimal('-1'),
|
146
|
-
# #=> "-0.
|
159
|
+
# BigMath.atan(BigDecimal('-1'), 32).to_s
|
160
|
+
# #=> "-0.78539816339744830961566084581988e0"
|
147
161
|
#
|
148
162
|
def atan(x, prec)
|
149
|
-
|
150
|
-
|
151
|
-
|
163
|
+
BigDecimal::Internal.validate_prec(prec, :atan)
|
164
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan)
|
165
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
166
|
+
n = prec + BigDecimal.double_fig
|
167
|
+
pi = PI(n)
|
152
168
|
x = -x if neg = x < 0
|
153
169
|
return pi.div(neg ? -2 : 2, prec) if x.infinite?
|
154
|
-
return pi
|
155
|
-
n = prec + BigDecimal.double_fig
|
170
|
+
return pi.div(neg ? -4 : 4, prec) if x.round(prec) == 1
|
156
171
|
x = BigDecimal("1").div(x, n) if inv = x > 1
|
157
172
|
x = (-1 + sqrt(1 + x.mult(x, n), n)).div(x, n) if dbl = x > 0.5
|
158
173
|
y = x
|
@@ -170,7 +185,7 @@ module BigMath
|
|
170
185
|
y *= 2 if dbl
|
171
186
|
y = pi / 2 - y if inv
|
172
187
|
y = -y if neg
|
173
|
-
y
|
188
|
+
y.mult(1, prec)
|
174
189
|
end
|
175
190
|
|
176
191
|
# call-seq:
|
@@ -179,11 +194,11 @@ module BigMath
|
|
179
194
|
# Computes the value of pi to the specified number of digits of precision,
|
180
195
|
# +numeric+.
|
181
196
|
#
|
182
|
-
# BigMath.PI(
|
183
|
-
# #=> "0.
|
197
|
+
# BigMath.PI(32).to_s
|
198
|
+
# #=> "0.31415926535897932384626433832795e1"
|
184
199
|
#
|
185
200
|
def PI(prec)
|
186
|
-
|
201
|
+
BigDecimal::Internal.validate_prec(prec, :PI)
|
187
202
|
n = prec + BigDecimal.double_fig
|
188
203
|
zero = BigDecimal("0")
|
189
204
|
one = BigDecimal("1")
|
@@ -215,7 +230,7 @@ module BigMath
|
|
215
230
|
pi = pi + d
|
216
231
|
k = k+two
|
217
232
|
end
|
218
|
-
pi
|
233
|
+
pi.mult(1, prec)
|
219
234
|
end
|
220
235
|
|
221
236
|
# call-seq:
|
@@ -224,11 +239,11 @@ module BigMath
|
|
224
239
|
# Computes e (the base of natural logarithms) to the specified number of
|
225
240
|
# digits of precision, +numeric+.
|
226
241
|
#
|
227
|
-
# BigMath.E(
|
228
|
-
# #=> "0.
|
242
|
+
# BigMath.E(32).to_s
|
243
|
+
# #=> "0.27182818284590452353602874713527e1"
|
229
244
|
#
|
230
245
|
def E(prec)
|
231
|
-
|
246
|
+
BigDecimal::Internal.validate_prec(prec, :E)
|
232
247
|
BigMath.exp(1, prec)
|
233
248
|
end
|
234
249
|
end
|
data/lib/bigdecimal/util.rb
CHANGED
@@ -119,8 +119,11 @@ class Rational < Numeric
|
|
119
119
|
#
|
120
120
|
# Returns the value as a BigDecimal.
|
121
121
|
#
|
122
|
-
# The
|
123
|
-
# significant digits for the result.
|
122
|
+
# The +precision+ parameter is used to determine the number of
|
123
|
+
# significant digits for the result. When +precision+ is set to +0+,
|
124
|
+
# the number of digits to represent the float being converted is determined
|
125
|
+
# automatically.
|
126
|
+
# The default +precision+ is +0+.
|
124
127
|
#
|
125
128
|
# require 'bigdecimal'
|
126
129
|
# require 'bigdecimal/util'
|
@@ -129,7 +132,7 @@ class Rational < Numeric
|
|
129
132
|
#
|
130
133
|
# See also Kernel.BigDecimal.
|
131
134
|
#
|
132
|
-
def to_d(precision)
|
135
|
+
def to_d(precision=0)
|
133
136
|
BigDecimal(self, precision)
|
134
137
|
end
|
135
138
|
end
|
@@ -141,29 +144,27 @@ class Complex < Numeric
|
|
141
144
|
# cmp.to_d(precision) -> bigdecimal
|
142
145
|
#
|
143
146
|
# Returns the value as a BigDecimal.
|
147
|
+
# If the imaginary part is not +0+, an error is raised
|
144
148
|
#
|
145
|
-
# The +precision+ parameter is
|
146
|
-
#
|
147
|
-
#
|
149
|
+
# The +precision+ parameter is used to determine the number of
|
150
|
+
# significant digits for the result. When +precision+ is set to +0+,
|
151
|
+
# the number of digits to represent the float being converted is determined
|
152
|
+
# automatically.
|
153
|
+
# The default +precision+ is +0+.
|
148
154
|
#
|
149
155
|
# require 'bigdecimal'
|
150
156
|
# require 'bigdecimal/util'
|
151
157
|
#
|
152
158
|
# Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
153
159
|
# Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
|
160
|
+
# Complex(1, 1).to_d # raises ArgumentError
|
154
161
|
#
|
155
162
|
# See also Kernel.BigDecimal.
|
156
163
|
#
|
157
|
-
def to_d(
|
164
|
+
def to_d(precision=0)
|
158
165
|
BigDecimal(self) unless self.imag.zero? # to raise error
|
159
166
|
|
160
|
-
|
161
|
-
case self.real
|
162
|
-
when Rational
|
163
|
-
BigDecimal(self.real) # to raise error
|
164
|
-
end
|
165
|
-
end
|
166
|
-
self.real.to_d(*args)
|
167
|
+
BigDecimal(self.real, precision)
|
167
168
|
end
|
168
169
|
end
|
169
170
|
|
data/lib/bigdecimal.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
if RUBY_ENGINE == 'jruby'
|
2
2
|
JRuby::Util.load_ext("org.jruby.ext.bigdecimal.BigDecimalLibrary")
|
3
|
-
|
3
|
+
|
4
|
+
class BigDecimal
|
5
|
+
def _decimal_shift(i) # :nodoc:
|
6
|
+
to_java.move_point_right(i).to_d
|
7
|
+
end
|
8
|
+
end
|
4
9
|
else
|
5
10
|
require 'bigdecimal.so'
|
6
11
|
end
|
@@ -15,7 +20,7 @@ class BigDecimal
|
|
15
20
|
when BigDecimal
|
16
21
|
return x
|
17
22
|
when Integer, Float
|
18
|
-
return BigDecimal(x)
|
23
|
+
return BigDecimal(x, 0)
|
19
24
|
when Rational
|
20
25
|
return BigDecimal(x, [prec, 2 * BigDecimal.double_fig].max)
|
21
26
|
end
|
@@ -160,22 +165,32 @@ class BigDecimal
|
|
160
165
|
return BigDecimal(1).div(inv, prec)
|
161
166
|
end
|
162
167
|
|
163
|
-
int_part = y.fix.to_i
|
164
168
|
prec2 = prec + BigDecimal.double_fig
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
169
|
+
|
170
|
+
if frac_part.zero? && y.exponent < Math.log(prec) * 5 + 20
|
171
|
+
# Use exponentiation by squaring if y is an integer and not too large
|
172
|
+
pow_prec = prec2 + y.exponent
|
173
|
+
n = 1
|
174
|
+
xn = x
|
175
|
+
ans = BigDecimal(1)
|
176
|
+
int_part = y.fix.to_i
|
177
|
+
while true
|
178
|
+
ans = ans.mult(xn, pow_prec) if int_part.allbits?(n)
|
179
|
+
n <<= 1
|
180
|
+
break if n > int_part
|
181
|
+
xn = xn.mult(xn, pow_prec)
|
182
|
+
end
|
183
|
+
ans.mult(1, prec)
|
184
|
+
else
|
185
|
+
if x > 1
|
186
|
+
# To calculate exp(z, prec), z needs prec+max(z.exponent, 0) precision if z > 0.
|
187
|
+
# Estimate (y*log(x)).exponent
|
188
|
+
logx_exponent = x < 2 ? (x - 1).exponent : Math.log10(x.exponent).round
|
189
|
+
ylogx_exponent = y.exponent + logx_exponent
|
190
|
+
prec2 += [ylogx_exponent, 0].max
|
191
|
+
end
|
192
|
+
BigMath.exp(BigMath.log(x, prec2).mult(y, prec2), prec)
|
177
193
|
end
|
178
|
-
ans.mult(1, prec)
|
179
194
|
end
|
180
195
|
|
181
196
|
# Returns the square root of the value.
|
@@ -190,23 +205,19 @@ class BigDecimal
|
|
190
205
|
raise FloatDomainError, "sqrt of 'NaN'(Not a Number)" if nan?
|
191
206
|
return self if zero?
|
192
207
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
# This feature maybe problematic for some cases.
|
197
|
-
n_digits = n_significant_digits
|
198
|
-
prec = [prec, n_digits].max
|
208
|
+
if prec == 0
|
209
|
+
prec = BigDecimal.limit.nonzero? || n_significant_digits + BigDecimal.double_fig
|
210
|
+
end
|
199
211
|
|
200
212
|
ex = exponent / 2
|
201
213
|
x = _decimal_shift(-2 * ex)
|
202
|
-
y = BigDecimal(Math.sqrt(x.to_f))
|
214
|
+
y = BigDecimal(Math.sqrt(x.to_f), 0)
|
203
215
|
precs = [prec + BigDecimal.double_fig]
|
204
216
|
precs << 2 + precs.last / 2 while precs.last > BigDecimal.double_fig
|
205
217
|
precs.reverse_each do |p|
|
206
218
|
y = y.add(x.div(y, p), p).div(2, p)
|
207
219
|
end
|
208
|
-
y
|
209
|
-
y._decimal_shift(ex)
|
220
|
+
y._decimal_shift(ex).mult(1, prec)
|
210
221
|
end
|
211
222
|
end
|
212
223
|
|
@@ -232,56 +243,67 @@ module BigMath
|
|
232
243
|
|
233
244
|
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log)
|
234
245
|
return BigDecimal::Internal.nan_computation_result if x.nan?
|
235
|
-
raise Math::DomainError, '
|
246
|
+
raise Math::DomainError, 'Negative argument for log' if x < 0
|
247
|
+
return -BigDecimal::Internal.infinity_computation_result if x.zero?
|
236
248
|
return BigDecimal::Internal.infinity_computation_result if x.infinite?
|
237
249
|
return BigDecimal(0) if x == 1
|
238
250
|
|
251
|
+
prec2 = prec + BigDecimal.double_fig
|
239
252
|
BigDecimal.save_limit do
|
240
253
|
BigDecimal.limit(0)
|
241
254
|
if x > 10 || x < 0.1
|
242
|
-
log10 = log(BigDecimal(10),
|
255
|
+
log10 = log(BigDecimal(10), prec2)
|
243
256
|
exponent = x.exponent
|
244
257
|
x = x._decimal_shift(-exponent)
|
245
258
|
if x < 0.3
|
246
259
|
x *= 10
|
247
260
|
exponent -= 1
|
248
261
|
end
|
249
|
-
return log10 * exponent
|
262
|
+
return (log10 * exponent).add(log(x, prec2), prec)
|
250
263
|
end
|
251
264
|
|
252
265
|
x_minus_one_exponent = (x - 1).exponent
|
253
|
-
prec += BigDecimal.double_fig
|
254
266
|
|
255
267
|
# log(x) = log(sqrt(sqrt(sqrt(sqrt(x))))) * 2**sqrt_steps
|
256
|
-
sqrt_steps = [Integer.sqrt(
|
268
|
+
sqrt_steps = [Integer.sqrt(prec2) + 3 * x_minus_one_exponent, 0].max
|
257
269
|
|
258
270
|
lg2 = 0.3010299956639812
|
259
|
-
|
271
|
+
sqrt_prec = prec2 + [-x_minus_one_exponent, 0].max + (sqrt_steps * lg2).ceil
|
260
272
|
|
261
273
|
sqrt_steps.times do
|
262
|
-
x = x.sqrt(
|
263
|
-
|
264
|
-
# Workaround for https://github.com/ruby/bigdecimal/issues/354
|
265
|
-
x = x.mult(1, prec2 + BigDecimal.double_fig)
|
274
|
+
x = x.sqrt(sqrt_prec)
|
266
275
|
end
|
267
276
|
|
268
277
|
# Taylor series for log(x) around 1
|
269
278
|
# log(x) = -log((1 + X) / (1 - X)) where X = (x - 1) / (x + 1)
|
270
279
|
# log(x) = 2 * (X + X**3 / 3 + X**5 / 5 + X**7 / 7 + ...)
|
271
|
-
x = (x - 1).div(x + 1,
|
280
|
+
x = (x - 1).div(x + 1, sqrt_prec)
|
272
281
|
y = x
|
273
|
-
x2 = x.mult(x,
|
282
|
+
x2 = x.mult(x, prec2)
|
274
283
|
1.step do |i|
|
275
|
-
n =
|
284
|
+
n = prec2 + x.exponent - y.exponent + x2.exponent
|
276
285
|
break if n <= 0 || x.zero?
|
277
286
|
x = x.mult(x2.round(n - x2.exponent), n)
|
278
|
-
y = y.add(x.div(2 * i + 1, n),
|
287
|
+
y = y.add(x.div(2 * i + 1, n), prec2)
|
279
288
|
end
|
280
289
|
|
281
290
|
y.mult(2 ** (sqrt_steps + 1), prec)
|
282
291
|
end
|
283
292
|
end
|
284
293
|
|
294
|
+
# Taylor series for exp(x) around 0
|
295
|
+
private_class_method def self._exp_taylor(x, prec) # :nodoc:
|
296
|
+
xn = BigDecimal(1)
|
297
|
+
y = BigDecimal(1)
|
298
|
+
1.step do |i|
|
299
|
+
n = prec + xn.exponent
|
300
|
+
break if n <= 0 || xn.zero?
|
301
|
+
xn = xn.mult(x, n).div(i, n)
|
302
|
+
y = y.add(xn, prec)
|
303
|
+
end
|
304
|
+
y
|
305
|
+
end
|
306
|
+
|
285
307
|
# call-seq:
|
286
308
|
# BigMath.exp(decimal, numeric) -> BigDecimal
|
287
309
|
#
|
@@ -298,23 +320,17 @@ module BigMath
|
|
298
320
|
return BigDecimal::Internal.nan_computation_result if x.nan?
|
299
321
|
return x.positive? ? BigDecimal::Internal.infinity_computation_result : BigDecimal(0) if x.infinite?
|
300
322
|
return BigDecimal(1) if x.zero?
|
301
|
-
return BigDecimal(1).div(exp(-x, prec), prec) if x < 0
|
302
323
|
|
303
324
|
# exp(x * 10**cnt) = exp(x)**(10**cnt)
|
304
|
-
cnt = x > 1 ? x.exponent : 0
|
325
|
+
cnt = x < -1 || x > 1 ? x.exponent : 0
|
305
326
|
prec2 = prec + BigDecimal.double_fig + cnt
|
306
327
|
x = x._decimal_shift(-cnt)
|
307
|
-
xn = BigDecimal(1)
|
308
|
-
y = BigDecimal(1)
|
309
328
|
|
310
|
-
#
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
xn = xn.mult(x, n).div(i, n)
|
316
|
-
y = y.add(xn, prec2)
|
317
|
-
end
|
329
|
+
# Calculation of exp(small_prec) is fast because calculation of x**n is fast
|
330
|
+
# Calculation of exp(small_abs) converges fast.
|
331
|
+
# exp(x) = exp(small_prec_part + small_abs_part) = exp(small_prec_part) * exp(small_abs_part)
|
332
|
+
x_small_prec = x.round(Integer.sqrt(prec2))
|
333
|
+
y = _exp_taylor(x_small_prec, prec2).mult(_exp_taylor(x.sub(x_small_prec, prec2), prec2), prec2)
|
318
334
|
|
319
335
|
# calculate exp(x * 10**cnt) from exp(x)
|
320
336
|
# exp(x * 10**k) = exp(x * 10**(k - 1)) ** 10
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bigdecimal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Kenta Murata
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
- Shigeo Kobayashi
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-
|
12
|
+
date: 2025-10-07 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: This library provides arbitrary-precision decimal floating-point number
|
15
15
|
class.
|