bigdecimal 3.1.4-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 +7 -0
- data/bigdecimal.gemspec +54 -0
- data/lib/bigdecimal/jacobian.rb +90 -0
- data/lib/bigdecimal/ludcmp.rb +89 -0
- data/lib/bigdecimal/math.rb +232 -0
- data/lib/bigdecimal/newton.rb +80 -0
- data/lib/bigdecimal/util.rb +185 -0
- data/lib/bigdecimal.rb +5 -0
- data/sample/linear.rb +74 -0
- data/sample/nlsolve.rb +40 -0
- data/sample/pi.rb +21 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e9fced8ced07121aeb95b8d3d0dfe0a341025ffda5382115e50b2f2e247b4cc5
|
4
|
+
data.tar.gz: eb74b46e55565a8d7d0669bf7bf42824498be32d3e0c514378b65d399b84cff3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e343e759448c7e3d25fa27557f7ee791e2269e8146813ece216da77923474be65407381aca04ba42f59795001058e38ff3efd7ed01c93e04f44824d6781ddc54
|
7
|
+
data.tar.gz: 211ca130d2b9cf5677eee155d4ef56d8483f60eb15855dfdbc65a0cdf343238efdcb8d66ef2d1e6d82111434e00c7283380dd2c5e29c27c0fcad0706396eb817
|
data/bigdecimal.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
name = File.basename(__FILE__, '.*')
|
4
|
+
source_version = ["", "ext/#{name}/"].find do |dir|
|
5
|
+
begin
|
6
|
+
break File.foreach(File.join(__dir__, "#{dir}#{name}.c")) {|line|
|
7
|
+
break $1.sub("-", ".") if /^#define\s+#{name.upcase}_VERSION\s+"(.+)"/o =~ line
|
8
|
+
}
|
9
|
+
rescue Errno::ENOENT
|
10
|
+
end
|
11
|
+
end or raise "can't find #{name.upcase}_VERSION"
|
12
|
+
|
13
|
+
Gem::Specification.new do |s|
|
14
|
+
s.name = name
|
15
|
+
s.version = source_version
|
16
|
+
s.authors = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"]
|
17
|
+
s.email = ["mrkn@mrkn.jp"]
|
18
|
+
|
19
|
+
s.summary = "Arbitrary-precision decimal floating-point number library."
|
20
|
+
s.description = "This library provides arbitrary-precision decimal floating-point number class."
|
21
|
+
s.homepage = "https://github.com/ruby/bigdecimal"
|
22
|
+
s.licenses = ["Ruby", "BSD-2-Clause"]
|
23
|
+
|
24
|
+
s.require_paths = %w[lib]
|
25
|
+
s.files = %w[
|
26
|
+
bigdecimal.gemspec
|
27
|
+
lib/bigdecimal.rb
|
28
|
+
lib/bigdecimal/jacobian.rb
|
29
|
+
lib/bigdecimal/ludcmp.rb
|
30
|
+
lib/bigdecimal/math.rb
|
31
|
+
lib/bigdecimal/newton.rb
|
32
|
+
lib/bigdecimal/util.rb
|
33
|
+
sample/linear.rb
|
34
|
+
sample/nlsolve.rb
|
35
|
+
sample/pi.rb
|
36
|
+
]
|
37
|
+
if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby'
|
38
|
+
s.platform = 'java'
|
39
|
+
else
|
40
|
+
s.extensions = %w[ext/bigdecimal/extconf.rb]
|
41
|
+
s.files += %w[
|
42
|
+
ext/bigdecimal/bigdecimal.c
|
43
|
+
ext/bigdecimal/bigdecimal.h
|
44
|
+
ext/bigdecimal/bits.h
|
45
|
+
ext/bigdecimal/feature.h
|
46
|
+
ext/bigdecimal/missing.c
|
47
|
+
ext/bigdecimal/missing.h
|
48
|
+
ext/bigdecimal/missing/dtoa.c
|
49
|
+
ext/bigdecimal/static_assert.h
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
54
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
|
5
|
+
# require 'bigdecimal/jacobian'
|
6
|
+
#
|
7
|
+
# Provides methods to compute the Jacobian matrix of a set of equations at a
|
8
|
+
# point x. In the methods below:
|
9
|
+
#
|
10
|
+
# f is an Object which is used to compute the Jacobian matrix of the equations.
|
11
|
+
# It must provide the following methods:
|
12
|
+
#
|
13
|
+
# f.values(x):: returns the values of all functions at x
|
14
|
+
#
|
15
|
+
# f.zero:: returns 0.0
|
16
|
+
# f.one:: returns 1.0
|
17
|
+
# f.two:: returns 2.0
|
18
|
+
# f.ten:: returns 10.0
|
19
|
+
#
|
20
|
+
# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal.
|
21
|
+
#
|
22
|
+
# x is the point at which to compute the Jacobian.
|
23
|
+
#
|
24
|
+
# fx is f.values(x).
|
25
|
+
#
|
26
|
+
module Jacobian
|
27
|
+
module_function
|
28
|
+
|
29
|
+
# Determines the equality of two numbers by comparing to zero, or using the epsilon value
|
30
|
+
def isEqual(a,b,zero=0.0,e=1.0e-8)
|
31
|
+
aa = a.abs
|
32
|
+
bb = b.abs
|
33
|
+
if aa == zero && bb == zero then
|
34
|
+
true
|
35
|
+
else
|
36
|
+
if ((a-b)/(aa+bb)).abs < e then
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Computes the derivative of +f[i]+ at +x[i]+.
|
46
|
+
# +fx+ is the value of +f+ at +x+.
|
47
|
+
def dfdxi(f,fx,x,i)
|
48
|
+
nRetry = 0
|
49
|
+
n = x.size
|
50
|
+
xSave = x[i]
|
51
|
+
ok = 0
|
52
|
+
ratio = f.ten*f.ten*f.ten
|
53
|
+
dx = x[i].abs/ratio
|
54
|
+
dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps)
|
55
|
+
dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps)
|
56
|
+
until ok>0 do
|
57
|
+
deriv = []
|
58
|
+
nRetry += 1
|
59
|
+
if nRetry > 100
|
60
|
+
raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]"
|
61
|
+
end
|
62
|
+
dx = dx*f.two
|
63
|
+
x[i] += dx
|
64
|
+
fxNew = f.values(x)
|
65
|
+
for j in 0...n do
|
66
|
+
if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then
|
67
|
+
ok += 1
|
68
|
+
deriv <<= (fxNew[j]-fx[j])/dx
|
69
|
+
else
|
70
|
+
deriv <<= f.zero
|
71
|
+
end
|
72
|
+
end
|
73
|
+
x[i] = xSave
|
74
|
+
end
|
75
|
+
deriv
|
76
|
+
end
|
77
|
+
|
78
|
+
# Computes the Jacobian of +f+ at +x+. +fx+ is the value of +f+ at +x+.
|
79
|
+
def jacobian(f,fx,x)
|
80
|
+
n = x.size
|
81
|
+
dfdx = Array.new(n*n)
|
82
|
+
for i in 0...n do
|
83
|
+
df = dfdxi(f,fx,x,i)
|
84
|
+
for j in 0...n do
|
85
|
+
dfdx[j*n+i] = df[j]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
dfdx
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Solves a*x = b for x, using LU decomposition.
|
6
|
+
#
|
7
|
+
module LUSolve
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Performs LU decomposition of the n by n matrix a.
|
11
|
+
def ludecomp(a,n,zero=0,one=1)
|
12
|
+
prec = BigDecimal.limit(nil)
|
13
|
+
ps = []
|
14
|
+
scales = []
|
15
|
+
for i in 0...n do # pick up largest(abs. val.) element in each row.
|
16
|
+
ps <<= i
|
17
|
+
nrmrow = zero
|
18
|
+
ixn = i*n
|
19
|
+
for j in 0...n do
|
20
|
+
biggst = a[ixn+j].abs
|
21
|
+
nrmrow = biggst if biggst>nrmrow
|
22
|
+
end
|
23
|
+
if nrmrow>zero then
|
24
|
+
scales <<= one.div(nrmrow,prec)
|
25
|
+
else
|
26
|
+
raise "Singular matrix"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
n1 = n - 1
|
30
|
+
for k in 0...n1 do # Gaussian elimination with partial pivoting.
|
31
|
+
biggst = zero;
|
32
|
+
for i in k...n do
|
33
|
+
size = a[ps[i]*n+k].abs*scales[ps[i]]
|
34
|
+
if size>biggst then
|
35
|
+
biggst = size
|
36
|
+
pividx = i
|
37
|
+
end
|
38
|
+
end
|
39
|
+
raise "Singular matrix" if biggst<=zero
|
40
|
+
if pividx!=k then
|
41
|
+
j = ps[k]
|
42
|
+
ps[k] = ps[pividx]
|
43
|
+
ps[pividx] = j
|
44
|
+
end
|
45
|
+
pivot = a[ps[k]*n+k]
|
46
|
+
for i in (k+1)...n do
|
47
|
+
psin = ps[i]*n
|
48
|
+
a[psin+k] = mult = a[psin+k].div(pivot,prec)
|
49
|
+
if mult!=zero then
|
50
|
+
pskn = ps[k]*n
|
51
|
+
for j in (k+1)...n do
|
52
|
+
a[psin+j] -= mult.mult(a[pskn+j],prec)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
raise "Singular matrix" if a[ps[n1]*n+n1] == zero
|
58
|
+
ps
|
59
|
+
end
|
60
|
+
|
61
|
+
# Solves a*x = b for x, using LU decomposition.
|
62
|
+
#
|
63
|
+
# a is a matrix, b is a constant vector, x is the solution vector.
|
64
|
+
#
|
65
|
+
# ps is the pivot, a vector which indicates the permutation of rows performed
|
66
|
+
# during LU decomposition.
|
67
|
+
def lusolve(a,b,ps,zero=0.0)
|
68
|
+
prec = BigDecimal.limit(nil)
|
69
|
+
n = ps.size
|
70
|
+
x = []
|
71
|
+
for i in 0...n do
|
72
|
+
dot = zero
|
73
|
+
psin = ps[i]*n
|
74
|
+
for j in 0...i do
|
75
|
+
dot = a[psin+j].mult(x[j],prec) + dot
|
76
|
+
end
|
77
|
+
x <<= b[ps[i]] - dot
|
78
|
+
end
|
79
|
+
(n-1).downto(0) do |i|
|
80
|
+
dot = zero
|
81
|
+
psin = ps[i]*n
|
82
|
+
for j in (i+1)...n do
|
83
|
+
dot = a[psin+j].mult(x[j],prec) + dot
|
84
|
+
end
|
85
|
+
x[i] = (x[i]-dot).div(a[psin+i],prec)
|
86
|
+
end
|
87
|
+
x
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
#
|
5
|
+
#--
|
6
|
+
# Contents:
|
7
|
+
# sqrt(x, prec)
|
8
|
+
# sin (x, prec)
|
9
|
+
# cos (x, prec)
|
10
|
+
# atan(x, prec) Note: |x|<1, x=0.9999 may not converge.
|
11
|
+
# PI (prec)
|
12
|
+
# E (prec) == exp(1.0,prec)
|
13
|
+
#
|
14
|
+
# where:
|
15
|
+
# x ... BigDecimal number to be computed.
|
16
|
+
# |x| must be small enough to get convergence.
|
17
|
+
# prec ... Number of digits to be obtained.
|
18
|
+
#++
|
19
|
+
#
|
20
|
+
# Provides mathematical functions.
|
21
|
+
#
|
22
|
+
# Example:
|
23
|
+
#
|
24
|
+
# require "bigdecimal/math"
|
25
|
+
#
|
26
|
+
# include BigMath
|
27
|
+
#
|
28
|
+
# a = BigDecimal((PI(100)/2).to_s)
|
29
|
+
# puts sin(a,100) # => 0.99999999999999999999......e0
|
30
|
+
#
|
31
|
+
module BigMath
|
32
|
+
module_function
|
33
|
+
|
34
|
+
# call-seq:
|
35
|
+
# sqrt(decimal, numeric) -> BigDecimal
|
36
|
+
#
|
37
|
+
# Computes the square root of +decimal+ to the specified number of digits of
|
38
|
+
# precision, +numeric+.
|
39
|
+
#
|
40
|
+
# BigMath.sqrt(BigDecimal('2'), 16).to_s
|
41
|
+
# #=> "0.1414213562373095048801688724e1"
|
42
|
+
#
|
43
|
+
def sqrt(x, prec)
|
44
|
+
x.sqrt(prec)
|
45
|
+
end
|
46
|
+
|
47
|
+
# call-seq:
|
48
|
+
# sin(decimal, numeric) -> BigDecimal
|
49
|
+
#
|
50
|
+
# Computes the sine of +decimal+ to the specified number of digits of
|
51
|
+
# precision, +numeric+.
|
52
|
+
#
|
53
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
54
|
+
#
|
55
|
+
# BigMath.sin(BigMath.PI(5)/4, 5).to_s
|
56
|
+
# #=> "0.70710678118654752440082036563292800375e0"
|
57
|
+
#
|
58
|
+
def sin(x, prec)
|
59
|
+
raise ArgumentError, "Zero or negative precision for sin" if prec <= 0
|
60
|
+
return BigDecimal("NaN") if x.infinite? || x.nan?
|
61
|
+
n = prec + BigDecimal.double_fig
|
62
|
+
one = BigDecimal("1")
|
63
|
+
two = BigDecimal("2")
|
64
|
+
x = -x if neg = x < 0
|
65
|
+
if x > (twopi = two * BigMath.PI(prec))
|
66
|
+
if x > 30
|
67
|
+
x %= twopi
|
68
|
+
else
|
69
|
+
x -= twopi while x > twopi
|
70
|
+
end
|
71
|
+
end
|
72
|
+
x1 = x
|
73
|
+
x2 = x.mult(x,n)
|
74
|
+
sign = 1
|
75
|
+
y = x
|
76
|
+
d = y
|
77
|
+
i = one
|
78
|
+
z = one
|
79
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
80
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
81
|
+
sign = -sign
|
82
|
+
x1 = x2.mult(x1,n)
|
83
|
+
i += two
|
84
|
+
z *= (i-one) * i
|
85
|
+
d = sign * x1.div(z,m)
|
86
|
+
y += d
|
87
|
+
end
|
88
|
+
neg ? -y : y
|
89
|
+
end
|
90
|
+
|
91
|
+
# call-seq:
|
92
|
+
# cos(decimal, numeric) -> BigDecimal
|
93
|
+
#
|
94
|
+
# Computes the cosine of +decimal+ to the specified number of digits of
|
95
|
+
# precision, +numeric+.
|
96
|
+
#
|
97
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
98
|
+
#
|
99
|
+
# BigMath.cos(BigMath.PI(4), 16).to_s
|
100
|
+
# #=> "-0.999999999999999999999999999999856613163740061349e0"
|
101
|
+
#
|
102
|
+
def cos(x, prec)
|
103
|
+
raise ArgumentError, "Zero or negative precision for cos" if prec <= 0
|
104
|
+
return BigDecimal("NaN") if x.infinite? || x.nan?
|
105
|
+
n = prec + BigDecimal.double_fig
|
106
|
+
one = BigDecimal("1")
|
107
|
+
two = BigDecimal("2")
|
108
|
+
x = -x if x < 0
|
109
|
+
if x > (twopi = two * BigMath.PI(prec))
|
110
|
+
if x > 30
|
111
|
+
x %= twopi
|
112
|
+
else
|
113
|
+
x -= twopi while x > twopi
|
114
|
+
end
|
115
|
+
end
|
116
|
+
x1 = one
|
117
|
+
x2 = x.mult(x,n)
|
118
|
+
sign = 1
|
119
|
+
y = one
|
120
|
+
d = y
|
121
|
+
i = BigDecimal("0")
|
122
|
+
z = one
|
123
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
124
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
125
|
+
sign = -sign
|
126
|
+
x1 = x2.mult(x1,n)
|
127
|
+
i += two
|
128
|
+
z *= (i-one) * i
|
129
|
+
d = sign * x1.div(z,m)
|
130
|
+
y += d
|
131
|
+
end
|
132
|
+
y
|
133
|
+
end
|
134
|
+
|
135
|
+
# call-seq:
|
136
|
+
# atan(decimal, numeric) -> BigDecimal
|
137
|
+
#
|
138
|
+
# Computes the arctangent of +decimal+ to the specified number of digits of
|
139
|
+
# precision, +numeric+.
|
140
|
+
#
|
141
|
+
# If +decimal+ is NaN, returns NaN.
|
142
|
+
#
|
143
|
+
# BigMath.atan(BigDecimal('-1'), 16).to_s
|
144
|
+
# #=> "-0.785398163397448309615660845819878471907514682065e0"
|
145
|
+
#
|
146
|
+
def atan(x, prec)
|
147
|
+
raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
|
148
|
+
return BigDecimal("NaN") if x.nan?
|
149
|
+
pi = PI(prec)
|
150
|
+
x = -x if neg = x < 0
|
151
|
+
return pi.div(neg ? -2 : 2, prec) if x.infinite?
|
152
|
+
return pi / (neg ? -4 : 4) if x.round(prec) == 1
|
153
|
+
x = BigDecimal("1").div(x, prec) if inv = x > 1
|
154
|
+
x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5
|
155
|
+
n = prec + BigDecimal.double_fig
|
156
|
+
y = x
|
157
|
+
d = y
|
158
|
+
t = x
|
159
|
+
r = BigDecimal("3")
|
160
|
+
x2 = x.mult(x,n)
|
161
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
162
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
163
|
+
t = -t.mult(x2,n)
|
164
|
+
d = t.div(r,m)
|
165
|
+
y += d
|
166
|
+
r += 2
|
167
|
+
end
|
168
|
+
y *= 2 if dbl
|
169
|
+
y = pi / 2 - y if inv
|
170
|
+
y = -y if neg
|
171
|
+
y
|
172
|
+
end
|
173
|
+
|
174
|
+
# call-seq:
|
175
|
+
# PI(numeric) -> BigDecimal
|
176
|
+
#
|
177
|
+
# Computes the value of pi to the specified number of digits of precision,
|
178
|
+
# +numeric+.
|
179
|
+
#
|
180
|
+
# BigMath.PI(10).to_s
|
181
|
+
# #=> "0.3141592653589793238462643388813853786957412e1"
|
182
|
+
#
|
183
|
+
def PI(prec)
|
184
|
+
raise ArgumentError, "Zero or negative precision for PI" if prec <= 0
|
185
|
+
n = prec + BigDecimal.double_fig
|
186
|
+
zero = BigDecimal("0")
|
187
|
+
one = BigDecimal("1")
|
188
|
+
two = BigDecimal("2")
|
189
|
+
|
190
|
+
m25 = BigDecimal("-0.04")
|
191
|
+
m57121 = BigDecimal("-57121")
|
192
|
+
|
193
|
+
pi = zero
|
194
|
+
|
195
|
+
d = one
|
196
|
+
k = one
|
197
|
+
t = BigDecimal("-80")
|
198
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
199
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
200
|
+
t = t*m25
|
201
|
+
d = t.div(k,m)
|
202
|
+
k = k+two
|
203
|
+
pi = pi + d
|
204
|
+
end
|
205
|
+
|
206
|
+
d = one
|
207
|
+
k = one
|
208
|
+
t = BigDecimal("956")
|
209
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
210
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
211
|
+
t = t.div(m57121,n)
|
212
|
+
d = t.div(k,m)
|
213
|
+
pi = pi + d
|
214
|
+
k = k+two
|
215
|
+
end
|
216
|
+
pi
|
217
|
+
end
|
218
|
+
|
219
|
+
# call-seq:
|
220
|
+
# E(numeric) -> BigDecimal
|
221
|
+
#
|
222
|
+
# Computes e (the base of natural logarithms) to the specified number of
|
223
|
+
# digits of precision, +numeric+.
|
224
|
+
#
|
225
|
+
# BigMath.E(10).to_s
|
226
|
+
# #=> "0.271828182845904523536028752390026306410273e1"
|
227
|
+
#
|
228
|
+
def E(prec)
|
229
|
+
raise ArgumentError, "Zero or negative precision for E" if prec <= 0
|
230
|
+
BigMath.exp(1, prec)
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require "bigdecimal/ludcmp"
|
3
|
+
require "bigdecimal/jacobian"
|
4
|
+
|
5
|
+
#
|
6
|
+
# newton.rb
|
7
|
+
#
|
8
|
+
# Solves the nonlinear algebraic equation system f = 0 by Newton's method.
|
9
|
+
# This program is not dependent on BigDecimal.
|
10
|
+
#
|
11
|
+
# To call:
|
12
|
+
# n = nlsolve(f,x)
|
13
|
+
# where n is the number of iterations required,
|
14
|
+
# x is the initial value vector
|
15
|
+
# f is an Object which is used to compute the values of the equations to be solved.
|
16
|
+
# It must provide the following methods:
|
17
|
+
#
|
18
|
+
# f.values(x):: returns the values of all functions at x
|
19
|
+
#
|
20
|
+
# f.zero:: returns 0.0
|
21
|
+
# f.one:: returns 1.0
|
22
|
+
# f.two:: returns 2.0
|
23
|
+
# f.ten:: returns 10.0
|
24
|
+
#
|
25
|
+
# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal.
|
26
|
+
#
|
27
|
+
# On exit, x is the solution vector.
|
28
|
+
#
|
29
|
+
module Newton
|
30
|
+
include LUSolve
|
31
|
+
include Jacobian
|
32
|
+
module_function
|
33
|
+
|
34
|
+
def norm(fv,zero=0.0) # :nodoc:
|
35
|
+
s = zero
|
36
|
+
n = fv.size
|
37
|
+
for i in 0...n do
|
38
|
+
s += fv[i]*fv[i]
|
39
|
+
end
|
40
|
+
s
|
41
|
+
end
|
42
|
+
|
43
|
+
# See also Newton
|
44
|
+
def nlsolve(f,x)
|
45
|
+
nRetry = 0
|
46
|
+
n = x.size
|
47
|
+
|
48
|
+
f0 = f.values(x)
|
49
|
+
zero = f.zero
|
50
|
+
one = f.one
|
51
|
+
two = f.two
|
52
|
+
p5 = one/two
|
53
|
+
d = norm(f0,zero)
|
54
|
+
minfact = f.ten*f.ten*f.ten
|
55
|
+
minfact = one/minfact
|
56
|
+
e = f.eps
|
57
|
+
while d >= e do
|
58
|
+
nRetry += 1
|
59
|
+
# Not yet converged. => Compute Jacobian matrix
|
60
|
+
dfdx = jacobian(f,f0,x)
|
61
|
+
# Solve dfdx*dx = -f0 to estimate dx
|
62
|
+
dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero)
|
63
|
+
fact = two
|
64
|
+
xs = x.dup
|
65
|
+
begin
|
66
|
+
fact *= p5
|
67
|
+
if fact < minfact then
|
68
|
+
raise "Failed to reduce function values."
|
69
|
+
end
|
70
|
+
for i in 0...n do
|
71
|
+
x[i] = xs[i] - dx[i]*fact
|
72
|
+
end
|
73
|
+
f0 = f.values(x)
|
74
|
+
dn = norm(f0,zero)
|
75
|
+
end while(dn>=d)
|
76
|
+
d = dn
|
77
|
+
end
|
78
|
+
nRetry
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# bigdecimal/util extends various native classes to provide the #to_d method,
|
5
|
+
# and provides BigDecimal#to_d and BigDecimal#to_digits.
|
6
|
+
#++
|
7
|
+
|
8
|
+
require 'bigdecimal'
|
9
|
+
|
10
|
+
class Integer < Numeric
|
11
|
+
# call-seq:
|
12
|
+
# int.to_d -> bigdecimal
|
13
|
+
#
|
14
|
+
# Returns the value of +int+ as a BigDecimal.
|
15
|
+
#
|
16
|
+
# require 'bigdecimal'
|
17
|
+
# require 'bigdecimal/util'
|
18
|
+
#
|
19
|
+
# 42.to_d # => 0.42e2
|
20
|
+
#
|
21
|
+
# See also BigDecimal::new.
|
22
|
+
#
|
23
|
+
def to_d
|
24
|
+
BigDecimal(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
class Float < Numeric
|
30
|
+
# call-seq:
|
31
|
+
# float.to_d -> bigdecimal
|
32
|
+
# float.to_d(precision) -> bigdecimal
|
33
|
+
#
|
34
|
+
# Returns the value of +float+ as a BigDecimal.
|
35
|
+
# The +precision+ parameter is used to determine the number of
|
36
|
+
# significant digits for the result. When +precision+ is set to +0+,
|
37
|
+
# the number of digits to represent the float being converted is determined
|
38
|
+
# automatically.
|
39
|
+
# The default +precision+ is +0+.
|
40
|
+
#
|
41
|
+
# require 'bigdecimal'
|
42
|
+
# require 'bigdecimal/util'
|
43
|
+
#
|
44
|
+
# 0.5.to_d # => 0.5e0
|
45
|
+
# 1.234.to_d # => 0.1234e1
|
46
|
+
# 1.234.to_d(2) # => 0.12e1
|
47
|
+
#
|
48
|
+
# See also BigDecimal::new.
|
49
|
+
#
|
50
|
+
def to_d(precision=0)
|
51
|
+
BigDecimal(self, precision)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class String
|
57
|
+
# call-seq:
|
58
|
+
# str.to_d -> bigdecimal
|
59
|
+
#
|
60
|
+
# Returns the result of interpreting leading characters in +str+
|
61
|
+
# as a BigDecimal.
|
62
|
+
#
|
63
|
+
# require 'bigdecimal'
|
64
|
+
# require 'bigdecimal/util'
|
65
|
+
#
|
66
|
+
# "0.5".to_d # => 0.5e0
|
67
|
+
# "123.45e1".to_d # => 0.12345e4
|
68
|
+
# "45.67 degrees".to_d # => 0.4567e2
|
69
|
+
#
|
70
|
+
# See also BigDecimal::new.
|
71
|
+
#
|
72
|
+
def to_d
|
73
|
+
BigDecimal.interpret_loosely(self)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
class BigDecimal < Numeric
|
79
|
+
# call-seq:
|
80
|
+
# a.to_digits -> string
|
81
|
+
#
|
82
|
+
# Converts a BigDecimal to a String of the form "nnnnnn.mmm".
|
83
|
+
# This method is deprecated; use BigDecimal#to_s("F") instead.
|
84
|
+
#
|
85
|
+
# require 'bigdecimal/util'
|
86
|
+
#
|
87
|
+
# d = BigDecimal("3.14")
|
88
|
+
# d.to_digits # => "3.14"
|
89
|
+
#
|
90
|
+
def to_digits
|
91
|
+
if self.nan? || self.infinite? || self.zero?
|
92
|
+
self.to_s
|
93
|
+
else
|
94
|
+
i = self.to_i.to_s
|
95
|
+
_,f,_,z = self.frac.split
|
96
|
+
i + "." + ("0"*(-z)) + f
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# call-seq:
|
101
|
+
# a.to_d -> bigdecimal
|
102
|
+
#
|
103
|
+
# Returns self.
|
104
|
+
#
|
105
|
+
# require 'bigdecimal/util'
|
106
|
+
#
|
107
|
+
# d = BigDecimal("3.14")
|
108
|
+
# d.to_d # => 0.314e1
|
109
|
+
#
|
110
|
+
def to_d
|
111
|
+
self
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
class Rational < Numeric
|
117
|
+
# call-seq:
|
118
|
+
# rat.to_d(precision) -> bigdecimal
|
119
|
+
#
|
120
|
+
# Returns the value as a BigDecimal.
|
121
|
+
#
|
122
|
+
# The required +precision+ parameter is used to determine the number of
|
123
|
+
# significant digits for the result.
|
124
|
+
#
|
125
|
+
# require 'bigdecimal'
|
126
|
+
# require 'bigdecimal/util'
|
127
|
+
#
|
128
|
+
# Rational(22, 7).to_d(3) # => 0.314e1
|
129
|
+
#
|
130
|
+
# See also BigDecimal::new.
|
131
|
+
#
|
132
|
+
def to_d(precision)
|
133
|
+
BigDecimal(self, precision)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
class Complex < Numeric
|
139
|
+
# call-seq:
|
140
|
+
# cmp.to_d -> bigdecimal
|
141
|
+
# cmp.to_d(precision) -> bigdecimal
|
142
|
+
#
|
143
|
+
# Returns the value as a BigDecimal.
|
144
|
+
#
|
145
|
+
# The +precision+ parameter is required for a rational complex number.
|
146
|
+
# This parameter is used to determine the number of significant digits
|
147
|
+
# for the result.
|
148
|
+
#
|
149
|
+
# require 'bigdecimal'
|
150
|
+
# require 'bigdecimal/util'
|
151
|
+
#
|
152
|
+
# Complex(0.1234567, 0).to_d(4) # => 0.1235e0
|
153
|
+
# Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
|
154
|
+
#
|
155
|
+
# See also BigDecimal::new.
|
156
|
+
#
|
157
|
+
def to_d(*args)
|
158
|
+
BigDecimal(self) unless self.imag.zero? # to raise eerror
|
159
|
+
|
160
|
+
if args.length == 0
|
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
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
class NilClass
|
172
|
+
# call-seq:
|
173
|
+
# nil.to_d -> bigdecimal
|
174
|
+
#
|
175
|
+
# Returns nil represented as a BigDecimal.
|
176
|
+
#
|
177
|
+
# require 'bigdecimal'
|
178
|
+
# require 'bigdecimal/util'
|
179
|
+
#
|
180
|
+
# nil.to_d # => 0.0
|
181
|
+
#
|
182
|
+
def to_d
|
183
|
+
BigDecimal(0)
|
184
|
+
end
|
185
|
+
end
|
data/lib/bigdecimal.rb
ADDED
data/sample/linear.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# linear.rb
|
6
|
+
#
|
7
|
+
# Solves linear equation system(A*x = b) by LU decomposition method.
|
8
|
+
# where A is a coefficient matrix,x is an answer vector,b is a constant vector.
|
9
|
+
#
|
10
|
+
# USAGE:
|
11
|
+
# ruby linear.rb [input file solved]
|
12
|
+
#
|
13
|
+
|
14
|
+
# :stopdoc:
|
15
|
+
require "bigdecimal"
|
16
|
+
require "bigdecimal/ludcmp"
|
17
|
+
|
18
|
+
#
|
19
|
+
# NOTE:
|
20
|
+
# Change following BigDecimal.limit() if needed.
|
21
|
+
BigDecimal.limit(100)
|
22
|
+
#
|
23
|
+
|
24
|
+
include LUSolve
|
25
|
+
def rd_order(na)
|
26
|
+
printf("Number of equations ?") if(na <= 0)
|
27
|
+
n = ARGF.gets().to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
na = ARGV.size
|
31
|
+
zero = BigDecimal("0.0")
|
32
|
+
one = BigDecimal("1.0")
|
33
|
+
|
34
|
+
while (n=rd_order(na))>0
|
35
|
+
a = []
|
36
|
+
as= []
|
37
|
+
b = []
|
38
|
+
if na <= 0
|
39
|
+
# Read data from console.
|
40
|
+
printf("\nEnter coefficient matrix element A[i,j]\n")
|
41
|
+
for i in 0...n do
|
42
|
+
for j in 0...n do
|
43
|
+
printf("A[%d,%d]? ",i,j); s = ARGF.gets
|
44
|
+
a << BigDecimal(s)
|
45
|
+
as << BigDecimal(s)
|
46
|
+
end
|
47
|
+
printf("Contatant vector element b[%d] ? ",i)
|
48
|
+
b << BigDecimal(ARGF.gets)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
# Read data from specified file.
|
52
|
+
printf("Coefficient matrix and constant vector.\n")
|
53
|
+
for i in 0...n do
|
54
|
+
s = ARGF.gets
|
55
|
+
printf("%d) %s",i,s)
|
56
|
+
s = s.split
|
57
|
+
for j in 0...n do
|
58
|
+
a << BigDecimal(s[j])
|
59
|
+
as << BigDecimal(s[j])
|
60
|
+
end
|
61
|
+
b << BigDecimal(s[n])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
x = lusolve(a,b,ludecomp(a,n,zero,one),zero)
|
65
|
+
printf("Answer(x[i] & (A*x-b)[i]) follows\n")
|
66
|
+
for i in 0...n do
|
67
|
+
printf("x[%d]=%s ",i,x[i].to_s)
|
68
|
+
s = zero
|
69
|
+
for j in 0...n do
|
70
|
+
s = s + as[i*n+j]*x[j]
|
71
|
+
end
|
72
|
+
printf(" & %s\n",(s-b[i]).to_s)
|
73
|
+
end
|
74
|
+
end
|
data/sample/nlsolve.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# nlsolve.rb
|
6
|
+
# An example for solving nonlinear algebraic equation system.
|
7
|
+
#
|
8
|
+
|
9
|
+
require "bigdecimal"
|
10
|
+
require "bigdecimal/newton"
|
11
|
+
include Newton
|
12
|
+
|
13
|
+
class Function # :nodoc: all
|
14
|
+
def initialize()
|
15
|
+
@zero = BigDecimal("0.0")
|
16
|
+
@one = BigDecimal("1.0")
|
17
|
+
@two = BigDecimal("2.0")
|
18
|
+
@ten = BigDecimal("10.0")
|
19
|
+
@eps = BigDecimal("1.0e-16")
|
20
|
+
end
|
21
|
+
def zero;@zero;end
|
22
|
+
def one ;@one ;end
|
23
|
+
def two ;@two ;end
|
24
|
+
def ten ;@ten ;end
|
25
|
+
def eps ;@eps ;end
|
26
|
+
def values(x) # <= defines functions solved
|
27
|
+
f = []
|
28
|
+
f1 = x[0]*x[0] + x[1]*x[1] - @two # f1 = x**2 + y**2 - 2 => 0
|
29
|
+
f2 = x[0] - x[1] # f2 = x - y => 0
|
30
|
+
f <<= f1
|
31
|
+
f <<= f2
|
32
|
+
f
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
f = BigDecimal.limit(100)
|
37
|
+
f = Function.new
|
38
|
+
x = [f.zero,f.zero] # Initial values
|
39
|
+
n = nlsolve(f,x)
|
40
|
+
p x
|
data/sample/pi.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
#
|
5
|
+
# pi.rb
|
6
|
+
#
|
7
|
+
# Calculates 3.1415.... (the number of times that a circle's diameter
|
8
|
+
# will fit around the circle) using J. Machin's formula.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "bigdecimal"
|
12
|
+
require "bigdecimal/math.rb"
|
13
|
+
|
14
|
+
include BigMath
|
15
|
+
|
16
|
+
if ARGV.size == 1
|
17
|
+
print "PI("+ARGV[0]+"):\n"
|
18
|
+
p PI(ARGV[0].to_i)
|
19
|
+
else
|
20
|
+
print "TRY: ruby pi.rb 1000 \n"
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bigdecimal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.1.4
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- Kenta Murata
|
8
|
+
- Zachary Scott
|
9
|
+
- Shigeo Kobayashi
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2023-09-05 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: This library provides arbitrary-precision decimal floating-point number
|
16
|
+
class.
|
17
|
+
email:
|
18
|
+
- mrkn@mrkn.jp
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- bigdecimal.gemspec
|
24
|
+
- lib/bigdecimal.rb
|
25
|
+
- lib/bigdecimal/jacobian.rb
|
26
|
+
- lib/bigdecimal/ludcmp.rb
|
27
|
+
- lib/bigdecimal/math.rb
|
28
|
+
- lib/bigdecimal/newton.rb
|
29
|
+
- lib/bigdecimal/util.rb
|
30
|
+
- sample/linear.rb
|
31
|
+
- sample/nlsolve.rb
|
32
|
+
- sample/pi.rb
|
33
|
+
homepage: https://github.com/ruby/bigdecimal
|
34
|
+
licenses:
|
35
|
+
- Ruby
|
36
|
+
- BSD-2-Clause
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.5.0
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubygems_version: 3.3.26
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Arbitrary-precision decimal floating-point number library.
|
57
|
+
test_files: []
|