Общий алгоритм деления числа любого размера на число любого размера нельзя построить с использованием команды DIV — такие операции выполняются при помощи сдвигов и вычитаний и оказываются весьма сложными. Рассмотрим сначала менее общую операцию (деление любого числа на слово или двойное слово), которую можно легко выполнить с помощью команд DIV:
; деление 64-битного числа divident на 16-битное число divisor. ; Частное помещается в 64-битную переменную quotent, ; а остаток - в 16-битную переменную modulo mov ax,word ptr divident[6] xor dx,dx div divisor mov word ptr quotent[6],ax mov ax,word ptr divident[4] div divisor mov word ptr quotent[4],ax mov ax,word ptr divident[2] div divisor mov word ptr quotent[2],ax mov ax,word ptr divident div divisor mov word ptr quotent,ax mov modulo,dx
Деление любого другого числа полностью аналогично — достаточно только добавить нужное число троек команд mov/div/mov в начало алгоритма.
Наиболее очевидный алгоритм для деления чисел любого размера на числа любого размера — деление в столбик с помощью последовательных вычитаний делителя (сдвинутого влево на соответствующее количество разрядов) из делимого, увеличивая соответствующий разряд частного на 1 при каждом вычитании, пока не останется число, меньшее делителя (остаток):
; деление 64-битного числа в EDX:EAX на 64-битное число в ЕСХ:ЕВХ. ; Частное помещается в EDX:EAX, и остаток - в ESI:EDI mov ebp,64 ; счетчик бит xor esi,esi xor edi,edi ; остаток = 0 bitloop: shl eax,1 rcl edx,1 rcl edi,1 ; сдвиг на 1 бит влево 128-битного числа rcl esi,1 ; ESI:EDI:EDX:EAX cmp esi,ecx ; сравнить старшие двойные слова ja divide jb next cmp edi,ebx ; сравнить младшие двойные слова jb next divide: sub edi,ebx sbb esi,ecx ; ESI:EDI = EBX:ECX inc eax ; установить младший бит в ЕАХ next: dec ebp ; повторить цикл 64 раза jne bitloop
Несмотря на то что этот алгоритм не использует сложных команд, он выполняется на порядок дольше, чем одна команда DIV.
Число, записанное с фиксированной запятой в формате 16:16, можно представить как число, умноженное на 216. Если разделить такие числа друг на друга сразу — мы получим результат деления целых чисел: (А * 216)/(В * 216) = А/В. Чтобы результат имел нужный нам вид (А/В) * 216, надо заранее умножить делимое на 216:
; деление числа с фиксированной запятой в формате 16:16 ; в регистре ЕАХ на такое же число в ЕВХ, без знака: xor edx,edx ror еах,16 xchg ax,dx ; EDX:ЕАХ = ЕАХ * 216
div ebx ; ЕАХ = результат деления
; деление числа с фиксированной запятой в формате 16:16 ; в регистре ЕАХ на такое же число в ЕВХ, со знаком: cdq ror еах,16 xchg ax,dx ; EDX:ЕАХ = ЕАХ * 216
idiv ebx ; ЕАХ = результат деления