bigdecimal 1.1.0

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