public double Solve(VariableRangeRestriction previousValue, VariableRangeRestriction restriction)
 {
     double result = _illinois.Solve(previousValue, restriction);
     if (double.IsNaN(result)) {
         result = _iteration.Solve(previousValue, restriction);
     }
     return result;
 }
        public double Solve(VariableRangeRestriction startValue, VariableRangeRestriction restriction)
        {
            double x0 = startValue.GetSomeValue();
            double delta = _delta;
            for (int i = 0; ; i++) {
                Range[] possibleRanges = Range.CreateClosed(x0 - delta, x0 + delta).Intersect(restriction.PossibleRanges).ToArray();
                if (possibleRanges.Length == 0) {
                    return double.NaN;
                }
                double x1 = possibleRanges[0].LoApproximateDouble; // TODO: But what if the range is open??
                double x2 = possibleRanges[0].HiApproximateDouble;
                for (int j = 1; j < possibleRanges.Length && x1 == x2; j++) {
                    x2 = possibleRanges[j].HiApproximateDouble;
                }

                double f1 = f(x1);
                double f2 = f(x2);
                // TODO: What if fL or fH is NaN? Should not happen, because we restrict ourselves to "restriction", but still ...

                double k = (f2 - f1) / (x2 - x1);
                double d = f2 - k * x2;

                x0 = -d / k;
                if (!restriction.Contains(x0)) {
                    // The secant intersects the x-axis in an undefined segment.
                    // So we have to replace x0 with some valid x; we use the nearest defined x.
                    double bestReplacement = 1e100;
                    foreach (var r in restriction.PossibleRanges) {
                        bestReplacement = BetterReplacement(bestReplacement, x0, r.LoApproximateDouble);
                        bestReplacement = BetterReplacement(bestReplacement, x0, r.HiApproximateDouble);
                    }
                    x0 = bestReplacement;
                }

                double f0 = f(x0);
                // TODO: Again, f0 could be NaN? Should not happen, because we restrict ourselves to "restriction", but still ...

                delta /= 2.0;

                if (x1.Near(x2) && f0.Near(0)) {
                    return (x1 + x2) / 2;
                }
                if ((1e6 * f0).Near(0)) {
                    return (x1 + x2) / 2;
                }
                if (double.IsNaN(f0) || i > 100) {
                    return double.NaN;
                }
            }
        }
 public double Solve(VariableRangeRestriction previousValue, VariableRangeRestriction restriction)
 {
     foreach (var range in restriction.PossibleRanges) {
         double x1 = range.LoApproximateDouble;
         double x2 = range.HiApproximateDouble;
         var f1 = f(x1);
         var f2 = f(x2);
         if (f1 * f2 <= 0) {
             double result = Illinois(x1, x2, f1, f2);
             if (!double.IsNaN(result)) {
                 return result;
             }
         }
     }
     return double.NaN;
 }