Rozszerzanie zakresu liczb

Autor: Wojciech Muła
Dodany:2002

Treść

Wstęp

CPU potrafi przeprowadzać operacje arytmetyczne tylko na rejestrach o tych samych rozmiarach. Dlatego też operacje na operandach o różnych rozmiarach trzeba poprzedzić poszerzeniem zakresu operandu o mniejszej liczbie bitów.

Rozszerzenie zakresu polega na zapisaniu tej samej wartości w słowie o większej liczbie bitów. Dla liczb bez znaku, zapisanych w naturalnym kodzie binarnym, jest to bardzo proste — wystarczy nowe, „dodane” bity wyzerować.

Np. 8-bitowa liczba 166=10100110b po rozszerzeniu na 32 bity ma postać:

00000000 00000000 00000000 10100110

Dla liczb ze znakiem jest to trochę trudniejsze — nowe bity należy wypełnić bitem znaku.

Np. 8-bitowa liczba -100 = 10011100b po rozszerzeniu na 32 bity ma postać:

11111111 11111111 11111111 10100110

Rozszerzanie liczb bez znaku

Poniższe sposoby można stosować dla dowolnych rejestrów.

extend_x86.asm:

; al -> ax
        xor   ah, ah     ; wyzeruj ah
        and   ax, 0x00ff ; j.w.
        movzx ax, al

; al -> eax
        and   eax, 0x000000ff
        movzx eax, al

extend_mmx.asm:

; packed byte -> packed word
; mm0 -> mm1:mm0

                   ; mm0 = 0x10ff200faabbccdd
pxor mm2, mm2      ; mm2 = 0x0000000000000000
movq mm1, mm0      ; mm1 = 0x0000000000000000

punpcklbw mm0, mm2 ; mm0 = 0x00aa00bb00cc00dd
punpckhbw mm1, mm2 ; mm1 = 0x001000ff0020000f

Lub inaczej:

extend_mmx.asm:

; packed byte -> packed word
; mm0 -> mm1:mm0

movq      mm1, mm0

punpcklbw mm0, mm0
punpckhbw mm1, mm1
psrlw     mm0, 8
psrlw     mm1, 8

Rozszerzanie liczb ze znakiem

Poniższe rozkazy działają tylko dla akumulatora (al, ax, eax).

extend_stdx86:

cbw       ;  al ->  ax
cwd       ;  ax -> eax
cwde      ; eax -> edx:eax

A te już dla dowolnych rejestrów i pamięci.

extend_u2.asm:

; al -> ax
mov ah, al
sar ah, al

; al -> eax
             ; eax = |xxxxxxxx|xxxxxxxx|xxxxxxxx|shhhllll|
shr eax, 24  ; eax = |shhhllll|00000000|00000000|00000000|
sar eax, 24  ; eax = |ssssssss|ssssssss|ssssssss|shhhllll|

; eax -> edx:eax
mov edx, eax
sar edx, eax

; lub troszkę dłuższy kod
xor   edx, edx
cmp   eax, 0
setge dl
sub   edx, 1

extend_u2mmx.asm:

; packed signed byte -> packed signed word
; mm0 -> mm1:mm0

movq      mm1, mm0
punpcklbw mm0, mm0
punpcklbw mm1, mm1
psraw     mm0, 8
psraw     mm1, 8