Está en la página 1de 18

Chapter 3

Algoritmos

3.1 Algoritmos
Un algoritmo es un método paso a paso para resolver algunos problemas. En la actualidad,
“algoritmo” suele referirse a una solución ejecutable por una computadora. Es decir, un algoritmo
es un conjunto finito de instrucciones precisas que sirve para realizar un cálculo o resolver un problema.
Hay que hacer énfasis en dos aspectos para que un algoritmo exista:
1. El número de pasos debe ser finito. De esta manera el algoritmo debe terminar en un tiempo
finito con la solución del problema,
2. El algoritmo debe ser capaz de determinar la solución del problema.
De este modo, podemos definir algoritmo como un conjunto de reglas operacionales inherentes a un
cómputo. Se trata de un método sistemático, susceptible de ser realizado mecánicamente, para resolver
un problema dado.
Los algoritmos no son exclusivos de la informática. También son algoritmos los que aprendemos en
el colegio para multiplicar y dividir números de varias cifras. De hecho, el algoritmo más famoso de la
historia es el algoritmo de Euclides para calcular el máximo común divisor.

3.1.1 Caracterı́sticas de un algoritmo


1. Entrada: definir lo que necesita el algoritmo.
2. Salida: definir lo que produce.
3. N o ambiguo: explı́cito, siempre saber qué comando ejecutar.
4. F inito: El algoritmo termina en un número finito de pasos.
5. Correcto: Hace lo que se supone que debe hacer. La solución es correcta.
6. Ef ectividad: Cada instrucción se completa en tiempo finito. Cada instrucción debe ser lo
suficientemente básica como para que en principio pueda ser ejecutada por cualquier persona usando
papel y lápiz.
7. General: Debe ser lo suficientemente general como para contemplar todos los casos de entrada.
Ası́, podemos decir que un Algoritmo es un conjunto finito de instrucciones precisas para resolver
un problema. Si el problema es visto como una función, entonces el algoritmo toma una entrada y la
transforma en la salida.
Un problema es una función o asociación de entradas con salidas. Un problema puede tener muchos
algoritmos.
Por tanto, un algoritmo es un procedimiento para resolver un problema cuyos pasos son concretos y
no ambiguos. El algoritmo debe ser correcto, de longitud finita y debe terminar para todas las entradas.
Un programa es una implementación de un algoritmo en un lenguaje de programación.
Ejemplo 3.1. Consideremos el siguiente algoritmo que encuentra el máximo de tres números a, b y c:
1. grande = a,
2. Si b > grande, entonces grande = b,
3. Si c > grande, entonces grande = c.

1
La idea del algoritmo es inspeccionar los números uno por uno y copiar el valor más grande
encontrado a la variable grande. En la conclusión del algoritmo, grande será igual al valor mayor
de los tres números.
Ahora se muestra la manera en que el algoritmo anterior se ejecuta para algunos valores especı́ficos
de a, b y c. Esta simulación se llama seguimiento o rastreo. Primero supongamos que a = 1, b = 5, c = 3.
En la lı́nea 1, grande tiene el valor de a (1). En la lı́nea 2, b > grande (5 > 1) es verdadera, de
manera que grande es igual a b (5). En la lı́nea 3, c > grande (3 > 5) es falsa, y no hay cambio. En
este punto grande es 5, el valor mayor entre a, b y c.
Supongamos que a = 6, b = 1, c = 9.
En la lı́nea 1, grande tiene el valor de a (6). En la lı́nea 2, b > grande (1 > 6) es falsa, y no hay
cambio. En la lı́nea 3, c > grande (9 > 6) es verdadera, de manera que grande es igual a 9. En este
punto grande es 9, el valor mayor entre a, b y c.
Se verifica que el ejemplo de algoritmo tiene las caracterı́sticas establecidas al inicio de esta sección.
El algoritmo recibe los tres valores a, b y c como entrada y produce el valor grande como salida.
Los pasos del algoritmo se establecen con suficiente precisión de manera que éste puede escribirse
en un lenguaje de programación y ser ejecutado por una computadora.
A partir de los valores de entrada, cada paso intermedio de un algoritmo produce un resultado único.
El algoritmo termina después de un número finito de pasos (tres pasos) y contesta correctamente la
pregunta planteada (encontrar el mayor de tres valores de entrada).
El algoritmo es general; permite encontrar el valor más grande de cualesquiera tres números.
Aunque el lenguaje común en ocasiones es adecuado para especificar un algoritmo, la mayorı́a de los
matemáticos y los especialistas en ciencias de la computación prefieren el seudocódigo por su precisión,
estructura y universalidad. El seudocódigo recibe este nombre porque se parece a un código real en
lenguaje de computadora, como C ++ . Existen muchas versiones de seudocódigo. A diferencia de los
lenguajes para computadora que deben preocuparse por puntos y comas, mayúsculas y minúsculas,
palabras reservadas y otros elementos, cualquier versión de seudocódigo es aceptable siempre y cuando
sus instrucciones no sean ambiguas.
Ejemplo 3.2. Encontrar el valor máximo en una sucesión finita de numeros. Usar el método del
ejemplo anterior.
Solución Pongamos Entrada: s,n
Salida: grande(el valor mayor en una sucesión s)
máx(s,n){
grande = s1
for i = 2 to n
if(si > grande)
grande = si
return grande
}
Un algoritmo puede ser caracterizado por una función lo cual asocia una salida: s = f (E) a cada
entrada E.
Se dice entonces que un algoritmo calcula una función f . Entonces la entrada es una variable
independiente básica en relación a la que se producen las salidas del algoritmo, y también los análisis
de tiempo y espacio.
Cuando se tiene un problema para el cual debemos especificar un algoritmo solución, tendremos en
cuenta varios puntos:

1. Si no se conoce un método para solucionar el problema en cuestión, debemos hacer un análisis del
mismo para llegar a una solución, después de evaluar alternativas, exigencias y excepciones.

2. Si se conoce un ”buen” método de solución al problema, se debe especificar exacta y completamente


el método o procedimiento de solución en un lenguaje que se pueda interpretar fácilmente.
3. Los problemas pueden agruparse en conjunto de problemas que son semejantes.

4. En algún sentido, en general, un método para solucionar todos los problemas de un conjunto dado,
se considera superior a un método para solucionar solamente un problema del conjunto.

2
5. Hay criterios para determinar que tan buena es una solución, distintos de ver si trabaja o no, o
hasta qué punto es general la aplicabilidad del método. Estos criterios involucran aspectos tales
como: eficiencia, elegancia, velocidad, etc.

