![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| Mayk |
|
||||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Предлагаю сделать трэд, в котором будем размещать всякие вкусности, которые позволяет выделывать си(нечто среднее между "Маленьким тестом" Явы и "Находками" дотНета, ближе к последнему).
Итак, начинаем. 1) Быстрый floor(float):
Для того, чтобы отбросить дробную часть переменной var, используем macro_float_floor(var); или var=inline_float_floor(var). Тест(прост до безобразия):
floor() - 9 секунд macro_float_floor() - 4 секунды. inline_float_floor() - 1(одна) секунда(!!!) БАГИ И ОГРАНИЧЕНИЯ: Число должно быть нормализованным(а для |f| < 1 это не всегда так). Если число меньше нуля, то округление срабатывает не верно - число округленное число будет больше, чем неокругленное. (напомню, что аргументы высчитываются справа налево, а конструкция (a,b) высчитывает a и возвращает b, именно по этим причинам macro стоит первым аргументом - если его поставить взад, то он изменит d, и др. ф-циям будет нечего высчитывать)
Это сообщение отредактировал(а) Mayk - 2.9.2005, 06:26 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||||
|
|||||||
| Mayk |
|
|||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Нда, не густо ответов. Ладно, вот маленький хак номер
2) Подсчет битов. Довольно известный(благодаря fortune), но всё же не лишне напомнить
Использование - очевидно BITCOUNT(var) Это сообщение отредактировал(а) Mayk - 3.9.2005, 21:24 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
|||
|
||||
| maxim1000 |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
побалуемся немного
1 + 2 - 2 & 1 % кроме того, не все процессоры любят % или / некоторые делают эту операцию в 16 раз дольше, чем обычный + впрочем, тот процессор вообще имел специальную операцию для подсчета битов да и вообще... не люблю я макросы уже на BITCOUNT((int)sqrt(x*1.28)) время увеличится в кучу раз (в этому случае по моим подсчетам в 8 раз) по сравнению с вызовом функции, особенно, если сделать ее inline... Это сообщение отредактировал(а) maxim1000 - 5.9.2005, 01:14 -------------------- qqq |
||||
|
|||||
| Mayk |
|
||||||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Хмм, BitCount(0xf) даёт 2, что не верно.
Кстати, примерах надо заменить % 255 на & 255, работает бо быстрее Ладно, до целочисленной арифметике мы еще дойдем. Продолжаем мучать флоаты(если немного подправить, то и даблы). На очереди 3) быстрое преобразование float->int Мы возьмем все биты мантиссы, которые определяют целую часть, добавим к ней еще 1 бит на перед, домножим на -1 если флоат был отрицательным и успокоимся. Ф-цию можно еще пооптимизировать, но не хочется. Воскресенье, блин, лениво Итак:
Небольшие пояснения При отрицательной экспоненте (exp < 0), модуль числа гарантированно будет меньше 1. Вернём 0 в этом случае. int s содержит знак числа. Если исходное число было отрицательным, то s станет тоже станет отрицательным, так как битовые знаки int32 и float совпадают. Далее происходит сдвиг на 31 раздряд вправо. Так как s число знаковое, то при сдвиге знаковый бит не сбрасывается. Таким образом, если в начале число было отрицательным,то после сдвига все биты будут установлены в 1. Если число было положительным(и знаковый бит не был установлен), то все биты будут сброшены в ноль. s |= 1 устанавливает 1-ый бит. Таким образом если s было нулем, то оно станет единицей. Таким образом мы получим знак 1 со знаком исходного числа. Проверка К сожалению, в bcc55 нет ф-ции rint, с которой стоило бы сравнить. Ну ладно, меньше поводов для разочарований, что нас, возможно, обогнали Мы будем сравнивать с приведением типа. На верность
Код выдаст на экран(у меня по крайне мере выдал) только 6 пар чисел - 2 пары нулей, и пары единиц и двоек обоих знаков. Можете закоментировать if(j!=h) и понаблюдать 2 колонки одинаковых чисел в процессе сравнения. На скорость.
j объявлена как volatile, чтоб особенно умные компиляторы(gcc к примеру) не выкинули вызов ф-ций, а добросовестно присвоили j его значение. Результат: 0.235 секунды. Заменим j=float2int(f) на j=f. Результат: 1(одна) секунда(!!!). Обогнали компилер в 4 раза Это сообщение отредактировал(а) Mayk - 4.9.2005, 11:06 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||||||
|
|||||||||
| maxim1000 |
|
||||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 17 Всего: 110 |
конечно, неверно... как же оно может быть верно, если я перевел из bin 1100 в hex 0xb? исправил...
и неправильнее тут вся фишка именно в этом %255 дело в том, что &255 эквивалентно %256, данная операция затрагивает только последние 8 бит а нам как раз надо собрать информацию из всех 4 байт, именно для этого там стоит %255... -------------------- qqq |
||||
|
|||||
| Mayk |
|
||||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Протупил, каюсь На ночь глядя вспомним быструю целочисленную арифметику. Быстрое деление на константу Деление, как известно, происходит медленнее умножения. На этом можно сыграть (идея честно стырена из "Ассемблера для DOS, WIN,UNIX" Зубкова). Поделим число 55 на 10.
Трюк заключается в том, что после умножения в старших битах будет искомое число. Действительно, ведь t*(256/10) это то же самое, что и (t/10)*256 (т.к. умножение - это сочетательная операция). Очевидно, что кол-во бит на которое сдвигаем, это исходная степень двойки из множителя. Если использовать последние достижения плюсов, до можно писать типа
чтобы у компилятора не возникало желания просчитать константный множитель run-time'ом, запихнуть его в память, а потом доставать от туда(константы - дело не надежное). ОГРАНИЧЕНИЯ Очевидно, что трюк годится для беззнаковых чисел; Знаменатель должен быть не больше максимальной степени двойки(иначе множитель просто обратится в ноль) Результат не всегда соответствует действительности(выдаётся меньше на единицу). ПРОВЕРКА НА СКОРОСТЬ С делением 0x7fffff чисел(от 0 до 0x7fffff) ф-ции справились так(в начале идёт деление умножением, потом оператором /, потом ф-цией div()). mult=0.141000 elapsed oper/=0.328000 elapsed div()=0.281000 elapsed Надо подумать над точностью... -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||||
|
|||||||
| Void |
|
||||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
Mayk
Для хаков обычные правила форматирования кода неприменимы? По сабжу: имхо, при современных процессорах и оптимизаторах польза сомнительная. Вот, например, Intel C++ (да и MSVC 7.1 тоже) считает, что быстрейший способ разделить на 55 такой:
Я ничего не могу понять в этом коде, но ведь он прав, черт подери!
50 ms, 63636 (точный результат). В то время как fastdiv<55> дает 60 ms и 63606. Эрго: время таких оптимизаций давно прошло. Ну или, быть может, они актуальны на специфических компиляторах и железе. -------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
||||
|
|||||
| Mayk |
|
||||||||||||
![]() ^аВаТаР^ сообщение>> ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2616 Регистрация: 22.5.2005 Где: за границей разум а Репутация: 45 Всего: 134 |
Аййападоноккаюсьнафик. Просто мессага и так большая получилась
Угу. Не спорю. Но поразвлечься не мешает, ведь так?
Вот это нашим ассемблерщикам лучше не показывать. Засмеют нафик. Компилятор не догадался перевернуть цикл в орбатном направлении, дабы заюзать loop, хотя догадался взять ecx в кач-ве счетчика. К тому же при обратном счёте(for i=777; i >= 0; --i)) сравнение будет происходить быстрее, даже без лупы. Например, так:
(в это безобразие наивно преобразует код bcc55) иногда может выполняется быстрее, чем cmp eax,777. Не всегда впрочем. Так что в оптимизацию компилятора верить не надо. Надо проверять Вот еще одна БУГАГА. Зацените код из vs2003: я валяюсь. Это с /Ox. Без ox код еще смешнее(add eax,1 - это круто!)
При обратном счёте код немного оптимизируется:
Отсюда правило - циклы лучше делать в обратном направлении, ибо компиляторы тупые нафиг. Нее, оптимизация компиляторов - это фантастика. Всегда полезно знать пару запасных вариантов Это сообщение отредактировал(а) Mayk - 6.9.2005, 07:01 -------------------- Здесь был кролик. Но его убили. Человеки < кроликов, йа считаю. |
||||||||||||
|
|||||||||||||
| Void |
|
||||
![]() λcat.lolcat ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2206 Регистрация: 16.11.2004 Где: Zürich Репутация: 40 Всего: 173 |
Чего ржешь? А вообще, преимущество компилятора хотя бы в том, что он (если он нормальный) помнит латентности всех инструкций, чего человек физически не может. Зуб даю, что на любом мало-мальски объемном коде, ручная оптимизация, сравнимая по эффективности с тем, что сделают ICC или MSVC, либо невозможна, либо займет очень много сил и времени.
Прогони один и тот же код на VC 7.1 с -Od и с -Ox - тогда посмотрим, какая это фантастика -------------------- “Coming back to where you started is not the same as never leaving.” — Terry Pratchett |
||||
|
|||||
| p0s0l |
|
||||
![]() Г-н Посол ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 3668 Регистрация: 13.7.2003 Где: 58°38' с.ш. 4 9°41' в.д. Репутация: 2 Всего: 112 |
Вобщем, то что на первый взгляд кажется тормознутым, на деле может оказаться шустрее "оптимального" кода, т.к. в дело вступают всякие "хитрости" современных процов... Рекомендую книжку от Intel'а "IA-32 Architecture Optimization Reference Manual". Я её (и не только эту) когда-то давно заказал с их сайта, совершенно бесплатно с доставкой на дом (до меня шло полгода А вообще тема интересная -------------------- С уважением, г-н Посол. |
||||
|
|||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |