#ассемблер
Пусть A и B – два 8-разрядных регистра в обыкновенном 16-разрядном процессоре. Следующая процедура выполняет сдвиг регистра A на число разрядов, заданное в регистре B. Loop: SHR A ;shift right A DEC B ;decrement B JNZ Loop ;loop again Задача - Написать программу, которая выполняет сдвиг быстрее. Пользоваться многократным сдвигом запрещено. ЗЫ Эту задачу когда-то мне предложили на собеседовании. Я ее решил не верно. У кого какие мысли? Гугл не поможет :) Надо думать самому! UPD: Нашел свое неверное решение MOV AH,A MOV AL,B Label: SHR AH DEC AL JNE Label
Ответы
Ответ 1
И третий вариант:) Предложен моим коллегой. Развернуть цикл. jmp $+sizeof(shr a)*(8-b) // $ - это адрес следующей за jmp инструкции shr a shr a shr a shr a shr a shr a shr a shr aОтвет 2
Начнем с того, что приведенный выше код не позволяет выполнить сдвиг на 0(ноль) разрядов, т.е. он всегда выполняет хотябы один сдвиг. (Жутко ненавижу задачи про ассемблерную оптимизацию)). Да, первое, что приходит на ум это вопрос: о каком "обыкновенном" процессоре речь? Если это RISC, то можно оперется на delay slot при бранчевании и написать так: loop: dec B jnz loop shr A Т.е., здесь "shr A" выполнится в delay slot предыдущей инструкции бранчевания "jnz loop", что позволит нам сэкономить 'B' операций. Для RISC процессоров этот и приведенный выше коды эквивалентны. Да, на этом моя мысль заканчивается))Ответ 3
С помощью AND убираем бесполезные сдвиги. немного увеличив время выполнения кода на 2 лишних такта, получили существенное увеличение производительности. and B, 7 jz fin loop: shr A dec B jnz loop fin:Ответ 4
Есть еще идейка, возможно это хотели увидеть ваши экзаменаторы). mov dx, a mov bx, b //кол-во сдвигов до правого края DL mov ax, 8 sub ax, bx //кол-во сдвигов до правого края DH cmp ax, bx jbe loop_shl: // если ax <= bx двигаем влево на ax, берем результат из DH loop_shr: // иначе двигаем вправо на bx, берем результат из DL shr dx dec bx jnz loop_shr jmp end: loop_shl: shl dx dec ax jnz loop_shl end:Ответ 5
mov cl,b shr a,clОтвет 6
Можно сделать следующим образом: ; прошу прощения за ошибки, давно не писал.. data segment ; 0 1 2 3 4 5 6 7 8 array db 1,2,4,8,16,32,64,128,256 data ends code segment ... start: ... mov cx,[bx+array] mul cx ... code ends end start суть идеи: при умножении или делении числа на два, его двоичный код смещается влево или вправо соответственно, это я и попытался использовать. В массиве мы храним числа, на которые мы должны умножить исходное число(значение ax), число сдвигов(значение bx) используется как смещение в массиве.
Комментариев нет:
Отправить комментарий