bigdecimal-fix 1.4.4

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,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