You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: roots.go
    path of file: ./repos/hoverfly/vendor/gonum.org/v1/gonum/mathext
    
    the code of the file until where you have to start completion: // Derived from SciPy's special/c_misc/fsolve.c and special/c_misc/misc.h
// https://github.com/scipy/scipy/blob/master/scipy/special/c_misc/fsolve.c
// https://github.com/scipy/scipy/blob/master/scipy/special/c_misc/misc.h

// Copyright Â©2017 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mathext

import "math"

type objectiveFunc func(float64, []float64) float64

type fSolveResult uint8

const (
	// An exact solution was found, in which case the first point on the
	// interval is the value
	fSolveExact fSolveResult = iota + 1
	// Interval width 
    
func falsePosition(x1, x2, f1, f2, absErr, relErr, bisectTil float64, f objectiveFunc, fExtra []float64) (fSolveResult, float64, float64, float64) {
	// The false position steps are either unmodified, or modified with the
	// Anderson-Bjorck method as appropriate. Theoretically, this has a "speed of
	// convergence" of 1.7 (bisection is 1, Newton is 2).
	// Note that this routine was designed initially to work with gammaincinv, so
	// it may not be tuned right for other problems. Don't use it blindly.

	if f1*f2 >= 0 {
		panic("Initial interval is not a bounding interval")
	}

	const (
		maxIterations = 100
		bisectIter    = 4
		bisectWidth   = 4.0
	)

	const (
		bisect = iota + 1
		falseP
	)

	var state uint8
	if bisectTil > 0 {
		state = bisect
	} else {
		state = falseP
	}

	gamma := 1.0

	w := math.Abs(x2 - x1)
	lastBisectWidth := w

	var nFalseP int
	var x3, f3, bestX, bestF float64
	for i := 0; i < maxIterations; i++ {
		switch state {
		case bisect:
			x3 = 0.5 * (x1 + x2)
			if x3 == x1 || x3 == x2 {
				// i.e., x1 and x2 are successive floating-point numbers
				bestX = x3
				if x3 == x1 {
					bestF = f1
				} else {
					bestF = f2
				}
				return fSolveConverged, bestX, bestF, w
			}

			f3 = f(x3, fExtra)
			if f3 == 0 {
				return fSolveExact, x3, f3, w
			}

			if f3*f2 < 0 {
				x1 = x2
				f1 = f2
			}
			x2 = x3
			f2 = f3
			w = math.Abs(x2 - x1)
			lastBisectWidth = w
			if bisectTil > 0 {
				if w < bisectTil {
					bisectTil = -1.0
					gamma = 1.0
					nFalseP = 0
					state = falseP
				}
			} else {
				gamma = 1.0
				nFalseP = 0
				state = falseP
			}
		case falseP:
			s12 := (f2 - gamma*f1) / (x2 - x1)
			x3 = x2 - f2/s12
			f3 = f(x3, fExtra)
			if f3 == 0 {
				return fSolveExact, x3, f3, w
			}

			nFalseP++
			if f3*f2 < 0 {
				gamma = 1.0
				x1 = x2
				f1 = f2
			} else {
				// Anderson-Bjorck method
				g := 1.0 - f3/f2
				if g <= 0 {
					g = 0.5
				}
				gamma *= g
			}
			x2 = x3
			f2 = f3
			w = math.Abs(x2 - x1)

			// Sanity check. For every 4 false position checks, see if we really are
			// decreasing the interval by comparing to what bisection would have
			// achieved (or, rather, a bit more lenient than that -- interval
			// decreased by 4 instead of by 16, as the fp could be decreasing gamma
			// for a bit). Note that this should guarantee convergence, as it makes
			// sure that we always end up decreasing the interval width with a
			// bisection.
			if nFalseP > bisectIter {
				if w*bisectWidth > lastBisectWidth {
					state = bisect
				}
				nFalseP = 0
				lastBisectWidth = w
			}
		}

		tol := absErr + relErr*math.Max(math.Max(math.Abs(x1), math.Abs(x2)), 1.0)
		if w <= tol {
			if math.Abs(f1) < math.Abs(f2) {
				bestX = x1
				bestF = f1
			} else {
				bestX = x2
				bestF = f2
			}
			return fSolveConverged, bestX, bestF, w
		}
	}

	return fSolveMaxIterations, x3, f3, w
}