如果我有以下功能:
func evaluateGraph(sender: GraphView, atX: Double) -> Double? {
return function?(atX)
}
其中function
是前面声明的变量,它是一个数学表达式(如x ^ 2)。本质上,此函数返回给定其x值的数学表达式的y值。在给定结果的情况下,如何找到此atX
的参数function
。如果y值为零,那么x值必须为function
提供零结果?
答案 0 :(得分:1)
您可以创建反函数来执行相反的操作。
所以f(x) = y
反f'
给出了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秒的速度流动,这是我没想到的。