считать в hex и переводить в десятичную систему будет быстрее, чем считать сразу в десятичной. 1 000 000 000?
Adrax, может объяснишь нам дуракам, в чем проблема? Скомпилил я код, который ты выдрал с VC++ (он находится здесь, просто тогда времени совсем не было разбираться http://forum.sources.ru/index.php?showtopic=201879 ). Сравнил с тем, что я выложил здесь. Сишный вариант оказался в 1.8 раз медленнее, считай как и Борландовский вариант, поскольку оптимизация у них еще та Так с чего ты взял, что он быстрее??? Было бы лучше, если бы не нужен был остаток от деления, а его так просто не получишь
AndNot Нахождение остатка от деления X на 10 используя умножение Код (Text): mov eax,X mov edi,eax;сохраняем X mov edx,1999999Ah;умножаем на 2^32/10 mul edx;в edx частное lea edx,[edx+edx*4];умножаем edx на 5 add edx,edx;умножаем edx на 2, теперь edx=edx*10 sub edi,edx;в edi остаток sbb edx,edx;коррекция остатка для X>40000004h and edx,10;если edi<0, тогда edx=10 иначе edx=0 add edi,edx;в edi скорректированный остаток
Что то подсказывает мне, что получится тот же вариант, что и с заменой условных переходов, т.е. ничего не даст, поскольку инструкций море и каждая зависит от предыдущей.
А вот так делит на 10 компилятор VC8: Код (Text): mov ecx, X mov eax, 1717986919 imul ecx sar edx, 2 mov eax, edx shr eax, 31 add eax, edx ; результат в eax
n0name Беззнаковое деление на 10 по VC: Код (Text): mov eax, -858993459 mul X shr edx, 3 mov eax, edx ; результат в eax
Уважаемые программисты! Прошу прощения, что давно не появлялся в этой теме, начатой мной же самим 2 AndNot У меня ассемблерный вариант оказался медленнее сишного - потому и встал вопрос низкоуровневой оптимизации. Неужели, код получился настолько процессорозависимым, что на одном проце обгоняет сишный, а на другом - безбожно отстаёт? И ещё... Ваш код намного компактнее и продуманнее моего, но пытаясь его использовать, я столкнулся с проблемой: проверка на минус, 0, 1 проходит нормально, а любое другое число даёт один и тот же результат 2009262131 (т.е. вообще цикл не выполняется, тупо выдаётся значение какой-то ячейки) Исходник вот: Код (Text): format PE console include 'win32axp.inc' .data dllka db 'msvcrt.dll',0 name1 db 'scanf',0 scanf dd ? name2 db 'printf',0 printf dd ? inp db 'Input N:',0 d db '%d',0 d4 db '%04d',0 crlf db 13,10,0 N dd ? array dw 1 dw 999999 dup 0 .code fuck: xor edi,edi xor ecx,ecx xor esi,esi inc ecx inc esi mov ebp,2710h invoke LoadLibrary,dllka push eax invoke GetProcAddress,eax,name1 mov [scanf],eax pop eax invoke GetProcAddress,eax,name2 mov [printf],eax cinvoke printf,inp cinvoke scanf,d,N mov eax,[N] test eax,eax jl konets dec eax test eax,eax jle mtk1 _loop: xor ebx,ebx _do: movzx eax,word[array+ebx*2] imul ecx add eax,edi xor edx,edx div ebp inc ebx mov edi,eax mov word[array+ebx*2-2],dx cmp ebx,esi jb _do or eax,eax jnz _do inc ecx mov esi,ebx cmp ecx,[N] jbe _loop mtk1: dec esi movzx eax,word [array+esi*2] cinvoke printf,d,eax jz konets mtk2: dec esi movzx ecx,word[array+esi*2] cinvoke printf,d4,ecx test esi,esi jnz mtk2 konets: cinvoke printf,crlf invoke ExitProcess,0 .end fuck Если ошибка очевидна, а я её не нашёл - не бейте ногами, пожалуйста. Просто сейчас на кофеиновом марафоне, пару суток вообще не спал, оттого могу тупить, сам того не осознавая
После invoke значение ecx портится. А вообще неплохо бы иметь оталдчик. [+] флаги тоже портятся: Код (Text): mtk1: dec esi movzx eax,word [array+esi*2] cinvoke printf,d,eax jz konets
Adrax, скачай с этого сайта Олю, проблем не будешь знать. Очень удобный отладчик, да еще и установки не требует.
2 All Ё ммоё!Сейчас стал перемерять скорость выполнения скомпиленных экзешников, вычисляя 150000! (AMD64 2800+XP S-754 1024Mb-DDR400 WinXP SP1 Pro) Сишный код (из первого поста) выполняется за 5:41 Ассемблерный по советам AndNot Код (Text): format PE console include 'win32axp.inc' .data dllka db 'msvcrt.dll',0 name1 db 'scanf',0 scanf dd ? name2 db 'printf',0 printf dd ? inp db 'Input N:',0 d db '%d',0 d4 db '%04d',0 crlf db 13,10,0 N dd ? array dw 1 dw 999999 dup 0 .code fuck: invoke LoadLibrary,dllka push eax invoke GetProcAddress,eax,name1 mov [scanf],eax pop eax invoke GetProcAddress,eax,name2 mov [printf],eax cinvoke printf,inp cinvoke scanf,d,N mov eax,[N] test eax,eax jl konets xor edi,edi xor ecx,ecx xor esi,esi inc ecx inc esi mov ebp,2710h dec eax test eax,eax jle mtk1 _loop: xor ebx,ebx _do: movzx eax,word[array+ebx*2] imul ecx add eax,edi xor edx,edx div ebp inc ebx mov edi,eax mov word[array+ebx*2-2],dx cmp ebx,esi jb _do or eax,eax jnz _do inc ecx mov esi,ebx cmp ecx,[N] jbe _loop mtk1: movzx eax,word [array-2+esi*2] cinvoke printf,d,eax mov edi,esi dec edi jz konets mtk2: dec edi movzx ecx,word[array+edi*2] cinvoke printf,d4,ecx test edi,edi jnz mtk2 konets: cinvoke printf,crlf invoke ExitProcess,0 .end fuck выполнился за 5:38 А вот этот Код (Text): format PE console include 'win32axp.inc' .data dllka db 'msvcrt.dll',0 name1 db 'scanf',0 scanf dd ? name2 db 'printf',0 printf dd ? inp db 'Input N:',0 d db '%d',0 d4 db '%04d',0 crlf db 13,10,0 N dd ? len dd 1 array dw 1 dw 999999 dup 0 .code fuck: invoke LoadLibrary,dllka push eax invoke GetProcAddress,eax,name1 mov [scanf],eax pop eax invoke GetProcAddress,eax,name2 mov [printf],eax cinvoke printf,inp cinvoke scanf,d,N mov ebx,[N] test ebx,ebx jl konets mov edi,[len] xor esi,esi inc esi xor eax,eax cmp ebx,esi jb mtk1 mtk0: xor ecx,ecx mtk: movzx edx,word [array+ecx*2] imul edx,esi add eax,edx xor edx,edx mov ebp,2710h div ebp mov word[array+ecx*2],dx inc ecx cmp ecx,edi jb mtk test eax,eax jnz mtk inc esi cmp esi,ebx mov edi,ecx jbe mtk0 mov [len],edi mtk1: movzx eax,word [array-2+edi*2] cinvoke printf,d,eax mov esi,[len] dec esi jz konets mtk2: dec esi movzx ecx,word[array+esi*2] cinvoke printf,d4,ecx test esi,esi jnz mtk2 konets: cinvoke printf,crlf invoke ExitProcess,0 .end fuck выполнился за 5:27, став чемпионом по скорости! А теперь объясните мне, почему так? Ведь последний исходник реально коряв (честно - я выдрал его из дизасма сишного кода с минимальными изменениями), там даже присвоение в цикле выполняется! Так почему оптимизированный вариант проигрывает корявому?
Adrax, я же говорил, что это неоптимизированный вариант. Замени: Код (Text): imul ecx на Код (Text): imul eax, ecx Скорость возрастет.
vc++ 7.0 делает достаточно быстрый код, чтобы его обогнать, косметических улучшений типа замены imul ecx на imul ecx,eax недостаточно. Переводя "в лоб" код на ассемблер, практически всегда будет получаться чуть более медленный код, чем прототип. Чтобы достичь реального прироста, нужно оптимизировать алгоритм, а не способ его реализации. Может, стоит посмотреть, как калькулятор считает факториал? На моей (гораздо проще, чем AMD64 2800+XP S-754 1024Mb) машине calc.exe считает факториал 150000 за 4:40. Для сравнения код из поста №1 считает за 6:05.
2 cresta В том-то и дело, что calc.exe использует аппроксимирующие формулы. Там гамма-функция Эйлера используется: калькулятор даёт 32 первых цифры результата, десятичный его порядок и может вычислять факториала дробных чисел А мне нужен точный результат. Потому алгоритм только один - "умножение в лоб". Весь вопрос в том, как его максимально оптимизировать...
Может стоит поискать какую-нибудь либу для работы с длинными числами? С кода в первом посте можно скинуть 5% времени, перейдя от unsigned short array[1000000] = {1}; к unsigned int array[1000000] = {1}; Думаю, это распространяется и на асм-клоны.