Эти две функции симметричны по a
и b, и поэтому точно так же симметрична f. При анализе программы мы ограничены действиями, происходящими внутри цикла. Величины r и s являются вспомогательными переменными, которые не оставляют никакой проблемы. Трудность вызывают преобразования, проделываемые над p и q. Чтобы ясно увидеть эту трудность, осуществим введение новых переменных без разрушения старых. Перепишем наш цикл:ПОКА q
≥ eps ВЫПОЛНЯТЬr
:= (q/p)2; s := r/(r + 4)p
' := (2 * s + 1) * p; q' := s * qp
:= p'; q := q'ВЕРНУТЬСЯ
Рассмотрим действия этой программы, производимые над данными a
, b с одной стороны и над ac, bc с другой.Когда мы входим в цикл, то и p
, и q умножаются на с при переходе от первого вычисления ко второму.Это не меняет величины r
и, следовательно, не меняет величины s. Таким образом, p и q в этих вычислениях умножаются на одни и те же сомножители, так что значения p', q' во втором вычислении получаются из значений p, q в первом вычислении умножением их обоих на c. Следовательно, мы еще раз входим в цикл при том же соотношении между входными данными; следовательно, это соотношение будет иметь место при каждом входе в цикл, и, следовательно, также и на выходе из цикла. Отсюда получаем, что f(ac, bc) = cf(a, b).Выполнение программы для вычисления g
(x) = f(x, 1) с x = 1 и eps = 10-5 дает мне результат, равный 1.4142.Дальше считать бесполезно, это √2.
Я немедленно изменяю программу, чтобы она выполняла вывод не только величины g
, но также и g2. Я получаю:x g
2(x)1 2
2 5
3 10
4 17
Нет возможности сомневаться: g
(х) = √х2 + 1.Перенося эту формулу в соотношение между f
и g, мы видим, проделав все вычисления, чтоf
(a, b) = √a2 + b2.«Осталось только» доказать это. Мы не можем доверять заверениям программистов, утверждающих, что их программа делает то-то и то-то. При входе в цикл p
и q имеют значения а и b в каком-то порядке, поэтомуp
2 + q2 = a2 + b2.Что происходит с величиной p
2 + q2 после изменений, которым p и q подвергаются в цикле? Вычислим p'2 + q'2:p
'2 + q'2 = (2s + 1)2p2 + s2q2 = s2 (4р2 + q2) + 4sp + р2.Вычислим s
:r
:= q2/p2, s = r/(r + 4) = q2(q2 + 4p2),откуда, наконец,
s
(4р2 + q2) = q2.Возвращаясь отсюда к предыдущему соотношению, получаем
p
'2 + q'2 = sq2 + 4sp2 + р2 = s(4р2 + q2) + p2 = p2 + q2.Таким образом, все кончено… Это соотношение гарантирует, что p
2 + q2 является инвариантом цикла. При каждом входе в цикл выполняется соотношениеp
2 + q2 = a2 + b2.При выходе из цикла
p
2 + q2 = a2 + b2, причем q < ерs.Отсюда следует, что
p
2 = (a2 + b2) * (1 − q2/(a2 + b2)).Cpaey получаем, что
p
= √a2 + b2с относительной ошибкой eps
2/(2 * (a2 + b2)).Чтобы получить точность до 10-5
, совершенно ненужно брать eps = 10-5; более чем достаточно eps = 0.004. Эта программа сходится очень быстро.3. Игры без стратегии
Игра 13.
Задача о наиболее длинном взятии не имеет однозначного решения. Вот как ее сделал я — с учетом моих привычек в программировании и упрощений, предоставляемых моим микрокомпьютером.
Я представил всю игру одной-единственной цепочкой символов с кодами возврата каретки, расположенными надлежащим образом — так, чтобы визуализация игры сводилась к визуализации этой цепочки бее какого-либо дополнительного исследования. Куры обозначаются в этой цепочке присвоенными им буквами, лисы — буквами X
, пустые игровые поля обозначаются точками. Остальные символы (пробелы или возврат каретки) не отвечают никаким используемым игровым полям. Я добавил в начале и в конце по строчке пробелов, чтобы не было необходимости изучать возможность некоторых перемещений на границе игрового поля.Я не храню положений лис с помощью двух переменных. Я отыскиваю их положение в цепочке, представляющей игру, с помощью функции «положение» языка LSE
. Это — существенная деталь. Поиск наиболее длинного взятия я осуществляю итеративно. Я образую две цепочки:— одна из них содержит список кур, уже взятых при исследовании данного пути (это — последовательность букв взятых кур),
— вторая цепочка содержит дуплеты: положение в игре и рассматриваемое направление (мы осуществляем взятие, исходя из положения x
и двигаясь в направлении, обозначенном через i).Находясь в положении x
и в направлении i я смотрю, есть ли кура на поле x + d[i]. Если ее нет, то в этом направлении никакое взятие невозможно. Если же такая кура есть, то я смотрю, не содержится ли буква этой куры в цепочке уже взятых кур. Если содержится, то в этом направлении ничего не сделаешь. Если же эта кура еще не взята, то я проверяю, действительно ли поле x + 2 * d[i] содержит именно точку — в противном случае никакого взятия нет. Действуя таким образом, я не сталкиваюсь ни с какими трудностями на краях (там есть предохранительная строка, и она не содержит ни одной куры).