bigdecimal 3.2.3 → 4.1.1

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.
@@ -2,6 +2,8 @@
2
2
  require "bigdecimal/ludcmp"
3
3
  require "bigdecimal/jacobian"
4
4
 
5
+ warn "'bigdecimal/newton' is deprecated and will be removed in a future release."
6
+
5
7
  #
6
8
  # newton.rb
7
9
  #
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  #
3
3
  #--
4
4
  # bigdecimal/util extends various native classes to provide the #to_d method,
@@ -119,8 +119,11 @@ class Rational < Numeric
119
119
  #
120
120
  # Returns the value as a BigDecimal.
121
121
  #
122
- # The required +precision+ parameter is used to determine the number of
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 required for a rational complex number.
146
- # This parameter is used to determine the number of significant digits
147
- # for the result.
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(*args)
164
+ def to_d(precision=0)
158
165
  BigDecimal(self) unless self.imag.zero? # to raise error
159
166
 
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
+ BigDecimal(self.real, precision)
167
168
  end
168
169
  end
169
170
 
data/lib/bigdecimal.rb CHANGED
@@ -1,12 +1,20 @@
1
1
  if RUBY_ENGINE == 'jruby'
2
2
  JRuby::Util.load_ext("org.jruby.ext.bigdecimal.BigDecimalLibrary")
3
- return
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
7
12
 
8
13
  class BigDecimal
9
14
  module Internal # :nodoc:
15
+ # Default extra precision for intermediate calculations
16
+ # This value is currently the same as BigDecimal.double_fig, but defined separately for future changes.
17
+ EXTRA_PREC = 16
10
18
 
11
19
  # Coerce x to BigDecimal with the specified precision.
12
20
  # TODO: some methods (example: BigMath.exp) require more precision than specified to coerce.
@@ -15,20 +23,31 @@ class BigDecimal
15
23
  when BigDecimal
16
24
  return x
17
25
  when Integer, Float
18
- return BigDecimal(x)
26
+ return BigDecimal(x, 0)
19
27
  when Rational
20
28
  return BigDecimal(x, [prec, 2 * BigDecimal.double_fig].max)
21
29
  end
22
30
  raise ArgumentError, "#{x.inspect} can't be coerced into BigDecimal"
23
31
  end
24
32
 
25
- def self.validate_prec(prec, method_name, accept_zero: false) # :nodoc:
26
- raise ArgumentError, 'precision must be an Integer' unless Integer === prec
33
+ def self.coerce_validate_prec(prec, method_name, accept_zero: false) # :nodoc:
34
+ unless Integer === prec
35
+ original = prec
36
+ # Emulate Integer.try_convert for ruby < 3.1
37
+ if prec.respond_to?(:to_int)
38
+ prec = prec.to_int
39
+ else
40
+ raise TypeError, "no implicit conversion of #{original.class} into Integer"
41
+ end
42
+ raise TypeError, "can't convert #{original.class} to Integer" unless Integer === prec
43
+ end
44
+
27
45
  if accept_zero
28
46
  raise ArgumentError, "Negative precision for #{method_name}" if prec < 0
29
47
  else
30
48
  raise ArgumentError, "Zero or negative precision for #{method_name}" if prec <= 0
31
49
  end
50
+ prec
32
51
  end
33
52
 
34
53
  def self.infinity_computation_result # :nodoc:
@@ -44,6 +63,55 @@ class BigDecimal
44
63
  end
45
64
  BigDecimal::NAN
46
65
  end
