Solving for the zero of an arbitrary function This methods solves for the zero of an arbitrary function using the Bisection Method. It works as desired, but I want to know if the code can be improved or made more readable and if I'm properly dealing with the various error conditions that might arise.

/// &lt;summary&gt;
/// Finds the input value of a function such that the output is zero within the range of min and max
/// &lt;/summary&gt;
/// &lt;param name="function"&gt;The function to zero&lt;/param&gt;
/// &lt;param name="min"&gt;The lower bound of the "zero search"&lt;/param&gt;
/// &lt;param name="max"&gt;The upper bound of the "zero search"&lt;/param&gt;
/// &lt;param name="counter"&gt;The amount of iterations to convergence&lt;/param&gt;
/// &lt;param name="eps"&gt;Desired precision&lt;/param&gt;
/// &lt;returns&gt;An input value such that 'function' returns 0 zero within the desired precision eps&lt;/returns&gt;
public static double Zero(this Func&lt;double, double&gt; function, double min, double max, out int counter, double eps = .001) {
    double lowerBound = min,
        upperBound = max;
    counter = 0;
    double range = double.MaxValue;
    double tryIndex = double.MinValue;
    double tryEval = double.MinValue;
    while (Math.Abs(tryEval) &gt; eps &amp;&amp; counter &lt; 10000) {
        counter++;
        range = upperBound - lowerBound;
        double maxEval = function(upperBound);
        double minEval = function(lowerBound);
        bool signMax = (maxEval &gt; 0);
        bool signMin = (minEval &gt; 0);
        if (signMax == signMin) {
            throw new Exception("Failed to converge");
        }
        tryIndex = lowerBound + (range / 2);
        tryEval = function(tryIndex);
        bool trySign = tryEval &gt; 0;
        if (trySign == signMax) {
            upperBound = tryIndex;
        } else lowerBound = tryIndex;
    }
    return tryIndex;
}
Wall of declarations


double lowerBound = min,
    upperBound = max;
counter = 0;
double range = double.MaxValue;
double tryIndex = double.MinValue;
double tryEval = double.MinValue;



Nobody likes being greeted by a wall of declarations like that.  Let's see what can be done to reduce them.

lowerBound and upperBound merely rename the parameters.  You could just use min and max directly everywhere.

counter is strongly related to the loop.  You could write the loop as

for (counter = 0; Math.Abs(tryEval) &gt; eps &amp;&amp; counter &lt; 10000; counter++)
{
    …
}


range is also local to the loop, and should be declared inside the loop.  It's also annoying that it's initialized on the 4th line of the function, redefined on the 9th line, and used 17th line. In fact, I wouldn't bother making a variable for it at all:

tryIndex = lowerBound + (min - max) / 2;


In general, you have a lot of expressions that don't need to be assigned to variables.

Loop structure

Initializing tryIndex and tryEval to double.MinValue is a code smell.  First of all, you should probably prefer double.NaN.  Secondly, it raises the question, under what circumstances might double.MinValue "leak" out as a result?  It's worth restructuring the program to avoid having those special values at all.

Restructuring the program will also reveal that there are two possible error conditions: failure to converge because the two endpoints evaluate to the same sign, and failure to converge because it took too many iterations.

public static double Zero(this Func&lt;double, double&gt; function, double min, double max, out int counter, double eps = .001)
{
    for (counter = 0; counter &lt; 10000; counter++)
    {
        bool signMax = (function(max) &gt; 0);
        if ((function(min) &gt; 0) == signMax)
        {
            // Same sign
            throw new Exception("Failed to converge (same sign)");
        }

        double tryIndex = min + (max - min) / 2;
        double tryEval = function(tryIndex);
        if (Math.Abs(tryEval) &lt;= eps)
        {
            return tryIndex;
        }
        else if ((tryEval &gt; 0) == signMax)
        {
            max = tryIndex;
        }
        else
        {
            min = tryIndex;
        }
    }
    throw new Exception("Failed to converge (too many iterations)");
}