code: function binSearchSolve(f, y, a, b) {
           var mid, vmid, niters;
  
           a = inferEndpoint(f, y, true, a);
           b = inferEndpoint(f, y, false, b);
  
           if (f(a) > f(b)) {
              return binSearchSolve(function(x) { return -f(x); }, -y, a, b);
           }
  
           if (utils.relativelyCloseTo(f(a), y)) { return a; }
           if (utils.relativelyCloseTo(f(b), y)) { return b; }
  
           if (f(a) > y || f(b) < y) {
              throw new Error('Binary search: Desired value not between endpoint values.');
           }
           niters = 0;
           while (niters < utils.maxSteps) {
              mid = (a + b) / 2;
              niters += 1;
              vmid = f(mid);
              if (utils.relativelyCloseTo(a, b) &&
                  utils.relativelyCloseTo(vmid, y)) {
                return mid;
              }
              if (vmid < y) {
                 a = mid;
              } else {
                 b = mid;
              }
           }
           throw new Error('Binary search: Too many iterations');
        }
docs: /* Binary search for solution to f(x) = y (provided f is strictly monotone)
  
  a, b are optional bounds. If not provided,
  the function will search for them using x = +/- 2^n
  
  Search will terminate when:
  - Provided a, b values do not satisfy f(a) <= y <= f(b) (error)
  - The search for a, b produces unreasonably large endpoints (error)
  - The relative size of the search interval becomes sufficiently small
  relative to its midpoint.
  - utils.maxSteps is reached (error)
  - utils.relativelyCloseTo (f(x), y) < utils.precision
   /* eslint-disable complexity