Al definir con exactitud un método de solución para un problema, este debe estar en capacidad de
encontrarla si existe; en caso de que no exista, el método debe reconocer esta situación y suspender
cualquier acción.
No se enseña nunca técnicas de cómo resolver problemas en general.
Al movernos dentro de la informática no siempre encontramos los problemas a punto de resolverlos,
es necesario empezar por hacer su formulación. Se exige hacerlo en términos concisos y claros partiendo
de las bases o supuestos que se dispone para especificar sus requerimientos.
Sólo a partir de una buena formulación será posible diseñar una estrategia de solución. Es necesario
aprender a desligar estos dos procesos. No se deben hacer formulaciones pensando paralelamente en
posibles soluciones. Es necesario darle consistencia e independencia para determinar con precisión a
qué se quiere dar solución y luego canalizar una gama de alternativas posibles.
Si ya se ha realizado la formulación del problema podemos cuestionarla con el fin de entenderlo bien.
En nuestra área, el análisis de un problema tiene dos etapas claramente definidas y relacionadas:

 Definición del problema
1. Formulación o planteamiento del problema Supuestos: aserciones y limitaciones dadas
Resultados esperados



 Análisis de alternativas y selección de la solución.
Especificación detallada del procedimiento solución.

2. Resolución del problema

 Adopción o uso de una herramienta para su
implementación, si es necesária.

En la etapa de planteamiento del problema lo que pretende un algoritmo es sintetizar de alguna


forma una tarea, cálculo o mecanismo antes de ser transcrito al computador. Los pasos que hay que
seguir son los siguientes:

• 1. Análisis previo del problema.


2. Primera visión del método de resolución
3. Descomposición en módulos.
4. Programación estructurada.
5. Búsqueda de soluciones parciales.
6. Ensamblaje de soluciones finales.

Hay que notar que el computador es un medio y no es el fin en la solución de problemas.


En otras palabras, no es el computador el que soluciona los problemas, somos nosotros quienes lo
hacemos y de alguna manera le contamos como es la cosa para que él con su velocidad y exactitud
trabaje con grandes volúmenes de datos.
Es ası́ que en el campo de las ciencias de la computación la solución de problemas se describe
mediante el diseño de procedimientos llamados algoritmos, los cuales posteriormente se implementan
como programas. Los programas son procedimientos que solucionan problemas y que se expresan en un
lenguaje conocido por el computador.
Se pueden dar problemas que por su tamaño es necesario subdividirlos en problemas más simples
para solucionarlos. Se parte del principio de que es más fácil solucionar varios problemas simples como
partes de un todo que seguir una implantación de ”Todo o Nada”. Desarrollar la capacidad de formular
y resolver problemas nos prepara para enfrentar situaciones desconocidas.

3.1.2 Algoritmos de búsqueda


Encontrar un texto especı́fico en un documento al correr un procesador de textos es un ejemplo de
un problema de búsqueda. Veremos un algoritmo para resolver el problema de buscar un texto.
Suponga que se da el texto t (por ejemplo, un documento en un procesador de palabras) y queremos
encontrar la primera ocurrencia del patrón p en t (por ejemplo, se desea encontrar la primera ocurrencia

3
de la cadena p = “Matemáticas Discretas” en t) o determinar que p no aparece en t. Se indexan los
caracteres en t comenzando con 1. Un enfoque para buscar p es verificar si p ocurre en el ı́ndice 1 en t.
Si ası́ es, nos detenemos, puesto que ya se encontró la primera ocurrencia de p en t. Si no, se verifica si
p ocurre en el ı́ndice 2 en t. Si ası́ es, nos detenemos, pues ya se encontró la primera ocurrencia de p en
t. Si no, se verifica el ı́ndice 3 en t, y ası́ sucesivamente.
El algoritmo de búsqueda de texto es el siguiente, como ejemplo:
Ejemplo 3.3. Búsqueda de texto. Este algoritmo busca una ocurrencia del patrón p en el texto t.
Regresa el ı́ndice más pequeño i tal que p ocurre en t comenzando en el ı́ndice i. Si p no ocurre en t,
regresa 0.
Entrada: p (indexada de 1 a m), m, t (indexada de 1 a n), n
Salida: i
busca texto(p, m, t, n){
for i = 1 to n - m + 1{
j=1
// i es el ı́ndice en t del primer carácter de la subcadena para comparar con p, y j es el
ı́ndice en p
// el ciclo “while” compara ti . . . ti+m−1 y p1 . . . pm
while (ti+j−1 == pj ){
j=j+1
if(j > m)
return i
}
}
return 0
}
La variable i marca el ı́ndice en t del primer carácter de la subcadena para compararlo con p. El
algoritmo primero intenta i = 1, después i = 2, y ası́ sucesivamente. El ı́ndice n − m + 1 es el último
valor posible para i ya que, en este punto, la cadena tn−m+1 tn−m+2 · · · tm tiene la longitud exacta m.
Después de establecer el valor i, el ciclo “while” compara ti ...ti+m−1 y p1 ...pm . Si los caracteres
coinciden,
ti+j−1 ̸= pj
j se incrementa
j =j+1
y se comparan los siguientes caracteres. Si j es m + 1, todos los m caracteres coinciden y hemos
encontrado p en el ı́ndice i en t. En este caso, el algoritmo regresa i:

if (j > m)
return i

Si el ciclo corrió hasta completarse, nunca se encontró una coincidencia, en cuyo caso el algoritmo
regresa 0.

3.1.3 Eficiencia de Algoritmos


Un objetivo natural en el desarrollo de un programa computacional es mantener tan bajo como sea
posible el consumo de los diversos recursos, aprovechándolos de la mejor manera que se encuentre. Se
desea un buen uso, eficiente, de los recursos disponibles, sin desperdiciarlos.
Para que un programa sea práctico, en términos de requerimientos de almacenamiento y tiempo de
ejecución, debe organizar sus datos en una forma que apoye el procesamiento eficiente.
Siempre que se trata de resolver un problema, puede interesar considerar distintos algoritmos, con el
fin de utilizar el más eficiente. Pero, ¿cómo determinar cuál es el mejor ? La estrategia empı́rica consiste
en programar los algoritmos y ejecutarlos en un computador sobre algunos ejemplares de prueba. La
estrategia teórica consiste en determinar matemáticamente la cantidad de recursos (tiempo, espacio,
etc.) que necesitará el algoritmo en función del tamaño del ejemplar considerado.

