class Silicium::NumericalIntegration

A class providing numerical integration methods

Public Class Methods

left_rect_integration(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the Left Rectangles method from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 58
def self.left_rect_integration(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :left_rect_integration_n, &block)
end
left_rect_integration_n(a, b, n, &block) click to toggle source

Computes integral by the Left Rectangles method from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 65
def self.left_rect_integration_n(a, b, n, &block)
  dx = (b - a) / n.to_f
  amount_calculation(a, [0, n], dx, &block)
end
middle_rectangles(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the Middle Rectangles method from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 102
def self.middle_rectangles(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :middle_rectangles_with_a_segment, &block)
end
middle_rectangles_with_a_segment(a, b, n, &block) click to toggle source

Computes integral by the Middle Rectangles method from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 88
def self.middle_rectangles_with_a_segment(a, b, n, &block)
  dx = (b - a) / n.to_f
  result = 0
  i = 0
  n.times do
    result += block.call(a + dx * (i + 1 / 2)) * dx
    i += 1
  end
  result
end
right_rect_integration(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the Right Rectangles method from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 73
def self.right_rect_integration(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :right_rect_integration_n, &block)
end
right_rect_integration_n(a, b, n, &block) click to toggle source

Computes integral by the Right Rectangles method from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 80
def self.right_rect_integration_n(a, b, n, &block)
  dx = (b - a) / n.to_f
  amount_calculation(a, [1, n + 1], dx, &block)
end
simpson_integration(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the Simpson's rule from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 51
def self.simpson_integration(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :simpson_integration_with_a_segment, &block)
end
simpson_integration_with_a_segment(a, b, n, &block) click to toggle source

Computes integral by the Simpson's rule from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 36
def self.simpson_integration_with_a_segment(a, b, n, &block)
  dx = (b - a) / n.to_f
  result = 0
  i = 0
  while i < n
    result += (block.call(a + i * dx) + 4 * block.call(((a + i * dx) +
        (a + (i + 1) * dx)) / 2.0) + block.call(a + (i + 1) * dx)) / 6.0 * dx
    i += 1
  end
  result
end
three_eights_integration(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the 3/8 rule from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 13
def self.three_eights_integration(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :three_eights_integration_n, &block)
end
three_eights_integration_n(a, b, n, &block) click to toggle source

Computes integral by the 3/8 rule from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 20
def self.three_eights_integration_n(a, b, n, &block)
  dx = (b - a) / n.to_f
  result = 0
  x = a
  n.times do
    result +=
      (block.call(x) + 3 * block.call((2 * x + x + dx) / 3.0) +
          3 * block.call((x + 2 * (x + dx)) / 3.0) + block.call(x + dx)) / 8.0 * dx
    x += dx
  end
  result
end
trapezoid(a, b, eps = 0.0001, &block) click to toggle source

Computes integral by the Trapezoid method from a to b of block with accuracy eps

# File lib/numerical_integration.rb, line 124
def self.trapezoid(a, b, eps = 0.0001, &block)
  wrapper_method([a, b], eps, :trapezoid_with_a_segment ,&block)
end
trapezoid_with_a_segment(a, b, n, &block) click to toggle source

Computes integral by the Trapezoid method from a to b of block with n segmentations

# File lib/numerical_integration.rb, line 109
def self.trapezoid_with_a_segment(a, b, n, &block)
  dx = (b - a) / n.to_f
  result = 0
  i = 1
  (n - 1).times do
    result += block.call(a + dx * i)
    i += 1
  end
  result += (block.call(a) + block.call(b)) / 2.0
  result * dx
end

Private Class Methods

amount_calculation(a, i_n, dx, &block) click to toggle source

Computes the sum of n rectangles on a segment of length dx at points of the form a + i * dx @param [Numeric] a - first division point @param [Array] i_n number of divisions @param [Numeric] dx - length of integration segment @param [Block] block - integrated function as Block

# File lib/numerical_integration.rb, line 173
def self.amount_calculation(a, i_n, dx, &block)
  result = 0
  while i_n[0] < i_n[1]
    result += block.call(a + i_n[0] * dx)
    i_n[0] += 1
  end
  result * dx
end
check_value(value) click to toggle source
# File lib/numerical_integration.rb, line 157
def self.check_value(value)
  if value.nan?
    raise IntegralDoesntExistError, 'We have not-a-number result :('
  end
  if value == Float::INFINITY
    raise IntegralDoesntExistError, 'We have infinity :('
  end
end
wrapper_method(a_b, eps, method_name, &block) click to toggle source

Wrapper method for num_integratons methods @param [Array] a_b integration range @param [Numeric] eps @param [Proc] proc - integration Proc @param [Block] block - integrated function as Block

# File lib/numerical_integration.rb, line 136
def self.wrapper_method(a_b, eps, method_name, &block)
  n = 1
  max_it = 10_000
  begin
    begin
      result = send(method_name, a_b[0], a_b[1], n, &block)
      check_value(result)
      n *= 5
      raise NumberofIterOutofRangeError if n > max_it
      result1 = send(method_name, a_b[0], a_b[1], n, &block)
      check_value(result1)
    end until (result - result1).abs < eps
      
  rescue Math::DomainError
    raise IntegralDoesntExistError, 'Domain error in math function'
  rescue ZeroDivisionError
    raise IntegralDoesntExistError, 'Divide by zero'
  end
  (result + result1) / 2.0
end