66
+
67
+ # Iteration for Newton's method with increasing precision
68
+ def self.newton_loop(prec, initial_precision: BigDecimal.double_fig / 2, safe_margin: 2) # :nodoc:
69
+ precs = []
70
+ while prec > initial_precision
71
+ precs << prec
72
+ prec = (precs.last + 1) / 2 + safe_margin
73
+ end
74
+ precs.reverse_each do |p|
75
+ yield p
76
+ end
77
+ end
78
+
79
+ # Fast and rough conversion to float for mathematical calculations.
80
+ # Bigdecimal#to_f is slow when n_significant_digits is large.
81
+ # This is because to_f internally converts BigDecimal to String
82
+ # to get the exact nearest float representation.
83
+ # TODO: Remove this workaround when BigDecimal#to_f is optimized.
84
+ def self.fast_to_f(x) # :nodoc:
85
+ x.n_significant_digits < 40 ? x.to_f : x.mult(1, 20).to_f
86
+ end
87
+
88
+ # Calculates Math.log(x.to_f) considering large or small exponent
89
+ def self.float_log(x) # :nodoc:
90
+ Math.log(fast_to_f(x._decimal_shift(-x.exponent))) + x.exponent * Math.log(10)
91
+ end
92
+
93
+ # Calculating Taylor series sum using binary splitting method
94
+ # Calculates f(x) = (x/d0)*(1+(x/d1)*(1+(x/d2)*(1+(x/d3)*(1+...))))
95
+ # x.n_significant_digits or ds.size must be small to be performant.
96
+ def self.taylor_sum_binary_splitting(x, ds, prec) # :nodoc:
97
+ fs = ds.map {|d| [0, BigDecimal(d)] }
98
+ # fs = [[a0, a1], [b0, b1], [c0, c1], ...]
99
+ # f(x) = a0/a1+(x/a1)*(1+b0/b1+(x/b1)*(1+c0/c1+(x/c1)*(1+d0/d1+(x/d1)*(1+...))))
100
+ while fs.size > 1
101
+ # Merge two adjacent fractions
102
+ # from: (1 + a0/a1 + x/a1 * (1 + b0/b1 + x/b1 * rest))
103
+ # to: (1 + (a0*b1+x*(b0+b1))/(a1*b1) + (x*x)/(a1*b1) * rest)
104
+ xn = xn ? xn.mult(xn, prec) : x
105
+ fs = fs.each_slice(2).map do |(a, b)|
106
+ b ||= [0, BigDecimal(1)._decimal_shift([xn.exponent, 0].max + 2)]
107
+ [
108
+ (a[0] * b[1]).add(xn * (b[0] + b[1]), prec),
109
+ a[1].mult(b[1], prec)
110
+ ]
111
+ end
112
+ end
113
+ BigDecimal(fs[0][0]).div(fs[0][1], prec)
114
+ end
47
115
  end
48
116
 
49
117
  # call-seq:
@@ -78,10 +146,10 @@ class BigDecimal
78
146
  #
79
147
  # Also available as the operator **.
80
148
  #
81
- def power(y, prec = nil)
82
- Internal.validate_prec(prec, :power) if prec
149
+ def power(y, prec = 0)
150
+ prec = Internal.coerce_validate_prec(prec, :power, accept_zero: true)
83
151
  x = self
84
- y = Internal.coerce_to_bigdecimal(y, prec || n_significant_digits, :power)
152
+ y = Internal.coerce_to_bigdecimal(y, prec.nonzero? || n_significant_digits, :power)
85
153
 
86
154
  return Internal.nan_computation_result if x.nan? || y.nan?
87
155
  return BigDecimal(1) if y.zero?
@@ -128,10 +196,10 @@ class BigDecimal
128
196
  return BigDecimal(1)
129
197
  end
130
198
 
131
- prec ||= BigDecimal.limit.nonzero?
199
+ limit = BigDecimal.limit
132
200
  frac_part = y.frac
133
201
 
134
- if frac_part.zero? && !prec
202
+ if frac_part.zero? && prec.zero? && limit.zero?
135
203
  # Infinite precision calculation for `x ** int` and `x.power(int)`
136
204
  int_part = y.fix.to_i
137
205
  int_part = -int_part if (neg = int_part < 0)
@@ -151,31 +219,42 @@ class BigDecimal
151
219
  return neg ? BigDecimal(1) / ans : ans
152
220
  end
153
221
 
154
- prec ||= [x.n_significant_digits, y.n_significant_digits, BigDecimal.double_fig].max + BigDecimal.double_fig
222
+ result_prec = prec.nonzero? || [x.n_significant_digits, y.n_significant_digits, BigDecimal.double_fig].max + BigDecimal.double_fig
223
+ result_prec = [result_prec, limit].min if prec.zero? && limit.nonzero?
224
+
225
+ prec2 = result_prec + BigDecimal::Internal::EXTRA_PREC
155
226
 