4
El tamaño de un ejemplar x corresponde formalmente al número de dı́gitos binarios necesarios para
representarlo en el computador. Pero a nivel algorı́tmico consideraremos el tamaño como el número de
elementos lógicos contenidos en el ejemplar.
Un algoritmo es eficiente cuando logra llegar a sus objetivos planteados utilizando la menor cantidad
de recursos posibles, es decir, minimizando el uso memoria, de pasos y de esfuerzo humano.
Un algoritmo es eficaz cuando alcanza el objetivo primordial, el análisis de resolución del problema
se lo realiza prioritariamente.
Puede darse el caso de que exista un algoritmo eficaz pero no eficiente, en lo posible debemos de
manejar estos dos conceptos conjuntamente.
La eficiencia de un programa tiene dos ingredientes fundamentales: espacio y tiempo.

1. La eficiencia en espacio es una medida de la cantidad de memoria requerida por un programa.


2. La eficiencia en tiempo se mide en términos de la cantidad de tiempo de ejecución del programa.

Ambas dependen del tipo de computador y compilador, por lo que veremos la eficiencia de los
programas, sino la eficiencia de los algoritmos. Asimismo, este análisis dependerá de si trabajamos con
máquinas de un solo procesador o de varios de ellos.
Centraremos nuestra atención en los algoritmos para máquinas de un solo procesador que ejecutan
una instrucción y luego otra.
Como hemos visto, existen muchos enfoques para resolver un problema. ¿Cómo escogemos entre
ellos? Generalmente hay dos metas en el diseño de programas de cómputo:

• El diseño de un algoritmo que sea fácil de entender, codificar y depurar (Ingenierı́a de Software).
• El diseño de un algoritmo que haga uso eficiente de los recursos de la computadora (Análisis y
Diseño de algoritmos).

El análisis de algoritmos nos permite medir la dificultad inherente de un problema y evaluar la


eficiencia de un algoritmo.
Una medida que suele ser útil conocer es el tiempo de ejecución de un algoritmo en función de n,
lo que denominaremos f (n). Esta función se puede medir fı́sicamente (ejecutando el programa, reloj
en mano), o calcularse sobre el código contando instrucciones a ejecutar y multiplicando por el tiempo
requerido por cada instrucción.
Ası́, una parte sencilla de programa
requiere
s1 ; for i:= 1 to n do s2 end;
f(n):= t1 + t2 *n
siendo t1 el tiempo que lleve ejecutar la serie ”s1 ” de sentencias, y t2 el que lleve la serie ”s2 ”.
Prácticamente todos los programas reales incluyen alguna sentencia condicional, haciendo que las
sentencias efectivamente ejecutadas dependan de los datos concretos que se le presenten. Esto hace que
más que un valor f (n) debamos hablar de un rango de valores:

f min (n) ≤ f (n) ≤ f max (n)

los extremos son habitualmente conocidos como caso peor y caso mejor.
Entre ambos se hallará algún caso promedio o más frecuente.
Cualquier fórmula f (n) incluye referencias al parámetro n y a una serie de constantes ”fi ” que
dependen de factores externos al algoritmo como pueden ser la calidad del código generado por el
compilador y la velocidad de ejecución de instrucciones del computador que lo ejecuta.
No se puede medir el tiempo en segundos porque no existe un computador estándar de referencia,
en su lugar medimos el número de operaciones básicas o elementales: suma, resta, multiplicación,
división y comparaciones que se indican explı́citamente en un enunciado si emplean uno de los sı́mbolos
relacionales <, ≤, >, ≥, = o ̸=.
Cuando se implementan los algoritmos en un particular lenguaje de programación y se ejecutan
en una determinada computadora, entonces algunas operaciones se efectúan más rápido que otras y,
de hecho, de una máquina a otra hay diferencias en los tiempos de ejecución. En ciertas situaciones
prácticas esos factores se toman en cuenta al decidir qué algoritmo o que máquina emplear para resolver
un problema especı́fico.

5
Sin embargo, en otros casos la máquina es dada y todo lo que necesitamos son burdas estimaciones
para determinar la clara superioridad de un algoritmo sobre otro. Como cada operación elemental se
ejecuta en un tiempo no mucho mayor que la más lenta, entonces la eficiencia temporal de un algoritmo
es aproximadamente proporcional al número de operaciones elementales requerido para ejecutar el
algoritmo.
Considere el ejemplo de dos algoritmos, A y B, diseñados para realizar cierto trabajo.
Supongamos que para una entrada de tamaño n, el número de operaciones elementales que se
necesitan para realizar el algoritmo A está entre 10n y 20n (al menos para n grandes) y que el número
de operaciones elementales requeridas para ejecutar el algoritmo B está entre 2n2 y 4n2 .
Observe que 20n < 2n2 siempre que n > 10, lo que significa que el número máximo de operaciones
necesitadas para ejecutar A es menor que el número mı́nimo de operaciones requeridas para implementar
B siempre que n > 10.
En efecto, 20n es mucho menor que 2n2 cuando n es grande. Por ejemplo, si n = 1000, entonces
20n = 20000 mientras que 2n2 = 2000000. Decimos que en el peor caso, el algoritmo A es Θ(n) (o que
tiene un peor caso de orden n) y el algoritmo B es Θ(n2 )(o que tiene un peor caso de orden n2 ).
Todo esto último se conoce como el crecimiento de funciones.

3.2 Crecimiento de funciones


3.2.1 Notaciones O, Ω y Θ

Frecuentemente ocurre que, de entre varios algoritmos, se podrı́a emplear uno para ejecutar cierto
trabajo, pero el tiempo o la capacidad de memoria que requieren varı́an dramáticamente. Las notaciones
O, Ω y Θ dan aproximaciones que hace fácil evaluar diferencias a gran escala en la eficiencia de un
algoritmo, mientras que se ignoran diferencias de un factor constante y diferencias que suceden sólo
para pequeños conjuntos de datos de entrada.
La más antigua de las notaciones, la O-notación (o la notación O), fue introducida por el matemático
alemán Paul Bachmann en 1894 en un libro sobre teorı́a analı́tica de números. Las notaciones Ω (Omega)
y Θ (Theta) fueron desarrolladas por Donald Knuth, uno de los pioneros de la ciencia de programación
computacional.
La idea de las notaciones es esta. Suponga que f y g son funciones reales de una variable real x.
1. Si, para valores de x suficientemente grandes, los valores de |f | son menores que los de un múltiplo
de |g|, entonces f es de orden a lo más g, o f (x) es O(g(x)).

|f | ≡ |f (x)|
|f (x)| ≤ |g (x)|

2. Si, para valores de x suficientemente grandes, los valores de |f | son más grandes que los de un
múltiplo de |g|, entonces f es de orden al menos g, o f (x) es Ω(g(x)).

α |g (x)| ≤ |f (x)|

3. Si, para valores de x suficientemente grandes, los valores de |f | están acotados por arriba y por
abajo por valores múltiplos de |g|, entonces f es de orden g, o f (x) es Θ(g(x)).

