Class: MoreMath::NewtonBisection

Inherits:
Object
  • Object
show all
Includes:
Exceptions
Defined in:
lib/more_math/newton_bisection.rb

Overview

This class is used to find the root of a function with Newton’s bisection method.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&function) ⇒ NewtonBisection

Creates a NewtonBisection instance for function, a one-argument block.



10
11
12
# File 'lib/more_math/newton_bisection.rb', line 10

def initialize(&function)
  @function = function
end

Instance Attribute Details

#functionObject (readonly)

The function, passed into the constructor.



15
16
17
# File 'lib/more_math/newton_bisection.rb', line 15

def function
  @function
end

Instance Method Details

#bracket(range = -1..1, n = 50, factor = 1.6) ⇒ Object

Return a bracket around a root, starting from the initial range. The method returns nil, if no such bracket around a root could be found after n tries with the scaling factor.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/more_math/newton_bisection.rb', line 20

def bracket(range = -1..1, n = 50, factor =  1.6)
  x1, x2 = range.first.to_f, range.last.to_f
  x1 >= x2 and raise ArgumentError, "bad initial range #{range}"
  f1, f2 = @function[x1], @function[x2]
  n.times do
    f1 * f2 < 0 and return x1..x2
    if f1.abs < f2.abs
      f1 = @function[x1 += factor * (x1 - x2)]
    else
      f2 = @function[x2 += factor * (x2 - x1)]
    end
  end
  return
end

#solve(range = nil, n = 1 << 16, epsilon = 1E-16) ⇒ Object

Find the root of function in range and return it. The method raises a DivergentException, if no such root could be found after n tries and in the epsilon environment.

Raises:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/more_math/newton_bisection.rb', line 38

def solve(range = nil, n = 1 << 16, epsilon = 1E-16)
  if range
    x1, x2 = range.first.to_f, range.last.to_f
    x1 >= x2 and raise ArgumentError, "bad initial range #{range}"
  elsif range = bracket
    x1, x2 = range.first, range.last
  else
    raise DivergentException, "bracket could not be determined"
  end
  f = @function[x1]
  fmid = @function[x2]
  f * fmid >= 0 and raise DivergentException, "root must be bracketed in #{range}"
  root = if f < 0
           dx = x2 - x1
           x1
         else
           dx = x1 - x2
           x2
         end
  n.times do
    fmid = @function[xmid = root + (dx *= 0.5)]
    fmid < 0 and root = xmid
    dx.abs < epsilon or fmid == 0 and return root
  end
  raise DivergentException, "too many iterations (#{n})"
end