156
227
  if y < 0
157
- inv = x.power(-y, prec)
228
+ inv = x.power(-y, prec2)
158
229
  return BigDecimal(0) if inv.infinite?
159
230
  return BigDecimal::Internal.infinity_computation_result if inv.zero?
160
- return BigDecimal(1).div(inv, prec)
231
+ return BigDecimal(1).div(inv, result_prec)
161
232
  end
162
233
 
163
- int_part = y.fix.to_i
164
- prec2 = prec + BigDecimal.double_fig
165
- pow_prec = prec2 + (int_part > 0 ? y.exponent : 0)
166
- ans = BigDecimal(1)
167
- n = 1
168
- xn = x
169
- while true
170
- ans = ans.mult(xn, pow_prec) if int_part.allbits?(n)
171
- n <<= 1
172
- break if n > int_part
173
- xn = xn.mult(xn, pow_prec)
174
- end
175
- unless frac_part.zero?
176
- ans = ans.mult(BigMath.exp(BigMath.log(x, prec2).mult(frac_part, prec2), prec2), prec2)
234
+ if frac_part.zero? && y.exponent < Math.log(result_prec) * 5 + 20
235
+ # Use exponentiation by squaring if y is an integer and not too large
236
+ pow_prec = prec2 + y.exponent
237
+ n = 1
238
+ xn = x
239
+ ans = BigDecimal(1)
240
+ int_part = y.fix.to_i
241
+ while true
242
+ ans = ans.mult(xn, pow_prec) if int_part.allbits?(n)
243
+ n <<= 1
244
+ break if n > int_part
245
+ xn = xn.mult(xn, pow_prec)
246
+ end
247
+ ans.mult(1, result_prec)
248
+ else
249
+ if x > 1 && x.finite?
250
+ # To calculate exp(z, prec), z needs prec+max(z.exponent, 0) precision if z > 0.
251
+ # Estimate (y*log(x)).exponent
252
+ logx_exponent = x < 2 ? (x - 1).exponent : Math.log10(x.exponent).round
253
+ ylogx_exponent = y.exponent + logx_exponent
254
+ prec2 += [ylogx_exponent, 0].max
255
+ end
256
+ BigMath.exp(BigMath.log(x, prec2).mult(y, prec2), result_prec)
177
257
  end
178
- ans.mult(1, prec)
179
258
  end
180
259
 
181
260
  # Returns the square root of the value.
@@ -183,36 +262,33 @@ class BigDecimal
183
262
  # Result has at least prec significant digits.
184
263
  #
185
264
  def sqrt(prec)
186
- Internal.validate_prec(prec, :sqrt, accept_zero: true)
265
+ prec = Internal.coerce_validate_prec(prec, :sqrt, accept_zero: true)
187
266
  return Internal.infinity_computation_result if infinite? == 1
188
267
 
189
268
  raise FloatDomainError, 'sqrt of negative value' if self < 0
190
269
  raise FloatDomainError, "sqrt of 'NaN'(Not a Number)" if nan?
191
270
  return self if zero?
192
271
 
193
- limit = BigDecimal.limit.nonzero? if prec == 0
194
-
195
- # BigDecimal#sqrt calculates at least n_significant_digits precision.
196
- # This feature maybe problematic for some cases.
197
- n_digits = n_significant_digits
198
- prec = [prec, n_digits].max
272
+ if prec == 0
273
+ limit = BigDecimal.limit
274
+ prec = n_significant_digits + BigDecimal.double_fig
275
+ prec = [limit, prec].min if limit.nonzero?
276
+ end
199
277
 
200
278
  ex = exponent / 2
201
279
  x = _decimal_shift(-2 * ex)
202
- y = BigDecimal(Math.sqrt(x.to_f))
203
- precs = [prec + BigDecimal.double_fig]
204
- precs << 2 + precs.last / 2 while precs.last > BigDecimal.double_fig
205
- precs.reverse_each do |p|
280
+ y = BigDecimal(Math.sqrt(BigDecimal::Internal.fast_to_f(x)), 0)
281
+ Internal.newton_loop(prec + BigDecimal::Internal::EXTRA_PREC) do |p|
206
282
  y = y.add(x.div(y, p), p).div(2, p)
