public static double findZero(FunctionModel f, double start, double eps) {

    double[] bounds = findZeroBrackets(f, start);
    double lower = bounds[0], upper = bounds[1];
    double ly = f.eval(lower), uy = f.eval(upper);

    // System.out.println(String.format("Zero: [%f, %f] (%f, %f)", lower, upper, ly, uy));

    boolean lsign = ly < 0.0;
    boolean usign = uy <= 0.0;

    while (Math.abs(upper - lower) > eps) {
      double middle = (upper + lower) / 2.0;
      double my = f.eval(middle);
      boolean msign = my < 0.0;

      if (my == 0.0) {
        return middle;
      } else if (msign == lsign) {
        lower = middle;
        ly = my;
        lsign = msign;
        // System.out.println(String.format("\tU: [%f, %f] (%f, %f)", lower, upper, ly, uy));
      } else {
        upper = middle;
        uy = my;
        usign = msign;
        // System.out.println(String.format("\tL: [%f, %f] (%f, %f)", lower, upper, ly, uy));
      }
    }

    double v = (lower + upper) / 2.0;
    // System.out.println(String.format("\t-> %f", v));
    return v;
  }
  public static double[] findZeroBrackets(FunctionModel f, double start) {
    double fstart = f.eval(start);

    if (Double.isInfinite(fstart) || Double.isNaN(fstart)) {
      throw new IllegalArgumentException(
          String.format("Illegal start: %f (%f)", start, f.eval(start)));
    }

    boolean sign = fstart >= 0.0;
    double lowerSpace = 1.0, upperSpace = 1.0;
    double upper = start + upperSpace, lower = start - lowerSpace;
    double pupper = start, plower = start;

    double fupper = f.eval(upper), flower = f.eval(lower);
    boolean usign = fupper >= 0.0, lsign = flower >= 0.0;
    int iters = 0;

    while ((isBad(fupper) || usign == sign) && (isBad(flower) || lsign == sign)) {
      iters += 1;

      if (isBad(fupper)) {
        upperSpace /= 2.0;
        upper -= upperSpace;
      } else {
        upperSpace *= 2.0;
        upper += upperSpace;
      }

      fupper = f.eval(upper);
      usign = fupper >= 0.0;

      if (isBad(flower)) {
        lowerSpace /= 2.0;
        lower += lowerSpace;
      } else {
        lowerSpace *= 2.0;
        lower -= lowerSpace;
      }

      flower = f.eval(lower);
      lsign = flower >= 0.0;
    }

    if (usign != sign) {
      // System.out.println(String.format("\n%f -> (%f, %f]", start, start, upper));
      return new double[] {start, upper};
    }

    if (lsign != sign) {
      // System.out.println(String.format("\n%f -> [%f, %f)", start, lower, start));
      return new double[] {lower, start};
    }

    throw new IllegalArgumentException("Couldn't find zero brackets!");
  }