bigdecimal-fix 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: false
2
+ require 'mkmf'
3
+
4
+ checking_for(checking_message("Windows")) do
5
+ case RUBY_PLATFORM
6
+ when /cygwin|mingw/
7
+ if ARGV.include?('-rdevkit') # check `rake -rdevkit compile` case
8
+ base_dir = File.expand_path('../../../..', __FILE__)
9
+ build_dir = File.join(base_dir, "tmp", RUBY_PLATFORM, "bigdecimal", RUBY_VERSION, "")
10
+ else
11
+ build_dir = "$(TARGET_SO_DIR)../"
12
+ end
13
+ $libs << " #{build_dir}bigdecimal.so"
14
+ true
15
+ when /mswin/
16
+ $DLDFLAGS << " -libpath:.."
17
+ $libs << " bigdecimal-$(arch).lib"
18
+ true
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ create_makefile('bigdecimal/util')
@@ -0,0 +1,9 @@
1
+ #include "ruby.h"
2
+
3
+ RUBY_EXTERN VALUE rmpd_util_str_to_d(VALUE str);
4
+
5
+ void
6
+ Init_util(void)
7
+ {
8
+ rb_define_method(rb_cString, "to_d", rmpd_util_str_to_d, 0);
9
+ }
@@ -0,0 +1,22 @@
1
+ begin
2
+ require "#{RUBY_VERSION[/\d+\.\d+/]}/bigdecimal.so"
3
+ rescue LoadError
4
+ require 'bigdecimal.so'
5
+ end
6
+
7
+ class BigDecimal
8
+ module Deprecation
9
+ def new(*args, **kwargs)
10
+ warn "BigDecimal.new is deprecated; use BigDecimal() method instead.", uplevel: 1
11
+ super
12
+ end
13
+ end
14
+
15
+ class << self
16
+ prepend Deprecation
17
+
18
+ def inherited(subclass)
19
+ warn "subclassing BigDecimal will be disallowed after bigdecimal version 2.0", uplevel: 1
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # require 'bigdecimal/jacobian'
4
+ #
5
+ # Provides methods to compute the Jacobian matrix of a set of equations at a
6
+ # point x. In the methods below:
7
+ #
8
+ # f is an Object which is used to compute the Jacobian matrix of the equations.
9
+ # It must provide the following methods:
10
+ #
11
+ # f.values(x):: returns the values of all functions at x
12
+ #
13
+ # f.zero:: returns 0.0
14
+ # f.one:: returns 1.0
15
+ # f.two:: returns 2.0
16
+ # f.ten:: returns 10.0
17
+ #
18
+ # 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.
19
+ #
20
+ # x is the point at which to compute the Jacobian.
21
+ #
22
+ # fx is f.values(x).
23
+ #
24
+
25
+ require 'bigdecimal'
26
+
27
+ module Jacobian
28
+ module_function
29
+
30
+ # Determines the equality of two numbers by comparing to zero, or using the epsilon value
31
+ def isEqual(a,b,zero=0.0,e=1.0e-8)
32
+ aa = a.abs
33
+ bb = b.abs
34
+ if aa == zero && bb == zero then
35
+ true
36
+ else
37
+ if ((a-b)/(aa+bb)).abs < e then
38
+ true
39
+ else
40
+ false
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ # Computes the derivative of f[i] at x[i].
47
+ # fx is the value of f at x.
48
+ def dfdxi(f,fx,x,i)
49
+ nRetry = 0
50
+ n = x.size
51
+ xSave = x[i]
52
+ ok = 0
53
+ ratio = f.ten*f.ten*f.ten
54
+ dx = x[i].abs/ratio
55
+ dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps)
56
+ dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps)
57
+ until ok>0 do
58
+ deriv = []
59
+ nRetry += 1
60
+ if nRetry > 100
61
+ raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]"
62
+ end
63
+ dx = dx*f.two
64
+ x[i] += dx
65
+ fxNew = f.values(x)
66
+ for j in 0...n do
67
+ if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then
68
+ ok += 1
69
+ deriv <<= (fxNew[j]-fx[j])/dx
70
+ else
71
+ deriv <<= f.zero
72
+ end
73
+ end
74
+ x[i] = xSave
75
+ end
76
+ deriv
77
+ end
78
+
79
+ # Computes the Jacobian of f at x. fx is the value of f at x.
80
+ def jacobian(f,fx,x)
81
+ n = x.size
82
+ dfdx = Array.new(n*n)
83
+ for i in 0...n do
84
+ df = dfdxi(f,fx,x,i)
85
+ for j in 0...n do
86
+ dfdx[j*n+i] = df[j]
87
+ end
88
+ end
89
+ dfdx
90
+ end
91
+ 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