Skip navigation

Osztás

Áttekintés

Mint a szorzásnak osztásnak is megkülönböztetjük az előjel nélküli és előjeles változatát.

Előjel nélküli osztás

DIV: A DIV (előjelnélküli osztás) utasítás használható 8, 16 és 32 bites verzióban is. Egyetlen operandusa van, az osztó, ami lehet egy regiszter vagy egy memória cím. A szintaxisa:

     DIV reg/mem8

     DIV reg/mem16

     DIV reg/mem32

 

A következő táblázat mutatja be a kapcsolatot az osztandó, az osztó, a hányados és a maradék között:

Osztandó Osztó (operandus) Hányados Maradék
AX reg/mem8 AL AH
DX:AX reg/mem16 AX DX
EDX:EAX reg/mem32 EAX EDX

 

A táblázatban leírtak értelmezése: Ha 8 bites az operandus, akkor az eredmény úgy áll elő, hogy az AL tartalmazza az AX/op hányadosát, a AH-ba pedig az AX/op maradéka kerül. Ha az operandus 16 bites, akkor AX-be a (DX:AX)/op hányadosa, DX-be pedig a (DX:AX)/op maradéka kerül. Ha az operandus 32 bites, akkor EAX-be az (EDX:EAX)/op hányadosa, míg az EDX-be az (EDX:EAX)/op maradéka kerül.

Példa:

A következő 8 bites előjelnélküli osztás esetén (83h/2h), a hányados értéke 41h, a maradék pedig 1h:

     MOV AX, 0083h  ; AX = 0083h (osztandó)

     MOV BL, 2h     ; BL = 2h (osztó)

     DIV BL         ; AL = 41h (hányados), AH = 01h (maradék)

 

A következő 16 bites előjelnélküli osztás esetén (8003h/100h), a hányados értéke 80h, a maradék pedig 3h. DX tartalmazza a felső 16 bitjét az osztandónak, ezért mindenképp ki kell nullázni még a DIV utasítás végrehajtása előtt:

     MOV DX, 0      ; DX = 0000, osztandó nullázása (felső 16 bit)

     MOV AX, 8003h  ; AX = 8003h, osztandó (alsó 16 bit)

     MOV CX, 100h   ; CX = 100h, osztó

     DIV CX         ; AX = 0080h (hányados), DX = 0003h (maradék)

 

A következő 32 bites előjelnélküli osztás memória operandust használ, mint osztó:

.data

     osztando  QWORD 0000000800300020h  ;    64 bites érték

     oszto     DWORD 00000100h

     .code

     MOV EDX, DWORD PRT osztando + 4    ;    felső 32 bit

     MOV EAX, DWORD PTR osztando        ;    alsó 32 bit

     DIV oszto ; EAX = 08003000h(hányados),EDX = 00000020h(maradék)

Előjeles osztás

IDIV: Az előjeles osztás közel megegyezik az előjelnélkülivel, egy fontos különbséggel: az osztandó előjel kiterjesztett kell, hogy legyen még az osztás elvégzése előtt. Az előjel kiterjesztés azt jelenti, hogy átmásoljuk a szám legfelső bitjét az összes felsőbb bit helyére az adott változóban vagy regiszterben. Ahhoz, hogy bemutassuk ennek a fontosságát, próbáljuk ki mi történik, ha kihagyjuk ezt a lépést. A következő kódban a MOV utasítással hozzá rendeljük a -101 értéket az AX regiszterhez, ami az EAX regiszter alsó 16 bitje:

.data

     szoValtozo     SWORD     -101

     .code

     MOV AX, szoValtozo       ;    AX = FF9Bh

     MOV BX, 2                ;    BX = 2 (osztó)

     IDIV BX                   ;    DX:AX/BX (előjeles művelet)

 

Igaz, hogy az AX regiszterben benne van az FF9Bh, viszont az osztáskor a DX értékét nem állítottuk be, így az bármi lehet. Így teljesen kérdéses, hogy milyen eredményt kapunk, de az biztos, hogy nem helyeset. Tehát az út a helyes megoldáshoz, hogy használjuk a CWD utasítást, ami az AX regisztert előjelhelyesen kiterjeszti DX:AX-re még az osztás végrehajtása előtt:

.data

     szoValtozo     SWORD     -101 ;    009Bh

.code

     MOV AX, szoValtozo       ;    AX = FF9Bh

     CWD                       ;    DX:AX = FFFF FF9Bh

     MOV BX, 2                ;    EBX = 2 (osztó)

     IDIV BX                   ;    AX = DX:AX/BX = FFFFFF9B/2 =FFCD

 

A már tárgyalt MOVSX parancs használata hasznos lehet ilyen műveletek esetén.

     MOVSX EAX, AX       ;    EAX = FFFF FF9Bh

                         ;    AX előjelhelyes kiterjesztése EAX-re

 

Osztásnál előfordulhat, hogy a hányados nem fér el az adott regiszterben, amiben tárolásra kerülne, ilyenkor azonnal abortál a program. Célszerű megelőző ellenőrzéseket végezni:

  • Nem nulla-e az osztó?
  • Nem túl nagy-e az osztó?