c++ crt и asm как делятся многобайтные числа

Тема в разделе "WASM.BEGINNERS", создана пользователем _evil, 5 дек 2024.

  1. _evil

    _evil Member

    Публикаций:
    0
    Регистрация:
    28 сен 2003
    Сообщения:
    64
    тип long long в С\С++ хранится в 2х регистрах и при вычислении деления компилятор вызывает ту программу в сполере. А каким методом эта программа эти числа делит? Раскажите пожалуйста или дайте ссылку.

    .xlist
    include cruntime.inc
    include mm.inc
    .list
    ;***
    ;lldiv - signed long divide
    ;
    ;Purpose:
    ; Does a signed long divide of the arguments. Arguments are
    ; not changed.
    ;
    ;Entry:
    ; Arguments are passed on the stack:
    ; 1st pushed: divisor (QWORD)
    ; 2nd pushed: dividend (QWORD)
    ;
    ;Exit:
    ; EDX:EAX contains the quotient (dividend/divisor)
    ; NOTE: this routine removes the parameters from the stack.
    ;
    ;Uses:
    ; ECX
    ;
    ;Exceptions:
    ;
    ;*******************************************************************************
    CODESEG
    _alldiv PROC NEAR
    .FPO (3, 4, 0, 0, 0, 0)
    push edi
    006316B0 push edi
    push esi
    006316B1 push esi
    push ebx
    006316B2 push ebx
    ; Set up the local stack and save the index registers. When this is done
    ; the stack frame will look as follows (assuming that the expression a/b will
    ; generate a call to lldiv(a, b)):
    ;
    ; -----------------
    ; | |
    ; |---------------|
    ; | |
    ; |--divisor (b)--|
    ; | |
    ; |---------------|
    ; | |
    ; |--dividend (a)-|
    ; | |
    ; |---------------|
    ; | return addr** |
    ; |---------------|
    ; | EDI |
    ; |---------------|
    ; | ESI |
    ; |---------------|
    ; ESP---->| EBX |
    ; -----------------
    ;
    DVND equ [esp + 16] ; stack address of dividend (a)
    DVSR equ [esp + 24] ; stack address of divisor (b)
    ; Determine sign of the result (edi = 0 if result is positive, non-zero
    ; otherwise) and make operands positive.
    xor edi,edi ; result sign assumed positive
    006316B3 xor edi,edi
    mov eax,HIWORD(DVND) ; hi word of a
    006316B5 mov eax,dword ptr [esp+14h]
    or eax,eax ; test to see if signed
    006316B9 or eax,eax
    jge short L1 ; skip rest if a is already positive
    006316BB jge L1 (6316D1h)
    inc edi ; complement result sign flag
    006316BD inc edi
    mov edx,LOWORD(DVND) ; lo word of a
    006316BE mov edx,dword ptr [esp+10h]
    neg eax ; make a positive
    006316C2 neg eax
    neg edx
    006316C4 neg edx
    sbb eax,0
    006316C6 sbb eax,0
    mov HIWORD(DVND),eax ; save positive value
    006316C9 mov dword ptr [esp+14h],eax
    mov LOWORD(DVND),edx
    006316CD mov dword ptr [esp+10h],edx
    L1:
    mov eax,HIWORD(DVSR) ; hi word of b
    006316D1 mov eax,dword ptr [esp+1Ch]
    or eax,eax ; test to see if signed
    006316D5 or eax,eax
    jge short L2 ; skip rest if b is already positive
    006316D7 jge L2 (6316EDh)
    inc edi ; complement the result sign flag
    006316D9 inc edi
    mov edx,LOWORD(DVSR) ; lo word of a
    006316DA mov edx,dword ptr [esp+18h]
    neg eax ; make b positive
    006316DE neg eax
    neg edx
    006316E0 neg edx
    sbb eax,0
    006316E2 sbb eax,0
    mov HIWORD(DVSR),eax ; save positive value
    006316E5 mov dword ptr [esp+1Ch],eax
    mov LOWORD(DVSR),edx
    006316E9 mov dword ptr [esp+18h],edx
    L2:
    ;
    ; Now do the divide. First look to see if the divisor is less than 4194304K.
    ; If so, then we can use a simple algorithm with word divides, otherwise
    ; things get a little more complex.
    ;
    ; NOTE - eax currently contains the high order word of DVSR
    ;
    or eax,eax ; check to see if divisor < 4194304K
    006316ED or eax,eax
    jnz short L3 ; nope, gotta do this the hard way
    006316EF jne L3 (631709h)
    mov ecx,LOWORD(DVSR) ; load divisor
    006316F1 mov ecx,dword ptr [esp+18h]
    mov eax,HIWORD(DVND) ; load high word of dividend
    006316F5 mov eax,dword ptr [esp+14h]
    xor edx,edx
    006316F9 xor edx,edx
    div ecx ; eax <- high order bits of quotient
    006316FB div eax,ecx
    mov ebx,eax ; save high bits of quotient
    006316FD mov ebx,eax
    mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
    006316FF mov eax,dword ptr [esp+10h]
    div ecx ; eax <- low order bits of quotient
    00631703 div eax,ecx
    mov edx,ebx ; edx:eax <- quotient
    00631705 mov edx,ebx
    jmp short L4 ; set sign, restore stack and return
    00631707 jmp L4 (63174Ah)
    ;
    ; Here we do it the hard way. Remember, eax contains the high word of DVSR
    ;
    L3:
    mov ebx,eax ; ebx:ecx <- divisor
    00631709 mov ebx,eax
    mov ecx,LOWORD(DVSR)
    0063170B mov ecx,dword ptr [esp+18h]
    mov edx,HIWORD(DVND) ; edx:eax <- dividend
    0063170F mov edx,dword ptr [esp+14h]
    mov eax,LOWORD(DVND)
    00631713 mov eax,dword ptr [esp+10h]
    L5:
    shr ebx,1 ; shift divisor right one bit
    00631717 shr ebx,1
    rcr ecx,1
    00631719 rcr ecx,1
    shr edx,1 ; shift dividend right one bit
    0063171B shr edx,1
    rcr eax,1
    0063171D rcr eax,1
    or ebx,ebx
    0063171F or ebx,ebx
    jnz short L5 ; loop until divisor < 4194304K
    00631721 jne L5 (631717h)
    div ecx ; now divide, ignore remainder
    00631723 div eax,ecx
    mov esi,eax ; save quotient
    00631725 mov esi,eax
    ;
    ; We may be off by one, so to check, we will multiply the quotient
    ; by the divisor and check the result against the orignal dividend
    ; Note that we must also check for overflow, which can occur if the
    ; dividend is close to 2**64 and the quotient is off by 1.
    ;
    mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
    00631727 mul eax,dword ptr [esp+1Ch]
    mov ecx,eax
    0063172B mov ecx,eax
    mov eax,LOWORD(DVSR)
    0063172D mov eax,dword ptr [esp+18h]
    mul esi ; QUOT * LOWORD(DVSR)
    00631731 mul eax,esi
    add edx,ecx ; EDX:EAX = QUOT * DVSR
    00631733 add edx,ecx
    jc short L6 ; carry means Quotient is off by 1
    00631735 jb L6 (631745h)
    ;
    ; do long compare here between original dividend and the result of the
    ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
    ; subtract one (1) from the quotient.
    ;
    cmp edx,HIWORD(DVND) ; compare hi words of result and original
    00631737 cmp edx,dword ptr [esp+14h]
    ja short L6 ; if result > original, do subtract
    0063173B ja L6 (631745h)
    jb short L7 ; if result < original, we are ok
    0063173D jb L7 (631746h)
    cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
    0063173F cmp eax,dword ptr [esp+10h]
    jbe short L7 ; if less or equal we are ok, else subtract
    00631743 jbe L7 (631746h)
    L6:
    dec esi ; subtract 1 from quotient
    00631745 dec esi
    L7:
    xor edx,edx ; edx:eax <- quotient
    00631746 xor edx,edx
    mov eax,esi
    00631748 mov eax,esi
    ;
    ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
    ; according to the save value, cleanup the stack, and return.
    ;
    L4:
    dec edi ; check to see if result is negative
    0063174A dec edi
    jnz short L8 ; if EDI == 0, result should be negative
    0063174B jne L8 (631754h)
    neg edx ; otherwise, negate the result
    0063174D neg edx
    neg eax
    0063174F neg eax
    sbb edx,0
    00631751 sbb edx,0
    ;
    ; Restore the saved registers and return.
    ;
    L8:
    pop ebx
    00631754 pop ebx
    pop esi
    00631755 pop esi
    pop edi
    00631756 pop edi
    ret 16
    00631757 ret 10h
     
  2. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    Есть такой чел - Агнер Фог, так вон он уже полжизни собирает всякие трюки компиляторов аля как у вас выше
    их там сотни -тыши уже :)

    https://www.agner.org/optimize/
     
    sl0n, _evil и Research нравится это.
  3. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.000
    https://mathsanew.com/articles/implementing_large_integers_division.pdf
    Дисциплина называется "длинная арифметика" (long math), этакая тайна древней Атлантиды, которую уже давно никто не помнит как реализовать.

    Также можно вспомнить nn.c, которая оперирует с дайджестами, по сути целыми числами любой невероятной длины. Интересующая тебя процедура - NN_Div.
     
    _evil и Research нравится это.
  4. _evil

    _evil Member

    Публикаций:
    0
    Регистрация:
    28 сен 2003
    Сообщения:
    64
    на русском всётаки лучше
    --- Сообщение объединено, 7 дек 2024 ---
    а есть обьяснение на русском для двух регистров - там както по другому?
     
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.797
    _evil,
    на русском и с исходными текстами
    Юров Assembler. Практикум 2-е изд. ― СПб.: Питер, 2006. ― 399 с.: ил
    Глава 1. Программирование целочисленных арифметических операций:
    • Деление N-байтового беззнакового целого на число размером 1 байт (стр. 30)
    • Деление (N+M)-разрядного беззнакового целого на число размером M байтов (стр. 32)
    Уоррен, Генри С. Алгоритмические трюки для программистов
    В ресурсах обе книги есть
    Еще можно в посмотреть Ю-Чжен Лю, Г.Гибсон Микропроцессоры семейства 8086/8088
    обложка.png
     
    Последнее редактирование: 8 дек 2024
    MaKsIm и _evil нравится это.
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.797
    Программа для беззнакового деления переменной, размером в 6 байт, на переменную, размером в 2 байта, используем только команды для 16-разрядного микропроцессора.
    Представим делимое как (a×232+216+c), делитель как d;
    1. первое деление a/d = частное r1 и остаток q1;
    2. второе деление (q1×216+b) / d = частное r2 и остаток q2;
    3. третье деление (q2×216+c) / d = частное r3 и остаток q3;
    4. результат = частное (r1×232+r2×216+r3) и остаток q3
     
    MaKsIm и _evil нравится это.
  7. _evil

    _evil Member

    Публикаций:
    0
    Регистрация:
    28 сен 2003
    Сообщения:
    64
    Эх жалко такого пояснения для "Деление (N+M)-разрядного беззнакового целого на число размером M байтов (стр. 32)" не хватает
     
  8. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    302
    пальцем в небо, но выложу

    upload_2024-12-13_23-48-54.png upload_2024-12-13_23-51-41.png upload_2024-12-13_23-51-51.png
     
    Mikl___ нравится это.