public double opt(Function f, double eps)
    {
        eps *= Math.abs(a-b); // make accuracy relative
        double x0 = Math.min(a,b);
        head = new Node(null, x0, f.eval(x0));
        x0 = Math.max(a,b);
        Node nn = new Node(null, x0, f.eval(x0));
        head.setNext(nn);
        double xMax, yMax;
        if ( head.getY() > nn.getY() ) nn = head;
        xMax = head.getX();
        yMax = head.getY();
        double dxMax;
        do {
            dxMax = 0.0;
            double optValue = Double.MAX_VALUE;
            Node n0 = head, n1;
            while ( (n1 = n0.getNext()) != null ) {
                double dx = n1.getX() - n0.getX();
                dxMax = Math.max(dxMax, dx);
                double dy = 2.0*yMax - n1.getY() - n0.getY();
                double value = (eps + dy)/Math.pow(dx,1.5);
                if ( value < optValue ) {
                    optValue = value;
                    nn = n0;
                }
                n0 = n1;
            }
            Node n2 = nn.getNext();
            double h = n2.getY() - nn.getY();
            double ratio = h > 0.0 ? DIVI : h < 0.0 ? 1.0 - DIVI : 0.5;
            x0 = nn.getX() + ratio*(n2.getX() - nn.getX());
            double y0 = f.eval(x0);
            Node n3 = new Node(n2, x0, y0);
            nn.setNext(n3);
            if ( y0 > yMax ) {
                xMax = x0;
                yMax = y0;
            }
        } while ( dxMax > eps );
        return xMax;
    }