207
283
  end
208
- y = y.mult(1, limit) if limit
209
- y._decimal_shift(ex)
284
+ y._decimal_shift(ex).mult(1, prec)
210
285
  end
211
286
  end
212
287
 
213
288
  # Core BigMath methods for BigDecimal (log, exp) are defined here.
214
289
  # Other methods (sin, cos, atan) are defined in 'bigdecimal/math.rb'.
215
290
  module BigMath
291
+ module_function
216
292
 
217
293
  # call-seq:
218
294
  # BigMath.log(decimal, numeric) -> BigDecimal
@@ -226,60 +302,47 @@ module BigMath
226
302
  #
227
303
  # If +decimal+ is NaN, returns NaN.
228
304
  #
229
- def self.log(x, prec)
230
- BigDecimal::Internal.validate_prec(prec, :log)
305
+ def log(x, prec)
306
+ prec = BigDecimal::Internal.coerce_validate_prec(prec, :log)
231
307
  raise Math::DomainError, 'Complex argument for BigMath.log' if Complex === x
232
308
 
233
309
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :log)
234
310
  return BigDecimal::Internal.nan_computation_result if x.nan?
235
- raise Math::DomainError, 'Zero or negative argument for log' if x <= 0
311
+ raise Math::DomainError, 'Negative argument for log' if x < 0
312
+ return -BigDecimal::Internal.infinity_computation_result if x.zero?
236
313
  return BigDecimal::Internal.infinity_computation_result if x.infinite?
237
314
  return BigDecimal(0) if x == 1
238
315
 
239
- BigDecimal.save_limit do
240
- BigDecimal.limit(0)
241
- if x > 10 || x < 0.1
242
- log10 = log(BigDecimal(10), prec)
243
- exponent = x.exponent
244
- x = x._decimal_shift(-exponent)
245
- if x < 0.3
246
- x *= 10
247
- exponent -= 1
248
- end
249
- return log10 * exponent + log(x, prec)
250
- end
251
-
252
- x_minus_one_exponent = (x - 1).exponent
253
- prec += BigDecimal.double_fig
254
-
255
- # log(x) = log(sqrt(sqrt(sqrt(sqrt(x))))) * 2**sqrt_steps
256
- sqrt_steps = [Integer.sqrt(prec) + 3 * x_minus_one_exponent, 0].max
257
-
258
- lg2 = 0.3010299956639812
259
- prec2 = prec + [-x_minus_one_exponent, 0].max + (sqrt_steps * lg2).ceil
260
-
261
- sqrt_steps.times do
262
- x = x.sqrt(prec2)
316
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC
263
317
 
264
- # Workaround for https://github.com/ruby/bigdecimal/issues/354
265
- x = x.mult(1, prec2 + BigDecimal.double_fig)
266
- end
267
-
268
- # Taylor series for log(x) around 1
269
- # log(x) = -log((1 + X) / (1 - X)) where X = (x - 1) / (x + 1)
270
- # log(x) = 2 * (X + X**3 / 3 + X**5 / 5 + X**7 / 7 + ...)
271
- x = (x - 1).div(x + 1, prec2)
272
- y = x
273
- x2 = x.mult(x, prec)
274
- 1.step do |i|
275
- n = prec + x.exponent - y.exponent + x2.exponent
276
- break if n <= 0 || x.zero?
277
- x = x.mult(x2.round(n - x2.exponent), n)
278
- y = y.add(x.div(2 * i + 1, n), prec)
279
- end
318
+ # Reduce x to near 1
319
+ if x > 1.01 || x < 0.99
320
+ # log(x) = log(x/exp(logx_approx)) + logx_approx
321
+ logx_approx = BigDecimal(BigDecimal::Internal.float_log(x), 0)
322
+ x = x.div(exp(logx_approx, prec2), prec2)
323
+ else
324
+ logx_approx = BigDecimal(0)
325
+ end
280
326
 
