Легкий мозговой штурм, лучший алгоритм

Это было в колледже. Я потерпел неудачу, но хочу знать ответ.

Проблема заключается в следующем: у вас есть 2D-массив структур, который представляет изображение. Каждая структура имеет красное, зеленое, синее и альфа-значение. Может быть больше информации, но не требуется для решения проблемы.

Скажите, что изображение 4000x4000 или 16 миллионов элементов. Каждый элемент необходимо обновлять/проверять на каждом шагу.

Для каждого элемента вам необходимо:

  • Установите красный байт в 50, если < 50 или установить значение 205 > 205
  • Установите зеленый байт в случайное значение от 0 до 255, используя rand()
  • Измените синий цвет "интересным" способом.

"Вы не можете перенаправить это, подумайте более разумно, вам нужен лучший алгоритм"

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

Также должен быть чистый C. Нет OpenMP/Threads или OpenGL shading, OpenCL и т.д.... только ANSI C со стандартными библиотеками (даже библиотеки GNU/POSIX были запрещены).

Я спросил о побитовых операциях, и он сказал, что "они очень дороги в C [??], и о написании быстрого и надежного алгоритма, а не об этих милых трюках, которые вы продолжаете придумывать".

Итак, какие-нибудь намеки?

Ответы

Ответ 1

Решение 1

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

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

Во-вторых, вы хотите обновить пиксели в том порядке, в котором они хранятся в памяти. Это означает, что во внутреннем цикле выполняется цикл по размеру внутреннего массива. Это позволяет компилятору и ЦП эффективно обращаться к пикселям в больших кусках (ключевые слова кеш-линии и предварительная выборка).

Решение 2

Совершенно другой подход заключается в добавлении слоя косвенности.

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

Это похоже на шаблон Decorator на объектно-ориентированном языке.

Ответ 2

Да, пусть все выяснят, как написать алогиризм, чтобы "Модифицировать синий" интересным "способом", если это "быстро и твердо". Гласные колледжи учатся так сильно. Я никогда не слышал, чтобы побитовые операции были дорогими. Дорогой по сравнению с чем? Когда вы говорите, что вы были "самым быстрым", вы имеете в виду, что вы первыми придумали ответ или что ваш ответ был наиболее эффективной реализацией? Если вы вынуждены хранить данные как 2D-массив структур (в отличие от дерева), я не уверен, что еще вы можете ожидать. Значит, вы знаете, что вам это не удалось, но не получили правильного ответа? Теперь, что я называю edjumacation!

Ответ 3

Вызов rand(), скорее всего, будет доминировать во время выполнения программы, поэтому нет смысла пытаться быть умным с помощью интеллектуальной структуры цикла или причудливых побитовых операций.

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


Что касается того, чего действительно хотел учитель, вот дикое предположение:

  • Используйте rand для установки зеленого байта
  • Используйте некоторый причудливый метод для установки красного байта
  • Включите синий байт где-нибудь в своем фантастическом методе, поэтому он получает новое значение как удобный побочный эффект
  • В конечном итоге с загадочным и бессмысленным однострочным (потому что он думает, что меньше строк, которые программа имеет быстрее, должна выполняться)

Ответ 4

Это похоже на вопрос интервью. Это глупо! Если вам нужно посетить каждый пиксель, вам нужно использовать циклы! В конце концов, это их цель. Лучшее, что вы можете сделать, это сделать один цикл вместо двух и отредактировать больше пикселей на каждой итерации

Ответ 5

ok - я вижу что-то интересное...

'на каждом обороте

поэтому, возможно, есть некоторая оптимизация, чтобы не выполнять красную проверку после первой итерации, поскольку эти значения будут статическими

Ответ 6

Единственным способом, которым я могу это понять, является то, что "скажем, что изображение составляет 4000x4000 или 16 миллионов элементов. Каждому элементу требуется для обновления/проверки на каждом шагу". на самом деле означает "Скажем, что изображение составляет 4000x4000 или 16 миллионов элементов. Каждому элементу понадобится, который будет обновляться/проверяться на каждом шагу".

Затем он говорит: "Также должен быть чистый C. Нет OpenMP/Threads или OpenGL shading, OpenCL и т.д.". Зачем упоминать "затенение OpenGL" для такого основного вопроса?

Я думаю (я только догадываюсь), что фактический вопрос был более подробным, и подталкивал ученика к тому, чтобы каким-то образом обрезать обработку изображения (т.е. какая-то часть изображения закрыта или выключена, поэтому вы можете пропустить эти биты).

Это просто догадка. Как сказал мой младший брат: "Это не имеет смысла иначе!!!"

Ответ 7

Возможно, инструктор искал некоторую производительность, полученную при обработке цветов в отдельных циклах:

for each pixel
    red pixel = (red pixel < 50) ? 50 : ((red pixel > 250) ? 250 : red pixel);
end-for

for each pixel
    green pixel = 256 * rand()
end-for

for each pixel
    blue pixel = (green pixel * 1024) % 256;
end-for

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

Изменить 1:

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