Как оптимально найти кол-во бит в '1' в переменной.
- Войдите на сайт для отправки комментариев
Есть задача найти количество бит, выставленных в '1', в переменной.
То есть, переменная, со значением, например, 0xAA, и нужно посчитать количество бит выставленных в '1' в этой переменной.
Результат для 0xAA - 4 бита = 4.
Переменная может быть: uint8_t, uint16_t, uint32_t... или int16_t, int32_t, int64_t...
Понятно что это можно это сделать сдвигом, и проверкой.
Тогда для переменной uint64_t будет сделано 64 цикла.
А как с минимальным временим, для МК, выполнить эту задачу?
Сегодня пока ехал домой с работы, и тер с приятелем на эту тему, родилось прикольное решение.
Для 0x55 можно сделать только 4 цикла и две строчки кода. ;)
Он знает мою слабость к булевой алгебре и оптимальным решениям типа вертикальных счетчиков :-).
А какова прикладная цель данной задачи? Что потом с результатом то будете делать? Просто интересно.
Сергей, вот в этой книге есть целая глава про эту задачу. Полюбопытствуйте.
Не мудрствуя лукаво
Не мудрствуя лукаво
O_O Это как раз мудрствуя. Не мудрствуя вот:
14 байт кода:
Вот и я таким же образом всегда делал.
Сергей, вот в этой книге есть целая глава про эту задачу. Полюбопытствуйте.
Книжка очень интересная, я раньше не сталкивался с ней. Спасибо!!!
Поднятая тема в ней раскрыта.
SergeiL там написано что если нет 256 байт под таблицу, то всё печально относительно скорости...
Раньше в библиотеке берёшь книжку, а там всё исписано "книга очень интересная"... Типа, отзывы.)
Даже в ARM не запасли встроенную инструкцию по этому поводу - видимо не очень часто используется.
14 байт кода:
Я на Асме под AVR не писал. Еще на 8051 перешел с Асма на Си.
Посмотрел вариант со сдвигом в цикле на Си, он ровно в такой же код как у вас компилируется.
Мне очень понравился данный вариант:
Тут в цикле крутимся только столько раз, сколько '1'
Понятно, что это "копейки", но прикольно.
Посмотрел вариант со сдвигом в цикле на Си, он ровно в такой же код как у вас компилируется.
ПРУФ будет ? Я то же посмотрел что во что вырисовывается.
Тут в цикле крутимся только столько раз, сколько '1'
дак в моём тоже, пока есть 1, крутимся, кончились - выходим
дак в моём тоже, пока есть 1, крутимся, кончились - выходим
нет Деда, тут большая разница. Твой цикл пропускает нули только в старших разрядах...
Если, для примера, взять байт 0b00010000 - то твой цикл отработает его за 5 итераций. а этот - всего за одну.
Тут в цикле крутимся только столько раз, сколько '1'
дак в моём тоже, пока есть 1, крутимся, кончились - выходим
А для 0x8000000000000000 сколько раз прокрутимся? Это uint64_t c 1 в старшем разряде.
Да понятно, что это только в теории. :-)
Да понятно, что это только в теории. :-)
почему "только в теории"? - алгоритм рабочий, ошибок в нем не вижу
добавка ... хотя нет, вроде понял, о чем вы... операция x & y , где оба операнда - uint64 - явно будет выполнена не за одну операцию контроллера...
дак в моём тоже, пока есть 1, крутимся, кончились - выходим
нет Деда, тут большая разница. Твой цикл пропускает нули только в старших разрядах...
Если, для примера, взять байт 0b00010000 - то твой цикл отработает его за 5 итераций. а этот - всего за одну.
Согласен.
А вот интересно, кто нибудь использовал подсчёт этих 1-ц? И для каких целей?
А вот интересно, кто нибудь использовал подсчёт этих 1-ц? И для каких целей?
У меня климат задний в машине светодиодиками показывает выставленный уровень.
Нужно его считать и вывести миганиями на индикатор на передней консоли.
Светодиоды ШИМ-тся для снижения яркости в вечернее время, тут все на ассиметричных вертикальных счетчиках прекрасно решается, по маске.
Незамаскированные биты (кнопки) обрабатываются симметрично.
Весь дребезг и ШИМ устраняется за 1 проход для всех каналов светодиодов и кнопок (без циклов). Т.К. они лезут в 1 байт.
Так и прикольно же написать "правильно" :-)
А вот интересно, кто нибудь использовал подсчёт этих 1-ц? И для каких целей?
Я использовал. Очень давно, правда, когда ещё бортовые вычислители программировал, а это уж почти неправда. По прямому назначению. Было восемь датчиков, каждый взводил свой бит, а мне было важно сколько датчиков сработало. Не важно, какие именно - важно сколько. Вот и использовал.
Код:
Листинг после компиляции:
SergeiL Чем компилировали ? (не похоже на GCC)
Очень похоже, но длиннее (реализации возврата еще не видно в листинге).
Вот вариант с обходом только единиц, 20 байт (аналог кода из #10):
Я использовал. Очень давно, правда...
А я совсем недавно. Приходилось шимить 7-ми сегментник, в зависимости от кол-ва одновременно горящих сегментов.
А ещё есть вот какое чудо):
Green сдвига на нужное число бит нет в AVR - листинг будет ужасен ...
Главное что бы исходник был запутанным.)
Обычно табличное преобразование. Делали и так.
А если двумя полубайтами прецтавить, длина таблицы существенно снизица.
SergeiL Чем компилировали ? (не похоже на GCC)
Очень похоже, но длиннее (реализации возврата еще не видно в листинге).
Вот вариант с обходом только единиц, 20 байт (аналог кода из #10):
Компилировал древним iccavr (от imagecraft). Билд v.7.23, аж от 2010-го года. Последний из v.7
Я им давно пользуюсь, где то с начала 2000-ных, начиная с v6. А вот версия 8 не зашла, очень тяжелая была.
Код из поста #10 компилируется так:
У ICCAVR с давних времен есть очень удобная штука "Application Builder"
Выбираем кристалл частоту, порты, и т.д.
Приложение генерит код, который можно править, не залезая в даташит.
ICC Генерит код:
Не, не очень. У CodevisionAVR Wizard начиная с v.3 генерит с наименованиями битов.
Есть и отдельные утилиты, типа AvrWiz. Чего только не выдумают для ленивцев.)