281
- y.mult(2 ** (sqrt_steps + 1), prec)
327
+ # Solve exp(y) - x = 0 with Newton's method
328
+ # Repeat: y -= (exp(y) - x) / exp(y)
329
+ y = BigDecimal(BigDecimal::Internal.float_log(x), 0)
330
+ exp_additional_prec = [-(x - 1).exponent, 0].max
331
+ BigDecimal::Internal.newton_loop(prec2) do |p|
332
+ expy = exp(y, p + exp_additional_prec)
333
+ y = y.sub(expy.sub(x, p).div(expy, p), p)
282
334
  end
335
+ y.add(logx_approx, prec)
336
+ end
337
+
338
+ private_class_method def _exp_binary_splitting(x, prec) # :nodoc:
339
+ return BigDecimal(1) if x.zero?
340
+ # Find k that satisfies x**k / k! < 10**(-prec)
341
+ log10 = Math.log(10)
342
+ logx = BigDecimal::Internal.float_log(x.abs)
343
+ step = (1..).bsearch { |k| Math.lgamma(k + 1)[0] - k * logx > prec * log10 }
344
+ # exp(x)-1 = x*(1+x/2*(1+x/3*(1+x/4*(1+x/5*(1+...)))))
345
+ 1 + BigDecimal::Internal.taylor_sum_binary_splitting(x, [*1..step], prec)
283
346
  end
284
347
 
285
348
  # call-seq:
@@ -292,28 +355,32 @@ module BigMath
292
355
  #
293
356
  # If +decimal+ is NaN, returns NaN.
294
357
  #
295
- def self.exp(x, prec)
296
- BigDecimal::Internal.validate_prec(prec, :exp)
358
+ def exp(x, prec)
359
+ prec = BigDecimal::Internal.coerce_validate_prec(prec, :exp)
297
360
  x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :exp)
298
361
  return BigDecimal::Internal.nan_computation_result if x.nan?
299
362
  return x.positive? ? BigDecimal::Internal.infinity_computation_result : BigDecimal(0) if x.infinite?
300
363
  return BigDecimal(1) if x.zero?
301
- return BigDecimal(1).div(exp(-x, prec), prec) if x < 0
302
364
 
303
365
  # exp(x * 10**cnt) = exp(x)**(10**cnt)
304
- cnt = x > 1 ? x.exponent : 0
305
- prec2 = prec + BigDecimal.double_fig + cnt
366
+ cnt = x < -1 || x > 1 ? x.exponent : 0
367
+ prec2 = prec + BigDecimal::Internal::EXTRA_PREC + cnt
306
368
  x = x._decimal_shift(-cnt)
307
- xn = BigDecimal(1)
308
- y = BigDecimal(1)
309
369
 
310
- # Taylor series for exp(x) around 0
311
- 1.step do |i|
312
- n = prec2 + xn.exponent
313
- break if n <= 0 || xn.zero?
314
- x = x.mult(1, n)
315
- xn = xn.mult(x, n).div(i, n)
316
- y = y.add(xn, prec2)
370
+ # Decimal form of bit-burst algorithm
371
+ # Calculate exp(x.xxxxxxxxxxxxxxxx) as
372
+ # exp(x.xx) * exp(0.00xx) * exp(0.0000xxxx) * exp(0.00000000xxxxxxxx)
373
+ x = x.mult(1, prec2)
374
+ n = 2
375
+ y = BigDecimal(1)
376
+ BigDecimal.save_limit do
377
+ BigDecimal.limit(0)
378
+ while x != 0 do
379
+ partial_x = x.truncate(n)
380
+ x -= partial_x
381
+ y = y.mult(_exp_binary_splitting(partial_x, prec2), prec2)
382
+ n *= 2
383
+ end
317
384
  end
318
385
 
319
386
  # calculate exp(x * 10**cnt) from exp(x)
data/sample/linear.rb CHANGED
@@ -1,6 +1,3 @@
1
- #!/usr/local/bin/ruby
2
- # frozen_string_literal: false
3
-
4
1
  #
5
2
  # linear.rb
6
3
  #