α |g (x)| ≤ |f (x)| ≤ β |g (x)|

Sean f y g funciones valuadas en los reales sobre el mismo conjunto de números reales no-negativos.
Entonces

1. f es de orden al menos g, y se escribe f (x) es Ω(g(x)), si y sólo si, existen un número real positivo
A y un número real no-negativo a tales que

A |g (x)| ≤ |f (x)|

para todos los números reales x > a.

6
2. f es de orden a lo más g, y se escribe f (x)es O(g(x)), si y sólo si, existen un número real positivo
B y un número real no-negativo b tales que

|f (x)| ≤ B |g (x)|

para todos los números reales x > b.


3. f es de orden g, y se escribe f (x) es Θ(g(x)), si y sólo si, existen números reales positivos A, B
y un número real no-negativo k tal que

A |g (x)| ≤ |f (x)| ≤ B |g (x)|

para todos los números reales x > k.

Ejemplo 3.4. Dado que 60n2 + 5n + 1 ≤ 60n2 + 5n2 + n2 = 66n2 para toda n ≥ 1, se puede tomar
B = 66 en la definición para obtener

60n2 + 5n + 1 = O(n2 ).

Como
60n2 + 5n + 1 ≥ 60n2
para toda n ≥ 1, se puede tomar A = 60 en la definición para obtener

60n2 + 5n + 1 = Ω(n2 ).

Como 60n2 + 5n + 1 = O(n2 ) y 60n2 + 5n + 1 = Ω(n2 ),

60n2 + 5n + 1 = Θ(n2 ).

Ejemplo 3.5. Como log2 n < n para toda n ≥ 1

3 log2 n < 3n ⇔ 2n + 3 log2 n < 2n + 3n

2n + 3 log2 n < 2n + 3n = 5n
para toda n ≥ 1. Ası́,
2n + 3 log2 n = O(n).
Además,
2n + 3 log2 n ≥ 2n
para toda n ≥ 1. Entonces,
2n + 3 log2 n = Ω(n).
Por lo tanto,
2n + 3 log2 n = Θ(n).
Ejemplo 3.6. Use la notación Θ para expresar el enunciado

10|x6 | ≤ |17x6 − 45x3 + 2x + 8| ≤ 30|x6 |,

para todos los números reales x > 2.


Ejemplo 3.7. Demostrar que log2 (n!) = Θ(n log2 n).
Ejemplo 3.8. Use las notaciones O y Ω para expresar los dos primeros enunciados

√ 15 x (2x + 9)
1. 15 | x| ≤ para todos los números reales x > 0.
x+1

≤ 45 |√x| para todos los números reales x > 7.
15 x (2x + 9)
2.

x+1

15 x (2x + 9) √
3. Justifique que es un Θ ( x).
x+1

7
Observación 3.9. El punto 3. del ejemplo 3.8 muestra el hecho de que si sabe que f es de orden a lo
más g y que f es de orden a lo menos g, entonces puede tomar k como el mayor de los números a y
b como se prometió en las definiciones de las notaciones omega y O y ası́ concluir que f es de orden
g. Inversamente, si f es de orden g, entonces a y b pueden tomarse como el número k prometido en la
definición de la notación theta, para ası́ demostrar que f es del orden a lo más g y que f es del orden
a lo menos g. Esos resultados y una propiedad transitiva de orden, se establecen formalmente en el
siguiente teorema.
Propiedades de las notaciones O, Ω y Θ
Sean f y g funciones valuadas en los reales definidas sobre el mismo conjunto de números reales
no-negativos.
1. f (x) es Ω(g(x)) y f (x) es O(g(x)) si y sólo si, f (x) es Θ(g(x)).
2. f (x) es Ω(g(x)) si y sólo si, g(x) es O(f (x)).
3. Si f (x) es O(g(x)) y g(x) es O(h(x)), entonces f (x) es O(h(x)).

3.3 Algoritmos complejos


El análisis de algoritmos constituye una tarea fundamental en computación, ya que para comparar
algoritmos se requieren algunos criterios que midan su eficiencia. En esta sección se aborda este
importante tema.
La complejidad (o costo) de un algoritmo es una medida de la cantidad de recursos (tiempo, memoria)
que el algoritmo necesita. La complejidad de un algoritmo se expresa en función del tamaño (o talla)
del problema.
La función de complejidad tiene como variable independiente el tamaño del problema y sirve para
medir la complejidad (espacial o temporal). Mide el tiempo/espacio relativo en función del tamaño del
problema.
El comportamiento de la función determina la eficiencia. No es única para un algoritmo, depende
de los datos. Para un mismo tamaño del problema, las distintas presentaciones iniciales de los datos
dan lugar a distintas funciones de complejidad. Es el caso de una ordenación si los datos están todos
inicialmente desordenados, parcialmente ordenados o en orden inverso.
Ejemplo 3.10. f (n) = 3n2 + 2n + 1, en donde n es el tamaño del problema y expresa el tiempo en
unidades de tiempo.
Suponga que A es un algoritmo y que n es el tamaño de los datos de entrada. Resulta evidente que
la complejidad f (n) de A crece cuando n aumenta; por lo que el análisis más común es la tasa o razón
de crecimiento de f (n), que se obtiene al comparar f (n) con alguna función estándar, como log2 (n), n,
n log2 (n), n2 , n3 , 2n .
En la tabla que sigue se muestran algunos de los órdenes más comúnmente empleados para describir
eficiencias de algoritmos. Ahı́ se ve que son más que astronómicas las diferencias entre los órdenes de
varios tipos de algoritmos. Un algoritmo de orden 2n para operar un conjunto de datos de tamaño 100
000 requiere un tiempo de aproximadamente 1030.076 veces la edad del universo (15 billones de años
de acuerdo a determinada teorı́a cosmológica). Por otro lado, un algoritmo de orden log2 n necesita a
lo más una fracción de segundo para procesar el mismo conjunto de datos. (Tiempo aproximado para
ejecutar f (n) operaciones suponiendo una operación por nanosegundo, es decir 10−9 seg.)

f (n) n = 10 n = 1000 n = 100000


log2 n 3.3 × 10−9 seg 10−8 seg 1.7 × 10−8 seg
n 10−8 seg 10−6 seg 0.0001seg
n log2 n 3 × 10−8 seg 10−5 seg 0.0017seg
n2 10−7 seg 10−3 seg 10seg
n3 10−6 seg 1seg 11.6dı́as
2n 10−6 seg 3.4 × 10284 años 3.1 × 1030086 años

Se dice que O(f (n)) define un orden de complejidad. Escogeremos como representante de este orden a
la función f (n) más sencilla del mismo.
Ası́ tendremos:
O(1) orden constante

