~ubuntu-branches/ubuntu/utopic/mricron/utopic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{ ******************************************************************
  Bisection method for nonlinear equation
  ****************************************************************** }

unit ubisect;

interface

uses
  utypes;

procedure RootBrack(Func             : TFunc;
                    var X, Y, FX, FY : Float);
{ ------------------------------------------------------------------
  Expands the interval [X,Y] until it contains a root of Func,
  i. e. Func(X) and Func(Y) have opposite signs. The corresponding
  function values are returned in FX and FY.
  ------------------------------------------------------------------ }

procedure Bisect (Func     : TFunc;
                  var X, Y : Float;
                  MaxIter  : Integer;
                  Tol      : Float;
                  var F    : Float);

implementation

procedure RootBrack(Func             : TFunc;
                    var X, Y, FX, FY : Float);

begin
  FX := Func(X);
  FY := Func(Y);

  while FX * FY > 0 do
    if Abs(FX) < Abs(FY) then
      begin
        X := X + Gold * (X - Y);
        FX := Func(X)
      end
    else
      begin
        Y := Y + Gold * (Y - X);
        FY := Func(Y)
      end;
end;

procedure Bisect (Func     : TFunc;
                  var X, Y : Float;
                  MaxIter  : Integer;
                  Tol      : Float;
                  var F    : Float);

var
  Iter     : Integer;
  G, Z, FZ : Float;

begin
  Iter := 0;
  SetErrCode(OptOk);

  F := Func(X);

  if MaxIter < 1 then Exit;

  G := Func(Y);

  if F * G >= 0 then RootBrack(Func, X, Y, F, G);

  repeat
    Iter := Iter + 1;
    if Iter > MaxIter then
      begin
        SetErrCode(OptNonConv);
        Exit;
      end;

    Z := 0.5 * (X + Y);
    FZ := Func(Z);

    if F * FZ > 0 then
      begin
        X := Z;
        F := FZ;
      end
    else
      begin
        Y := Z;
        G := FZ;
      end;
  until Abs(X - Y) < Tol * (Abs(X) + Abs(Y));

  X := 0.5 * (X + Y);
  F := Func(X);
end;

end.