- •4.13 Особенности арифметических операций c двоичными данными.
- •Многословное сложение
- •Word1a 0123
- •Буззнаковые и знаковые данные
- •Беззнаковое Знаковое
- •4.13.2 Умножение
- •ДоАн alПослеAx
- •Знаковое умножение: команда imul
- •C10mul endp
- •Многословноe умножение
- •Сдвиг влево на 4 бита
- •4.13.3 Деление
- •До ax После ан al
- •Беззнаковое деление: команда div
- •Знаковое деление: команда idiv
- •Переполнения и прерывания
- •Деление вычитанием
- •4.13.4 Преобразование знака
Переполнения и прерывания
Используя команды DIV и особенно IDIV, очень просто вызвать переполнение. Прерывания приводят (по крайней мере в системе, используемой при тестировании этих программ) к непредсказуемым результатам. В операциях деления предполагается, что частное значительно меньше, чем делимое. Деление на нуль всегда вызывает прерывание. Но деление на 1 генерирует частное, которое равно делимому, что может также легко вызвать прерывание.
Рекомендуется использовать следующее правило: если делитель - байт, то его значение должно быть меньше, чем левый байт (АН) делимого; если делитель - слово, то его значение должно быть меньше, чем левое слово (DX) делимого.
Проиллюстрируем данное правило для делителя, равного 1:
Операция деления:
Делимое Делитель Частное
Слово на байт: 0123 01 (1)23
Двойное слово на слово: 0001 4026 0001 (1)4026
В обоих случаях частное превышает возможный размер. Для того чтобы избежать подобных ситуаций, полезно вставлять перед командами DIV и IDIV соответствующую проверку. В первом из следующих примеров предположим, что DIVBYTE - однобайтовый делитель, а делимое находится уже в регистре AX. Во втором примере предположим, что DIVWORD - двухбайтовый делитель, а делимое находится в регистровой паре DX:AX.
Слово на байт Двойное слово на байт
CMP AH,DIVBYTE CMP DX,DIVWORD
JNB ;переполнение JNB ;переполнение
DIV DIVBYTE DIV DIVWORD
Для команды IDIV данная логика должна учитывать тот факт, что либо делимое, либо делитель могут быть отрицательными, а так как сравниваются абсолютные значения, то необходимо использовать команду NEG для временного перевода отрицательного значения в положительное.
Деление вычитанием
Если частное велико, а делитель маленький, то деление можно выполнить с помощью циклического вычитания. Метод заключается в том, что делитель вычитается из делимого и в этом же цикле частное увеличивается на 1. Вычитание продолжается до тех пор, пока делимое остается больше делителя. В следующем примере делитель находится в регистре AX, а делимое - в EBX, частное вырабатывается в CX:
SUB CX,CX ;Очистка частного
С20: CMP AX,BX ;Если делимое < делителя,
JB СЗ0 ;то выйти
SUB AX,BX ;Вычит. делит. из делимого
INC CX ;Инкремент частного
JMP С20 ;Повторить цикл
СЗ0: RET ;Частное в CX, остаток в AX
В конце подпрограммы регистр CX будет содержать частное, а AX - остаток. Пример умышленно примитивен, цель его -продемонстрировать данный способ деления. Если частное получается в регистровой паре DX:AX, то необходимо сделать два дополнения:
1. В метке С20 сравнивать AX и BX только при нулевом DX.
2. После команды SUB вставить команду SBB DX,00 (Вычитание с заимствованием).
Примечание: очень большое частное и малый делитель могут вызвать тысячи циклов.