Browse Source

Fixed accuracy handling in RootFinding.Bisection (#403)

* Fixed accuracy handling in RootFinding.Bisection
* Fixed F# unit tests
* Actually fixed F# unit tests
* One less iteration, same accuracy guarantees
v3
Konstantin Tretyakov 10 years ago
committed by Christoph Ruegg
parent
commit
a2baaba2cc
  1. 10
      src/FSharpUnitTests/FindRootsTests.fs
  2. 37
      src/Numerics/RootFinding/Bisection.cs
  3. 140
      src/UnitTests/RootFindingTests/BisectionTest.cs

10
src/FSharpUnitTests/FindRootsTests.fs

@ -21,8 +21,14 @@ module FindRootsTests =
[<Test>] [<Test>]
let ``Bisection should find both roots of (x - 3) * (x - 4)``() = let ``Bisection should find both roots of (x - 3) * (x - 4)``() =
f |> FindRoots.bisection 100 1e-14 -5.0 3.5 |> shouldEqual (Some 3.0) f |> FindRoots.bisection 100 1e-14 -5.0 3.5 |> (fun x ->
f |> FindRoots.bisection 100 1e-14 3.2 5.0 |> shouldEqual (Some 4.0) match x with
| Some x -> should (equalWithin 1e-14) 3.0
| None -> failwith "The element is not equal.") |> ignore
f |> FindRoots.bisection 100 1e-14 3.2 5.0 |> (fun x ->
match x with
| Some x -> should (equalWithin 1e-14) 4.0
| None -> failwith "The element is not equal.") |> ignore
[<Test>] [<Test>]
let ``Brent should find both roots of (x - 3) * (x - 4)``() = let ``Brent should find both roots of (x - 3) * (x - 4)``() =

37
src/Numerics/RootFinding/Bisection.cs

@ -61,7 +61,7 @@ namespace MathNet.Numerics.RootFinding
/// <param name="maxIterations">Maximum number of iterations. Default 100.</param> /// <param name="maxIterations">Maximum number of iterations. Default 100.</param>
/// <returns>Returns the root with the specified accuracy.</returns> /// <returns>Returns the root with the specified accuracy.</returns>
/// <exception cref="NonConvergenceException"></exception> /// <exception cref="NonConvergenceException"></exception>
public static double FindRoot(Func<double, double> f, double lowerBound, double upperBound, double accuracy = 1e-8, int maxIterations = 100) public static double FindRoot(Func<double, double> f, double lowerBound, double upperBound, double accuracy = 1e-14, int maxIterations = 100)
{ {
double root; double root;
if (TryFindRoot(f, lowerBound, upperBound, accuracy, maxIterations, out root)) if (TryFindRoot(f, lowerBound, upperBound, accuracy, maxIterations, out root))
@ -76,29 +76,34 @@ namespace MathNet.Numerics.RootFinding
/// <param name="f">The function to find roots from.</param> /// <param name="f">The function to find roots from.</param>
/// <param name="lowerBound">The low value of the range where the root is supposed to be.</param> /// <param name="lowerBound">The low value of the range where the root is supposed to be.</param>
/// <param name="upperBound">The high value of the range where the root is supposed to be.</param> /// <param name="upperBound">The high value of the range where the root is supposed to be.</param>
/// <param name="accuracy">Desired accuracy. The root will be refined until the accuracy or the maximum number of iterations is reached.</param> /// <param name="accuracy">Desired accuracy for both the root and the function value at the root. The root will be refined until the accuracy or the maximum number of iterations is reached.</param>
/// <param name="maxIterations">Maximum number of iterations. Usually 100.</param> /// <param name="maxIterations">Maximum number of iterations. Usually 100.</param>
/// <param name="root">The root that was found, if any. Undefined if the function returns false.</param> /// <param name="root">The root that was found, if any. Undefined if the function returns false.</param>
/// <returns>True if a root with the specified accuracy was found, else false.</returns> /// <returns>True if a root with the specified accuracy was found, else false.</returns>
public static bool TryFindRoot(Func<double, double> f, double lowerBound, double upperBound, double accuracy, int maxIterations, out double root) public static bool TryFindRoot(Func<double, double> f, double lowerBound, double upperBound, double accuracy, int maxIterations, out double root)
{ {
double fmin = f(lowerBound); if (upperBound < lowerBound)
double fmax = f(upperBound); {
var t = upperBound;
upperBound = lowerBound;
lowerBound = t;
}
// already there? double fmin = f(lowerBound);
if (Math.Abs(fmin) < accuracy) if (Math.Sign(fmin) == 0)
{ {
root = lowerBound; root = lowerBound;
return true; return true;
} }
if (Math.Abs(fmax) < accuracy) double fmax = f(upperBound);
if (Math.Sign(fmax) == 0)
{ {
root = upperBound; root = upperBound;
return true; return true;
} }
root = 0.5*(lowerBound + upperBound); root = 0.5 * (lowerBound + upperBound);
// bad bracketing? // bad bracketing?
if (Math.Sign(fmin) == Math.Sign(fmax)) if (Math.Sign(fmin) == Math.Sign(fmax))
@ -108,7 +113,9 @@ namespace MathNet.Numerics.RootFinding
for (int i = 0; i <= maxIterations; i++) for (int i = 0; i <= maxIterations; i++)
{ {
if (Math.Abs(fmax - fmin) < 0.5*accuracy && upperBound.AlmostEqualRelative(lowerBound)) double froot = f(root);
if (upperBound - lowerBound <= 2*accuracy && Math.Abs(froot) <= accuracy)
{ {
return true; return true;
} }
@ -119,19 +126,17 @@ namespace MathNet.Numerics.RootFinding
return false; return false;
} }
double midval = f(root); if (Math.Sign(froot) == Math.Sign(fmin))
if (Math.Sign(midval) == Math.Sign(fmin))
{ {
lowerBound = root; lowerBound = root;
fmin = midval; fmin = froot;
} }
else if (Math.Sign(midval) == Math.Sign(fmax)) else if (Math.Sign(froot) == Math.Sign(fmax))
{ {
upperBound = root; upperBound = root;
fmax = midval; fmax = froot;
} }
else else // Math.Sign(froot) == 0
{ {
return true; return true;
} }

140
src/UnitTests/RootFindingTests/BisectionTest.cs

@ -41,19 +41,19 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
{ {
// Roots at -2, 2 // Roots at -2, 2
Func<double, double> f1 = x => x*x - 4; Func<double, double> f1 = x => x*x - 4;
Assert.AreEqual(0, f1(Bisection.FindRoot(f1, 0, 5, 1e-14))); Assert.AreEqual(0, f1(Bisection.FindRoot(f1, 0, 5, 1e-14)), 1e-14);
Assert.AreEqual(0, f1(Bisection.FindRootExpand(f1, 3, 4, 1e-14))); Assert.AreEqual(0, f1(Bisection.FindRootExpand(f1, 3, 4, 1e-14)), 1e-14);
Assert.AreEqual(-2, Bisection.FindRoot(f1, -5, -1, 1e-14)); Assert.AreEqual(-2, Bisection.FindRoot(f1, -5, -1, 1e-14), 1e-14);
Assert.AreEqual(2, Bisection.FindRoot(f1, 1, 4, 1e-14)); Assert.AreEqual(2, Bisection.FindRoot(f1, 1, 4, 1e-14), 1e-14);
Assert.AreEqual(0, f1(Bisection.FindRoot(x => -f1(x), 0, 5, 1e-14))); Assert.AreEqual(0, f1(Bisection.FindRoot(x => -f1(x), 0, 5, 1e-14)), 1e-14);
Assert.AreEqual(-2, Bisection.FindRoot(x => -f1(x), -5, -1, 1e-14)); Assert.AreEqual(-2, Bisection.FindRoot(x => -f1(x), -5, -1, 1e-14), 1e-14);
Assert.AreEqual(2, Bisection.FindRoot(x => -f1(x), 1, 4, 1e-14)); Assert.AreEqual(2, Bisection.FindRoot(x => -f1(x), 1, 4, 1e-14), 1e-14);
// Roots at 3, 4 // Roots at 3, 4
Func<double, double> f2 = x => (x - 3)*(x - 4); Func<double, double> f2 = x => (x - 3)*(x - 4);
Assert.AreEqual(0, f2(Bisection.FindRoot(f2, 3.5, 5, 1e-14)), 1e-14); Assert.AreEqual(0, f2(Bisection.FindRoot(f2, 3.5, 5, 1e-14)), 1e-14);
Assert.AreEqual(3, Bisection.FindRoot(f2, -5, 3.5, 1e-14)); Assert.AreEqual(3, Bisection.FindRoot(f2, -5, 3.5, 1e-14), 1e-14);
Assert.AreEqual(4, Bisection.FindRoot(f2, 3.2, 5, 1e-14)); Assert.AreEqual(4, Bisection.FindRoot(f2, 3.2, 5, 1e-14), 1e-14);
Assert.AreEqual(3, Bisection.FindRoot(f2, 2.1, 3.9, 0.001), 0.001); Assert.AreEqual(3, Bisection.FindRoot(f2, 2.1, 3.9, 0.001), 0.001);
Assert.AreEqual(3, Bisection.FindRoot(f2, 2.1, 3.4, 0.001), 0.001); Assert.AreEqual(3, Bisection.FindRoot(f2, 2.1, 3.4, 0.001), 0.001);
} }
@ -80,7 +80,7 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
Func<double, double> f1 = z => 8*Math.Pow((4 - z)*z, 2)/(Math.Pow(6 - 3*z, 2)*(2 - z)) - 0.186; Func<double, double> f1 = z => 8*Math.Pow((4 - z)*z, 2)/(Math.Pow(6 - 3*z, 2)*(2 - z)) - 0.186;
double x = Bisection.FindRoot(f1, 0.1, 0.9, accuracy: 1e-9, maxIterations: 80); double x = Bisection.FindRoot(f1, 0.1, 0.9, accuracy: 1e-9, maxIterations: 80);
Assert.AreEqual(0.277759543089215, x, 1e-9); Assert.AreEqual(0.277759543089215, x, 1e-9);
Assert.AreEqual(0, f1(x), 1e-16); Assert.AreEqual(0, f1(x), 1e-9);
} }
[Test] [Test]
@ -128,9 +128,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return 1 - k1*x1 - k2*x2; return 1 - k1*x1 - k2*x2;
}; };
double x = Bisection.FindRoot(f1, 0, 100); double x = Bisection.FindRoot(f1, 0, 100, 1e-9);
Assert.AreEqual(70.9000000710300, x, 1e-9); Assert.AreEqual(70.9000000710300, x, 1e-9);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-9);
} }
[Test] [Test]
@ -172,7 +172,7 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return DH + TR*(ALPHA + TR*(BETA/2 + TR*GAMMA/3)) - 298.0*(ALPHA + 298.0*(BETA/2 + 298.0*GAMMA/3)); return DH + TR*(ALPHA + TR*(BETA/2 + TR*GAMMA/3)) - 298.0*(ALPHA + 298.0*(BETA/2 + 298.0*GAMMA/3));
}; };
double x = Bisection.FindRoot(f1, 3000, 5000); double x = Bisection.FindRoot(f1, 3000, 5000, 1e-10);
Assert.AreEqual(4305.30991366774, x, 1e-5); Assert.AreEqual(4305.30991366774, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-10); Assert.AreEqual(0, f1(x), 1e-10);
} }
@ -198,9 +198,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return R*T/V + Beta/(V*V) + Gama/(V*V*V) + Delta/(V*V*V*V) - P; return R*T/V + Beta/(V*V) + Gama/(V*V*V) + Delta/(V*V*V*V) - P;
}; };
double x = Bisection.FindRoot(f1, 0.1, 1); double x = Bisection.FindRoot(f1, 0.1, 1, 1e-8);
Assert.AreEqual(0.174749531708621, x, 1e-5); Assert.AreEqual(0.174749531708621, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-12); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -234,7 +234,7 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
{ {
// Test case from http://www.polymath-software.com/library/nle/Oneeq7.htm // Test case from http://www.polymath-software.com/library/nle/Oneeq7.htm
Func<double, double> f1 = x => x/(1 - x) - 5*Math.Log(0.4*(1 - x)/(0.4 - 0.5*x)) + 4.45977; Func<double, double> f1 = x => x/(1 - x) - 5*Math.Log(0.4*(1 - x)/(0.4 - 0.5*x)) + 4.45977;
double r = Bisection.FindRoot(f1, 0, 0.79, 1e-2); double r = Bisection.FindRoot(f1, 0, 0.79, 1e-13);
Assert.AreEqual(0.757396293891, r, 1e-5); Assert.AreEqual(0.757396293891, r, 1e-5);
Assert.AreEqual(0, f1(r), 1e-13); Assert.AreEqual(0, f1(r), 1e-13);
} }
@ -252,9 +252,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return a*v*v + b*Math.Pow(v, 7/4) - c; return a*v*v + b*Math.Pow(v, 7/4) - c;
}; };
double x = Bisection.FindRoot(f1, 0.01, 1); double x = Bisection.FindRoot(f1, 0.01, 1, 1e-10);
Assert.AreEqual(0.842524411168525, x, 1e-2); Assert.AreEqual(0.842524411168525, x, 1e-2); // Hmm, we do not find the correct root within requested accuracy here.
Assert.AreEqual(0, f1(x), 1e-12); Assert.AreEqual(0, f1(x), 1e-10);
} }
[Test] [Test]
@ -274,9 +274,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
double x = Bisection.FindRoot(f1, 1, 50); double x = Bisection.FindRoot(f1, 1, 50);
Assert.AreEqual(25.743977294088, x, 1e-5); Assert.AreEqual(25.743977294088, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-14);
x = Bisection.FindRoot(f1, 50, 100); x = Bisection.FindRoot(f1, 50, 100, 1e-8);
Assert.AreEqual(78.905412035983, x, 1e-5); Assert.AreEqual(78.905412035983, x, 1e-8);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -285,12 +285,12 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
// Test case from http://www.polymath-software.com/library/nle/Oneeq10.htm // Test case from http://www.polymath-software.com/library/nle/Oneeq10.htm
Func<double, double> f1 = x => (1.0/63.0)*Math.Log(x) + (64.0/63.0)*Math.Log(1/(1 - x)) + Math.Log(0.95 - x) - Math.Log(0.9); Func<double, double> f1 = x => (1.0/63.0)*Math.Log(x) + (64.0/63.0)*Math.Log(1/(1 - x)) + Math.Log(0.95 - x) - Math.Log(0.9);
double r = Bisection.FindRoot(f1, .01, 0.35); double r = Bisection.FindRoot(f1, .01, 0.35, 1e-8);
Assert.AreEqual(0.036210083704, r, 1e-5); Assert.AreEqual(0.036210083704, r, 1e-5);
Assert.AreEqual(0, f1(r), 1e-14); Assert.AreEqual(0, f1(r), 1e-8);
r = Bisection.FindRoot(f1, 0.35, 0.7); r = Bisection.FindRoot(f1, 0.35, 0.7, 1e-8);
Assert.AreEqual(0.5, r, 1e-5); Assert.AreEqual(0.5, r, 1e-8);
Assert.AreEqual(0, f1(r), 1e-14); Assert.AreEqual(0, f1(r), 1e-8);
} }
[Test] [Test]
@ -308,12 +308,12 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return a - Math.Pow((c + 2*x)*(a + b + c - 2*x), 2)/(kp*P*P*Math.Pow(b - 3*x, 3)) - x; return a - Math.Pow((c + 2*x)*(a + b + c - 2*x), 2)/(kp*P*P*Math.Pow(b - 3*x, 3)) - x;
}; };
double r = Bisection.FindRoot(f1, 0, 0.25); double r = Bisection.FindRoot(f1, 0, 0.25, 1e-8);
Assert.AreEqual(0.058654581076661, r, 1e-5); Assert.AreEqual(0.058654581076661, r, 1e-7); // Fails with tolerance 1e-8, hmm...
Assert.AreEqual(0, f1(r), 1e-14); Assert.AreEqual(0, f1(r), 1e-8);
r = Bisection.FindRoot(f1, 0.3, 1); r = Bisection.FindRoot(f1, 0.3, 1, 1e-8);
Assert.AreEqual(0.600323116977323, r, 1e-5); Assert.AreEqual(0.600323116977323, r, 1e-8);
Assert.AreEqual(0, f1(r), 1e-14); Assert.AreEqual(0, f1(r), 1e-8);
} }
[Test] [Test]
@ -331,9 +331,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return (b - Math.Pow(Math.Pow((c + 2*x)*(a + b + c - 2*x), 2)/(kp*P*P*(a - x)), 1.0/3.0))/3.0 - x; return (b - Math.Pow(Math.Pow((c + 2*x)*(a + b + c - 2*x), 2)/(kp*P*P*(a - x)), 1.0/3.0))/3.0 - x;
}; };
double r = Bisection.FindRoot(f1, 0.01, 0.45); double r = Bisection.FindRoot(f1, 0.01, 0.45, 1e-8);
Assert.AreEqual(0.058654571042804, r, 1e-5); Assert.AreEqual(0.058654571042804, r, 1e-8);
Assert.AreEqual(0, f1(r), 1e-14); Assert.AreEqual(0, f1(r), 1e-8);
// Could not test the following root, since Math.Pow(y,1/3) does not work for y<0 // Could not test the following root, since Math.Pow(y,1/3) does not work for y<0
// r = Bisection.FindRoot(f1, 0.55, 0.7); // r = Bisection.FindRoot(f1, 0.55, 0.7);
// Assert.AreEqual(0.600323117488527, r, 1e-5); // Assert.AreEqual(0.600323117488527, r, 1e-5);
@ -355,9 +355,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return (R*T/P)*(1 + b/v + c/(v*v)) - v; return (R*T/P)*(1 + b/v + c/(v*v)) - v;
}; };
double x = Bisection.FindRoot(f1, 100, 300); double x = Bisection.FindRoot(f1, 100, 300, 1e-8);
Assert.AreEqual(213.001818272273, x, 1e-5); Assert.AreEqual(213.001818272273, x, 1e-8);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -377,9 +377,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return R*Math.Pow(T, 1.5)*V*(V + B)/(P*Math.Sqrt(T)*V*(V + B) + A) + B - V; return R*Math.Pow(T, 1.5)*V*(V + B)/(P*Math.Sqrt(T)*V*(V + B) + A) + B - V;
}; };
double x = Bisection.FindRoot(f1, .01, .3); double x = Bisection.FindRoot(f1, .01, .3, 1e-8);
Assert.AreEqual(0.075699587993613, x, 1e-9); Assert.AreEqual(0.075699587993613, x, 1e-8);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -402,9 +402,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return U*A*(DT2 - DT1)/Math.Log(DT2/DT1) - Q; return U*A*(DT2 - DT1)/Math.Log(DT2/DT1) - Q;
}; };
double x = Bisection.FindRoot(f1, 1000000, 7000000); double x = Bisection.FindRoot(f1, 1000000, 7000000, 1e-8);
Assert.AreEqual(5281024.23857737, x, 1e-5); Assert.AreEqual(5281024.23857737, x, 1e-6); // Fails with tolerance 1e-8, hmm...
Assert.AreEqual(0, f1(x), 1e-9); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -496,9 +496,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return 1.296*(T - Tp) + 10369*k*Pp; return 1.296*(T - Tp) + 10369*k*Pp;
}; };
double x = Bisection.FindRoot(f1, 500, 725); double x = Bisection.FindRoot(f1, 500, 725, 1e-8);
Assert.AreEqual(690.4486645013260, x, 1e-5); Assert.AreEqual(690.4486645013260, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-12); Assert.AreEqual(0, f1(x), 1e-8);
x = Bisection.FindRoot(f1, 725, 850, 1e-12); x = Bisection.FindRoot(f1, 725, 850, 1e-12);
Assert.AreEqual(758.3286948959860, x, 1e-5); Assert.AreEqual(758.3286948959860, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-12); Assert.AreEqual(0, f1(x), 1e-12);
@ -521,9 +521,9 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
return 1.3*(T - Tp) + 1.04e4*k*Pp; return 1.3*(T - Tp) + 1.04e4*k*Pp;
}; };
double x = Bisection.FindRoot(f1, 500, 1500); double x = Bisection.FindRoot(f1, 500, 1500, 1e-8);
Assert.AreEqual(1208.2863599396200, x, 1e-4); Assert.AreEqual(1208.2863599396200, x, 1e-4);
Assert.AreEqual(0, f1(x), 1e-12); Assert.AreEqual(0, f1(x), 1e-8);
} }
[Test] [Test]
@ -742,5 +742,47 @@ namespace MathNet.Numerics.UnitTests.RootFindingTests
Assert.AreEqual(0.26405262123160, x, 1e-5); Assert.AreEqual(0.26405262123160, x, 1e-5);
Assert.AreEqual(0, f1(x), 1e-14); Assert.AreEqual(0, f1(x), 1e-14);
} }
[Test]
public void Accuracy()
{
// Verify that x-accuracy is being sought, despite good y-accuracy already at the boundaries
Assert.AreEqual(0.5, Bisection.FindRoot(x => 1e-5 * (x - 0.5), 0.0, 1.0, 1e-5), 1e-5);
// Verify that y-accuracy is being sought despide good x-accuracy at the boundaries
Assert.AreEqual(Math.Sqrt(2), Bisection.FindRoot(x => 1e10 * (x - Math.Sqrt(2)), 1.0, 2.0, 1.0), 1e-10);
// Verify that a discontinuity is not considered a root.
double root;
Assert.IsFalse(Bisection.TryFindRoot(x => (x<0)? -1 : 1, -1, 1, 1e-5, 100, out root));
// ... unless it is a very small discontinuity
Assert.AreEqual(0.0, Bisection.FindRoot(x => (x < 0) ? -1e-5 : 1e-5, -1, Math.Sqrt(2), 1e-5), 1e-5);
// Verify no unnecessary iterations are done after the requested accuracy is achieved
var niter = 0;
Func<double, double> f = x => { niter++; return x - Math.Sqrt(2); };
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 2);
Assert.LessOrEqual(niter, 3);
niter = 0;
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 4);
Assert.LessOrEqual(niter, 4);
niter = 0;
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 8);
Assert.LessOrEqual(niter, 5);
niter = 0;
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 16);
Assert.LessOrEqual(niter, 6);
niter = 0;
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 32);
Assert.LessOrEqual(niter, 7);
niter = 0;
Bisection.FindRoot(f, 1.0, 2.0, 1.0 / 64);
Assert.LessOrEqual(niter, 8);
}
} }
} }

Loading…
Cancel
Save