Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Воган Ли - Python для хакеров (Библиотека программиста) - 2023.pdf
Скачиваний:
4
Добавлен:
07.04.2024
Размер:
14.76 Mб
Скачать

344      Глава 12. Находимся ли мы в компьютерной симуляции?

Помимо ограничения размера объектов, сетка в симуляции может определять предпочтительную ориентацию, или анизотропию, материи космоса. Анизотропия характеризует различие свойств среды в зависимости от направления. Например, дерево проще расколоть вдоль волокон, чем поперек. Если внимательно посмотреть на траектории движения Йертл в симуляции (рис. 12.3), то мы увидим признаки анизотропии. Верхняя, слегка наклонная траектория неровная, а нижняя — с запада на восток — идеально прямая.

Рис. 12.3.

Траектории движения черепахи

Изображение неортогональной линии на ортогональной сетке выглядит некрасиво. Но здесь дело не только в эстетике. Перемещение вдоль x или y требует прибавления или вычитания только целых значений (рис. 12.4, слева). Перемещение под углом требует тригонометрического вычисления частичного смещения в направлениях x и y (рис. 12.4, справа).

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

1 + 1 + 1 + 1 + . . .

Ѳ

а

П

С

Рис. 12.4. Перемещение вдоль строк или столбцов (слева) требует более простых арифметических вычислений, чем перемещение с пересечением строки

или столбца (справа)

Измерение затрат на пересечение строк или столбцов сетки

Чтобы вычислить разницу во времени при рисовании линии вдоль строки или столбца и линии, пересекающей их, необходимо нарисовать две линии одинаковой длины. Но при этом нужно помнить, что turtle работает только с целыми

Проект #16. Жизнь, Вселенная и пруд черепахи Йертл      345

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

Для нахождения этих углов можно использовать пифагорову тройку, набор положительных целых чисел a, b и с, которые удовлетворяют квадратному уравнению a2 + b2 = c2. Известна тройка 3-4-5, но нам может потребоваться более длинная линия, чтобы время, затраченное на рисование линии, не оказалось меньше точности измерения часов компьютера. Удобно, что другие тройки значений можно также найти онлайн. Неплохим вариантом будет, например, сочетание 62-960-962, так как линия получится достаточно длинной и при этом поместится на экране turtle.

Код для сравнения линий

Для рисования диагональной и прямой линий мы воспользуемся turtle (листинг 12.3). Первую линию мы рисуем параллельно оси x (то есть запад-восток), а вторую под небольшим углом к ней. Верный угол можно вычислить с помощью тригонометрии; в данном случае это 3.695220532 градуса. Код многократно повторяет цикл for и записывает время, затраченное на каждую линию, используя модуль time. В итоге сравнивается среднее время для обеих линий.

Средние мы берем, потому что CPU компьютера непрерывно обрабатывает множество процессов. Операционная система планирует эти процессы внутренне, выполняя один и откладывая другой, пока ресурс ввода/вывода не станет доступен. Следовательно, сложно зарегистрировать абсолютное время выполнения заданной функции. Вычисление среднего значения времени для множества выполнений учитывает это обстоятельство.

Код, line_compare.py, можно скачать с сайта книги.

Листинг 12.3. Отрисовка прямой и наклонной линий и регистрация затраченного на каждую линию времени

line_compare.py

from time import perf_counter import statistics

import turtle

turtle.setup(1200, 600) screen = turtle.Screen()

ANGLES = (0, 3.695220532) # В градусах

NUM_RUNS = 20 SPEED = 0

for angle in ANGLES:times = []

346      Глава 12. Находимся ли мы в компьютерной симуляции?

for _ in range(NUM_RUNS): line = turtle.Turtle() line.speed(SPEED) line.hideturtle() line.penup() line.lt(angle) line.setpos(-470, 0) line.pendown() line.showturtle()

start_time = perf_counter() line.fd(962)

end_time = perf_counter() times.append(end_time - start_time)

line_ave = statistics.mean(times)

print("Angle {} degrees: average time for {} runs at speed {} = {:.5f}"

.format(angle, NUM_RUNS, SPEED, line_ave))

Начинаем с импорта счетчика производительности perf_counter из модуля time. Эта функция возвращает время в секундах в виде значения с плавающей точкой. При этом ответ она дает более точный, чем time.clock(), которую заменила, начиная с Python 3.8.

Далее импортируем модуль statistics, с помощью которого вычислим среднее значение по множеству запусков симуляции. После импортируем turtle и настраиваем turtle screen. Вы можете подстроить экран под свой монитор, но помните, что у вас должна быть возможность видеть линию длиной 962 пикселя.

Теперь присваиваем значения ключей для симуляции. Помещаем углы для прямой и наклонной линий в кортеж ANGLES, после чего присваиваем переменную для хранения числа циклов for и скорости отрисовки линии.

Начинаем перебор углов в кортеже ANGLES. Создаем пустой список для хранения измеренных значений времени , после чего настраиваем объект turtle, как делали это ранее. Поворачиваем объект turtle влево на значение angle и с помощью setpos() перемещаем его к левому краю экрана.

Перемещаем указатель-черепаху вперед на 962 пикселя, вписывая команду между вызовами perf_counter(), чтобы замерить время этого перемещения . Вычитаем итоговое время из начального и заносим результат в список times.

Завершаем процесс, используя функцию statistics.mean() для вычисления среднего времени отрисовки каждой линии. Выводим результат с точностью до пяти десятичных знаков. После выполнения программы результат должен выглядеть, как на рис. 12.5.

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

Проект #16. Жизнь, Вселенная и пруд черепахи Йертл      347

гарантирует одинаковую длину обеих линий и точность сравнения времени их отрисовки.

Рис. 12.5. Результирующее изображение на экране turtle для line_compare.py

Результаты

Если вы нарисуете каждую линию 500 раз и сравните результаты, то увидите, что на наклонную линию тратится примерно в 2.4 раза больше времени.

Angle 0 degrees: average time for 500 runs at speed 0 = 0.06492

Angle 3.695220532 degrees: average time for 500 runs at speed 0 = 0.15691

У вас значения времени наверняка будут немного отличаться, поскольку на скорость выполнения влияют и другие программы, параллельно выполняемые на вашем компьютере. Как я уже отмечал, всеми этими процессами руководит планировщик задач CPU, обеспечивая быстродействие системы, а также эффективность и равномерность распределения ее ресурсов.

Если повторить эксперимент 1000 раз, то результаты должны оказаться такими же. (Если решите это проделать, то не забудьте прежде запастись чашечкой кофе и вкусностями.) Наклонная линия требует примерно в 2.7 раза больше времени.

Angle 0 degrees: average time for 1000 runs at speed 0 = 0.10911

Angle 3.695220532 degrees: average time for 1000 runs at speed 0 = 0.29681

Здесь мы выполняли короткую функцию с высокой скоростью отрисовки. Если вас беспокоит тот факт, что turtle с целью повышения скорости выполняет оптимизацию, пренебрегая точностью, то можете уменьшить значение скорости и выполнить программу еще раз. При установке значения speed = 6 на рисование