@@ -13,62 +10,101 @@
13
10
 
14
11
  # :stopdoc:
15
12
  require "bigdecimal"
16
- require "bigdecimal/ludcmp"
17
13
 
18
- #
19
- # NOTE:
20
- # Change following BigDecimal.limit() if needed.
21
- BigDecimal.limit(100)
22
- #
14
+ # Requires gem matrix
15
+ require "matrix"
16
+
17
+ class PrecisionSpecifiedValue
18
+ # NOTE:
19
+ # Change following PREC if needed.
20
+
21
+ attr_reader :value
22
+ def initialize(value, prec)
23
+ @value = BigDecimal(value)
24
+ @prec = prec
25
+ end
26
+
27
+ def unwrap(value)
28
+ PrecisionSpecifiedValue === value ? value.value : value
29
+ end
30
+
31
+ def coerce(other)
32
+ [self.class.new(unwrap(other), @prec), self]
33
+ end
34
+
35
+ def abs
36
+ self.class.new(@value.abs, @prec)
37
+ end
38
+
39
+ def >(other)
40
+ @value > unwrap(other)
41
+ end
42
+
43
+ def <(other)
44
+ @value < unwrap(other)
45
+ end
46
+
47
+ def -(other)
48
+ self.class.new(@value.sub(unwrap(other), @prec), @prec)
49
+ end
50
+
51
+ def +(other)
52
+ self.class.new(@value.add(unwrap(other), @prec), @prec)
53
+ end
54
+
55
+ def *(other)
56
+ self.class.new(@value.mult(unwrap(other), @prec), @prec)
57
+ end
58
+
59
+ def quo(other)
60
+ self.class.new(@value.div(unwrap(other), @prec), @prec)
61
+ end
62
+ end
63
+
64
+ return if __FILE__ != $0
23
65
 
24
- include LUSolve
25
66
  def rd_order(na)
26
- printf("Number of equations ?") if(na <= 0)
27
- n = ARGF.gets().to_i
67
+ printf("Number of equations ?") if(na <= 0)
68
+ ARGF.gets().to_i
28
69
  end
29
70
 
30
- na = ARGV.size
31
- zero = BigDecimal("0.0")
32
- one = BigDecimal("1.0")
71
+ na = ARGV.size
33
72
 
34
73
  while (n=rd_order(na))>0
35
74
  a = []
36
- as= []
37
75
  b = []
38
76
  if na <= 0
39
77
  # Read data from console.
40
78
  printf("\nEnter coefficient matrix element A[i,j]\n")
41
79
  for i in 0...n do
42
- for j in 0...n do
80
+ a << n.times.map do |j|
43
81
  printf("A[%d,%d]? ",i,j); s = ARGF.gets
44
- a << BigDecimal(s)
45
- as << BigDecimal(s)
82
+ BigDecimal(s)
46
83
  end
47
84
  printf("Contatant vector element b[%d] ? ",i)
48
85
  b << BigDecimal(ARGF.gets)
49
86
  end
50
87
  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
88
+ # Read data from specified file.
89
+ printf("Coefficient matrix and constant vector.\n")
90
+ for i in 0...n do
91
+ s = ARGF.gets
92
+ printf("%d) %s",i,s)
93
+ s = s.split
94
+ a << n.times.map {|j| BigDecimal(s[j]) }
95
+ b << BigDecimal(s[n])
96
+ end
63
97
  end
64
- x = lusolve(a,b,ludecomp(a,n,zero,one),zero)
98
+
99
+ prec = 100
100
+ matrix = Matrix[*a.map {|row| row.map {|v| PrecisionSpecifiedValue.new(v, prec) } }]
101
+ vector = b.map {|v| PrecisionSpecifiedValue.new(v, prec) }
102
+ x = matrix.lup.solve(vector).map(&:value)
103
+
65
104
  printf("Answer(x[i] & (A*x-b)[i]) follows\n")
66
105
  for i in 0...n do
67
106
  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)
107
+ diff = a[i].zip(x).sum {|aij, xj| aij*xj }.sub(b[i], 10)
108
+ printf(" & %s\n", diff.to_s)
73
109
  end
74
110
  end