2 que se van a necesitar realmente En todo momento, a lo largo de nuestra implementación, hemos procurado que cada variable de tipo NUMERO empleada
4.3.2. Operadores aritméticos.
Ya hemos presentado, en un epígrafe previo, algunos fundamentos matemáticos sencillos sobre el modo en que se realizan algunas de las operaciones aritméticas básicas. Vamos ahora a mostrar las funciones aritméticas implementadas.
4.3.2.1. Implementación de la operación para la suma.
Como hemos explicado antes, en nuestra implementación hemos trabajado con una codificación de enteros que toma la base 32
2
=
B
: cada dígito viene codificado en un entero sin signo de 32 bits. Cada dígito es un elemento de memoria de cuatro bytes que codifica valores enteros comprendidos entre0
y2
32−1
.Para determinar si en cada suma de dígitos del mismo peso hemos tenido acarreo existen muchos procedimientos. El valor de cada dígito de la suma, obtenido a partir de los dígitos de cada sumando más el acarreo de la suma de los dígitos previos (
z
j=(x
j+
y
j+C
j−1)(modB)
), se obtiene de forma inmediata sin necesidad de realizar la operación módulomodB
: por la misma definiciónde dígito dentro de la memoria del ordenador (elemento de formato entero sin signo de 32 bits: dominio de valores entre
0
yB=2
32−1
) se cumplirá que si el valor suma de los dígitos del mismo peso de cada uno de los sumandos es mayor queB
(si(x
j+y
j+C
j−1)≥B
), tendremos unasituación de overflow en la variable UINT4
z
i: es decir, llegado al valor máximoB=2
32−1
, el siguiente entero después del máximo es el cero; por lo tanto, la suma de dígitos se realiza automáticamente en su forma modularmodB
.Para la operación de la suma hemos definido dos funciones:
void SUMA(NUMERO*,NUMERO*,NUMERO*); void Suma(NUMERO*,UINT4,NUMERO*);
La primera de las dos funciones realiza la suma de los dos primeros parámetros, direcciones de variables de tipo NUMERO, y deja el resultado en la dirección de la variable que viene como tercer parámetro. La segunda función está definida para realizar la suma de una variable tipo NUMERO con un entero de 32 bits (tipo UINT4); el tercer parámetro de la función es la variable donde quedará almacenado el valor del resultado de la operación.
La primera función viene definida de manera que los tres parámetros pueden direccionar a una misma variable; o dos parámetros a una misma variable y el tercero a otra diferente; o los tres parámetros direccionar a variables distintas.
4.3.2.2. Implementación de la operación para la resta.
Para la implementación de la resta tenemos en cuenta cuanto hemos dicho antes, cuando hemos recogido algunos fundamentos matemáticos. El comportamiento de las variables en el
Una nueva implementación de entero largo para procesos de factorización 88 lenguaje de programación escogido facilita, como veremos ahora, la implementación de esta función.
Hemos definido la estructura NUMERO, encargada de codificar los enteros largos, de tal manera que cualquier entero codificado sea positivo. Y además cada dígito es un elemento unsigned
long int. Cada dígito de nuestra estructura tipo NUMERO puede codificar un valor entero
comprendido entre
0
y2
32−1=4.294.967.295
. Su dominio queda restringido a valores enteros positivos.Supongamos que
(x
j−y
j−b
j−1)>0
. En tal caso, como ya ha quedado dicho, el residuoB
b
y
x
z
j=(
j−
j−
j−1)mod
será el dígito que debemos almacenar en la cifra de la resta. Además, el cálculomodB
no será necesario en ningún caso puesto que(x
j−y
j−b
j−1)<B
siempre.Supongamos ahora que ese valor
(x
j−y
j−b
j−1)=−d
, donde0<d
<B
.¿Cuál debe ser el dígito a guardar? : como ya quedamos, será el residuo
z
j≡−dmodB
. Comosabemos,
z
j≡−dmodB⇔z
j+d=k⋅B
. Tomamosk
=+1
y llegamos a que el dígito será un valorj
z
tal qued
B
z
j=
−
(9)Ese es el residuo dentro del conjunto de residuos en el que trabajamos. Y este es el valor que se obtiene en la ALU cuando se opera con dos variables de codificación entera sin signo. Al resultar un valor fuera del dominio del tipo de dato, se produce un overflow (el valor que se obtiene al restar
1
al valor0
es el númeroB−1=2
32−1
) y el valor obtenido como resultado es precisamented
−
32
2
.Hemos probado una forma de implementar la resta, aprovechando el hecho de que los enteros con signo codifican el entero en su complemento a la base cuando el entero es negativo y en su forma binaria cuando el entero es positivo; y el signo –como se sabe– viene recogido en el bit más significativo: un cero si el número es positivo; un uno si es negativo.
En el compilador gcc de Linux disponemos de un tipo de dato estándar de formato entero de 64 bits: long long int, que puede ser declarado signed o unsigned. Definimos el tipo de dato SINT8: typedef signed long long int SINT8;
Supongamos por ejemplo la siguiente situación: UINT4 a = 0x00000001;
UINT4 b = 0x00000002;
SINT8 c = (SINT8)a – (SINT8)b; printf(“\n%llX\n”,c);
que ofrece como salida en pantalla el valor 0xFFFFFFFFFFFFFFFF, que como sabemos y esperábamos resulta ser el complemento a la base del entero
1
(valor absoluto del resultado de la resta realizada), en una numeración de 63 dígitos binarios (el bit más significativo se reserva para elUna nueva implementación de entero largo para procesos de factorización 89 signo y queda a 1 porque el resultado es negativo).
Los 32 bits menos significativos de la diferencia (la variable c) nos ofrecen (como veremos más adelante) el valor correspondiente al dígito de la resta de enteros largos que deberemos guardar. Los 32 bits más significativos nos ofrecen la información sobre el acarreo de la resta. Siempre que se produzca acarreo tendremos estos 32 bits al valor
1
; si no hay acarreo los 32 bits más significativos estarán a0
. El caso extremo del anterior es...UINT4 a = 0x00000000; UINT4 b = 0xFFFFFFFF;
SINT8 c = (SINT8)a – (SINT8)b; printf(“\n%llX\n”,c);
que ofrece como salida en pantalla el valor 0xFFFFFFFF00000001.
y que, tomando los 32 bits menos significativos, codifica el complemento a la base del valor 0XFFFFFFFF, que es el valor absoluto del resultado de la resta.
Por tanto, para averiguar si tenemos acarreo en la resta bastaría comprobar si cualquiera de los 32 bits más significativos de la variable c de tipo SINT8 está a uno.
Veamos desde un punto de vista más teórico las posibilidades que ofrece la codificación con el complemento a la base de los enteros negativos.
El concepto de complemento a la base depende de una premisa: del número de dígitos utilizados para codificar el número. Supongamos que trabajamos en una base
B
y que disponemos dek
dígitos para codificar nuestro número
N
. Evidentemente, siN
no requiere de todos losk
dígitos para su codificación en la baseB
, bastará dejar a cero todos los dígitos a la izquierda de la codificación. Definimos el complemento a la base deN
(y lo denotamos comoC
B(N)
) al valor resultante de restarB
k−N
. Y definimos el complemento a la base menos uno deN
(y lodenotamos como
C
B−1(N)
) al valorC
B(N)−1
.Como se sabe, esta definición es muy útil cuando trabajamos en base
B=2
, porque entonces tenemos que el valor del complemento a la base menos uno de cualquierN
se halla de forma inmediata: allí dondeN
tiene un dígito1
,C
1(N)
tiene un dígito0
; y viceversa.Los ordenadores suelen almacenar los enteros negativos en formato complemento a la base. El bit más significativo queda reservado para el signo (
1
siN
es negativo;0
siN
es positivo); y el resto de los bits codifican el entero en su formato binario suN≥0
, o codificanC
2(N)
siN<0
.Es decir, si queremos codificar
−N
(dondeN
>0
), tenemos que si∑
=⋅
=
31 02
i i iN
N
,Una nueva implementación de entero largo para procesos de factorización 90
1
2
1
)
(
)
(
31 0 1 2−
=
−
+
=∑
⋅
+
= i i iN
N
C
N
C
donde cada