Module: MyMathGem::Calculus

Defined in:
lib/my_math_gem/calculus.rb

Class Method Summary collapse

Class Method Details

.adaptive_integral(f, a, b, tol = 1e-6, max_recursion = 20) ⇒ Object

Integral adaptif sederhana menggunakan recursive Simpson’s rule

Raises:

  • (ArgumentError)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/my_math_gem/calculus.rb', line 33

def self.adaptive_integral(f, a, b, tol=1e-6, max_recursion=20)
  raise ArgumentError, "f harus callable" unless f.respond_to?(:call)

  simpson = ->(fa, fm, fb, h) { h * (fa + 4*fm + fb) / 6.0 }

  recursive_adaptive = lambda do |f, a, b, fa, fm, fb, integral, tol, depth|
    mid = (a + b) / 2.0
    f1 = f.call((a + mid) / 2.0)
    f2 = f.call((mid + b) / 2.0)
    left = simpson.call(fa, f1, fm, (mid - a))
    right = simpson.call(fm, f2, fb, (b - mid))
    if depth >= max_recursion || (left + right - integral).abs < 15 * tol
      return left + right + (left + right - integral) / 15.0
    else
      left_int = recursive_adaptive.call(f, a, mid, fa, f1, fm, left, tol/2, depth + 1)
      right_int = recursive_adaptive.call(f, mid, b, fm, f2, fb, right, tol/2, depth + 1)
      left_int + right_int
    end
  end

  fa = f.call(a)
  fb = f.call(b)
  mid = (a + b) / 2.0
  fm = f.call(mid)
  initial = simpson.call(fa, fm, fb, (b - a))

  recursive_adaptive.call(f, a, b, fa, fm, fb, initial, tol, 0)
end

.derivative(f, x, h = 1e-5, method = :central) ⇒ Object

Turunan numerik standar fungsi f di titik x Metode: :central (default), :forward, :backward

Raises:

  • (ArgumentError)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/my_math_gem/calculus.rb', line 64

def self.derivative(f, x, h=1e-5, method=:central)
  raise ArgumentError, "f harus callable" unless f.respond_to?(:call)

  case method
  when :central
    (f.call(x + h) - f.call(x - h)) / (2 * h)
  when :forward
    (f.call(x + h) - f.call(x)) / h
  when :backward
    (f.call(x) - f.call(x - h)) / h
  else
    raise ArgumentError, "Method tidak valid. Gunakan :central, :forward, atau :backward"
  end
end

.derivative_n(f, x, n = 1, h = 1e-5) ⇒ Object

Turunan orde n menggunakan finite difference (central difference)

Raises:

  • (ArgumentError)


4
5
6
7
8
9
10
11
12
13
14
15
16
# File 'lib/my_math_gem/calculus.rb', line 4

def self.derivative_n(f, x, n=1, h=1e-5)
  raise ArgumentError, "n harus positif integer" unless n.is_a?(Integer) && n > 0
  raise ArgumentError, "f harus callable" unless f.respond_to?(:call)

  # Turunan orde 1
  if n == 1
    return derivative(f, x, h, :central)
  end

  # Rekursif turunan orde lebih tinggi
  lower_order = ->(t) { derivative_n(f, t, n - 1, h) }
  derivative(lower_order, x, h, :central)
end

.integral(f, a, b, n = 1000, method = :trapezoid) ⇒ Object

Integral numerik fungsi f dari a ke b Metode: :trapezoid (default) atau :simpson n = jumlah segmen, genap jika pakai Simpson

Raises:

  • (ArgumentError)


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/my_math_gem/calculus.rb', line 82

def self.integral(f, a, b, n=1000, method=:trapezoid)
  raise ArgumentError, "f harus callable" unless f.respond_to?(:call)
  raise ArgumentError, "n harus positif integer" unless n.is_a?(Integer) && n > 0
  raise ArgumentError, "Untuk Simpson, n harus genap" if method == :simpson && n.odd?

  case method
  when :trapezoid
    dx = (b - a).to_f / n
    total = 0.0
    n.times do |i|
      x0 = a + i * dx
      x1 = x0 + dx
      total += 0.5 * (f.call(x0) + f.call(x1)) * dx
    end
    total

  when :simpson
    dx = (b - a).to_f / n
    sum = f.call(a) + f.call(b)
    (1...n).each do |i|
      x = a + i * dx
      weight = i.odd? ? 4 : 2
      sum += weight * f.call(x)
    end
    (dx / 3) * sum

  else
    raise ArgumentError, "Method tidak valid. Gunakan :trapezoid atau :simpson"
  end
end

.partial_derivative(f, args, var_idx, h = 1e-5) ⇒ Object

Turunan parsial fungsi multivariabel f, terhadap variabel index var_idx (0-based) args = array nilai input [x,y,z,…]

Raises:

  • (ArgumentError)


20
21
22
23
24
25
26
27
28
29
30
# File 'lib/my_math_gem/calculus.rb', line 20

def self.partial_derivative(f, args, var_idx, h=1e-5)
  raise ArgumentError, "f harus callable" unless f.respond_to?(:call)
  raise ArgumentError, "args harus array" unless args.is_a?(Array)
  raise ArgumentError, "var_idx di luar jangkauan" unless var_idx.between?(0, args.length-1)

  args_forward = args.dup
  args_backward = args.dup
  args_forward[var_idx] += h
  args_backward[var_idx] -= h
  (f.call(*args_forward) - f.call(*args_backward)) / (2 * h)
end