8
O(log n) orden logarı́tmico (búsqueda binaria)
O(n) orden lineal
O(n2 ) orden cuadrático (ordenamiento burbuja)
O(na ) orden polinomial (a > 2)
O(an ) orden exponencial (a > 2)
O(n!) orden factorial
Se puede identificar una jerarquı́a de órdenes de complejidad que coincide con el orden de la tabla
anterior; jerarquı́a en el sentido de que cada orden de complejidad superior tiene a los inferiores como
subconjuntos. Si un algoritmo A se puede demostrar de un cierto orden O1 , es cierto que también
pertenece a todos los órdenes superiores; pero en la práctica lo útil es encontrar la ”menor cota superior”,
es decir el menor orden de complejidad que lo cubra.
En el análisis de algoritmos se considera usualmente el caso peor, si bien a veces conviene analizar
igualmente el caso mejor y hacer alguna estimación sobre un caso promedio. Para independizarse de
factores coyunturales, tales como el lenguaje de programación, la habilidad del codificador, la máquina
de soporte, etc. se suele trabajar con un cálculo asintótico que indica cómo se comporta el algoritmo
para datos muy grandes y salvo algún coeficiente multiplicativo. Para problemas pequeños casi todos
los algoritmos son ”más o menos iguales”, primando otros aspectos como esfuerzo de codificación,
legibilidad, etc. Los órdenes de complejidad son importantes para grandes problemas.

3.4 Representación entera y algoritmos.


Los enteros se pueden expresar usando cualquier entero mayor que uno como base, como veremos en
esta sección. Aunque comúnmente usamos representaciones decimales (base 10), las representaciones
binarias (base 2), octales (base 8) y hexadecimales (base 16) a menudo se usan, especialmente en
informática. Dada una base b y un entero n, mostraremos cómo construir la representación en base b de
este entero. También explicaremos cómo convertir rápidamente entre binario y octal y entre notaciones
binarias y hexadecimales.
En ciencia computacional, la notación de base 2, o la notación binaria es de especial importancia
ya que las señales utilizadas en electrónica moderna están siempre en uno de los dos estados. (La raı́z
latina bi significa “dos”.)
Describiremos un algoritmo eficiente para la exponenciación modular, el que es un algoritmo particularmente
importante para la criptografı́a.
En el sistema numérico decimal, para representar los enteros se usan los 10 sı́mbolos 0, 1, 2, 3, 4, 5, 6, 7, 8
y 9.
Al representar un entero, la posición del sı́mbolo es significativa; leyendo desde la derecha, el primer
sı́mbolo representa al número de unidades, el siguiente sı́mbolo el número de decenas, el siguiente el
número de centenas, y ası́ sucesivamente.
Ası́ pues, un número x en un sistema posicional en base b se escribe como una secuencia de dı́gitos:
x = xn xn−1 ...x1 x0 .x−1 x−2 ...x−m
donde cada dı́gito xi posee un valor intrı́nseco |xi | en el conjunto {0, ..., b − 1} (i ∈ {−m, ..., n}). El
valor del número x, denotado |x|, es:
Xn
|x| = |xi | bi
i=−m

A este número |x| en el Teorema 3.11 que sigue lo escribimos como n, los |xi | los escribimos como ai .
Por lo general, los dı́gitos hexadecimales utilizados son 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F ,
donde las letras de la A a la F representan los dı́gitos correspondientes a los números del 10 al 15 (en
notación decimal).
Por ejemplo,
3854 = 3 · 103 + 8 · 102 + 5 · 101 + 4 · 100
En el sistema numérico binario (base 2), para representar enteros se necesitan sólo dos sı́mbolos, 0 y 1.
Para representar un entero, leyendo de derecha a izquierda, el primer sı́mbolo representa el número de
unos, el siguiente sı́mbolo el número de números dos, el siguiente el número de cuatros, el siguiente el
número de ochos, etc. Por ejemplo, en base 2,
101101 = 1 · 25 + 0 · 24 + 1 · 23 + 1 · 22 + 0 · 21 + 1 · 20

9
En general, tenemos el siguiente teorema.
Teorema 3.11. Sea b un número entero mayor que 1. Entonces, si n es un número entero positivo,
este puede expresarse de manera única en la forma n = ak bk + ak−1 bk−1 +· · · +a1 b + a0 , donde k es
un entero no negativo, a0 , a1 , ..., ak son enteros no negativos menores que b, y ak ̸= 0.
En el teorema b se llama la base y la expresión para el entero n, se llama la representación en la
base b.
Ejemplo 3.12. Expresar el número 27 en base dos.
Ejemplo 3.13. Representar 209 en base 2.

3.4.1 Conversión de base


Describiremos un algoritmo para construir la representación en base b de un entero n. Primero, se
divide n entre b para obtener un cociente y el resto, es decir,

n = bq0 + a0 , 0 ≤ a0 < b.

El resto, a0 , es el dı́gito más a la derecha en la representación base b de n. Luego, se divide q0 por b


para obtener
q0 = bq1 + a1 , 0 ≤ a1 < b.
Vemos que a1 es el segundo dı́gito desde la derecha en la representación base b de n. Se continúa este
proceso, dividiendo sucesivamente los cocientes por b, obteniendo dı́gitos de base b adicionales como el
resto. Este proceso termina cuando obtenemos un cociente igual a cero. Produce los dı́gitos de la base
b de n de derecha a izquierda.
Ejemplo 3.14. Convertir el número decimal 20385 en hexadecimal.
Ejemplo 3.15. Convertir el número 2AE0B16 a un número en base 10.

Algunos algoritmos
Algunos algoritmos

1. Conversión de un entero de base b en decimal.


Este algoritmo regresa el valor decimal del entero en base b cn cn−1 · · · c1 c0 .
Entrada: c, n, b
Salida: val dec
base b a dec(c, n, b) {
val dec = 0
potencia = 0
for i = 0 to n {
val dec = val dec + ci *potencia
potencia = potencia*b
}
return val dec
}

2. Conversión de un entero decimal a la base b.


Este algoritmo convierte el entero positivo m en un entero base b cn cn−1 · · · c1 c0 . La variable n
se usa como ı́ndice en la sucesión c. El valor de m mod b es el residuo cuando m se divide entre b.
El valor de m/b es el cociente cuando m se divide entre b.
Entrada: m, b

10
Salida: c, n
dec a base b(m, b, c, n){
n = –1
while(m > 0){
n=n+1
cn = m mod b
m = ⌊m/b⌋
}
}

Operaciones con enteros


