В академических наихудших случаях Big O обучают всему остальному. По сравнению с пространственной сложностью, обычным анализом случаев, простотой над сложностью и т. Д.
Что особенно важно для программирования и индустрии игр, и почему?
Ссылки будут очень полезны.
software-engineering
algorithm
Дэвид Янг
источник
источник
Ответы:
Как и в случае с любым другим вопросом, касающимся «что такое единственно верный путь», все это инструменты в вашем наборе инструментов, и есть случаи, когда big-O превосходит все и в местах, где это не имеет значения (тм).
Вы бы «никогда» не писали физический решатель, не заботясь о big-O. Вы бы не реализовали алгоритм сортировки (для любого, кроме самых маленьких наборов данных), не заботясь об этом. Если вы пишете сетевую игру, вы будете обеспокоены тем, как производительность и сетевой трафик масштабируются для каждого пользователя.
Вы можете не беспокоиться о биг-о, когда, ну, я не могу вспомнить время, но я уверен, что они есть. :) К счастью, большинство вещей, которые мы делаем в играх, масштабируются линейно; Вы хотите прочитать файл с диска? Это займет некоторое время, линейно пропорциональное размеру файла (исключая постоянный коэффициент поиска и возможные последствия размера сектора).
Однако что, если вы хотите найти конкретную сущность в списке сущностей? Это линейный поиск каждый раз, когда вы делаете это. Если вам нужно найти игрока по одному разу для каждой сущности в мире, этот подход убьет вас для всех, кроме самых тривиальных игр, и даже тогда, вероятно, стоит «оптимизировать» этот поиск, чтобы он был постоянным (например, хранить в индексе). или указатель на игрока где-нибудь), что дает вам больше времени, чтобы делать другие вещи, которые на самом деле видны игроку.
Я думаю, что это подводит итог, хотя; всякий раз, когда процессор делает что-то, что не может быть непосредственно представлено игроку, это напрасная трата времени. Максимальное количество времени, в течение которого процессор вычисляет данные, которые будут показаны игроку, максимизирует WOW! вы даете игроку.
источник
Мое эмпирическое правило заключается в том, что если вы не (страшно), другие ваши проблемы более актуальны.
Мое другое эмпирическое правило заключается в том, что данные являются королем. Если вы не профилируете свой код с реалистичным набором данных, вы просто делаете предположения.
Изменить: Если говорить чуть более подробно, ваш большой O не так важен, поскольку (по крайней мере, по моему опыту) большинство ваших наборов данных относительно крошечные. Возможно, вам не важен ваш верхний предел производительности, когда вы работаете со структурой данных, содержащей менее нескольких сотен элементов. И если в ваших списках более 100 тыс. Элементов, вам действительно нужно учитывать все аспекты ваших алгоритмов. Это, и из моего опыта память является более ограничивающим фактором, чем скорость процессора. Более быстрый алгоритм захвата памяти может быть не таким хорошим, как более тонкий, но более медленным, в зависимости от ваших вариантов использования.
источник
Большая O имеет значение в большинстве случаев, но иногда «худший» алгоритм теоретически оказывается намного быстрее на практике.
Посмотрите отличный пример от Тони Альбрехта: http://seven-degrees-of-freedom.blogspot.com/2010/07/question-of-sorts.html
Вы найдете это повсеместно в разработке игр, где количество элементов в операции либо настолько велико, что совсем другой алгоритм работает быстрее, либо настолько мало, что алгоритма тупее достаточно (или помещается в кэш, так что он переопределяет эффективность от лучшего алгоритма).
Проблема с Big O заключается в том, что это общее обозначение сложности задачи и не учитывает сложность современного целевого оборудования, а также не дает никаких сведений о накладных расходах времени установки.
Во многих случаях лучшее оптимальное решение - это два шага. На практике разработчики игр, как правило, стремятся использовать алгоритмы с низким уровнем O, но при этом затрачивают время на разработку или отладку. Когда у вас есть разумное решение, вы всегда должны смотреть на то, как аппаратное обеспечение справляется с задачей, и как сделать так, чтобы аппаратное обеспечение сделало больше за меньшее время.
источник
Когда я кодирование в движке, я часто касается только с фиксированным
n
: Я уже получил раздел пространственного ограничивающего числа объектов приемаupdate()
,physics()
иrender()
примерно тех , кто на экране и прилегающих районах. Максимальный размер партии обычно довольно четко определен для каждой игры, хотя он всегда немного больше, чем вы планировали.В этом случае меня интересует не столько биг-о, сколько множитель с постоянным множителем и члены более низкого порядка. Для функции со средой выполнения, подобной
a*n^2 + b*n + c
(которая естьO(n^2)
), я часто гораздо больше озабочен сокращениемa
и, возможно, устранениемc
. Стоимость установки или демонтажаc
может стать пропорционально большой по сравнению с небольшойn
.Однако это не означает, что big-O (или, более конкретно, big-theta ) является отличным индикатором запаха кода. Посмотрите
O(n^4)
где-нибудь или, что еще хуже,O(k^n)
геометрическое время, и пришло время убедиться, что вы рассматриваете другие варианты.Я, как правило, гораздо больше беспокоюсь об оптимальности Big-O и прыгаю через обручи, чтобы найти алгоритмы с более низким Big-O, когда я имею дело с инструментами создания данных. Хотя количество объектов в данном уровне / области потоковой передачи, как правило, четко определено, общее количество объектов / художественных ресурсов / файлов конфигурации / и т. Д. Во всей игре может не совпадать. Это также намного большее число. Даже запуская параллельное создание данных, мы все еще ждем порядка минуты (я знаю, скулить - записи данных для консолей могут занять часы - мы в основном небольшие портативные игры), чтобы пройти
jam data-clean && jam data
цикл.Чтобы привести конкретный пример: это действительно вышло из-под контроля с помощью алгоритма фоновой потоковой передачи потоков, который обрабатывает 8x8 256-цветных листов. Полезно разделять потоковые буферы между фоновыми «слоями», и у нас может быть до 6 из них на данном уровне, совместно использующих один и тот же буфер. Проблема состоит в том, что оценка размера необходимого буфера основана на возможных позициях всех 6 слоев - и если они имеют простое число ширина / высота / скорость прокрутки, вы быстро начнете выполнять исчерпывающий поиск - который начинает приближаться
O(6^numTiles)
- которая во многих случаях относится к категории «дольше, чем будет вселенная». К счастью, в большинстве случаев это всего 2-3 слоя, но даже в этом случае мы работаем выше получаса. На данный момент мы выбираем очень небольшое подмножество этих возможностей, увеличивая степень детализации до тех пор, пока не пройдет заданный промежуток времени (или мы выполнили задачу, которая может произойти для небольших двухслойных конфигураций). Мы немного повысили эту оценку на основе предыдущих статистических данных о том, как часто мы ошибались, а затем добавили немного дополнительных отступов для хорошей оценки.Еще один забавный пример: некоторое время назад в компьютерной игре ведущий инженер некоторое время экспериментировал с пропуском списков . Перерасход памяти приводит к увеличению эффектов кэша, что добавляет неконстантный множитель для всего дела - так что они действительно не являются хорошим выбором для маленьких
n
. Но для больших отсортированных списков, где поиск часто, они обеспечивают выгоду.(Я часто нахожу, что наивный алгоритм выше, чем big-O, быстрее для небольших наборов данных и легче для понимания; более интересные / сложные (например, patricia trie) людям труднее понять и поддерживать, но более высокую производительность при больших наборы данных.)
источник
Это может быть удобно, но может быть и неактуально. Возьмите, к примеру, мою последнюю игру, которая является чем-то вроде клона Smash TV. Сверху вниз игра, монстры вливаются с боков, вы их стреляете.
Сейчас есть много умных способов определения столкновений. Вы можете использовать KDtrees для разделения пространства, чтобы не проверять пули против монстров, которых они не могли поразить. И, конечно, я мог бы быть умным, и я мог бы сделать это.
Но мне было лень, поэтому я сравнил каждую пулю с каждым монстром. Даже в самых напряженных ситуациях код столкновения использовал намного меньше 10% игрового процессора при 60 кадрах в секунду. Big-O: неважно.
Точно так же у меня была игра в стиле 4x, в которой вы строили города на островах, а иногда города разрушались. Я мог бы быть умным и попытаться вычесть доход разрушенного города из переменных дохода. Но я не сделал. Я просто стирал доход и пересчитывал его с нуля каждый раз, когда что-то менялось. Совершенно не имеет значения с точки зрения процессора.
Big-O так же важен в играх, как и во всем остальном: то есть совершенно неважно, вплоть до критического уровня.
Иди напиши какой-нибудь код. Если это слишком медленно, то профилируйте это.
источник
Анализ Big-O важен, но это не первое, о чем нужно думать при разработке игр. Поскольку в создании игр было много сложного кода, я всегда рекомендовал Code Simplicity в качестве первого критерия для алгоритма. Алгоритмы со сложной бухгалтерией просто тратят ваше время.
Я думаю, что очень важно, чтобы ваша игра всегда работала со скоростью 60 кадров в секунду во время разработки. Когда вы опускаетесь ниже этого уровня, первое, что вы делаете, это запускаете профилировщик. Как только вы найдете узкое место, вы атакуете его. Большую часть времени вам нужно делать некодирующие вещи, такие как указывать дизайнерам уровней, чтобы они помещали меньше вещей в область (и предоставляли им инструменты для этого).
Иногда вы на самом деле идентифицируете некоторый код, который необходимо ускорить. Я считаю, что это забавная инженерия! Я хотел бы иметь больше возможностей сделать это. И, конечно же, вы хотите повторить изменение одной вещи за раз и измерить производительность. Типичные проблемы, которые я нахожу:
источник
Нотация Big-O по определению является асимптотической сложностью, т. Е. Показывает, как масштабируется время, когда N (или какие-либо переменные, которые у вас есть) становятся «очень» большими. Чтобы повторить комментарий Тетрада (который я поднял) «данные - король». Если N «очень большой» в вашей конкретной ситуации, это имеет значение, если N «очень маленький», это не имеет значения. Опыт и практика дадут вам представление о том, как количественно определить «очень большой» и «очень маленький».
Очевидно, что сначала всегда нужно профилировать, а в последний раз оптимизировать (если вы не выполняете технико-экономическое обоснование).
источник
Важность Big-O в вашем программном обеспечении - O (N 2 ). С ростом N важность правильного алгоритма возрастает еще больше. :)
источник
Big-O - это просто руководство - то, что говорит вам о приблизительной производительности, которую вы можете ожидать от алгоритма, - и о том, как вы должны ожидать, что производительность будет увеличиваться по мере увеличения размера набора данных . Вы должны помнить две основные вещи в отношении Big-O:
1) Если у вас есть два алгоритма, которые в основном делают одно и то же, но у одного лучше O, вы, вероятно, должны пойти на этот (очевидно)
2) Большой О связан с асимптотическим анализом . Big-O действительно вступает в игру только тогда, когда n большое . Например, алгоритм O (n) может быть очень похож по производительности на алгоритм O (n ^ 2) .. для малых n . Если вы говорите об алгоритме , который требует п ^ 2 операций в вершине, а п = 2 или п = 3, то есть не большая разница между O (N ^ 2) алгоритм ( с 4 и 9 опс RESP) и O (N) один (2 и 3 операций соответственно). Однако, если n = 9, то вы вдруг говорите о 81 операции для алгоритма O (n ^ 2) и только 9 для алгоритма O (n) - большая разница - и если n = 100, то вы говорить о 100 опс против 10000 - гораздо большая разница.
Таким образом, вы всегда должны рассматривать Big-O в этом свете: оно предназначено для сравнения алгоритмов, которые делают то же самое, основываясь на худшей производительности, когда n становится большим . Различия между алгоритмами могут быть незначительными, если n очень мало.
источник
У меня нет ссылок, но Big O, по крайней мере, удобно знать при анализе проблемы и обсуждении. С другой стороны, если, конечно, O (журнал N) версия имеет способ более активное участие O, чем O (N) версия этого сравнение спорно. И как со всем, всегда есть компромисс. Сложность пространства может быть проблемой, хотя это может быть выражено и в целом. Нормальный анализ случая ... меньше, потому что вы не хотите, чтобы выбросы тоже резко возросли. Простота, а не сложность, на мой взгляд, относительно бесполезна в разработке игр, так как скорость почти всегда является проблемой, поэтому, если простота не приводит к ускорению (но тогда это означает, что ваш сложный случай был неправильным по неправильным причинам), простота должна пойти из окна в пользу скорости. Но Big O определенно полезен,
источник
Когда прототип функции игры или аспект игры, вы не должны беспокоиться об оптимизации вообще .
В ходе создания прототипа и изучения особенностей этой функциональности необходимые оптимизации станут очевидными и будут влиять на окончательный дизайн, как 2-й характер ... большую часть времени.
Не парься.
источник
Это не должно быть началом и концом всего. Но это помогает разобраться в очевидных проблемах, которые могут привести к снижению производительности; зачем использовать что-то за O (n ^ 2), когда вы можете сделать то же самое за O (log n)?
Я думаю, что это относится к играм в большей степени, чем к большинству других отраслей, так как рынок - это тот, кто больше всего заметит проблемы со скоростью. Кому-то, работающему с текстовым процессором, все равно, будет ли задержка в полсекунды для выполнения действия X, но геймеры, вероятно, пойдут «Боже мой, игра Y настолько медленная, что для выполнения действия Z требуются целые годы».
источник
В разработке игр (и большинства других) мы жалуемся на одну дополнительную операцию, выполняемую за цикл:
против
В большинстве современных игр есть физика, и вы найдете проблему симуляции n-body . В наивном алгоритме это O (n ^ 2), но есть оптимизация, которая делает его O (n log n) (но жертвует некоторой точностью).
Вы могли бы сказать, что вы программируете не гравитацию, а взаимодействие частиц, а как насчет командного поведения армии (зомби), где они движутся в зависимости от других локаций (более конкретным словом: роение)?
В обычном алгоритме обнаружения столкновений временная сложность равна O (n ^ 2), как и n-body. Однако есть лучший способ: разделить мир на множество мелких частей, чтобы только объекты внутри одной части были обнаружены при столкновении. См. Http://www.videotutorialsrock.com/opengl_tutorial/collision_detection/text.php .
Если ваша игра написана для сценариев, НЕ заставляйте сценария писать в скрипте O (n ^ 2) (и более) алгоритмов перебора чисел, таких как поиск в сумке пользователя. Вместо этого сделайте встроенную функцию в коде.
источник
В реальном мире важна только сырая производительность. Теперь Big-O алгоритма может служить первым указанием на то, что использовать, но в зависимости от аппаратного обеспечения реализация может быть ужасно неэффективной. Например, выполнение линейного поиска часто может быть быстрее, чем бинарный поиск, потому что вы получаете линейный доступ к памяти и никаких ветвей.
Кроме того, из-за текущего направления в многопоточных платформах и архитектурах Big-O теряет большое значение, поскольку он учитывает только вертикальную масштабируемость памяти или касаний данных на операцию, а также не учитывает то, как алгоритм весы с большим количеством нитей.
источник