Documentos de Académico
Documentos de Profesional
Documentos de Cultura
El procesador matemático
1.1 Introducción
El coprocesador matemático, 8087 tiene 8 registros de coma flotante de 80 bits, maneja enteros
con signo, BCD y punto flotante. El 8086/8088 deberá funcionar en modo máximo para trabajar
con el 8087. Las instrucciones del 8087 incluyen un juego completo de funciones: aritméticas,
exponenciales, logarítmicas y trigonométricas. Utiliza un formato interno de números en coma
flotante de 80 bits con el cual gestiona siete formatos exteriores. El 8087 posee 45.000 transistores
y consume 3 watt.
El coprocesador trabaja con números reales, que casi nunca pueden representarse exactamente; sin
embargo, en la práctica la representación en coma flotante permite una muy buena aproximación.
Con este sistema, la representación de un número consta de tres partes: el signo, el exponente y
la mantisa.
Los enteros con signo pueden ser de 16 bits, que se definen con DW; de 32 bits, que se definen
con DD y de 64 bits, que se definen con DQ. En los tres casos los números positivos se almace-
nan en formato verdadero con un bit de signo igual a “0” en el extremo izquierdo. Los números
negativos se almacenan en complemento a dos, con el bit de signo igual a “1” en el extremo izquierdo.
Los números BCD requieren 80 bits. Se almacenan como enteros empaquetados de 18 dígitos, en
nueve bytes, con dos dígitos por byte. El décimo byte contiene el bit de signo. Los números positivos
y negativos son almacenados en formato real utilizando la directiva DT.
Los números en punto flotante o números reales, constan de tres partes: un bit de signo, un expo-
nente descentrado (bias) y una mantisa. Se pueden manejar tres tipos de números de punto flotante
1
1.2. LOS NÚMEROS REALES Y SU TRATAMIENTO 2
con el estándar IEEE-754: real corto de 32 bits que se define con DD, real largo de 64 bits que se
define con DQ y real temporal de 80 bits que se define con DT.
Formato Rango Precisión Byte 9 Byte 8 Byte 7 Byte 6 Byte 5 Byte 4 Byte 3 Byte 2 Byte 1 Byte 0
Word 104 16 bits I15 I0
Integer Short 109 32 bits I31 I0
Long 1018 64 bits I63 I0
Packed BCD 1018 S D17 D0
Short 10±38 24 bits S E1 E0 F8 F23
Real Long 10±308 54 bits S E 10 E0 F4 F12 F20 F28 F36 F44 F52
Temporary 10±932 64 bits S E8 E0 F0 F7 F15 F23 F31 F39 F47 F55 F63
En los números reales Short y Long el bit F0 es implícito (F0 •), esto se aclarará con un ejemplo.
En los números reales Temporary el bit F0 es explícito. Por precisión se entiende la exactitud de un
número, en la representación de coma flotante, la mantisa es la encargada de la precisión. El rango
está relacionado con el tamaño de los números que se pueden representar, en la notación de coma
flotante, es el exponente el que fija el rango
El número 0 se almacena como solo ceros, exceptuando el bit de signo, que puede ser “1” para
representar un cero negativo. El ±∞ se almacena con todos los bits del exponente en “1” y todos
los bits de la mantisa en “0” y el bit de signo en “1” negativo o “0” positivo. Finalmente un NAN
(no es un número) es un resultado no válido en punto flotante que tiene todos los bits del exponente
en “1” y todos los bits de la mantisa en “0”.
Ejemplo 1.1
Convertir a binario 137.25
1. Convertir a binario 137.25d = 10001001.01b
2. Normalizar
1 , 0 0 0 1 0 0 1 0 1 × 27
mantisa
F0 bit 1 implícito
3. Cálculo del exponente desplazado (bias)
07h = 0 0 0 0 0 1 1 1 Exponente
7Fh = 0 1 1 1 1 1 1 1 Polarización
86h = 1 0 0 0 0 1 1 0 Exponente polarizado
4. Número en formato IEEE-754
F0
S E7 E6 E5 E4 E 3 E 2 E1 E0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23
S Exponente Mantisa
0 1 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4h 3h 0h 9h 4h 0h 0h 0h
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 3
Para ver esto en nuestro programa, simplemente definimos un número en el segmento de datos y
escribimos el encabezamiento de un programa que termina como .exe.
push ds
sub ax , ax
push ax
mov ax , datos
mov ds , ax
Después de hacer correr, paso a paso el encabezamiento (de push ds a mov ds,ax), podemos ver que
en el segmento de datos de la computadora está el número en formato hexadecimal e invertido.
ds:0000 00 40 09 43. Es decir, 137.25 = 43 09 40 00 ¿Cómo se obtiene esto? Lo mostramos a
continuación
137 = 10001001
.25 x 2 = 0 .5
.5 x 2 = 1
AD15 − AD0
8087
Reg. Control
Reg. Estado S2
A16 /S3 S1
A17 /S4 Reg. Marcas
S0
A18 /S5 QS 0
A19 /S6 D79 D0
QS 1
st(0)
BHE/S7 st(1) BU SY
RQ/GT 1 st(2) READY
st(3)
RQ/GT 0 st(4) RESET
IN T st(5) V cc
st(6)
CLK st(7) GN D
Ejemplo 1.2
El registro de etiquetas marca el contenido de cada registro ST. La función principal de las etiquetas
es optimizar el rendimiento del coprocesador. Sin embargo, las etiquetas pueden utilizarse para
interpretar el contenido de los registros del coprocesador.
D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
TAG(7) TAG(6) TAG(5) TAG(4) TAG(3) TAG(2) TAG(1) TAG(0)
Los valores de las etiquetas son:
00 = Válido
01 = Cero
10 = Inválido o infinito
11 = Vacío
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 6
Las constantes no pueden ser operandos de las instrucciones del coprocesador. Las constantes debe
estar ubicadas en memoria de datos de la computadora. Sin embargo, hay algunas instrucciones
para cargar ciertas constantes en ST(0), entre ellas: 0.0, 1.0, π y algunas constantes logarítmicas.
El área de datos del coprocesador, o parte de él, puede ser guardado en memoria y luego se puede
volver a cargar. Una razón para hace esto es guardar una imagen del estado del coprocesador antes
de llamar una subrutina para luego restaurar. Otra razón es para modificar el comportamiento
del coprocesador, almacenando ciertos datos en memoria, operar con los mismos utilizando instruc-
ciones del µProcesador y finalmente cargarlo de nuevo en el coprocesador.
Se puede transferir el área de datos del coprocesador, los registros de control, o simplemente la
palabra de estado o de control.
Cada instrucción de carga tiene dos formas: i) La forma con espera verifica excepciones de errores
numéricos no enmascarados y espera a que sean atendidos. ii) La forma sin espera (cuyo mnemotéc-
nico comienza con “FN”) ignora excepciones sin enmascarar. Aquí [N] significa opcional.
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 7
FLDCW mem2byte: Carga la palabra de control desde la memoria de datos del µProccesador.
F[N]STCW mem2byte: Almacena la palabra de control en la memoria de datos del µProcesador.
F[N]STSW mem2byte: Almacena la palabra de estado en la memoria de datos del µProccesador.
FLENV mem14byte: Carga el entorno desde la memoria de datos del µProccesador.
F[N]STENV mem14byte: Almacena el entorno en la memoria de datos del µProccesador.
FRSTOR mem94byte: Restaura el estado completo del coprocesador.
F[N]SAVE mem94byte: Salva el estado completo del coprocesador.
FADD: Hace ST(1) más ST(0), ajusta el puntero de pila y pone el resultado en ST(0), por lo que
ambos operandos se destruyen.
FADD mem: Hace ST(0) ← ST(0) + [mem]. En mem deberá haber un número real en punto flotante.
FIADD mem: Hace ST(0) ← ST(0) + [mem]. En mem deberá haber un número entero en complemento
a dos.
FADD ST(num), ST(0): Realiza ST(num) ← ST(num) + ST(0).
FADD ST, ST(num): Realiza ST(0) ← ST(0) + ST(num).
FADDP ST(num), ST(0): Realiza ST(num) ← ST(num) + ST(0) y retira el valor de ST(0) de la pila, con lo que
ambos operandos se destruyen.
FSUB: Hace ST(1) menos ST(0), ajusta el puntero de pila y pone el resultado en ST(0), por lo
que ambos operandos se destruyen.
FSUB mem: Hace ST(0) ← ST(0) - [mem]. En mem deberá haber un número real en punto flotante.
FISUB mem: Hace ST(0) ← ST(0) - [mem]. En mem deberá haber un número entero en complemento
a dos.
FSUB ST(num), ST(0): Realiza ST(num) ← ST(num) - ST(0).
FSUB ST(0), ST(num): Realiza ST(0) ← ST(0) - ST(num).
FSUBP ST(num), ST(0): Realiza ST(num) ← ST(num) - ST(0) y retira el valor de ST(0) de la pila, con lo que
ambos operandos se destruyen.
FSUBR: Hace ST(0) menos ST(1), ajusta el puntero de pila y pone el resultado en ST(0), por lo
que ambos operandos se destruyen.
FSUBR mem: Hace ST(0) ← [mem] - ST(0). En mem deberá haber un número real en punto flotante.
FISUBR mem: Hace ST(0) ← [mem] - ST(0). En mem deberá haber un número entero en complemento
a dos.
FSUBR ST(num), ST(0): Realiza ST(num) ← ST(0) - ST(num).
FSUBR ST(0), ST(num): Realiza ST(0) ← ST(num) - ST(0).
FSUBRP ST(num), ST(0): Realiza ST(num) ← ST(0) - ST(num) y retira el valor de ST(0) de la pila, con lo que
ambos operandos se destruyen.
FDIV: Dividir el valor de ST(1) por ST(0), ajusta el puntero de pila y pone el resultado en ST(0),
por lo que ambos operandos se destruyen.
FDIV mem: Hace ST(0) ← ST(0)/[mem]. En mem deberá haber un número real en punto flotante.
FIDIV mem: Hace ST(0) ← ST(0)/[mem]. En mem deberá haber un número entero en complemento
a dos.
FDIV ST(num), ST(0): Realiza ST(num) ← ST(num)/ST.
FDIV ST(0), ST(num): Realiza ST ← ST(0)/ST(num).
FDIVP ST(num), ST(0): Realiza ST(num) ← ST(num)/ST(0) y retira el valor de ST(0) de la pila, con lo que ambos
operandos se destruyen.
FDIVR: Hace ST(0) dividido ST(1), ajusta el puntero de pila y pone el resultado en ST, por lo
que ambos operandos se destruyen.
FDIVR mem: Hace ST(0) ← [mem]/ST(0). En mem deberá haber un número real en punto flotante.
FIDIVR mem: Hace ST(0) ← [mem]/ST(0). En mem deberá haber un número entero en complemento
a dos.
FDIVR ST(num), ST(0): Realiza ST(num) ← ST(0)/ST(num).
FDIVR ST(0), ST(num): Realiza ST(0) ← ST(num)/ST(0).
FDIVRP ST(num), ST(0): Realiza ST(num) ← ST(0)/ST(num) y retira el valor de ST(0) de la pila, con lo que ambos
operandos se destruyen.
FABS: Pone el signo de ST(0) a positivo (valor absoluto).
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 8
Ahora que disponemos de las instrucciones del coprocesador, con el Turbo Debbuger, analizamos
un programa en ensamblador, que utiliza instrucciones del coprocesador. Primero analizaremos la
definición del segmento de código:
Veamos las figuras 1.2 y 1.3. El programa de la figura 1.2a define el segmento de código como
siempre lo hacemos; es decir, el segmento de código no permite utilizar registros de 16 bits, el
resultado se ve en el recuadro amarillo de la figura 1.3a. Por otro lado el programa de la figura 1.2b,
permite utilizar registros de 16 bits. Esto logramos con la directiva use16. El resultado se ve en la
recuadro amarillo de la figura 1.3b. También fíjese que es necesario utilizar las directivas .386, para
habilitar los registros de 16 bits del µProcesador y, .387, para utilizar el procesador matemático.
copro1.asm copro2.asm
.386 .386
.387 .387
; ------------------------------------- ; -------------------------------------
datos segment para ' data ' datos segment para ' data '
dato1 dd -3 .1415 ; precision sencilla angulo dw 45
dato3 dd 15 ; numeros enteros seno dw 0 ; seno ( angulo )
datos ends datos ends
; ------------------------------------- ; -------------------------------------
En segundo lugar, veremos como corre, paso a paso, un programa que utiliza el procesador matemático.
Para esto proponemos el programa de la figura 1.5. En el veremos operaciones con números enteros
y operaciones con números reales.
Para ver los registros de coprocesador, proceda como en la figura 1.4, haga correr el programa paso
a paso hasta la instrucción mov ds,ax, para ver los datos en el segmento de datos. En los registros
del coprocesador, verá como se cargan (con fld) los números -3,1415 y 3.0 y se suman con fadd para
luego depositar (con fstp) el resultado en la variable, suma. Luego vera como se carga (con fild) el
número 15, y se suma (con fiadd) directamente con el número 30, que esta en el segmento de datos
del µProcesador, luego la suma la depositamos (con fst) en la variable suma1. El estudiante debe
ver la diferencia entre las instrucciones fstp y fst. La primera extrae de ST(0) y deposita en suma,
la segunda copia de ST(0) a suma1. Con la ayuda del programa de la figura 1.5, el estudiante
deberá verificar la representación de números reales utilizando el estandar IEEE-754.
.386
.387
; Ejemplo de suma con el coprocesador matematico
; ----------------------------------------------------------
pila segment para stack ' stack '
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 11
dw 30 dup (0)
pila ends
; ----------------------------------------------------------
datos segment para ' data '
El programa de la figura 1.6, calcula el seno de angulo = 45◦ . En primer lugar. Haga correr
el programa paso a paso. Cuando llegue a la instrucción fsin, verá que en realidad se ejecuta la
instrucción fcos, por esta razón utilizamos la identidad trigonométrica,
En segundo lugar. El coprocesador matemático trabaja en radianes, por tanto hay que convertir
los grados a radianes,
π
radianes = angulo
180◦
Finalmente el valor de sin(x) multiplicamos por 100 y redondeamos (frndint). Esto para dibujar un
pixel, que represente el punto (x,sin(x)), en una pantalla gráfica. El programa debe revisarse con
el Turbo Debbuger.
1.3. SEÑALES DEL PROCESADOR MATEMÁTICO, 8087 12
.386
.387
; program para calcular el sen ( x ) = cos (x -90)
; -----------------------------------------------------
pila segment para stack ' stack '
dw 30 dup (0)
pila ends
; -----------------------------------------------------
datos segment para ' data '
angulo dw 45
seno dw 0 ; seno ( angulo )
tem dw 0 ; Temporal
datos ends
; -----------------------------------------------------
codigo segment use16
program proc far
assume ss : pila , ds : datos , cs : codigo , es : datos
push ds
sub ax , ax
push ax
mov ax , datos
mov ds , ax
finit
fild angulo ; -+ angulo = angulo -90
mov tem ,90 ; |
fild tem ; |
fsubp st (1) , st ; -+
fldpi ; -+ angulo a radianes
fmulp st (1) , st ; |
mov tem ,180 ; |
fild tem ; |
fdiv ; -+
fsin ; sen ( x ) = cos (x -90)
mov tem ,100 ; -+ escalamos el resultado
fild tem ; | para graficar
fmulp st (1) , st ; |
frndint ; -+
fistp seno ; guarda sen ( x ) escalado
ret
program endp
; -----------------------------------------------------
codigo ends
end program
Sistemas de computación
13
8.1. NORMALIZACIÓN DE LA PANTALLA 14
Este problema lo resolvemos de la siguiente manera: i) Identificamos el tamaño de los ejes ‘x’
e ‘y’, ii) restamos máximo menos mínimo para cada eje, iii) dividimos entre (máximo-mínimo)
y iv) multiplicamos por ancho y alto respectivamente. Esto implementamos matemáticamente a
continuación:
Para las abscisas Para las ordenadas
0 ≤ x ≤ 2π −1 ≤ y ≤ 1
xmin − xmin ≤ x − xmin ≤ xmax − xmin ymin − ymin ≤ y − ymin ≤ ymax − ymin
x−xmin y−ymin
0≤ xmax −xmin ≤1 0≤ ymax −ymin ≤1
x−xmin y−ymin
0≤ xmax −xmin × ancho ≤ ancho 0≤ ymax −ymin × alto ≤ alto
x − xmin
xp = × ancho (8.1)
xmax − xmin
y a las ordenadas como
y − ymin
yp = × alto (8.2)
ymax − ymin
Por tanto cada punto (x,y) que calculemos, ajustaremos con las ecuaciones 8.1 y 8.2 para obtener los
puntos [xp ,yp ] y dibujarlos en la pantalla. Para continuar, además de ajustar el punto (x,y), debe-
mos trasladarlo; por ejemplo, de la esquina superior izquierda al centro de la pantalla y, también
podemos modificarlo de acuerdo a las necesidades de la interfaz de usuario; por ejemplo, márgenes
izquierdo y derecho como superior e inferior. Entonces tendríamos:
.386
.387
; Grafica la funcion y = sen ( x )
; -----------------------------------------------------
pila segment para stack ' stack '
dw 30 dup (0)
pila ends
; -----------------------------------------------------
datos segment para ' data '
maxX equ 360
minX equ 0
maxY equ 2
minY equ -2
ancho equ 320
alto equ 200
N equ 5 ; Cada N pixels un punto
DESX equ ancho ; despl azamient o abscisa
DESY equ alto ; de splazamie nto ordenada
GREEN = 10
WHITE = 07
YELLOW = 14
seriex dw maxX / N dup (0) ; angulos en el eje x
seriey dw maxX / N dup (0) ; sen ( angulo )
temI dw 0
temR dd 0 .0
vian dw 0
ajusX dd 0 .0 ; ancho /( Xmax - Xmin )
ajusY dd 0 .0 ; alto /( Ymax - Ymin )
datos ends
; -----------------------------------------------------
codigo segment use16
program proc far
assume ss : pila , ds : datos , cs : codigo , es : datos
push ds
sub ax , ax
push ax
mov ax , datos
mov ds , ax
; ------------------------
graf proc
mov cx , maxX / N ; numero de puntos a graficar
mov si ,0
G01 : push cx
mov temI , minX ; - -+
fild temI ; |
fild seriex [ si ] ; |
fxch st (1) ; | (x - xmin )
fsubp st (1) , st ; | - - - - - - - - - - - x ancho
fld ajusX ; | ( Xmax - Xmin )
fmulp st (1) , st ; |
frndint ; |
fistp temI ; - -+ guarda el valor de x
mov cx , temI
add cx , ancho ; -+ d esplazam iento en 'x '
mov dx , seriey [ si ] ; | y en 'y '
neg dx ; |
add dx , alto ; -+
mov al , YELLOW
call punto
inc si
inc si
pop cx
loop G01
ret
graf endp
; - - - - - - - - - - - - - - - Obtiene modo de video - - - - - - - - - - - - - - - - -
; ---------------------
omovi proc
mov ah ,0 fh
int 10 h
mov vian , ax
ret
omovi endp
; - - - - - - - - - - - - - - - - - - - Pone modo de video - - - - - - - - - - - - - - - -
; ------------------
pmovi proc
mov ah ,00
int 10 h
ret
pmovi endp
; - - - - - - - - - - - - - - - - - - pone un pixel - - - - - - - - - - - - - - - - - - - - - -
; -------------
punto proc
mov ah ,0 ch
mov bh ,00 ; pagina 0
int 10 h
ret
punto endp
; - - - - - - - - - - - - - - - - Dibuja las coordenadas - - - - - - - - - - - - - - -
; ----------------------
ejes proc
mov cx ,0 ; Abscisa
mov dx , alto /2
mov al , WHITE
EJE1 : call punto
inc cx
cmp cx , ancho
jne EJE1
mov dx ,0 ; Ordenada
mov cx , ancho /2
mov al , WHITE
EJE2 : call punto
inc dx
8.2. ALGORITMO DE BRESENHAM 18
cmp dx , alto
jne EJE2
ret
ejes endp
; -----------------------------------------------------
codigo ends
end program
Cuyo resultado se muestra en la figura 8.1. Observe que no coincide en punto (0,0) de las coorde-
nadas con el cruce por cero de la función sin(x).
Comenzamos con el pixel P1 p(x1p ,y1p ), luego seleccionamos los píxeles subsiguientes a medida que
avanzamos hacia la derecha, una posición de píxel a la vez, en la dirección horizontal hacia el
pixel P2 p(x2p ,y2p ). Una vez que se elige un píxel en cualquier paso, el siguiente píxel es el de su
derecha (que constituye un límite inferior para la línea) o el que está a su derecha y hacia arriba
(que constituye un límite superior para la línea) debido al límite de la pendiente m. La línea se
aproxima mejor por aquellos píxeles que caen a la menor distancia de su camino real entre P1p y P2p .
8.2. ALGORITMO DE BRESENHAM 19
∆X < 0 ∆X > 0
III ∆Y > 0 ∆Y > 0 II
∆X < ∆Y ∆X < ∆Y
y IV I
P2
•
– • P2 ∆X < 0 ∆X > 0
P2p ∆Y > 0 ∆Y > 0
∆X > ∆Y ∆X > ∆Y
yi+1 – T
•
• P1 x
t ∆X < 0 ∆X > 0
∆Y < 0 ∆Y < 0
s ∆X > ∆Y ∆X > ∆Y
P1
yi – • •
P1p S
Usando la notación de la figura 8.2a), las coordenadas del último píxel elegido al ingresar al paso i
son (xi , yi ). Debemos eligir el siguiente, entre el píxel inferior S y el píxel superior T. Si se elige S,
tenemos x[i+1] = x[i] + 1 y y[i+1] = y[i] , si se elige T, tenemos x[i+1] = x[i] + 1 y y[i+1] = y[i] + 1. La
coordenada y real de la línea en x = x[i+1] es y = mx[i+1] + b = m(x[i] + 1) + b. La distancia de S a
la línea real en la dirección y es s = y − y[i] . La distancia de T a la línea real en la dirección y es
t = (y[i] + 1) − y.
Ahora consideremos la diferencia entre estos dos valores de distancia: s − t. Cuando s − t < 0,
tenemos s < t y el píxel más cercano es S. Por el contrario, cuando s − t ≥ 0, tenemos s ≥ t y el
pixel más cercano es T. Esta diferencia es:
∆y
s−t=2 (x + 1) + 2b − 2y[i] − 1
∆x [i]
De donde
Si definimos una variable de decisión, dn[i] = ∆x(s − t), que tiene el mismo signo que (s − t), ya
que ∆x es positivo en nuestro caso, tenemos:
De manera similar, podemos escribir la variable de decisión dn(i+1) para el siguiente paso como
Luego
Si el píxel elegido es el píxel superior T (es decir dn[i] ≥ 0), entonces y[i+1] = y[i] + 1 luego tenemos
por otro lado, si el píxel elegido es el píxel inferior S (es decir dn[i] < 0), entonces y[i+1] = y[i] luego
tenemos
finalmente, calculamos dn[i] , el valor del caso base para esta fórmula recursiva, a partir de la
definición original de la variable de decisión dn[i] :
dn[i] = 2∆y − ∆x
Para implementar el programa vamos a hacer: dnT = 2(DeltaY - DeltaX), dnS = 2DeltaY
y dni = 2DeltaY - DeltaX. En resumen, el algoritmo de Bresenham para convertir por barrido
una línea de P1p (x1p , y1p ) hasta P2p (x2p , y2p ) con las condiciones que: x1p < x2p y 0 < m < 1, el
algoritmo de Bresenham para el primer octante, ver figura 8.2b), puede implementarse como en la
figura 8.3.
8.2. ALGORITMO DE BRESENHAM 21
liBres proc
Bresenham mov ax , x1 ; x = x1
mov x , ax
x ← x1 mov ax , y1 ; y = y1
y ← y1 mov y , ax
mov ax , x2 ; -+
sub ax , x1 ; | > DeltaX = x2 - x1
DeltaX ← x2 - x1
mov DeltaX , ax ; -+
DeltaY ← y2 - y1
mov ax , y2 ; -+
sub ax , y1 ; | > DeltaY = y2 - y1
mov DeltaY , ax ; -+
dnS ← 2DeltaY
dni ← 2DeltaY - DeltaX shl ax ,1 ; 2 DeltaY
mov dnS , ax ; dnS = 2 DeltaY
sub ax , DeltaX ; 2 DeltaY - DeltaX
dnT ← 2(DeltaY - DeltaX) mov dni , ax ; dni = 2 DeltaY - DeltaX
mov ax , DeltaY ; -+
sub ax , DeltaX ; | > 2( DeltaY - DeltaX )
call putPix shl ax ,1 ; -+
mov dnT , ax ; dnT
libre2 :
x←x+1
call putPix
inc x ; x = x +1
no mov ax , x
x < x2 ret
cmp ax , x2 ; x < x2
si jnb libre0
cmp dni ,0 ; dni >= 0
no
dni ≥ x2 dni ← dni + dnS jnge libre1
inc y ; y = y + 1
si
mov ax , dnT ;
y←y+1 add dni , ax ; dn ( i +1) = dni + dnT
jmp libre2
libre1 :
dni ← dni + dnT
mov ax , dnS ;
add dni , ax ; dn ( i +1) = dni + dnS
jmp libre2
libre0 :
ret
liBres endp
En la figura 8.3 primero inicializamos la variable dn[i] y establecemos el píxel P1p . Durante cada
iteración del ciclo, incrementamos x a la siguiente posición horizontal, luego usamos el valor actual
de dn[i] para seleccionar el píxel inferior o superior (incrementar y) y actualizamos dn[i] , y al final
establecemos el píxel elegido.
En cuanto a las líneas que tienen otros valores de m, podemos hacer uso del hecho de que pueden
reflejarse horizontal, vertical o diagonalmente en este rango de ángulos de 0◦ a 45◦ , ver figura 8.2b).
Por ejemplo, una línea de (x1p ,y1p ) a (x2p ,y2p ) con −1 < m < 0 tiene una contraparte reflejada
horizontalmente de (x1p ,−y1p ) a (x2p ,−y2p ) con 0 < m < 1. Simplemente podemos usar el algoritmo
para escanear y convertir esta contraparte, pero negar la coordenada y al final de cada iteración
para establecer el píxel correcto para la línea. Para una línea cuya pendiente está en el rango de
45◦ a 90◦ , podemos obtener su contraparte reflejada intercambiando las coordenadas x e y de sus
extremos. Podemos escanear y convertir esta contraparte, pero debemos intercambiar x e y en la
llamada a putPix. Entonces el programa que implementa el algoritmo de Bresenham par los ocho
octantes es el de la figura 8.4
8.2. ALGORITMO DE BRESENHAM 22
liBres proc
Bresenham mov ax , x2
sub ax , x1
mov DtaX , ax ; DtaX = x2 - x1
DeltaX ← x2 - x1
mov ax , y2
DeltaY ← y2 - y1
sub ax , y1
libre4: mov DtaY , ax ; DtaY = y2 - y1
no ∆Y ← -∆Y cmp DtaY ,0 ; DtaY >= 0 ?
∆Y ≥ 0
inY ← -1 jnge libre4
si
mov inY ,1
libre1 : cmp DtaX ,0 ; DtaX >= 0 ?
inY ← 1
jnge libre5
libre1: mov inX ,1
libre5:
no ∆X ← -∆X libre2 : mov ax , DtaX
∆X ≥ 0 cmp ax , DtaY
inX ← -1
jnge libre5 ; DtaX >= DtaY?
si
mov inYr ,0 ; InYr = 0
inX ← 1 mov bx , inX
libre2:
libre6: mov inXr , bx ; inXr = inX
libre3 : mov ax , DtaY
no inXr ← 0
∆X ≥ ∆Y shl ax ,1 ; 2 DtaY
inYr ← inY
mov dnS , ax ; dnS = 2 DtaY
si sub ax , DtaX ; 2 DtaY - DtaX
inYr ← 0 ∆X ← ∆Y mov dni , ax ; dni = 2 DtaY - DtaX
inXr ← inX ∆Y ← ∆X sub ax , DtaX ; 2 DtaY -2 DtaX
mov dnT , ax ; dnT = 2 DtaY -2 DtaX
libre3: mov ax , x1
dnS ← 2DeltaY mov x , ax ; x = x1
dni ← 2DeltaY - DeltaX mov ax , y1
dnT ← 2(DeltaY - DeltaX) mov y , ax ; y = y1
jmp libre7
libre4 : neg DtaY ; Dtay = - DtaY
x ← x1 mov inY , -1 ; inY = -1
y ← y1 jmp libre1
libre5 : neg DtaX ; DtaX = - DtaX
libre7: mov inX , -1 ; inX -1
call putPix jmp libre2
libre5 : mov inXr ,0 ; inXr = 0
si si
mov bx , inY
x = x2 y = y2 ret mov inYr , bx ; inYr = inY
mov bx , DtaY
no
libre8: libre9: mov DtaX , bx ; DTaX = DtaY
no x ← x + inXr
mov DtaY , ax ; DtaY = DtaX
dni ≥ 0
y ← y + inYr jmp libre3
libre7 : call putPix
si mov ax , x
x ← x + inX dni ← dni + dnS cmp ax , x2 ; x = x2 ?
y ← y + inY jne libre8
mov ax , y
dni ← dni + dnT cmp ax , y2 ; y = y2 ?
jne libre8
ret
libre8 : cmp dni ,0 ; dni >= 0 ?
jnge libre9
mov ax , inX
add x , ax
mov ax , inY ; x = x + inX
add y , ax ; y = y + inY
mov ax , dnT
add dni , ax ; dn ( i +1) = dni + dnT
jmp libre7
libre9 : mov ax , inXr
add x , ax ; x = x + inXr
mov ax , inYr
add y , ax ; y = y + inYr
mov ax , dnS
add dni , ax ; dn ( i +1) = dni + dnS
jmp libre7
liBres endp
Figura 8.4: Algoritmo de Bresenham para todos los octantes, figura 8.2b)