Программирование игр и головоломок - [66]

Шрифт
Интервал

, b, p через а', b', p' соответственно:

а' = 2*а, p' = p/2 − а/2 − b, b' = a + b.

Для этих значений получаем:

a'*p' = a*pa>2 − 2a*b = а*р − (а + b)>2 + b>2 = а*рb'>2 + b>2.

Это, наконец, дает

а'*p' + b'>2 = а*р + b>2.

Инвариантной величиной цикла оказывается, таким образом, сумма ар + b>2, причем p остается четным. Это обеспечивается тем, что в случаях, когда p/2 нечетно, мы вычитаем нечетные b из нечетного p/2. Что касается b, то он нечетен потому, что он начинается со значения 1 и к нему прибавляются только четные значения а.

В начале а = 4, p (целая часть дроби (n − 1)/4) четно, b = 1, так что ар + b>2 = n.

Наконец, a, начиная с 4, умножается на 2 при каждом прохождении цикла; b начинается с 1, которое меньше соответствующего начального а = 4.

Тогда при переходе от a, b, p к a', b', p' либо

b' = b, а' = 2*а, так что если b < а, то и b' < а';

либо

b' = а + b, а' = 2*а, что также сохраняет справедливость отношения а' < b'.

Следовательно, вот ситуация, которую цикл оставляет инвариантной:

n = а*p + b>2;

а — степень двойки,

p четно,

b нечетно, b < а.

Кроме того, мы знаем, что при выходе из цикла p < а.

Если p равно нулю, то n = b>2. Тогда мы видим, что n — квадрат числа b, которое выводится, и все закончено.

Но n может оказаться полным квадратом и тогда, когда p не нуль. Попробуем рассмотреть все возможные случаи. Положим n = r>2 (r нечетно). Соотношение

r>2 = ар + b дает

r>2b>2 = ар.

Положим r + b = 2u, rb = 2v (r и b нечетны). Отсюда получаем 4uv = ар.

Поскольку r = u + v, где r нечетно, получаем, что u и v не могут быть числами одинаковой четности, так что одно из них четно, а другое нечетно. Так как а является степенью двойки, то нечетный сомножитель относится к p. Выявим его, полагая р = s2>t, где s нечетно, a t ≥ 1 (p четно).

Напомним, что а = 2>k. В этих обозначениях 4uv = ар = s2>k+t, uv = s2>k+t−2.

Возможные решения для пары u, v имеют вид пар

s'2>k+t-2, s''

где s's" = s.

Покажем сначала, что s" — меньший из этих двух элементов пары. Вследствие t ≥ 1 имеем ktk + t − 2.

Вследствие p < а последовательно выводим

s2>t < 2>k,

s's"2>t < 2>k.

s's" < 2>k-t ≤ 2>k+t-2s'>22>k+t-2

(потому что s' нечетен и не меньше 1).

Следовательно, нужно взять u = s'2>k+t-2, v = s".

Покажем теперь, что нужно обязательно взять s' =1, s" = s. По выбору u и v

b = 2>k+t−2s' − s" < а = 2>k.

Отсюда получаем:

s" > 2>k+t−2s' − 2>k,

и, так как t ≥ 1:

s" > 2>k−1s' − 2>k,

s = s's" > 2>k−1s'>2 − 2>ks = 2>k−1s' (s' − 2).

Вследствие р = s2>t < а = 2>k выводим s < 2>kt ≤ 2>k−1.

Объединим два полученных неравенства:

2>k−1s' (s' − 2) < x < 2>k−1, поэтому s' (s' − 2) < 1.

Единственное нечетное число s', удовлетворяющее этому соотношению, это s' = 1. Следовательно, у нас остается единственная возможность:

u = 2>k+t-2, v = s,

b = uv = 2>k+t-2s < а = 2>k,

s > 2>k+t-2 − 2>k.

Так как s < 2>kt, то t должно быть таким, чтобы

2>kt > 2>k+t-2 − 2>k.

Поскольку t должно быть строго положительно, то его единственными возможными значениями являются t = 1 и t = 2.

При t = 1 имеем

p = 2s, b = 2>kts = a/2 − p/2.

Следовательно, если 2b = аp, то n — квадрат числа (а + p)/2 = аb.

При t = 2 имеем

p = 4s, b = 2>ks = ap/4.

Следовательно, если p = 4(ab), то n — квадрат числа a + p/4 = 2аb.

Этим исчерпываются случаи, когда n может быть полным квадратом.

Можно спросить себя, могут ли эти различные случаи действительно осуществляться. Заметим, что при вступлении в цикл у нас b = 1, a = 4. После этого b может быть изменено добавлением а, т. е. кратным числа 4. Следовательно, b остается сравнимым с 1 по модулю 4. В трех возможных случаях:

p = 0, r = b,

p = а − 2b, r = ab,

p = 4 (ab), r = 2ab,

первый случай — единственный, в котором квадратный корень из n сравним с 1 по модулю 4; два других дают квадратный корень, сравнимый с 3 по модулю 4. При выходе из цикла равенство

b = ар + b>2

с учетом соотношений p < a, b < a дает n < 2a>2 и, следовательно, при выходе из цикла a>2 > n/2. Равенство

ар = nb>2

дает p = (nb>2)/a < n/а.

Если окажется, что n/а < a, то непременно p < а и цикл закончен. Чтобы цикл остановился, необходимо, чтобы a>2 > n/2, и цикл заведомо останавливается, если a>3 > n.

Следовательно, все зависит от положения n по отношению к степеням двойки. Существует такое целое n, что

4>q < n < 4>q+1.

Возможны два случая. Во-первых, может выполняться неравенство

4>q = 2>2q < n < 2>2q+1,

и тогда для k = q число a>2 = 2>2q > n/2 может быть значением остановки, но в этом нет уверенности. С другой стороны, если

2>2q+1 < n < 2>2q+2,

то единственное значение a, удовлетворяющее условию a>2 > n/2, есть a = 2>q+1, и для этого значения имеем a>2 > n, что гарантирует остановку. Поскольку r = ab, то а = r + b > r и, следовательно, a>2 > n.

Во втором случае

r = 2ab и b < а, откуда а < 2ab = r.

Таким образом, все три распознаваемые программой случая являются единственными возможными исходами программы, и каждый из них может произойти.

Таким образом, перед нами — очень забавный алгоритм, который дает значение квадратного корня, и который определяет случай, когда n не является корнем, но в этом случае не дает никакой дополнительной информации.

Программа заведомо останавливается при


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Геймдизайн. Рецепты успеха лучших компьютерных игр от Super Mario и Doom до Assassin’s Creed и дальше

Что такое ГЕЙМДИЗАЙН? Это не код, графика или звук. Это не создание персонажей или раскрашивание игрового поля. Геймдизайн – это симулятор мечты, набор правил, благодаря которым игра оживает. Как создать игру, которую полюбят, от которой не смогут оторваться? Знаменитый геймдизайнер Тайнан Сильвестр на примере кейсов из самых популярных игр рассказывает как объединить эмоции и впечатления, игровую механику и мотивацию игроков. Познакомитесь с принципами дизайна, которыми пользуются ведущие студии мира! Создайте игровую механику, вызывающую эмоции и обеспечивающую разнообразие.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


MFC и OpenGL

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.