ed-precompiled_bigdecimal 3.3.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.
- checksums.yaml +7 -0
- data/LICENSE +56 -0
- data/bigdecimal.gemspec +57 -0
- data/ext/bigdecimal/bigdecimal.c +6238 -0
- data/ext/bigdecimal/bigdecimal.h +292 -0
- data/ext/bigdecimal/bits.h +144 -0
- data/ext/bigdecimal/extconf.rb +60 -0
- data/ext/bigdecimal/feature.h +68 -0
- data/ext/bigdecimal/missing/dtoa.c +3462 -0
- data/ext/bigdecimal/missing.c +28 -0
- data/ext/bigdecimal/missing.h +104 -0
- data/ext/bigdecimal/static_assert.h +54 -0
- data/lib/bigdecimal/jacobian.rb +90 -0
- data/lib/bigdecimal/ludcmp.rb +89 -0
- data/lib/bigdecimal/math.rb +249 -0
- data/lib/bigdecimal/newton.rb +80 -0
- data/lib/bigdecimal/util.rb +186 -0
- data/lib/bigdecimal.rb +361 -0
- data/sample/linear.rb +74 -0
- data/sample/nlsolve.rb +40 -0
- data/sample/pi.rb +21 -0
- metadata +66 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
#include <ruby/ruby.h>
|
2
|
+
|
3
|
+
#ifdef HAVE_RUBY_ATOMIC_H
|
4
|
+
# include <ruby/atomic.h>
|
5
|
+
#endif
|
6
|
+
|
7
|
+
#ifdef RUBY_ATOMIC_PTR_CAS
|
8
|
+
# define ATOMIC_PTR_CAS(var, old, new) RUBY_ATOMIC_PTR_CAS(var, old, new)
|
9
|
+
#endif
|
10
|
+
|
11
|
+
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
12
|
+
/* GCC warns about unknown sanitizer, which is annoying. */
|
13
|
+
# undef NO_SANITIZE
|
14
|
+
# define NO_SANITIZE(x, y) \
|
15
|
+
_Pragma("GCC diagnostic push") \
|
16
|
+
_Pragma("GCC diagnostic ignored \"-Wattributes\"") \
|
17
|
+
__attribute__((__no_sanitize__(x))) y; \
|
18
|
+
_Pragma("GCC diagnostic pop") \
|
19
|
+
y
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#undef strtod
|
23
|
+
#define strtod BigDecimal_strtod
|
24
|
+
#undef dtoa
|
25
|
+
#define dtoa BigDecimal_dtoa
|
26
|
+
#undef hdtoa
|
27
|
+
#define hdtoa BigDecimal_hdtoa
|
28
|
+
#include "missing/dtoa.c"
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#ifndef MISSING_H
|
2
|
+
#define MISSING_H 1
|
3
|
+
|
4
|
+
#if defined(__cplusplus)
|
5
|
+
extern "C" {
|
6
|
+
#if 0
|
7
|
+
} /* satisfy cc-mode */
|
8
|
+
#endif
|
9
|
+
#endif
|
10
|
+
|
11
|
+
#ifndef RB_UNUSED_VAR
|
12
|
+
# if defined(_MSC_VER) && _MSC_VER >= 1911
|
13
|
+
# define RB_UNUSED_VAR(x) x [[maybe_unused]]
|
14
|
+
|
15
|
+
# elif defined(__has_cpp_attribute) && __has_cpp_attribute(maybe_unused)
|
16
|
+
# define RB_UNUSED_VAR(x) x [[maybe_unused]]
|
17
|
+
|
18
|
+
# elif defined(__has_c_attribute) && __has_c_attribute(maybe_unused)
|
19
|
+
# define RB_UNUSED_VAR(x) x [[maybe_unused]]
|
20
|
+
|
21
|
+
# elif defined(__GNUC__)
|
22
|
+
# define RB_UNUSED_VAR(x) x __attribute__ ((unused))
|
23
|
+
|
24
|
+
# else
|
25
|
+
# define RB_UNUSED_VAR(x) x
|
26
|
+
# endif
|
27
|
+
#endif /* RB_UNUSED_VAR */
|
28
|
+
|
29
|
+
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
30
|
+
# define HAVE___ASSUME 1
|
31
|
+
|
32
|
+
#elif defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300
|
33
|
+
# define HAVE___ASSUME 1
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#ifndef UNREACHABLE
|
37
|
+
# if __has_builtin(__builtin_unreachable)
|
38
|
+
# define UNREACHABLE __builtin_unreachable()
|
39
|
+
|
40
|
+
# elif defined(HAVE___ASSUME)
|
41
|
+
# define UNREACHABLE __assume(0)
|
42
|
+
|
43
|
+
# else
|
44
|
+
# define UNREACHABLE /* unreachable */
|
45
|
+
# endif
|
46
|
+
#endif /* UNREACHABLE */
|
47
|
+
|
48
|
+
/* bool */
|
49
|
+
|
50
|
+
#ifndef __bool_true_false_are_defined
|
51
|
+
# include <stdbool.h>
|
52
|
+
#endif
|
53
|
+
|
54
|
+
/* dtoa */
|
55
|
+
char *BigDecimal_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
|
56
|
+
|
57
|
+
/* complex */
|
58
|
+
|
59
|
+
#ifndef HAVE_RB_COMPLEX_REAL
|
60
|
+
static inline VALUE
|
61
|
+
rb_complex_real(VALUE cmp)
|
62
|
+
{
|
63
|
+
#ifdef RCOMPLEX
|
64
|
+
return RCOMPLEX(cmp)->real;
|
65
|
+
#else
|
66
|
+
return rb_funcall(cmp, rb_intern("real"), 0);
|
67
|
+
#endif
|
68
|
+
}
|
69
|
+
#endif
|
70
|
+
|
71
|
+
#ifndef HAVE_RB_COMPLEX_IMAG
|
72
|
+
static inline VALUE
|
73
|
+
rb_complex_imag(VALUE cmp)
|
74
|
+
{
|
75
|
+
# ifdef RCOMPLEX
|
76
|
+
return RCOMPLEX(cmp)->imag;
|
77
|
+
# else
|
78
|
+
return rb_funcall(cmp, rb_intern("imag"), 0);
|
79
|
+
# endif
|
80
|
+
}
|
81
|
+
#endif
|
82
|
+
|
83
|
+
/* st */
|
84
|
+
|
85
|
+
#ifndef ST2FIX
|
86
|
+
# undef RB_ST2FIX
|
87
|
+
# define RB_ST2FIX(h) LONG2FIX((long)(h))
|
88
|
+
# define ST2FIX(h) RB_ST2FIX(h)
|
89
|
+
#endif
|
90
|
+
|
91
|
+
/* warning */
|
92
|
+
|
93
|
+
#if !defined(HAVE_RB_CATEGORY_WARN) || !defined(HAVE_CONST_RB_WARN_CATEGORY_DEPRECATED)
|
94
|
+
# define rb_category_warn(category, ...) rb_warn(__VA_ARGS__)
|
95
|
+
#endif
|
96
|
+
|
97
|
+
#if defined(__cplusplus)
|
98
|
+
#if 0
|
99
|
+
{ /* satisfy cc-mode */
|
100
|
+
#endif
|
101
|
+
} /* extern "C" { */
|
102
|
+
#endif
|
103
|
+
|
104
|
+
#endif /* MISSING_H */
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#ifndef BIGDECIMAL_STATIC_ASSERT_H
|
2
|
+
#define BIGDECIMAL_STATIC_ASSERT_H
|
3
|
+
|
4
|
+
#include "feature.h"
|
5
|
+
|
6
|
+
#ifdef HAVE_RUBY_INTERNAL_STATIC_ASSERT_H
|
7
|
+
# include <ruby/internal/static_assert.h>
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#ifdef RBIMPL_STATIC_ASSERT
|
11
|
+
# define STATIC_ASSERT RBIMPL_STATIC_ASSERT
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifndef STATIC_ASSERT
|
15
|
+
# /* The following section is copied from CRuby's static_assert.h */
|
16
|
+
|
17
|
+
# if defined(__cplusplus) && defined(__cpp_static_assert)
|
18
|
+
# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
|
19
|
+
# define BIGDECIMAL_STATIC_ASSERT0 static_assert
|
20
|
+
|
21
|
+
# elif defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER >= 1600
|
22
|
+
# define BIGDECIMAL_STATIC_ASSERT0 static_assert
|
23
|
+
|
24
|
+
# elif defined(__INTEL_CXX11_MODE__)
|
25
|
+
# define BIGDECIMAL_STATIC_ASSERT0 static_assert
|
26
|
+
|
27
|
+
# elif defined(__cplusplus) && __cplusplus >= 201103L
|
28
|
+
# define BIGDECIMAL_STATIC_ASSERT0 static_assert
|
29
|
+
|
30
|
+
# elif defined(__cplusplus) && __has_extension(cxx_static_assert)
|
31
|
+
# define BIGDECIMAL_STATIC_ASSERT0 __extension__ static_assert
|
32
|
+
|
33
|
+
# elif defined(__STDC_VERSION__) && __has_extension(c_static_assert)
|
34
|
+
# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
|
35
|
+
|
36
|
+
# elif defined(__STDC_VERSION__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
37
|
+
# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
|
38
|
+
#endif
|
39
|
+
|
40
|
+
# if defined(__DOXYGEN__)
|
41
|
+
# define STATIC_ASSERT static_assert
|
42
|
+
|
43
|
+
# elif defined(BIGDECIMAL_STATIC_ASSERT0)
|
44
|
+
# define STATIC_ASSERT(name, expr) \
|
45
|
+
BIGDECIMAL_STATIC_ASSERT0(expr, #name ": " #expr)
|
46
|
+
|
47
|
+
# else
|
48
|
+
# define STATIC_ASSERT(name, expr) \
|
49
|
+
typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
|
50
|
+
# endif
|
51
|
+
#endif /* STATIC_ASSERT */
|
52
|
+
|
53
|
+
|
54
|
+
#endif /* BIGDECIMAL_STATIC_ASSERT_H */
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
|
5
|
+
# require 'bigdecimal/jacobian'
|
6
|
+
#
|
7
|
+
# Provides methods to compute the Jacobian matrix of a set of equations at a
|
8
|
+
# point x. In the methods below:
|
9
|
+
#
|
10
|
+
# f is an Object which is used to compute the Jacobian matrix of the equations.
|
11
|
+
# It must provide the following methods:
|
12
|
+
#
|
13
|
+
# f.values(x):: returns the values of all functions at x
|
14
|
+
#
|
15
|
+
# f.zero:: returns 0.0
|
16
|
+
# f.one:: returns 1.0
|
17
|
+
# f.two:: returns 2.0
|
18
|
+
# f.ten:: returns 10.0
|
19
|
+
#
|
20
|
+
# 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.
|
21
|
+
#
|
22
|
+
# x is the point at which to compute the Jacobian.
|
23
|
+
#
|
24
|
+
# fx is f.values(x).
|
25
|
+
#
|
26
|
+
module Jacobian
|
27
|
+
module_function
|
28
|
+
|
29
|
+
# Determines the equality of two numbers by comparing to zero, or using the epsilon value
|
30
|
+
def isEqual(a,b,zero=0.0,e=1.0e-8)
|
31
|
+
aa = a.abs
|
32
|
+
bb = b.abs
|
33
|
+
if aa == zero && bb == zero then
|
34
|
+
true
|
35
|
+
else
|
36
|
+
if ((a-b)/(aa+bb)).abs < e then
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Computes the derivative of +f[i]+ at +x[i]+.
|
46
|
+
# +fx+ is the value of +f+ at +x+.
|
47
|
+
def dfdxi(f,fx,x,i)
|
48
|
+
nRetry = 0
|
49
|
+
n = x.size
|
50
|
+
xSave = x[i]
|
51
|
+
ok = 0
|
52
|
+
ratio = f.ten*f.ten*f.ten
|
53
|
+
dx = x[i].abs/ratio
|
54
|
+
dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps)
|
55
|
+
dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps)
|
56
|
+
until ok>0 do
|
57
|
+
deriv = []
|
58
|
+
nRetry += 1
|
59
|
+
if nRetry > 100
|
60
|
+
raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]"
|
61
|
+
end
|
62
|
+
dx = dx*f.two
|
63
|
+
x[i] += dx
|
64
|
+
fxNew = f.values(x)
|
65
|
+
for j in 0...n do
|
66
|
+
if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then
|
67
|
+
ok += 1
|
68
|
+
deriv <<= (fxNew[j]-fx[j])/dx
|
69
|
+
else
|
70
|
+
deriv <<= f.zero
|
71
|
+
end
|
72
|
+
end
|
73
|
+
x[i] = xSave
|
74
|
+
end
|
75
|
+
deriv
|
76
|
+
end
|
77
|
+
|
78
|
+
# Computes the Jacobian of +f+ at +x+. +fx+ is the value of +f+ at +x+.
|
79
|
+
def jacobian(f,fx,x)
|
80
|
+
n = x.size
|
81
|
+
dfdx = Array.new(n*n)
|
82
|
+
for i in 0...n do
|
83
|
+
df = dfdxi(f,fx,x,i)
|
84
|
+
for j in 0...n do
|
85
|
+
dfdx[j*n+i] = df[j]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
dfdx
|
89
|
+
end
|
90
|
+
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,249 @@
|
|
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
|
+
# tan (x, prec)
|
11
|
+
# atan(x, prec)
|
12
|
+
# PI (prec)
|
13
|
+
# E (prec) == exp(1.0,prec)
|
14
|
+
#
|
15
|
+
# where:
|
16
|
+
# x ... BigDecimal number to be computed.
|
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(49)/2).to_s)
|
29
|
+
# puts sin(a,100) # => 0.9999999999...9999999986e0
|
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'), 32).to_s
|
41
|
+
# #=> "0.14142135623730950488016887242097e1"
|
42
|
+
#
|
43
|
+
def sqrt(x, prec)
|
44
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :sqrt)
|
45
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sqrt)
|
46
|
+
x.sqrt(prec)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Returns [sign, reduced_x] where reduced_x is in -pi/2..pi/2
|
51
|
+
# and satisfies sin(x) = sign * sin(reduced_x)
|
52
|
+
# If add_half_pi is true, adds pi/2 to x before reduction.
|
53
|
+
# Precision of pi is adjusted to ensure reduced_x has the required precision.
|
54
|
+
private_class_method def _sin_periodic_reduction(x, prec, add_half_pi: false) # :nodoc:
|
55
|
+
return [1, x] if -Math::PI/2 <= x && x <= Math::PI/2 && !add_half_pi
|
56
|
+
|
57
|
+
mod_prec = prec + BigDecimal.double_fig
|
58
|
+
pi_extra_prec = [x.exponent, 0].max + BigDecimal.double_fig
|
59
|
+
while true
|
60
|
+
pi = PI(mod_prec + pi_extra_prec)
|
61
|
+
half_pi = pi / 2
|
62
|
+
div, mod = (add_half_pi ? x + pi : x + half_pi).divmod(pi)
|
63
|
+
mod -= half_pi
|
64
|
+
if mod.zero? || mod_prec + mod.exponent <= 0
|
65
|
+
# mod is too small to estimate required pi precision
|
66
|
+
mod_prec = mod_prec * 3 / 2 + BigDecimal.double_fig
|
67
|
+
elsif mod_prec + mod.exponent < prec
|
68
|
+
# Estimate required precision of pi
|
69
|
+
mod_prec = prec - mod.exponent + BigDecimal.double_fig
|
70
|
+
else
|
71
|
+
return [div % 2 == 0 ? 1 : -1, mod.mult(1, prec)]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# call-seq:
|
77
|
+
# sin(decimal, numeric) -> BigDecimal
|
78
|
+
#
|
79
|
+
# Computes the sine of +decimal+ to the specified number of digits of
|
80
|
+
# precision, +numeric+.
|
81
|
+
#
|
82
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
83
|
+
#
|
84
|
+
# BigMath.sin(BigMath.PI(5)/4, 32).to_s
|
85
|
+
# #=> "0.70710807985947359435812921837984e0"
|
86
|
+
#
|
87
|
+
def sin(x, prec)
|
88
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :sin)
|
89
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :sin)
|
90
|
+
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
91
|
+
n = prec + BigDecimal.double_fig
|
92
|
+
one = BigDecimal("1")
|
93
|
+
two = BigDecimal("2")
|
94
|
+
sign, x = _sin_periodic_reduction(x, n)
|
95
|
+
x1 = x
|
96
|
+
x2 = x.mult(x,n)
|
97
|
+
y = x
|
98
|
+
d = y
|
99
|
+
i = one
|
100
|
+
z = one
|
101
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
102
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
103
|
+
x1 = -x2.mult(x1,n)
|
104
|
+
i += two
|
105
|
+
z *= (i-one) * i
|
106
|
+
d = x1.div(z,m)
|
107
|
+
y += d
|
108
|
+
end
|
109
|
+
y = BigDecimal("1") if y > 1
|
110
|
+
y.mult(sign, prec)
|
111
|
+
end
|
112
|
+
|
113
|
+
# call-seq:
|
114
|
+
# cos(decimal, numeric) -> BigDecimal
|
115
|
+
#
|
116
|
+
# Computes the cosine of +decimal+ to the specified number of digits of
|
117
|
+
# precision, +numeric+.
|
118
|
+
#
|
119
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
120
|
+
#
|
121
|
+
# BigMath.cos(BigMath.PI(16), 32).to_s
|
122
|
+
# #=> "-0.99999999999999999999999999999997e0"
|
123
|
+
#
|
124
|
+
def cos(x, prec)
|
125
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :cos)
|
126
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :cos)
|
127
|
+
return BigDecimal::Internal.nan_computation_result if x.infinite? || x.nan?
|
128
|
+
sign, x = _sin_periodic_reduction(x, prec + BigDecimal.double_fig, add_half_pi: true)
|
129
|
+
sign * sin(x, prec)
|
130
|
+
end
|
131
|
+
|
132
|
+
# call-seq:
|
133
|
+
# tan(decimal, numeric) -> BigDecimal
|
134
|
+
#
|
135
|
+
# Computes the tangent of +decimal+ to the specified number of digits of
|
136
|
+
# precision, +numeric+.
|
137
|
+
#
|
138
|
+
# If +decimal+ is Infinity or NaN, returns NaN.
|
139
|
+
#
|
140
|
+
# BigMath.tan(BigDecimal("0.0"), 4).to_s
|
141
|
+
# #=> "0.0"
|
142
|
+
#
|
143
|
+
# BigMath.tan(BigMath.PI(24) / 4, 32).to_s
|
144
|
+
# #=> "0.99999999999999999999999830836025e0"
|
145
|
+
#
|
146
|
+
def tan(x, prec)
|
147
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :tan)
|
148
|
+
sin(x, prec + BigDecimal.double_fig).div(cos(x, prec + BigDecimal.double_fig), prec)
|
149
|
+
end
|
150
|
+
|
151
|
+
# call-seq:
|
152
|
+
# atan(decimal, numeric) -> BigDecimal
|
153
|
+
#
|
154
|
+
# Computes the arctangent of +decimal+ to the specified number of digits of
|
155
|
+
# precision, +numeric+.
|
156
|
+
#
|
157
|
+
# If +decimal+ is NaN, returns NaN.
|
158
|
+
#
|
159
|
+
# BigMath.atan(BigDecimal('-1'), 32).to_s
|
160
|
+
# #=> "-0.78539816339744830961566084581988e0"
|
161
|
+
#
|
162
|
+
def atan(x, prec)
|
163
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :atan)
|
164
|
+
x = BigDecimal::Internal.coerce_to_bigdecimal(x, prec, :atan)
|
165
|
+
return BigDecimal::Internal.nan_computation_result if x.nan?
|
166
|
+
n = prec + BigDecimal.double_fig
|
167
|
+
pi = PI(n)
|
168
|
+
x = -x if neg = x < 0
|
169
|
+
return pi.div(neg ? -2 : 2, prec) if x.infinite?
|
170
|
+
return pi.div(neg ? -4 : 4, prec) if x.round(prec) == 1
|
171
|
+
x = BigDecimal("1").div(x, n) if inv = x > 1
|
172
|
+
x = (-1 + sqrt(1 + x.mult(x, n), n)).div(x, n) if dbl = x > 0.5
|
173
|
+
y = x
|
174
|
+
d = y
|
175
|
+
t = x
|
176
|
+
r = BigDecimal("3")
|
177
|
+
x2 = x.mult(x,n)
|
178
|
+
while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
|
179
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
180
|
+
t = -t.mult(x2,n)
|
181
|
+
d = t.div(r,m)
|
182
|
+
y += d
|
183
|
+
r += 2
|
184
|
+
end
|
185
|
+
y *= 2 if dbl
|
186
|
+
y = pi / 2 - y if inv
|
187
|
+
y = -y if neg
|
188
|
+
y.mult(1, prec)
|
189
|
+
end
|
190
|
+
|
191
|
+
# call-seq:
|
192
|
+
# PI(numeric) -> BigDecimal
|
193
|
+
#
|
194
|
+
# Computes the value of pi to the specified number of digits of precision,
|
195
|
+
# +numeric+.
|
196
|
+
#
|
197
|
+
# BigMath.PI(32).to_s
|
198
|
+
# #=> "0.31415926535897932384626433832795e1"
|
199
|
+
#
|
200
|
+
def PI(prec)
|
201
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :PI)
|
202
|
+
n = prec + BigDecimal.double_fig
|
203
|
+
zero = BigDecimal("0")
|
204
|
+
one = BigDecimal("1")
|
205
|
+
two = BigDecimal("2")
|
206
|
+
|
207
|
+
m25 = BigDecimal("-0.04")
|
208
|
+
m57121 = BigDecimal("-57121")
|
209
|
+
|
210
|
+
pi = zero
|
211
|
+
|
212
|
+
d = one
|
213
|
+
k = one
|
214
|
+
t = BigDecimal("-80")
|
215
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
216
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
217
|
+
t = t*m25
|
218
|
+
d = t.div(k,m)
|
219
|
+
k = k+two
|
220
|
+
pi = pi + d
|
221
|
+
end
|
222
|
+
|
223
|
+
d = one
|
224
|
+
k = one
|
225
|
+
t = BigDecimal("956")
|
226
|
+
while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
|
227
|
+
m = BigDecimal.double_fig if m < BigDecimal.double_fig
|
228
|
+
t = t.div(m57121,n)
|
229
|
+
d = t.div(k,m)
|
230
|
+
pi = pi + d
|
231
|
+
k = k+two
|
232
|
+
end
|
233
|
+
pi.mult(1, prec)
|
234
|
+
end
|
235
|
+
|
236
|
+
# call-seq:
|
237
|
+
# E(numeric) -> BigDecimal
|
238
|
+
#
|
239
|
+
# Computes e (the base of natural logarithms) to the specified number of
|
240
|
+
# digits of precision, +numeric+.
|
241
|
+
#
|
242
|
+
# BigMath.E(32).to_s
|
243
|
+
# #=> "0.27182818284590452353602874713527e1"
|
244
|
+
#
|
245
|
+
def E(prec)
|
246
|
+
prec = BigDecimal::Internal.coerce_validate_prec(prec, :E)
|
247
|
+
BigMath.exp(1, prec)
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require "bigdecimal/ludcmp"
|
3
|
+
require "bigdecimal/jacobian"
|
4
|
+
|
5
|
+
#
|
6
|
+
# newton.rb
|
7
|
+
#
|
8
|
+
# Solves the nonlinear algebraic equation system f = 0 by Newton's method.
|
9
|
+
# This program is not dependent on BigDecimal.
|
10
|
+
#
|
11
|
+
# To call:
|
12
|
+
# n = nlsolve(f,x)
|
13
|
+
# where n is the number of iterations required,
|
14
|
+
# x is the initial value vector
|
15
|
+
# f is an Object which is used to compute the values of the equations to be solved.
|
16
|
+
# It must provide the following methods:
|
17
|
+
#
|
18
|
+
# f.values(x):: returns the values of all functions at x
|
19
|
+
#
|
20
|
+
# f.zero:: returns 0.0
|
21
|
+
# f.one:: returns 1.0
|
22
|
+
# f.two:: returns 2.0
|
23
|
+
# f.ten:: returns 10.0
|
24
|
+
#
|
25
|
+
# 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.
|
26
|
+
#
|
27
|
+
# On exit, x is the solution vector.
|
28
|
+
#
|
29
|
+
module Newton
|
30
|
+
include LUSolve
|
31
|
+
include Jacobian
|
32
|
+
module_function
|
33
|
+
|
34
|
+
def norm(fv,zero=0.0) # :nodoc:
|
35
|
+
s = zero
|
36
|
+
n = fv.size
|
37
|
+
for i in 0...n do
|
38
|
+
s += fv[i]*fv[i]
|
39
|
+
end
|
40
|
+
s
|
41
|
+
end
|
42
|
+
|
43
|
+
# See also Newton
|
44
|
+
def nlsolve(f,x)
|
45
|
+
nRetry = 0
|
46
|
+
n = x.size
|
47
|
+
|
48
|
+
f0 = f.values(x)
|
49
|
+
zero = f.zero
|
50
|
+
one = f.one
|
51
|
+
two = f.two
|
52
|
+
p5 = one/two
|
53
|
+
d = norm(f0,zero)
|
54
|
+
minfact = f.ten*f.ten*f.ten
|
55
|
+
minfact = one/minfact
|
56
|
+
e = f.eps
|
57
|
+
while d >= e do
|
58
|
+
nRetry += 1
|
59
|
+
# Not yet converged. => Compute Jacobian matrix
|
60
|
+
dfdx = jacobian(f,f0,x)
|
61
|
+
# Solve dfdx*dx = -f0 to estimate dx
|
62
|
+
dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero)
|
63
|
+
fact = two
|
64
|
+
xs = x.dup
|
65
|
+
begin
|
66
|
+
fact *= p5
|
67
|
+
if fact < minfact then
|
68
|
+
raise "Failed to reduce function values."
|
69
|
+
end
|
70
|
+
for i in 0...n do
|
71
|
+
x[i] = xs[i] - dx[i]*fact
|
72
|
+
end
|
73
|
+
f0 = f.values(x)
|
74
|
+
dn = norm(f0,zero)
|
75
|
+
end while(dn>=d)
|
76
|
+
d = dn
|
77
|
+
end
|
78
|
+
nRetry
|
79
|
+
end
|
80
|
+
end
|