Как сделать сверхбыстрое деление? Может быть кто-нибудь сравнит с div или с подбором и последующей заменой деления на умножение, пока вот такой набросок Код (Text): mov edx,ДЕЛИМОЕ bsr ecx,edx mov ebx,ДЕЛИТЕЛЬ bsr eax,ebx sub ecx,eax mov ebp,1 shl ebp,cl shl ebx,cl xor eax,eax; в EAX место под частное, в EDX -- остаток or esi,-1 a1: mov edi,ebx add edi,esi xor edi,esi; neg edi add edx,edi sbb esi,esi; esi=-1 or esi=0 mov edi,esi and edi,ebp; edi=ebp or edi=0 add eax,edi test edx,edx jz a2;exit shr ebx,1 shr ebp,1 jnz a1 a2:
Что-то мне кажется вряд ли процедура, в которой два три десятка строк и два уловных перехода, сможет обогнать одну команду.... Да вот ещё строки в ней непонятные есть... Код (Text): or esi,-1
Если делитель -- произвольное число, то обогнать команду DIV/IDIV невозможно. Вот если делителем является заранее известная величина, т.е. константа, тогда это вполне возможно, чем и пользуются "умные" компиляторы.
В Уоррене есть глава, посвещенная делению произвольных целых чисел, а также отдельная глава выделена быстрым способам деления на константы.
Надеюсь, не сочтут варезом.. http://rapidshare.com/files/185136839/Henry_warren-algorithmicheskie_tryuki_dla_programmistov.rar.html
Proteus or esi,-1 (3 байта) более компактный аналог mov esi,0FFFFFFFFh (5 байт) у Уоррена процедура деления длинее 23 строк -- однако его никто не ругает
Уорен чаще для RISK проц. пишет. И процедура соотв. имеет смысл на камне у которого команды деления нет. Там она видать и покороче будет. Вообще Уорена я первый раз читал, вроде всё понятно всё просто. Потом спустя год перечитываешь (когда что-то срочно вспомнить надо), и всё таки снова поражаешься, насколько красивые вещи в нём найти можно. А так делилка неплохая получилась...
Mikl___, выручай! Собсна, нужно брать остаток быстро от деления на F3000001 или D0000001, можно выбрать где проще... Такие заковыристые модули нужны для Быстрого Преобразования Фурье на 2^n точках. Сама процедура уже написана, но там стоит заглушка в виде DIV =))) Пробовал еще Фурье на числе 65537, там взятие модуля занимает строчек десять, но они работают в разы быстрее DIV. A сначала я сам тоже весьма скептически относился к замене одной DIV на кучу кода. Но это было квази 16-битное Фурье, а хочется квази 32-х битное. Для взятия этих остатков без деления нужно всетаки как- то ухитряться делить на F3 или 0D... С таблицами связываться не хочется, хочется чтобы все в регистрах было Короче говоря, нужно 64-битное число в регистрах edx,eax редуцировать по модулю F3000001 и вернуть резалт в регистре eax. Можно использовать сдвиги регистровых пар типа shrd eax,edx,24 , а на счет mul точно не знаю, можно обойтись без него или нет.
persicum Если на скорую руку. Делим на заранее известные числа F3000001 или D0000001 оба числа 32 разрядные ищем обратное к ним (2^63)/F3000001=2262369603,9224372979735059262368 после запятой число больше 0,5 поправка не нужна (2^63)/D0000001=2643056796,7810650889744365762706 после запятой число больше 0,5 поправка не нужна. делимое = частное * делитель + остаток остаток = делимое - частное * делитель ищем остаток от деления на F3000001 Код (Text): mov eax,2262369604; магическое число для F3000001 mul X; X - число от которого берем остаток, в EDX получим частное от деления mov eax,0F3000001h shr edx,31 mul edx neg eax add eax,X; в eax остаток от деления для D0000001 аналогично, только магическое число равно 2643056797
Спасибо за быструю реакцию! Однако есть пару возражений 1) метод универсальный и не учитывает квази ферматную структуру чисел. Может, можно было бы подвигать регистры? 2)...
2) нельзя ли для тупеньких причесать код чтобы входные 64 бита лежали в паре регистров edx, eax. У Вас по ходу дела в X кладется старшая половина от учетверенного слова? А где младшая? Или это я торможу, или Вы перепутали 64 битные данные с 32-х битными?
С этого места можно по-подробнее? ЗЫ. Я же написал "на скорую руку" дома поупражняюсь, до завтра терпимо?
Если число больше D0000001h, то остаток равен x-D0000001h. Иначе остаток равен x. Это верно для 32-битных чисел без знака. Код (Text): sub eax,D0000001h sbb edx,edx and edx,D0000001h add eax,D0000001h Жесть!
Многоуважаемый Mikl___! Если Вы всерьез решили помочь с написанием оптимального кода, то можете возвращаться к этой проблеме хоть всю неделю, хоть две, ибо оно конечно терпит, поскольку стандартный DIV вставлен пока в качестве вполне работоспособной заглушки. x = a*2^24 + b = (q*F3+r)*2^24 + b + q - q = q*(F3*2^24+1) + r*2^24 + b - q = r*2^24 + b - q
Чё-то сообщение не редактируется. Я хотел написать Код (Text): sub eax,D0000001h sbb edx,edx and edx,D0000001h add eax,edx
Если точнее, это числа Proth'а, которые я выловил с помощью одноименной программы, они же делители чисел Ферма 2^2^n+1.
А я хочу редуцировать 64-битные числа по модулю F3000001. Переполнения гарантированно нет, т.к. они сами получаются в результате MUL и лежат в паре регистров EAX-EDX.
Ещё так можно Код (Text): mov edx,eax sub eax,D0000001h cmovc eax,edx Про замену деления умножением есть в AMD Athlon™ Processor x86 Code Optimization Guide.