Очевидно, что вы хотите реализовать метод деления пополам , чтобы найти (реальное) решение («корень») уравнения.Первый шаг - определить это уравнение как функцию, , чтобы его можно было оценить в различных точках:
func f(_ x: Double) -> Double {
return pow(x, 3) - 2 * pow(x, 2) - 5
}
Затем вам понадобятся две переменные для левой и правой границытекущий интервалОни должны быть выбраны так, чтобы f(x)
имел противоположные знаки на границах.В вашем примере:
var xleft = 2.0 // f(xleft) < 0
var xright = 4.0 // f(xright) > 0
Теперь вы можете запустить итерацию: вычислите f(x)
в средней точке текущего интервала и замените xleft
на xright
, в зависимости от того, является ли f(x)
отрицательнымили положительный.Продолжайте, пока приближение не будет достаточно для ваших целей:
let eps = 0.0000001 // Desired precision
let leftSign = f(xleft).sign
repeat {
let x = (xleft + xright)/2.0
let y = f(x)
if y == 0 {
xleft = x
break
} else if y.sign == leftSign {
xleft = x
} else {
xright = x
}
// print(xleft, xright)
} while xright - xleft > eps
// Print approximate solution:
print(xleft)
Следующим шагом будет реализация самого метода деления пополам как функции:
func bisect(_ f: ((Double) -> Double), xleft: Double, xright: Double, eps: Double = 1.0e-6) -> Double {
let yleft = f(xleft)
let yright = f(xright)
precondition(yleft * yright <= 0, "f must have opposite sign at the boundaries")
var xleft = xleft
var xright = xright
repeat {
let x = (xleft + xright)/2.0
let y = f(x)
if y == 0 {
return x
} else if y.sign == yleft.sign {
xleft = x
} else {
xright = x
}
} while xright - xleft > eps
return (xleft + xright)/2.0
}
, чтобы онможет использоваться с произвольными уравнениями:
let sol1 = bisect({ x in pow(x, 3) - 2 * pow(x, 2) - 5 }, xleft: 2.0, xright: 4.0)
print(sol1) // 2.690647602081299
let sol2 = bisect({ x in cos(x/2)}, xleft: 3.0, xright: 4.0, eps: 1.0e-15)
print(sol2) // 3.1415926535897936