Suma y resta binaria
Los métodos de cálculo de aritmética binaria son análogos a los de aritmética decimal. En aritmética
binaria el número 2 (= 102 en notación binaria) desempeña un papel similar al del número 10 en
aritmética decimal.
Ejemplo 3.16. Sume 11012 y 1112 usando notación binaria.
Ejemplo 3.17. Sume los números binarios 10011011 y 1011011.
Algoritmo Suma de números binarios
Este algoritmo suma los números binarios y guarda la suma en sn+1 sn sn−1 · · · s1 s0 .
Entrada: b, b’ , n
Salida: s
suma binaria(b, b’, n, s) {
lleva = 0
for i = 0 to n {
si = (bi + bi ’ + lleva) mod 2
lleva = ⌊bi + bi ’ + lleva)/2⌋
}
sn+1 = lleva
}
El algoritmo anterior corre en un tiempo Θ(n).
Ejemplo 3.18. Resta en notación binaria. Reste 10112 de 110002 usando notación binaria.
Suma hexadecimal
Ejemplo 3.19. Sumar los números hexadecimales 84F y 42EA.
Se pueden multiplicar números binarios modificando el algoritmo estándar para la multiplicación de
números decimales.
Veremos un algoritmo para calcular una potencia an (sin incluir mod z). La manera directa de
calcular esta potencia es multiplicar repetidas veces por a
n aes
z }| {
a · a · a · ··· · a

que usa n−1 multiplicaciones. Se logran mejores resultados si se eleva al cuadrado repetidas veces.
Ejemplo 3.20. Calcular a29 .
Solución
Primero se calcula a2 = a · a, que requiere una multiplicación. Después se calcula a4 = a2 · a2 ,
que usa una multiplicación más. Luego se calcula a8 = a4 ·a4 , que usa una multiplicación adicional y
después se calcula a16 = a8 ·a8 , que requiere una multiplicación más. Hasta aquı́ se han empleado sólo
4 multiplicaciones. Observe que la expansión de 29 en potencias de 2, que es la expansión binaria, es

29 = 1 + 4 + 8 + 16,

11
vemos que se puede calcular a29 como

a29 = a1 · a4 · a8 · a16 ,

que usa 3 multiplicaciones adicionales con un total de 7 multiplicaciones. La técnica directa utiliza 28
multiplicaciones.
En el ejemplo 3.12, (representar 209 en base 2) se vio que los residuos, cuando n se divide repetidas
veces entre 2, dan la expansión binaria de n. Si el residuo es 1, se incluye la potencia de 2 correspondiente;
de otra manera, no se incluye.
Se puede formalizar la técnica de elevar al cuadrado repetidas veces si se determina al mismo tiempo
la expansión binaria del exponente.
La tabla que sigue muestra cómo se calcula a29 elevando al cuadrado una y otra vez. Inicialmente,
x se hace igual a a, y n al valor del exponente, en este caso 29. Después se calcula n mod 2. Como este
valor es 1, se sabe que 1 = 20 está incluido en la expansión binaria de 29. Por lo tanto, a1 se incluye
en el producto. Se da seguimiento al producto parcial en el resultado; ası́, el resultado se hace igual a
a. Luego se calcula el cociente cuando 29 se divide entre 2. El cociente 14 se vuelve el nuevo valor de
n. Después se repite este proceso.

Valor Cociente cuando n actual


x de n n mod 2 Resultado se divide entre 2
a 29 1 a 14
a2 14 0 sin cambio 7
a4 7 1 a · a4 = a5 3
a8 3 1 a5 · a8 = a13 1
a16 1 1 a13 · a16 = a29 0

Algoritmo: Elevar a un exponente elevando al cuadrado varias veces.


Este algoritmo calcula an elevando al cuadrado repetidas veces. El algoritmo se explica en el ejemplo
anterior.
Entrada: a, n
Salida: an
exp via cuadrado repetido(a, n) {
resultado = 1
x=a
while (n > 0) {
if (n mod 2==1)
resultado = resultado * x
x=x*x
n = ⌊n/2⌋
}
return resultado
}
El número de veces que se ejecuta el ciclo “while” está determinado por n. La variable n se divide
entre 2 repetidas veces
⌊n/2⌋
y cuando n es cero, el ciclo termina.
Algoritmo Elevar un exponente mod z elevando al cuadrado varias veces
Este algoritmo calcula an mod z elevando al cuadrado una y otra vez.
Entrada: a, n, z
Salida: an mod z
exp mod z via cuadrado repetido(a, n, z) {
resultado = 1
x = a mod z
while (n > 0) {
if (n mod 2== 1)
resultado = (resultado * x) mod z
x = (x * x) mod z

12
n = ⌊n/2⌋
}
return resultado
}

3.4.2 Representación de un número real N


En general, podemos representar un número real N en cualquiera de los sistemas de numeración
que se utilizan en un computador: decimal, binario, hexadecimal, octal. Escribimos

N = Ne + Nf

donde Ne es la parte entera de N y Nf es la parte fraccionaria de N .


Conversión de base 10 a base b.
1. Se divide Ne y cada cociente sucesivo por la base b, hasta obtener cero como cociente, sin considerar
resto
La sucesión de restos en orden inverso es la representación de Ne en la base b.
2. Se multiplica Nf y la parte fraccionaria de cada producto sucesivo por la base b, hasta obtener
una parte fraccionaria cero o repetida (términos periódicos).
La sucesión (finita o infinita) de las partes enteras de los productos, precedida del punto decimal,
es la representación de Nf en base b.
Ejemplo 3.21. Convertir 38.625 a base 8.
Ejemplo 3.22. Convertir 2245.65625 a base 16.
Ejemplo 3.23. Convertir 14.7 a base 2.
Conversiones especiales
Si una base es potencia entera de la otra.
1. Si b1 = bk2 , cada cifra en base b1 se representa con k cifras en b2 .
2. Si bk1 = b2 , cada grupo de k cifras en base b1 se representa con una cifra en base b2 .
Ejemplo 3.24. Convertir 93A · 6516 a base 2.
Ejemplo 3.25. Convertir 1010010 · 1011112 a base 16.
Complemento a la base
El complemento a la base es lo que le falta a un número N expresado en base b para ser la menor
potencia de b que sea mayor que N . Lo denotamos por Cb (N .)
El complemento a la base se encuentra restando a cada cifra del número, comenzando por la
izquierda, de la base menos uno, hasta llegar a la última cifra diferente de cero a la que se le resta
de la base y se completa con ceros a la derecha. Equivalentemente, se puede calcular en la forma

Cb (N ) = (10k · · · 01 ) − N

con N representado en k dı́gitos en la base b.


Ejemplo 3.26. Encontrar el complemento a 10 de 4076.
Ejemplo 3.27. Hallar el complemento a 10 de 3700.
Ejemplo 3.28. Hallar el complemento a 2 de 10112 .
Ejemplo 3.29. Encontrar el complemento a 2 de 10102 .
Complemento a la base menos uno
El complemento a la base menos uno se obtiene restando cada cifra del número de la base menos
uno. Lo escribimos como Cb (N ) − 1 = Cb−1 (N ). Por tanto Cb (N ) = Cb−1 (N ) + 1.
Ejemplo 3.30. Hallar el complemento a 9 de 4076.
Ejemplo 3.31. Hallar el complemento a 9 de 3700

13
Ejemplo 3.32. Hallar el complemento a 1 de 10112
Ejemplo 3.33. Encontrar el complemento a 1 de 10102
Representación de Datos en el computador
Los datos pueden ser

1. Numéricos

(a) Enteros: sin signo, con signo.


(b) Reales.

2. Alfanuméricos.
1. Numéricos

(a) Enteros
Normalmente utilizamos el sı́mbolo “−” precediendo a un número para indicar que éste es
menor que cero. Esta es una notación muy práctica en la vida cotidiana pero no puede ser
utilizada en la representación que se hace de los números en una computadora, recordemos
que sólo se pueden utilizar los dı́gitos binarios para representar cualquier cosa en ellas y el
“−” no es ningún bit.
Pero podemos utilizar la misma idea, preceder el número de un bit que indique su signo,
después de todo sólo hay dos posibles signos, a saber: “+” y “−”. Todo lo que tenemos que
hacer es asignar arbitrariamente un bit a cada signo. Convencionalmente se hace: “+”= 0,
“−”= 1.
A este método de representación de números negativos se le denomina signo y magnitud
porque, análogamente a lo que solemos hacer, se coloca un sı́mbolo que precede al número y
que indica su signo y luego se pone la magnitud del número. En esta notación por ejemplo

1 010102 = −1010

De esta manera es muy fácil distinguir los números positivos de los negativos, si utilizamos
un número fijo de bits para representarlos y decidimos que siempre el primer bit es para
el signo del número, entonces basta con observar el primer bit de la izquierda (al que en
este caso no podemos decirle formalmente “el más significativo”, dado que no tiene asociada
ninguna potencia de 2) para determinar si se trata de un número negativo o positivo.
En este caso la “multiplicación por −1” de un número equivale a negar o invertir el bit de
la extrema izquierda, esto es, convertirlo en cero si vale 1 y viceversa. De hecho la idea
fundamental detrás de la representación de signo y magnitud es que ocurra: −(−a) = a.
Lo que nos parece evidente por estar acostumbrados a nuestra representación de números
negativos convencional.
Un inconveniente del sistema de signo y magnitud es que existen dos representaciones distintas
para el cero, es decir, el neutro aditivo no es único formalmente hablando, tanto el 10...0
como el 00...0 son cero, el primero con signo “−” y el segundo con signo “+”, lo que tampoco
es correcto desde el punto de vista matemático, dado que el cero no es ni positivo ni negativo.
Esta dualidad del cero tiene implicaciones importantes en una computadora digital. Los
procesadores tienen generalmente instrucciones para cambiar al flujo de los programas llamadas
saltos, hay saltos incondicionales (siempre que el procesador ejecuta la instrucción de salto la
siguiente instrucción es aquella indicada por el salto) y hay saltos condicionales (la instrucción
siguiente es a veces la que está bajo la del salto y a veces la indicada por el salto dependiendo
de alguna condición). Y generalmente la condición de salto es establecida comparando algún
dato con cero. Si hay dos representaciones del cero hay que hacer dos comparaciones y eso
lleva más tiempo que hacer sólo una.
Enteros sin signo
Los enteros sin signo son representados como números en base dos. Si se dispone de n bits
se puede representar 2n enteros sin signo. Su rango es

0 ≤ N ≤ 2n − 1

14
Ejemplo Si se dispone de n = 4 bits, el cero se representa por 0000. El 15 se representa por
11112 .
Enteros con signo
Los enteros con signo se pueden representar en:
• Signo y magnitud.
• Complemento a uno.
• Complemento a dos.
• Exceso.
• Representación en signo y magnitud
Hay varias convenciones alternativas que se pueden utilizar para representar números
enteros tanto positivos como negativos. Todas ellas implican tratar el bit más significativo
(el más a la izquierda) de la palabra como un bit de signo: si dicho bit es 0 el número
es positivo, y si es 1, el número es negativo.
La forma más sencilla de representación que emplea un bit de signo es la denominada
representación signo-magnitud. En una palabra de n bits, los n − 1 bits de la derecha
representan la magnitud del entero.
Rango:
− 2n−1 − 1 ≤ N ≤ 2n−1 − 1
 

Ejemplo Si se dispone de n = 8 bits


18 se representa por 00010010
18 = 9×2+0
9 = 4×2+1
4 = 2×2+0
2 = 1×2+0
y
00010100
−18 se representa por 10010010 (signo-magnitud)
Ejemplo Si se dispone de n = 4 bits
−7 se representa por 1111
7 se representa por 0111
La cadena 0011 representa al 3
La cadena 1101 representa a −5
La cadena 0000 representa a 0
La cadena 1000 representa a −0.
La representación signo y magnitud tiene varias limitaciones. Una es que la suma y la
resta requieren tener en cuenta tanto los signos de los números como sus magnitudes
relativas para hacer la operación en cuestión. Otra es la que hemos visto antes: la doble
representación para el cero.
• Representación en Complemento a uno
Tiene un bit de signo, y se usa 0 para el signo positivo y 1 para el signo negativo. Es
decir, si se dispone de n bits, si N ≥ 0, se le representa como binario con un cero en el
primer bit de la izquierda; si N ≤ 0, se le representa como complemento a uno (se cambia
1 por 0 y 0 por 1) de la representación del valor absoluto de N . Esta representación es
obsoleta.
Rango
− 2n−1 − 1 ≤ N ≤ 2n−1 − 1
 

Ejemplo Si se dispone de n = 4 bits


−7 se representa por 0111
7 se representa por 1000
La cadena 0100 representa a 4
La cadena 1010 representa a −5
La cadena 0000 representa al 0.
La cadena 1111 represeta al −0.

15
• Representación en Complemento a dos
Al igual que la de signo y magnitud, la representación en complemento a dos utiliza el bit
más significativo como bit de signo, facilitando la comprobación de si el entero es positivo
o negativo. Difiere de la representación signo-magnitud en la manera de interpretar los
bits restantes. La negación de un número es un proceso de dos pasos. Primero, cada 1
se sustituye por un 0 y cada 0 por un 1, igual que en el complemento a uno. Luego se
suma 1 al resultado. La suma binaria es igual a la suma decimal, excepto que se genera
un acarreo si la suma es mayor que 1, no si la suma es mayor que 9. Por ejemplo, la
conversión de 6 a complemento a dos se efectúa en dos pasos

00000110 (+6)
11111001 (−6 en complemento a uno)
11111010 (−6 en complemento a dos)

Si hay un acarreo hacia la izquierda del bit de la extrema izquierda, se desecha.


Es decir, si de dispone de n bits y si
i. N ≥ 0, se le representa como binario con un cero en el primer bit de la izquierda
ii. N ≤ 0, se le representa como el complemento a dos (se cambia 1 por 0 y 0 por 1 y
se suma 1) de la representación del valor absoluto de N .
iii. N = −2n−1 , se le representa por 10 . . . 0 (que el del complemento a dos de 2n−1 )
Rango
− 2n−1 ≤ N ≤ 2n−1 − 1
 

Ejemplo Si se dispone de n = 4 bits


7 se representa por 0111
−7 se representa por 1001

1000
+1
1001

−8 se representa por 1000

1000
0111
+1
1000

La cadena 0100 representa el 4


La cadena 1110 representa al −2
La cadena 0000 representa al 0.
• Representación por exceso
Si se dispone de n bits, se representa el número N como la representación binaria de
N + 2n−1 .
Rango
− 2n−1 ≤ N ≤ 2n−1 − 1
 

Ejemplo Si se dispone de n = 4 bits


7 se representa por 1111
−8 se representa por 0000
0 se representa por 1000
La cadena 1101 representa a 5
La cadena 0101 representa a −3

16
En la tabla siguiente se dan, para n = 8 bits, una representación de algunos enteros

N(decimal) N(binario) N(sig-mag) N(comp 1) N(comp 2 N(Exceso)


1 00000001 10000001 11111110 11111111 01111111
2 00000010 10000010 11111101 11111110 01111110
3 00000011 10000011 11111100 11111101 01111101
4 00000100 10000100 11111011 11111100 01111100
5 00000101 10000101 11111010 11111011 01111011
6 00000110 10000110 11111011 11111010 01111010
7 00000111 10000111 11111000 11111001 01111001
8 00001000 10001000 11110111 11111000 01111000
9 00001001 10001001 11110110 11110111 01110111
10 00001010 10001010 11110101 11110110 01110110

(b) Reales
Los reales se pueden representar en
i. Punto fijo.
ii. Notación Cientı́fica Decimal.
iii. Notación Cientı́fica Binaria.
iv. Notación Cientı́fica Binaria con mantisa normalizada.
1) Punto fijo
Se trabaja con un número fijo de decimales. Se utliza el primer bit de la izquierda para
representar el signo (cero para + y uno para -).
Se tiene un número fijo de bits para representar la parte entera y un número fijo de bits
para representar la parte decimal como enteros sin signo.
Ejemplo Se dispone de n = 32 bits, asignando 1 bit para el signo, 21 bits para la parte
entera y 10 bits para la parte decimal.
Como se dispone de 10 bits para representar la parte decimal y como 210 = 1024, entonces
se puede representar 3 decimales.
El 38.325 se representa por

0 000000000000000100110 0101000101

pues 38 = 1001102 y 325 = 1010001012 .


El −38.2 se representa por

1 000000000000000100110 0101000000

pues 38 = 1001102 y 320 = 1010000002 .


El 38.300 se representa por

0 000000000000000100110 0100101100

pues 38 = 1001102 y 300 = 1001011002 .


2) Notación Cientı́fica Decimal.
Se expresa el valor absoluto del número en notación cientı́fica decimal, es decir, de la
forma
f × 10k
donde f se llama la mantisa, f ∈ [0,1, 1[ y el exponente k ∈ Z.
Se usa el primer bit de la izquierda para representar el signo (cero para + y uno para -).
Se tiene un número fijo de bits para representar el exponente en exceso y un número fijo
de bits para representar la mantisa como entero sin signo. Ası́, el −3.25 se representa
por
1 1000001 000000000000000101000101
pues 3.25 = 0.325 × 101 , 325 = 1010001012 y el 1 se representa por 1000001.

17
3) Notación Cientı́fica Binaria
Se expresa el número en notación cientı́fica binaria.
Se usa el primer bit de la izquierda para representar el signo (cero para + y uno para -).
Se tiene un número fijo de bits para representar el exponente en exceso y un número fijo
de bits para la mantisa.
Ejemplo Si se dispone de n = 32 bits, asignamos 1 bit para el signo, 7 bits para el
exponente y 24 bits para la mantisa.
Ası́, el −419.8125 se representa por

1 1001001 110100011110100000000000

pues 419.8125 = 110100011 · 11012 = 0.1101000111101 × 29 y el 9 se representa en exceso


por 1001001.
4) Notación Cientı́fica Binaria con mantisa normalizada
En notación cientı́fica binaria con mantisa normalizada se representa la mantisa sin el
primer bit de la izquierda, pues este bit es siempre igual a uno.
Ejemplo Si se dispone de n = 32 bits, asignamos 1 bit para el signo, 7 bits para el
exponente y 24 bits para la mantisa normalizada.
Ası́, el −419.8125 se representa por

