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.
@@ -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