Здравствуйте! У меня такой вопросик: мона ли тут что-нить оптимизировать, и если да, то, что конкретно: Код (Text): int Lyrik(const char* buff) { long total = 0; _asm { xor eax,eax; xor ecx,ecx; mov esi,buff; cikl: mov cl,byte ptr [esi]; test cl,cl; jz endstr; cmp cl,'0'; jge ok; opt: inc esi; jmp cikl; ok: cmp cl,'9'; jle okey; jmp opt; okey: sub cl,'0'; imul eax,0xA; add eax,ecx; jmp opt; endstr: mov esi,buff; mov cl, byte ptr [esi]; cmp cl,'-'; jne kon; neg eax; kon: mov total,eax; } return total; }
Можно избавиться от секции opt: Код (Text): xor eax,eax; xor ecx,ecx; mov esi,buff; dec esi; cikl: inc esi; mov cl,byte ptr [esi]; test cl,cl; jz endstr; cmp cl,'0'; jl cikl; ok: cmp cl,'9'; jg cikl; sub cl,'0'; imul eax,0xA; add eax,ecx; jmp cikl; endstr: mov esi,buff; mov cl, byte ptr [esi]; cmp cl,'-'; jne kon; neg eax; kon: mov total,eax;
Ну и можно удалить cmp cl,'0', сразу заменив его на sub cl,'0' Код (Text): xor eax,eax xor ecx,ecx mov esi,buff dec esi cikl: inc esi mov cl,byte ptr [esi] test cl,cl jz endstr sub cl,'0' js cikl cmp cl,9 jg cikl imul eax,0xA add eax,ecx jmp cikl endstr: mov esi,buff mov cl, byte ptr [esi] cmp cl,'-' jne kon neg eax kon:
Lyrik Код (Text): imul eax,0xA add eax,ecx замени на Код (Text): lea eax,[eax+eax*4] lea eax,[ecx+eax*2] S_T_A_S_ что должен делать __asm код Afaik atoi/atol.
Lyrik А такой вопросик - на предмет чего оптимизируем? Скорость, размер, удобочитаемость? Кол-во переходов, конечно, потрясает. Такое подойдет? Код (Text): mov esi, buff dec esi xor eax, eax xor ebx, ebx @@: inc esi movzx eax, byte ptr [esi] test eax, eax jz @F sub eax, 30h sbb edx, edx sub eax, 10 sbb ecx, ecx not edx and edx, ecx jz @B lea ebx, [ebx+ebx*4] lea ebx, [eax+ebx*2+10] jmp @B @@: mov esi, buff movzx eax, byte ptr [esi] cmp eax, "-" jnz @F neg ebx @@: mov total, ebx
S_T_A_S_ Оригинальная версия вернет 1, т.к. закончит преобразование, встретив пробел между "1" и "!". Afaik когда речь идет об оптимизации подразумевается, что исходные данные идеальны.
глядя на избыточный код первоначальной версии, сложно сказать что исходные данные идеальны. Код (Text): int __fastcall my_atoi(const char * s) { while( *s++ <= ' ' ) ; int sign = s[-1] != '-'; s -= sign--; int res = 0; while( true ) { unsigned digit = *(unsigned char *)s++ - '0'; if( digit <= 9 ) res = 10 * res + digit; else return (sign ^ res) - sign; } } на всякий случай дизасм: Код (Text): 0040103D /$ 8A01 /mov al, [ecx] 0040103F |. 41 |inc ecx 00401040 |. 3C 20 |cmp al, 20 00401042 |.^ 7E F9 \jle short 0040103D 00401044 |. 33C0 xor eax, eax 00401046 |. 8079 FF 2D cmp [byte ecx-1], 2D 0040104A |. 56 push esi 0040104B |. 0F95C0 setne al 0040104E |. 8BF0 mov esi, eax 00401050 |. 2BCE sub ecx, esi 00401052 |. 4E dec esi 00401053 |. 33C0 xor eax, eax 00401055 |. EB 05 jmp short 0040105C 00401057 |> 6BC0 0A /imul eax, eax, 0A 0040105A |. 03C2 |add eax, edx 0040105C |> 0FB611 movzx edx, [byte ecx] 0040105F |. 83EA 30 |sub edx, 30 00401062 |. 41 |inc ecx 00401063 |. 83FA 09 |cmp edx, 9 00401066 |.^ 76 EF \jbe short 00401057 00401068 |. 33C6 xor eax, esi 0040106A |. 2BC6 sub eax, esi 0040106C |. 5E pop esi 0040106D \. C3 retn
masquer > "Такое подойдет?" Подойдет, только имхо намудрил чуток Может проверку диапазона проще так делать Код (Text): sub eax,30h setb dl ;1 если < '0', 0 если >= '0' cmp eax,9 sbb dl,0 ;'0'..'9' -> -1, иначе 0 или 1 jge @B
Нужны ли _вообще_ все эти проверки? Вариант с одним переходом (если не считать ведущие whitespace) : Код (Text): int a2i(const char * s) { while( *s++ <= ' ' ) ; int sign = s[-1] != '-'; s -= sign--; int res = 0; unsigned digit = 0; do { res = 10 * res + digit; digit = *(unsigned char *)s++ - '0'; } while( digit <= 9 ); return (sign ^ res) - sign; } Код (Text): 0040103D /$ 8A01 /mov al, [ecx] 0040103F |. 41 |inc ecx 00401040 |. 3C 20 |cmp al, 20 00401042 |.^ 7E F9 \jle short 0040103D 00401044 |. 33D2 xor edx, edx 00401046 |. 8079 FF 2D cmp [byte ecx-1], 2D 0040104A |. 56 push esi 0040104B |. 0F95C2 setne dl 0040104E |. 33C0 xor eax, eax 00401050 |. 2BCA sub ecx, edx 00401052 |. 4A dec edx 00401053 |. 33F6 xor esi, esi 00401055 |> 6BC0 0A /imul eax, eax, 0A 00401058 |. 03C6 |add eax, esi 0040105A |. 0FB631 |movzx esi, [byte ecx] 0040105D |. 83EE 30 |sub esi, 30 00401060 |. 41 |inc ecx 00401061 |. 83FE 09 |cmp esi, 9 00401064 |.^ 76 EF \jbe short 00401055 00401066 |. 33C2 xor eax, edx 00401068 |. 2BC2 sub eax, edx 0040106A |. 5E pop esi 0040106B \. C3 retn
S_T_A_S_ Да, ты прав: отдельное сравнение на < '0' действительно не нужно. Достаточно Код (Text): sub eax,30h cmp eax,9 ;беззнаковое сравнение jbe или ja А так, в твоем варианте только imul на lea заменить и будет ОК.
Спасибо, что ответили. Естественно на скорость выполнения. Чтобы меньше занимало тактов процессора Так что какой последний вариант?
leo Да я не про те проверки - пока не понятно, нужно ли atoi или всё же оптимизировать первоначальный вариант (смысл которого мне не совсем понятен). Lyrik ты так и не прояснил условия задачи. если нужен atoi, бери последний вариант, но перед ним напиши: #pragma optimize( "gt", on ) чтобы был msvc поставил lea вместо умножения. (хотя imho такие задачи оптимизировать по скорости не нужно) если ведущих пробелов не будет, можно убрать первый цикл.
Как раз я хочу написать своего рода универсальный atoi, чтобы были и пробелы и буквы и т.д. Опции компилера ставить не хочу. Хочу оптимизировать вручную, то, что я написал - естсественно мой пробный и не особо быстрый вариант. И я обратился к Вам за помощью
В современных - нет Вот вариант, как я понял самый оптимальный: Код (Text): int Lyrik(const char* buff) { long total = 0; _asm { xor eax,eax xor ecx,ecx mov esi,buff dec esi cikl: inc esi mov cl,byte ptr [esi] test cl,cl jz endstr sub cl,'0' js cikl cmp cl,9 jg cikl lea eax,[eax+eax*4] lea eax,[ecx+eax*2] jmp cikl endstr: mov esi,buff mov cl, byte ptr [esi] cmp cl,'-' jne kon neg eax kon: mov total,eax } return total; }
Читал, извините, не то опубликовал <_< Код (Text): int Lyrik(const char* buff) { long total = 0; _asm { xor eax,eax mov esi,buff dec esi cikl: xor ecx,ecx inc esi mov cl,byte ptr [esi] test cl,cl jz endstr sub ecx,0x30 cmp ecx,9 ja cikl lea eax,[eax+eax*4] lea eax,[ecx+eax*2] jmp cikl endstr: mov esi,buff mov cl, byte ptr [esi] cmp cl,'-' jne kon neg eax kon: mov total,eax } return total; }