bigdecimal 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +60 -0
- data/bigdecimal.c +5936 -0
- data/bigdecimal.gemspec +30 -0
- data/bigdecimal.h +291 -0
- data/depend +1 -0
- data/extconf.rb +6 -0
- data/lib/bigdecimal/jacobian.rb +87 -0
- data/lib/bigdecimal/ludcmp.rb +88 -0
- data/lib/bigdecimal/math.rb +206 -0
- data/lib/bigdecimal/newton.rb +78 -0
- data/lib/bigdecimal/util.rb +105 -0
- data/sample/linear.rb +71 -0
- data/sample/nlsolve.rb +38 -0
- data/sample/pi.rb +20 -0
- metadata +61 -0
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
#
|
4
|
+
#--
|
5
|
+
# Contents:
|
6
|
+
# sqrt(x, prec)
|
7
|
+
# sin (x, prec)
|
8
|
+
# cos (x, prec)
|
9
|
+
# atan(x, prec) Note: |x|<1, x=0.9999 may not converge.
|
10
|
+
# log (x, prec)
|
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"
|
25
|
+
# require "bigdecimal/math"
|
26
|
+
#
|
27
|
+
# include BigMath
|
28
|
+
#
|
29
|
+
# a = BigDecimal((PI(100)/2).to_s)
|
30
|
+
# puts sin(a,100) # -> 0.10000000000000000000......E1
|
31
|
+
#
|
32
|
+
module BigMath
|
33
|
+
module_function
|
34
|
+
|
35
|
+
# Computes the square root of x to the specified number of digits of
|
36
|
+
# precision.
|
37
|
+
#
|
38
|
+
# BigDecimal.new('2').sqrt(16).to_s
|
39
|
+
# -> "0.14142135623730950488016887242096975E1"
|
40
|
+
#
|
41
|
+
def sqrt(x,prec)
|
42
|
+
x.sqrt(prec)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Computes the sine of x to the specified number of digits of precision.
|
46
|
+
#
|
47
|
+
# If x is infinite or NaN, returns NaN.
|
48
|
+
def sin(x, prec)
|
49
|
+
raise ArgumentError, "Zero or negative precision for sin" if prec <= 0
|
50
|
+
return BigDecimal("NaN") if x.infinite? || x.nan?
|
51
|
+
n = prec + BigDecimal.double_fig
|
52
|
+
one = BigDecimal("1")
|
53
|
+
two = BigDecimal("2")
|
54
|
+
x = -x if neg = x < 0
|
55
|
+
if x > (twopi = two * BigMath.PI(prec))
|
56
|
+
if x > 30
|
57
|
+
x %= twopi
|
58
|
+
else
|
59
|
+
x -= twopi while x > twopi
|
60
|
+
end
|
61
|
+
end
|
62
|
+
x1 = x
|
63
|
+
x2 = x.mult(x,n)
|
64
|
+
sign = 1
|
65
|
+
y = x
|
66
|
+
d = y
|
67
|
+
i = one
|
68
|
+
z = one
|
69
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
70
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
71
|
+
sign = -sign
|
72
|
+
x1 = x2.mult(x1,n)
|
73
|
+
i += two
|
74
|
+
z *= (i-one) * i
|
75
|
+
d = sign * x1.div(z,m)
|
76
|
+
y += d
|
77
|
+
end
|
78
|
+
neg ? -y : y
|
79
|
+
end
|
80
|
+
|
81
|
+
# Computes the cosine of x to the specified number of digits of precision.
|
82
|
+
#
|
83
|
+
# If x is infinite or NaN, returns NaN.
|
84
|
+
def cos(x, prec)
|
85
|
+
raise ArgumentError, "Zero or negative precision for cos" if prec <= 0
|
86
|
+
return BigDecimal("NaN") if x.infinite? || x.nan?
|
87
|
+
n = prec + BigDecimal.double_fig
|
88
|
+
one = BigDecimal("1")
|
89
|
+
two = BigDecimal("2")
|
90
|
+
x = -x if x < 0
|
91
|
+
if x > (twopi = two * BigMath.PI(prec))
|
92
|
+
if x > 30
|
93
|
+
x %= twopi
|
94
|
+
else
|
95
|
+
x -= twopi while x > twopi
|
96
|
+
end
|
97
|
+
end
|
98
|
+
x1 = one
|
99
|
+
x2 = x.mult(x,n)
|
100
|
+
sign = 1
|
101
|
+
y = one
|
102
|
+
d = y
|
103
|
+
i = BigDecimal("0")
|
104
|
+
z = one
|
105
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
106
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
107
|
+
sign = -sign
|
108
|
+
x1 = x2.mult(x1,n)
|
109
|
+
i += two
|
110
|
+
z *= (i-one) * i
|
111
|
+
d = sign * x1.div(z,m)
|
112
|
+
y += d
|
113
|
+
end
|
114
|
+
y
|
115
|
+
end
|
116
|
+
|
117
|
+
# Computes the arctangent of x to the specified number of digits of precision.
|
118
|
+
#
|
119
|
+
# If x is NaN, returns NaN.
|
120
|
+
def atan(x, prec)
|
121
|
+
raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
|
122
|
+
return BigDecimal("NaN") if x.nan?
|
123
|
+
pi = PI(prec)
|
124
|
+
x = -x if neg = x < 0
|
125
|
+
return pi.div(neg ? -2 : 2, prec) if x.infinite?
|
126
|
+
return pi / (neg ? -4 : 4) if x.round(prec) == 1
|
127
|
+
x = BigDecimal("1").div(x, prec) if inv = x > 1
|
128
|
+
x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5
|
129
|
+
n = prec + BigDecimal.double_fig
|
130
|
+
y = x
|
131
|
+
d = y
|
132
|
+
t = x
|
133
|
+
r = BigDecimal("3")
|
134
|
+
x2 = x.mult(x,n)
|
135
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
136
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
137
|
+
t = -t.mult(x2,n)
|
138
|
+
d = t.div(r,m)
|
139
|
+
y += d
|
140
|
+
r += 2
|
141
|
+
end
|
142
|
+
y *= 2 if dbl
|
143
|
+
y = pi / 2 - y if inv
|
144
|
+
y = -y if neg
|
145
|
+
y
|
146
|
+
end
|
147
|
+
|
148
|
+
# Computes the value of pi to the specified number of digits of precision.
|
149
|
+
def PI(prec)
|
150
|
+
raise ArgumentError, "Zero or negative argument for PI" if prec <= 0
|
151
|
+
n = prec + BigDecimal.double_fig
|
152
|
+
zero = BigDecimal("0")
|
153
|
+
one = BigDecimal("1")
|
154
|
+
two = BigDecimal("2")
|
155
|
+
|
156
|
+
m25 = BigDecimal("-0.04")
|
157
|
+
m57121 = BigDecimal("-57121")
|
158
|
+
|
159
|
+
pi = zero
|
160
|
+
|
161
|
+
d = one
|
162
|
+
k = one
|
163
|
+
w = one
|
164
|
+
t = BigDecimal("-80")
|
165
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
166
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
167
|
+
t = t*m25
|
168
|
+
d = t.div(k,m)
|
169
|
+
k = k+two
|
170
|
+
pi = pi + d
|
171
|
+
end
|
172
|
+
|
173
|
+
d = one
|
174
|
+
k = one
|
175
|
+
w = one
|
176
|
+
t = BigDecimal("956")
|
177
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
178
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
179
|
+
t = t.div(m57121,n)
|
180
|
+
d = t.div(k,m)
|
181
|
+
pi = pi + d
|
182
|
+
k = k+two
|
183
|
+
end
|
184
|
+
pi
|
185
|
+
end
|
186
|
+
|
187
|
+
# Computes e (the base of natural logarithms) to the specified number of
|
188
|
+
# digits of precision.
|
189
|
+
def E(prec)
|
190
|
+
raise ArgumentError, "Zero or negative precision for E" if prec <= 0
|
191
|
+
n = prec + BigDecimal.double_fig
|
192
|
+
one = BigDecimal("1")
|
193
|
+
y = one
|
194
|
+
d = y
|
195
|
+
z = one
|
196
|
+
i = 0
|
197
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
198
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
199
|
+
i += 1
|
200
|
+
z *= i
|
201
|
+
d = one.div(z,m)
|
202
|
+
y += d
|
203
|
+
end
|
204
|
+
y
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "bigdecimal/ludcmp"
|
2
|
+
require "bigdecimal/jacobian"
|
3
|
+
|
4
|
+
#
|
5
|
+
# newton.rb
|
6
|
+
#
|
7
|
+
# Solves the nonlinear algebraic equation system f = 0 by Newton's method.
|
8
|
+
# This program is not dependent on BigDecimal.
|
9
|
+
#
|
10
|
+
# To call:
|
11
|
+
# n = nlsolve(f,x)
|
12
|
+
# where n is the number of iterations required,
|
13
|
+
# x is the initial value vector
|
14
|
+
# f is an Object which is used to compute the values of the equations to be solved.
|
15
|
+
# It must provide the following methods:
|
16
|
+
#
|
17
|
+
# f.values(x):: returns the values of all functions at x
|
18
|
+
#
|
19
|
+
# f.zero:: returns 0.0
|
20
|
+
# f.one:: returns 1.0
|
21
|
+
# f.two:: returns 1.0
|
22
|
+
# f.ten:: returns 10.0
|
23
|
+
#
|
24
|
+
# 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.
|
25
|
+
#
|
26
|
+
# On exit, x is the solution vector.
|
27
|
+
#
|
28
|
+
module Newton
|
29
|
+
include LUSolve
|
30
|
+
include Jacobian
|
31
|
+
module_function
|
32
|
+
|
33
|
+
def norm(fv,zero=0.0)
|
34
|
+
s = zero
|
35
|
+
n = fv.size
|
36
|
+
for i in 0...n do
|
37
|
+
s += fv[i]*fv[i]
|
38
|
+
end
|
39
|
+
s
|
40
|
+
end
|
41
|
+
|
42
|
+
def nlsolve(f,x)
|
43
|
+
nRetry = 0
|
44
|
+
n = x.size
|
45
|
+
|
46
|
+
f0 = f.values(x)
|
47
|
+
zero = f.zero
|
48
|
+
one = f.one
|
49
|
+
two = f.two
|
50
|
+
p5 = one/two
|
51
|
+
d = norm(f0,zero)
|
52
|
+
minfact = f.ten*f.ten*f.ten
|
53
|
+
minfact = one/minfact
|
54
|
+
e = f.eps
|
55
|
+
while d >= e do
|
56
|
+
nRetry += 1
|
57
|
+
# Not yet converged. => Compute Jacobian matrix
|
58
|
+
dfdx = jacobian(f,f0,x)
|
59
|
+
# Solve dfdx*dx = -f0 to estimate dx
|
60
|
+
dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero)
|
61
|
+
fact = two
|
62
|
+
xs = x.dup
|
63
|
+
begin
|
64
|
+
fact *= p5
|
65
|
+
if fact < minfact then
|
66
|
+
raise "Failed to reduce function values."
|
67
|
+
end
|
68
|
+
for i in 0...n do
|
69
|
+
x[i] = xs[i] - dx[i]*fact
|
70
|
+
end
|
71
|
+
f0 = f.values(x)
|
72
|
+
dn = norm(f0,zero)
|
73
|
+
end while(dn>=d)
|
74
|
+
d = dn
|
75
|
+
end
|
76
|
+
nRetry
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class Integer < Numeric
|
2
|
+
# call-seq:
|
3
|
+
# int.to_d -> bigdecimal
|
4
|
+
#
|
5
|
+
# Convert +int+ to a BigDecimal and return it.
|
6
|
+
#
|
7
|
+
# require 'bigdecimal'
|
8
|
+
# require 'bigdecimal/util'
|
9
|
+
#
|
10
|
+
# 42.to_d
|
11
|
+
# # => #<BigDecimal:1008ef070,'0.42E2',9(36)>
|
12
|
+
#
|
13
|
+
def to_d
|
14
|
+
BigDecimal(self)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Float < Numeric
|
19
|
+
# call-seq:
|
20
|
+
# flt.to_d -> bigdecimal
|
21
|
+
#
|
22
|
+
# Convert +flt+ to a BigDecimal and return it.
|
23
|
+
#
|
24
|
+
# require 'bigdecimal'
|
25
|
+
# require 'bigdecimal/util'
|
26
|
+
#
|
27
|
+
# 0.5.to_d
|
28
|
+
# # => #<BigDecimal:1dc69e0,'0.5E0',9(18)>
|
29
|
+
#
|
30
|
+
def to_d(precision=nil)
|
31
|
+
BigDecimal(self, precision || Float::DIG+1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class String
|
36
|
+
# call-seq:
|
37
|
+
# string.to_d -> bigdecimal
|
38
|
+
#
|
39
|
+
# Convert +string+ to a BigDecimal and return it.
|
40
|
+
#
|
41
|
+
# require 'bigdecimal'
|
42
|
+
# require 'bigdecimal/util'
|
43
|
+
#
|
44
|
+
# "0.5".to_d
|
45
|
+
# # => #<BigDecimal:1dc69e0,'0.5E0',9(18)>
|
46
|
+
#
|
47
|
+
def to_d
|
48
|
+
BigDecimal(self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class BigDecimal < Numeric
|
53
|
+
# call-seq:
|
54
|
+
# a.to_digits -> string
|
55
|
+
#
|
56
|
+
# Converts a BigDecimal to a String of the form "nnnnnn.mmm".
|
57
|
+
# This method is deprecated; use BigDecimal#to_s("F") instead.
|
58
|
+
#
|
59
|
+
# require 'bigdecimal'
|
60
|
+
# require 'bigdecimal/util'
|
61
|
+
#
|
62
|
+
# d = BigDecimal.new("3.14")
|
63
|
+
# d.to_digits
|
64
|
+
# # => "3.14"
|
65
|
+
def to_digits
|
66
|
+
if self.nan? || self.infinite? || self.zero?
|
67
|
+
self.to_s
|
68
|
+
else
|
69
|
+
i = self.to_i.to_s
|
70
|
+
_,f,_,z = self.frac.split
|
71
|
+
i + "." + ("0"*(-z)) + f
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# call-seq:
|
76
|
+
# a.to_d -> bigdecimal
|
77
|
+
#
|
78
|
+
# Returns self.
|
79
|
+
def to_d
|
80
|
+
self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Rational < Numeric
|
85
|
+
# call-seq:
|
86
|
+
# r.to_d -> bigdecimal
|
87
|
+
# r.to_d(sig) -> bigdecimal
|
88
|
+
#
|
89
|
+
# Converts a Rational to a BigDecimal. Takes an optional parameter +sig+ to
|
90
|
+
# limit the amount of significant digits.
|
91
|
+
#
|
92
|
+
# r = (22/7.0).to_r
|
93
|
+
# # => (7077085128725065/2251799813685248)
|
94
|
+
# r.to_d
|
95
|
+
# # => #<BigDecimal:1a52bd8,'0.3142857142 8571427937 0154144999 105E1',45(63)>
|
96
|
+
# r.to_d(3)
|
97
|
+
# # => #<BigDecimal:1a44d08,'0.314E1',18(36)>
|
98
|
+
def to_d(precision)
|
99
|
+
if precision <= 0
|
100
|
+
raise ArgumentError, "negative precision"
|
101
|
+
end
|
102
|
+
num = self.numerator
|
103
|
+
BigDecimal(num).div(self.denominator, precision)
|
104
|
+
end
|
105
|
+
end
|
data/sample/linear.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# linear.rb
|
5
|
+
#
|
6
|
+
# Solves linear equation system(A*x = b) by LU decomposition method.
|
7
|
+
# where A is a coefficient matrix,x is an answer vector,b is a constant vector.
|
8
|
+
#
|
9
|
+
# USAGE:
|
10
|
+
# ruby linear.rb [input file solved]
|
11
|
+
#
|
12
|
+
|
13
|
+
require "bigdecimal"
|
14
|
+
require "bigdecimal/ludcmp"
|
15
|
+
|
16
|
+
#
|
17
|
+
# NOTE:
|
18
|
+
# Change following BigDecimal::limit() if needed.
|
19
|
+
BigDecimal::limit(100)
|
20
|
+
#
|
21
|
+
|
22
|
+
include LUSolve
|
23
|
+
def rd_order(na)
|
24
|
+
printf("Number of equations ?") if(na <= 0)
|
25
|
+
n = ARGF.gets().to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
na = ARGV.size
|
29
|
+
zero = BigDecimal::new("0.0")
|
30
|
+
one = BigDecimal::new("1.0")
|
31
|
+
|
32
|
+
while (n=rd_order(na))>0
|
33
|
+
a = []
|
34
|
+
as= []
|
35
|
+
b = []
|
36
|
+
if na <= 0
|
37
|
+
# Read data from console.
|
38
|
+
printf("\nEnter coefficient matrix element A[i,j]\n");
|
39
|
+
for i in 0...n do
|
40
|
+
for j in 0...n do
|
41
|
+
printf("A[%d,%d]? ",i,j); s = ARGF.gets
|
42
|
+
a << BigDecimal::new(s);
|
43
|
+
as << BigDecimal::new(s);
|
44
|
+
end
|
45
|
+
printf("Contatant vector element b[%d] ? ",i); b << BigDecimal::new(ARGF.gets);
|
46
|
+
end
|
47
|
+
else
|
48
|
+
# Read data from specified file.
|
49
|
+
printf("Coefficient matrix and constant vector.\n");
|
50
|
+
for i in 0...n do
|
51
|
+
s = ARGF.gets
|
52
|
+
printf("%d) %s",i,s)
|
53
|
+
s = s.split
|
54
|
+
for j in 0...n do
|
55
|
+
a << BigDecimal::new(s[j]);
|
56
|
+
as << BigDecimal::new(s[j]);
|
57
|
+
end
|
58
|
+
b << BigDecimal::new(s[n]);
|
59
|
+
end
|
60
|
+
end
|
61
|
+
x = lusolve(a,b,ludecomp(a,n,zero,one),zero)
|
62
|
+
printf("Answer(x[i] & (A*x-b)[i]) follows\n")
|
63
|
+
for i in 0...n do
|
64
|
+
printf("x[%d]=%s ",i,x[i].to_s)
|
65
|
+
s = zero
|
66
|
+
for j in 0...n do
|
67
|
+
s = s + as[i*n+j]*x[j]
|
68
|
+
end
|
69
|
+
printf(" & %s\n",(s-b[i]).to_s)
|
70
|
+
end
|
71
|
+
end
|