查找给定函数结果swift的函数参数

时间:2015-07-12 21:55:52

标签: swift function math

如果我有以下功能:

func evaluateGraph(sender: GraphView, atX: Double) -> Double? {
        return function?(atX)
    }

其中function是前面声明的变量,它是一个数学表达式(如x ^ 2)。本质上,此函数返回给定其x值的数学表达式的y值。在给定结果的情况下,如何找到此atX的参数function。如果y值为零,那么x值必须为function提供零结果?

3 个答案:

答案 0 :(得分:1)

您可以创建反函数来执行相反的操作。

所以f(x) = yf'给出了f'(y) = x

因此,如果你定义的函数是对输入求平方,那么逆是返回平方根,依此类推。

在f(x)返回正方形的情况下,你可能会遇到像f'(1) = 1 and -1那样的问题。

答案 1 :(得分:1)

如果没有实际编写逆方法,实际上反向推断输入提供输出的唯一方法是,我们能做的最好的事情是编写我们的程序进行猜测,直到它达到一定精度。

因此,举例来说,我们说我们有square函数:

func square(input: Double) -> Double {
    return input * input
}

现在,如果我们不想对这个函数的反函数(对于任何给定的输出实际上有两个输入),那么我们必须编写一个函数来猜测。

func inverseFunction(output: Double, function: (Double)->Double) -> Double

这需要一个double表示输出,一个函数(生成输出的那个),并在答案处返回其最佳猜测。

那么,我们怎么猜?

嗯,就像我们在预微积分和任何微积分1类的早期部分一样。选择一个起始编号,通过该函数运行它,将结果与我们正在寻找的输出进行比较。记录增量。选择第二个数字,在函数中运行,将结果与我们正在寻找的输出进行比较。记录增量,将其与第一个增量进行比较。

持续执行此操作,直到您将增量最小化到可接受的准确度级别(0.1 delta好?0.01?0.0001?)。增量越小,计算所需的时间越长。但无论如何,它都需要很长时间。

猜测算法?这是一个我无法回答的数学问题。我甚至不知道从哪里开始。

最后,最好的办法是简单地为您想要反转的任何函数编写反函数。

答案 2 :(得分:1)

假设您只想知道GraphView中的反函数(希望不是无穷大),您可以使用以下内容:

// higher percision -> better accuracy, start...end: Interval, f: function
func getZero(#precision: Int, var #start: Double, var #end: Double, f: Double -> Double) -> Double? {

    let fS = f(start)
    let fE = f(end)     

    let isStartNegative = fS.isSignMinus
    if isStartNegative == fE.isSignMinus { return nil }

    let fMin = min(fS, fE)
    let fMax = max(fS, fE)

    let doublePrecision = pow(10, -Double(precision))

    while end - start > doublePrecision {
        let mid = (start + end) / 2
        let fMid = f(mid)
        if fMid < fMin || fMax < fMid {
            return nil
        }
        if (fMid > 0) == isStartNegative {
            end = mid
        } else {
            start = mid
        }
    }

    return (start + end) / 2
}

// same as above but it returns an array of points
func getZerosInRange(#precision: Int, #start: Double, #end: Double, f: Double -> Double) -> [Double] {

    let doublePrecision = pow(10, -Double(precision))

    /// accuracy/step count between interval; "antiproportional" performance!!!!
    let stepCount = 100.0
    let by = (end - start) / stepCount
    var zeros = [Double]()

    for x in stride(from: start, to: end, by: by) {
        if let xZero = getZero(precision: precision, start: x, end: x + by, f) {
            zeros.append(xZero)
        }
    }
    return zeros
}

// using currying; all return values should be elements of the interval start...end
func inverse(#precision: Int, #start: Double, #end: Double, f: Double -> Double)(_ x: Double) -> [Double] {
    return getZerosInRange(precision: precision, start: start, end: end) { f($0) - x }
}

let f = { (x: Double) in x * x }

// you would pass the min and max Y values of the GraphView
// type: Double -> [Double]
let inverseF = inverse(precision: 10, start: -10, end: 10, f)

inverseF(4) // outputs [-1.999999999953436, 2.000000000046564]

有趣的是,这段代码在操场上以约0.5秒的速度流动,这是我没想到的。