1 1001001 101000111101000000000000

pues 419.8125 = 0.1101000111101 × 29 .

2) Alfanuméricos
Los caracteres alfanuméricos pueden ser dı́gitos, letras o caracteres especiales como los signos de
puntuación, de agrupamientos, matemáticos, gráficos, o de control.
Los caracteres son representados por cadenas binarias iguales al código asociado a cada caracter.
Las tablas más usuales son la ASCII y la tabla EBCDIC. ASCII es el Código Estándard Americano
para Intercambio de Información. Cada caracter ASCII tiene 7 bits, lo que permite representar
un total de 128 caracteres.
Hoy también existe un nuevo sistema llamado UNICODE, actualmente varios lenguajes de programación(como
Java), algunos sistemas operativos (como windows NT) y muchas aplicaciones reconocen UNICODE.
La idea en la que se basa UNICODE es asignar a cada caracter y sı́mbolo un valor único y
permanente de 16 bits, llamado punto de código. No se usan caracteres de múltiples bytes ni
sucesiones de escape. Al hacer que cada sı́mbolo tenga 16 bits la escritura de software se simplifica
mucho.
Con sı́mbolos de 16 bits, UNICODE tiene 65,356 puntos de código. Ya que los idiomas del mundo
emplean colectivamente unos 200,000 sı́mbolos, los puntos de código son un recurso escaso que
debe asignarse con mucho cuidado. Existe todo un trabajo centrado en los puntos de código que
faciliten la conversión entre ASCII y UNICODE.

18

También podría gustarte