Tema2 PDF
Tema2 PDF
Tema2 PDF
REPRESENTACIÓN DE LA
INFORMACIÓN
Fundamentos de Informática
Departamento de Ingeniería de Sistemas y Automática. EII.
Universidad de Valladolid
Índice
1. Introducción
2. Sistemas de numeración
3. Representación binaria de números enteros
4. Aritmética binaria de enteros
5. Representación binaria de números reales
6. Desbordamiento de la representación
7. Representación de caracteres
8. Conversión entre tipos de datos
Temas de ampliación
1. Representación binaria de números reales.
Procedimiento de cálculo general
Casos especiales
Rangos
Introducción
La información es un conjunto de datos, cuyo significado
depende del contexto. Su propósito puede ser el de reducir la
incertidumbre o incrementar el conocimiento acerca de algo.
4
Introducción
¿Cómo almacena el ordenador la información?
Un bit sólo distingue entre dos
posibilidades:
carga/no carga
• La memoria del convención: 1 / 0
ordenador es una tabla
de n octetos o bytes.
Cada byte está
compuesto de 8 bits.
• El bit es la unidad de
información.
Esta es la solución más
robusta y eficiente.
5
Introducción
¿Cómo almacena el ordenador la información?
6
Introducción
¿Cómo suministramos la información?
Cuando introducimos datos vía teclado
trabajamos con caracteres:
dígitos, letras, signos de puntuación, etc.,
pero el ordenador trabaja con 0’s y 1’s.
¡Tendremos que codificar la información!
Codificación
7
Introducción
La codificación de la información
La codificación es una transformación que representa los
elementos de un conjunto mediante los de otro, de tal forma
que a cada elemento del primer conjunto le corresponda un
elemento distinto del segundo.
• Ejemplo:
- Código postal
- NIA
- DNI
8
Introducción
La codificación de la información
La existencia de dos conjuntos diferentes de caracteres, uno
externo para el usuario y otro interno para el ordenador, hace
necesario codificar los caracteres de un conjunto con los del otro.
Son los llamados códigos de E/S (por ejemplo el código ACSII).
9
Introducción
La codificación de la información
Un aspecto fundamental en la codificación es el número de valores
diferentes que podemos codificar a partir de una cantidad fija de 𝒏 bits.
¿Cuántos 𝒎 valores diferentes con 𝒏 bits? 𝒎 = 2𝒏
Ejemplo: Con 𝟏𝟎 bits podemos representar 𝟏𝟎𝟐𝟒 = 2𝟏𝟎 valores diferentes
10
Sistemas de numeración
Un sistema de numeración es una colección de símbolos
utilizado para representar cantidades, junto al conjunto de
reglas que permiten construir números válidos.
Sistemas de numeración posicional
El número de símbolos (cifras) permitidos en un sistema de
numeración posicional se conoce como base del sistema de
numeración.
Por ejemplo, en el sistema decimal la base es b=10.
El conjunto de 10 símbolos es: {0,1,2,3,4,5,6,7,8,9}
Un número se expresará mediante una secuencia de cifras,
contribuyendo cada una de ellas con un valor dependiente de:
• El valor que representa esa cifra
• La posición que ocupe dentro del número
El sistema de numeración romano es un ejemplo de sistema de
numeración no posicional.
11
Sistemas de numeración
Para construir un número 𝑁 en la base 𝑏 con:
𝑛 cifras enteras
𝑘 cifras fraccionarias
puede usarse con carácter general la siguiente fórmula:
𝑛−1
𝑑𝑛−1 … 𝑑1 𝑑0 . 𝑑−1 … 𝑑−𝑘 = 𝑑𝑖 𝑏 𝑖
𝑁= 𝑖=−𝑘
𝑁 = 𝑑𝑛−1 𝑏 𝑛−1 + ⋯ + 𝑑1 𝑏 + 𝑑0 + 𝑑−1 𝑏 −1 + … + 𝑑−𝑘 𝑏 −𝑘
14
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b
Se transforma por separado la parte entera y la parte fraccionaria del
número:
• Parte entera: divisiones sucesivas entre b.
• Parte fraccionaria: productos sucesivos por b.
15
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b: parte entera
Haremos divisiones sucesivas del número 𝑵 por la base 𝒃 hasta alcanzar
un cociente 𝑪𝒏−𝟏 que sea menor que la base 𝒃.
𝑵 𝒃
𝒓𝟎 𝑪𝟏 𝒃
𝒓𝟏 𝑪𝟐
⋱
⋱
𝑪𝒏−𝟐 𝒃
𝒓𝒏−𝟐 𝑪𝒏−𝟏
16
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b : parte entera
𝑵 𝒃
𝒓𝟎 𝑪𝟏 𝒃
𝒓𝟏 𝑪𝟐
⋱
⋱
𝑪𝒏−𝟐 𝒃
𝒓𝒏−𝟐 𝑪𝒏−𝟏
𝑵 𝒃 𝑪𝟏 𝒃
→ 𝑵 = 𝒃 ∙ 𝑪𝟏 +𝒓𝟎 → 𝑪𝟏 = 𝒃 ∙ 𝑪𝟐 +𝒓𝟏
𝒓𝟎 𝑪𝟏 𝒓𝟏 𝑪𝟐
Sustituyendo 𝐂𝟏 en la 1ª ecuación:
𝑵 = 𝒃 ∙ (𝒃 ∙ 𝑪𝟐 +𝒓𝟏 )+𝒓𝟎 = 𝒃𝟐 ∙ 𝑪𝟐 + 𝒃 ∙ 𝒓𝟏 +𝒓𝟎
17
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b : parte entera
𝑵 𝒃
𝒓𝟎 𝑪𝟏 𝒃
𝒓𝟏 𝑪𝟐
⋱
⋱
𝑪𝒏−𝟐 𝒃
𝒓𝒏−𝟐 𝑪𝒏−𝟏
𝑵 𝒃 𝑪𝒊−𝟏 𝒃
→ 𝑵 = 𝒃 ∙ 𝑪𝟏 +𝒓𝟎 → 𝑪𝒊−𝟏 = 𝒃 ∙ 𝑪𝒊+𝒓𝒊−𝟏
𝒓𝟎 𝑪𝟏 𝒓𝒊−𝟏 𝑪𝒊
𝟑𝟓 𝟐
𝟏 𝟏𝟕 𝟐
𝟏 𝟖 𝟐
𝟎 𝟒 𝟐
𝟎 𝟐 𝟐
𝟎 𝟏
𝟑𝟓𝟏𝟎 = 𝟏𝟎𝟎𝟎𝟏𝟏𝟐
20
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b: parte entera
𝟑𝟓 𝟖
𝟑 𝟒
𝟑𝟓𝟏𝟎 = 𝟒𝟑𝟖
21
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a un sistema en base b: parte entera
4𝟓 𝟏𝟔
𝟏𝟑 𝟐
𝟒𝟓𝟏𝟎 = 𝟐𝐃𝟏𝟔
22
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a base b: parte fraccionaria
La parte fraccionaria de un número es aquella que representa una
cantidad inferior a la de la unidad.
Un número fraccionario 𝑁𝑏 en base b será:
𝑁𝑏 =. 𝑎−1 𝑎−2 … 𝑎−𝑗+1 𝑎−𝑗
Por tanto, la parte fraccionaria 𝑁10 en base 10 será:
𝑁10 = 𝑎−1 𝑏−1 + 𝑎−2 𝑏−2 + ⋯ + 𝑎−𝑗+1 𝑏−𝑗+1 𝑎−𝑗 𝑏−𝑗
23
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión desde decimal a base b: parte fraccionaria
Veamos que mediante multiplicaciones sucesivas por el valor de la
base 𝑏, podemos obtener esos coeficientes:
𝑏 ∙ 𝑁10 = 𝑏 ∙ 𝑎−1 𝑏−1 + 𝑎−2 𝑏−2 + ⋯ + 𝑎−𝑗+1 𝑏−𝑗+1 𝑎−𝑗 𝑏−𝑗
= 𝒂−𝟏 + 𝑎−2 𝑏 −1 + ⋯ + 𝑎−𝑗+1 𝑏−𝑗+2 𝑎−𝑗 𝑏−𝑗+1 = 𝒂−𝟏 . 𝑥−1 𝑥−2 …
Por tanto, en la primera multiplicación obtenemos un número cuya parte
entera es precisamente el primer coeficiente buscado.
¿Cómo obtener el 2º coeficiente? Quedándonos con la parte fraccionaria
del valor obtenido en la etapa anterior y volviendo a multiplicar por 𝑏.
𝒂−𝟏 . 𝑥−1 𝑥−2 … − 𝒂−𝟏 = 𝑏 ∙ 𝑁10 − 𝒂−𝟏 = 𝑎−2 𝑏 −1 + ⋯ + 𝑎−𝑗+1 𝑏 −𝑗+2 𝑎−𝑗 𝑏 −𝑗+1
En base 8 (octal) 0 5 6 4 . 6 5
2
3
4
0010
0011
0100
5 0101
000101110100,110101 00 6
7
0110
0111
8 1000
9 1001
A 1010
En base 16 (hexadecimal) 1 7 4 . D 4 B
C
1011
1100
D 1101
E 1110
F 1111 27
Sistemas de numeración
Conversión entre sistemas de numeración
Conversión entre binario, octal y hexadecimal
30
Representación binaria de números enteros
Enteros: representación signo magnitud
Esta representación es muy poco utilizada en computación para enteros
(se estudia por motivos pedagógicos). Tiene 2 problemas:
• el 0 tiene 2 codificaciones
32
Representación binaria de números enteros
Enteros: representación en complemento a 2
El complemento a la base 𝒃 de un número positivo 𝑿 codificado con
𝒏 posiciones es:
ComplementoBase 𝑿 = 𝒃𝒏 − 𝑿
En binario, 𝒃 = 𝟐, de ahí complemento a 2. Es una representación muy
extendida para trabajar con enteros negativos y es la que usa C++:
• El valor 0 y los positivos se representan como en signo magnitud.
• Los negativos se representan con el complemento a 2 del valor absoluto
Decimal
Representación binario complemento a 2 para n=4 bits
con signo
Signo Bit 2 Bit 1 Bit 0 Cálculo polinomio equivalente 𝒃𝒏 − 𝑿
-8 1 0 0 0 −𝟏 ∙ 23 + 0 ∙ 22 +0 ∙ 21 +0 ∙ 20 24 − 8 = 8
-7 1 0 0 1 −𝟏 ∙ 23 + 0 ∙ 22 +0 ∙ 21 +1 ∙ 20 24 − 7 = 9
… … … … … … … … …
3 2 1 0
-1 1 1 1 1 −𝟏 ∙ 2 + 1 ∙ 2 +1 ∙ 2 +1 ∙ 2 24 − 1 = 15
0 0 0 0 0 +𝟎 ∙ 23 + 0 ∙ 22 +0 ∙ 21 +0 ∙ 20
+1 0 0 0 1 +𝟎 ∙ 23 + 0 ∙ 22 +0 ∙ 21 +1 ∙ 20
… … … … … … … … …
3 2 1 0
+6 0 1 1 0 +𝟎 ∙ 2 + 1 ∙ 2 +1 ∙ 2 +0 ∙ 2
+7 0 1 1 1 +𝟎 ∙ 23 + 1 ∙ 22 +1 ∙ 21 +1 ∙ 20 34
Representación binaria de números enteros
Enteros: representación en complemento a 2
Existe una regla muy fácil (que los circuitos electrónicos aprovechan) para
obtener el complemento a 2 de un número binario positivo:
1. Nos desplazamos de derecha a izquierda bit a bit hasta encontrar el
primer 1. Lo dejamos inalterado.
2. A partir de este 1, cambiamos 0’s por 1’s y 1’s por 0’s.
36
Representación binaria de números enteros
Enteros: representación en complemento a 2
Ejemplos
Representar -1310 en binario complemento a 2 con 10 bits
Método 1
Obtenemos 1310 con 10 bits: 1310 =810+410+110=00000011012
De derecha a izquierda buscamos el primer 1: 00000011012
A partir del primer 1, cambiamos 0’s por 1’s y 1’s por 0’s: 11111100112
Método 2
Por definición, ComplementoBase 𝑿 = 𝒃𝒏 − 𝑿 = 210-13=1024-13=1011
Obtenemos 101110 con 10 bits:
101110=51210+25610+12810+6410+3210+1610+210+110=11111100112
37
Representación binaria de números enteros
Enteros: representación en C++
La representación interna, aunque similar, va a depender de cada
lenguaje de programación, compilador y arquitectura del
ordenador.
El lenguaje C++ permite trabajar con enteros almacenados en
memoria ocupando 1(8), 2(16), 4(32) y 8(64) bytes(bits).
Como hemos visto, el número 𝒏 de bits determina el número de
posibles valores representables.
C++ permite trabajar utilizando valores con signo y sin signo.
Java no contempla el uso de enteros sin signo. Python o Lisp
permiten trabajar con enteros con un número ilimitado de bits.
En este curso nos limitaremos a usar siempre int para referirnos a valores enteros.
Un tipo de dato que nos será útil más adelante es size_t. Este tipo de dato es un
entero sin signo que nos garantiza almacenar el máximo valor posible en ese
dispositivo. 42
Aritmética binaria de enteros
El álgebra de Boole
George Boole (1815 – 1864) observó que, codificando los
valores lógicos VERDAD y FALSO con los valores binarios 1 y 0,
podía formularse un álgebra que capturaba los principios básicos
del razonamiento lógico.
Claude Shannon (1916 – 2001), padre de la Teoría de la
Información, mostró en su tesis doctoral en 1937 que el álgebra
de Boole podía aplicarse al análisis y diseño de relés
electromecánicos, es decir, sistemas digitales.
43
Aritmética binaria de enteros
El álgebra de Boole
Las operaciones básicas del álgebra de Boole pueden representarse con tablas
de verdad.
~ NOT & AND | OR ^ XOR
0 1 0 0 0 0 0 0 0 0 0
1 0 0 1 0 0 1 1 0 1 1
1 0 0 1 0 1 1 0 1
1 1 1 1 1 1 1 1 0
Una tabla de verdad despliega el valor de verdad de una proposición para cada
combinación de valores de verdad que se pueda asignar a sus componentes.
Por ejemplo:
Dadas dos proposiciones P y Q,
la proposición compuesta P AND Q es cierta si P es cierta y Q es cierta.
la proposición compuesta P OR Q es cierta si P es cierta o Q es cierta.
A nivel de bits, dados dos bits 𝑝 y 𝑞,
𝑝&𝑞 = 1 si 𝑝 = 1 y 𝑞 = 1
𝑝|𝑞 = 1 si 𝑝 = 1 o 𝑞 = 1
Las 4 operaciones básicas del álgebra de Boole pueden aplicarse también a
secuencias de bits
1 0 1 0 1 0 1 0 1 0 1 0
& 1 1 0 0 | 1 1 0 0 ^ 1 1 0 0 ~ 1 1 0 0
1 0 0 0 1 1 1 0 0 1 1 0 0 0 1 1 44
Aritmética binaria de enteros
El álgebra de Boole
C++ posee los operadores a nivel de bits &, |, ^ y ~.
Ejemplo: si ejecutamos el siguiente programa
#include <iostream>
using namespace std;
int main()
{
int x=10;
cout <<"x="<<x<<endl;
x=~x; // Aplicamos el operador negación NOT
cout <<"~x="<<x<<endl;
}
vemos que la salida por consola es:
La representación de 1010 es 00000000 00000000 00000000 00001010
Por tanto, ~1010 es 11111111 11111111 11111111 11110101
48
Aritmética binaria de enteros
La suma binaria
El sumador completo binario podemos describirlo con una tabla de
verdad con tres bits de entrada, 𝑝, 𝑞 y 𝐶𝑒 y dos bits de salida 𝑆 y 𝐶𝑠 .
𝐶𝑒 es el valor de acarreo procedente de la suma de los bits anteriores y
𝐶𝑠 es el acarreo que se inyecta a la siguiente suma de bits.
SUMADOR COMPLETO
𝒑 𝒒 BINARIO
𝒑 𝒒 𝑪𝒆 𝑺 𝑪𝒔
0 0 0 0 0
0 0 1 1 0
Sumador 0 1 0 1 0
𝑪𝒔 𝑪𝒆 0 1 1 0 1
completo
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
𝑺
49
Aritmética binaria de enteros
La suma binaria
Supongamos que necesitamos sumar dos números binarios 𝒙 e 𝒚 de 4
bits. Bastaría disponer de 4 sumadores completos colocados en serie
para realizar la operación en paralelo.
𝒙𝟑 𝒚𝟑 𝒙𝟐 𝒚𝟐 𝒙𝟏 𝒚𝟏 𝒙𝟎 𝒚𝟎
𝑺𝟑 𝑺𝟐 𝑺𝟏 𝑺𝟎
Coma fija
Se asigna una cantidad fija de dígitos para la parte entera y una cantidad
fija para la parte fraccionaria.
Ejemplo: Obviando por el momento el signo, si disponemos de 8 bits y
reservamos 5 bits para la parte fija y 3 para la fraccionaria, el número 21.7510
sería 10101.110
54
Representación binaria de números reales
Coma flotante
Un número real 𝑟 en coma flotante se representa según la notación
científica:
𝑟 = 𝑚 ∙ 𝑏𝑒
donde:
• 𝑚 es la mantisa, un coeficiente formado por un número real con una
sola cifra entera seguido por una coma (o punto) y de varias cifras
fraccionarias.
• 𝑏 es la base del sistema de numeración (10 en el caso decimal y 2 en
el binario).
• 𝑒 es el exponente al que se eleva la base.
55
Representación binaria de números reales
Coma flotante: norma IEEE 754
Hasta la década de los 80, cada fabricante de chips usaba su propia
representación, lo que dificultaba el desarrollo de algoritmos eficientes
de cálculo, procesadores estándar, etc.
Por ello, la asociación IEEE desarrolló el estándar IEEE 754, que
contempla, entre otros, dos posibles formatos:
nc bits
1 bit de nm bits
exponente
signo mantisa
(característica)
58
Representación binaria de números reales
Coma flotante: norma IEEE 754
Representación de los exponentes: la característica
En el caso de la representación del exponente nos encontramos con el
hecho de que éste puede ser positivo (3.45 ∙ 10𝟑 ) o negativo (2.7 ∙ 10−𝟔 )
y, por tanto, además de un bit de signo para determinar si el número es
positivo o negativo, necesitamos un segundo bit de signo para el
exponente.
Este segundo bit de signo es un grave inconveniente pues su uso
invalidaría el poder comparar de forma sencilla dos valores reales entre
sí. Afortunadamente, podemos ahorrarnos ese segundo bit de signo para
el exponente usando una representación en exceso.
59
Representación binaria de números reales
Coma flotante: norma IEEE 754
Representación de los exponentes: la característica
La representación en exceso 𝒌 de un número 𝑥 es tan simple como
sumar al número un número positivo 𝑘, 𝑥𝑒𝑛_𝑒𝑥𝑐𝑒𝑠𝑜 = 𝑥 + 𝑘.
La norma IEEE 754 define el rango de valores para los exponentes de la
siguiente forma:
60
Representación binaria de números reales
Coma flotante: norma IEEE 754
Representación de los exponentes: la característica
La representación en exceso tiene la importante propiedad de que dos
números representados en exceso conservan sus propiedades de orden
(las tareas de ordenación son muy habituales en los algoritmos).
𝑥𝑒𝑛_𝑒𝑥𝑐𝑒𝑠𝑜 ≤ 𝑦𝑒𝑛_𝑒𝑥𝑐𝑒𝑠𝑜 ⟺ 𝑥 ≤ 𝑦
61
Representación binaria de números reales
Coma flotante: norma IEEE 754
Representación de la mantisa
Se utiliza la notación científica, normalizando del modo 1. 𝑚: el primer
uno (bit más significativo) del número se sitúa a la izquierda de la coma.
Uno de los retos que debe lograrse para representar los números reales
es conseguir poder representar el mayor rango de ellos y con la mejor
precisión posible. Una posibilidad es la de ahorrarnos bits superfluos:
Puesto que siempre tendremos un único 1 a la izquierda del punto
fraccionario, no hace falta representarlo (uno implícito).
62
Representación binaria de números reales
Coma flotante: norma IEEE 754
Ejemplo: representar 13.125|10 en simple precisión
1) Transformamos a binario la parte entera y la parte fraccionaria
13.125|10 = 1101.001|2
2) Determinamos el signo
El número es positivo, luego el bit de signo es 0.
3) Representamos el número según la notación científica
1101.001 = 1.101001 ∙ 23
4) Identificamos la mantisa (desechamos el 1 implícito) y el exponente
𝟏. 𝟏𝟎𝟏𝟎𝟎𝟏 ∙ 2𝟑
5) Rellenamos la mantisa de 0’s por la derecha hasta completar los 23 bits que
marca la norma
𝟏𝟎𝟏𝟎𝟎𝟏𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎
6) Añadimos el exceso 𝟏𝟐𝟕 al exponente y lo representamos en binario
con 8 bits
(𝟑 + 𝟏𝟐𝟕)10 = 13010 = (128 + 2)10 = (27 +21 )10 = 𝟏𝟎𝟎𝟎𝟎𝟎𝟏𝟎𝟐
7) Formamos el número
𝟎𝟏𝟎𝟎𝟎𝟎𝟎𝟏𝟎𝟏𝟎𝟏𝟎𝟎𝟏𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎𝟎
8 bits exponente 23 bits mantisa
63
Representación binaria de números reales
Coma flotante: norma IEEE 754
Ejemplo: A partir del valor 01000010111011010000000000000000
obtener su valor decimal.
1) Agrupamos los 1+8+23 bits para identificar signo, exponente y mantisa
0 10000101 11011010000000000000000
2) Determinamos el signo
El número es positivo, pues el bit de signo es 0.
3) Calculamos el exponente
𝟏𝟎𝟎𝟎𝟎𝟏𝟎𝟏 = 27 + 22 + 20 = 133
Eliminando el exceso, 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡𝑒 = 133 − 127 = 𝟔
4) Calculamos la mantisa añadiendo el bit implícito y desechando 0’s superfluos
11011010000000000000000 1.1101101
5) Formamos el número en notación científica 𝑚 ∙ 2𝑒
1.1101101 ∙ 𝟐𝟔
6) Por comodidad de cálculo, eliminamos el término 𝟐𝒆 desplazando la coma 𝒆
posiciones (a la derecha si el signo es positivo y a la izquierda si es negativo)
1.1101101 ∙ 𝟐𝟔 = 𝟏𝟏𝟏𝟎𝟏𝟏𝟎. 𝟏
7) Transformamos a base 10
𝟏𝟏𝟏𝟎𝟏𝟏𝟎. 𝟏𝟐 = (𝟐𝟔 + 𝟐𝟓 + 𝟐𝟒 + 𝟐𝟐 + 𝟐𝟏 + 𝟐−𝟏 )𝟏𝟎 = 𝟏𝟏𝟖. 𝟓𝟏𝟎
64
Representación binaria de números reales
Coma flotante: norma IEEE 754
Número de bits de la mantisa
La influencia de disponer de un bit a mayores en la mantisa supone que la
distancia entre 2 números consecutivos representables se divide por 2.
Según esto el término “doble precisión” no es riguroso. La precisión que
ofrece es mucho mayor.
Distribución en la recta real
Los números no están uniformemente distribuidos sobre la recta real, sino que
están más próximos cerca del origen (exponentes más pequeños) y más
separados a medida que nos alejamos de él (exponentes más grandes).
http://jasss.soc.surrey.ac.uk/9/4/4.html
65
Representación binaria de números reales
Coma flotante: norma IEEE 754
Precisión
Veamos qué pasa representando el valor 0.1|10 en simple precisión.
1) Transformamos a binario la parte entera y la parte fraccionaria
0.1|10 = 0.0001100110011…|2 Es 1 el último bit en lugar
2) Determinamos el signo de 0 por que se redondea al
valor más próximo
El número es positivo, luego el bit de signo es 0.
3) Representamos el número según la notación científica
0.000110011 … = 1.100110011 … ∙ 2−4
4) Identificamos la mantisa (desechamos el 1 implícito) y el exponente
𝟏. 𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟏 ∙ 2−𝟒
5) Añadimos el exceso 𝟏𝟐𝟕 al exponente y lo representamos en binario
con 8 bits
(−𝟒 + 𝟏𝟐𝟕)10 = 12310 = (64 + 32 + 16 + 8 + 2 + 1)10 = 𝟎𝟏𝟏𝟏𝟏𝟎𝟏𝟏𝟐
7) Formamos el número
𝟎𝟎𝟏𝟏𝟏𝟏𝟎𝟏𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟎𝟏𝟏𝟎𝟏
Resumiendo:
• Para sumas y restas tenemos que ajustar al mismo valor los exponentes de los
operandos. Esto los programas software o los circuitos electrónicos lo hacen
fácilmente pues:
• multiplicar por 2 (sumar 1 a uno de los exponentes) es desplazar un bit a la
izquierda
• dividir por 2 (restar 1 a uno de los exponentes) desplazar un bit a la derecha.
• Una vez hecho esto, podemos sumar o restar las mantisas en aritmética de
enteros y normalizar el resultado final si es necesario.
68
Representación binaria de números reales
Reales: representación en C++
En C++ una declaración como
float x;
reservará espacio en memoria para la variable real x usando la norma IEEE 754
simple precisión y, por tanto, usando 4 bytes.
La declaración
double x;
reservará espacio en memoria para la variable real x usando la norma IEEE 754
doble precisión y, por tanto, usando 8 bytes.
Como hemos comentado, C++ permite diferentes tamaños de almacenamiento
para los tipos de datos fundamentales, pero 4 y 8 bytes respectivamente es lo
habitual.
Se recomienda usar siempre double cuando declaremos variables reales en
nuestros programas:
• A pesar de usar doble capacidad de almacenamiento, hoy en día gran parte del
hardware hace las operaciones más rápidas en precisión doble.
• Como ingenieros, necesitaremos programar algoritmos en los que la precisión
puede ser fundamental. 69
Representación binaria de números reales
Reales: representación en C++
Precisión
Supongamos que en un programa C++ tenemos 3 variables en coma flotante
como en el siguiente ejemplo:
double x=0.5;
double y=0.1;
double z=0.4;
La representación del valor 0.5 es exacta, pero la de 0.1 y 0.4 no. Como
consecuencia de esto, x es distinto de y+z, y, por tanto x-(y+z) es distinto de 0.
70
Desbordamiento de la representación
Se produce un desbordamiento (overflow) cuando tras operar entre dos
números, el resultado sale del rango de representación.
Supongamos que disponemos de 4 bits para representar enteros en
complemento a 2. Sumemos 610 y 510.
1 Acarreo
0110 610
0101 510
1011 -510
71
Desbordamiento de la representación
En C++ debemos vigilar el desbordamiento, ya sea al operar entre variables o al
introducir los datos. Se muestra un ejemplo con enteros.
#include <iostream>
using namespace std;
int main()
{
int x=2147483647; //Limite superior para 4 bytes
int y=1;
cout<<x+y<<endl; //Suma es el límite inferior del rango
x=4294967296;
cout<<x<<endl; //El valor almacenado es 0
//Si introducimos un valor fuera de rango, C++ lo trunca
//al valor superior o inferior del rango
cout <<"Introduzca un valor superior o inferior al rango:";
cin>>x;
cout<<x<<endl;
}
Salida:
72
Desbordamiento de la representación
En el caso de números reales, si hay desbordamiento, C++ nos mostrará por
pantalla la salida inf.
#include <iostream>
using namespace std;
int main()
{
cout<<endl;
float x=2e38; //Cerca del limite superior para 4 bytes
//Producto superior al límite superior del rango
cout<<2*x<<endl;
//Si introducimos un valor fuera de rango, C++ lo trunca
//al valor superior o inferior del rango
cout<<"Introduzca un valor superior o inferior al rango:";
cin>>x;
cout<<x<<endl;
}
Salida:
73
Representación de caracteres
La representación de caracteres se basa en asociar un código entero a
cada carácter.
Aunque hay diferentes codificaciones propuestas, las más importantes
son la codificación ASCII y la UNICODE. Ambas son estándares.
La codificación ASCII permite codificar 256 caracteres, por lo que
necesita 1 byte (8 bits) para lograrlo.
La codificación UNICODE permite codificar 65536 caracteres, para lo que
emplea 2 bytes (16 bits). UNICODE facilita la transmisión y visualización
de textos de múltiples lenguajes (incluso lenguas muertas) y en
diferentes disciplinas técnicas. El término Unicode refleja sus objetivos de
universalidad, eficiencia y unicidad.
74
Representación de caracteres
Código ASCII (American Standard Code for Information Interchange)
Inicialmente constaba de 128 caracteres. Luego fue extendido para incluir
caracteres con tildes y otros símbolos.
http://www.elcodigoascii.com.ar
75
Representación de caracteres
Código ASCII (American Standard Code for Information Interchange)
Nótese que los caracteres numéricos (0, 1, 2, … ,9) ocupan posiciones
consecutivas con códigos desde el 48 al 57. Esto facilita la conversión entre
caracteres y números enteros y viceversa, por ejemplo, en las operaciones de
entrada/salida.
Carácter 0 48 0011 0000 Número 0
Carácter 1 49 0011 0001 Número 1
Carácter 2 50 0011 0010 Número 2
…
Carácter 9 57 0011 1001 Número 9
Las mayúsculas y las minúsculas se diferencian únicamente en un bit:
internamente, los programas podrán pasar de minúsculas a mayúsculas y
viceversa de forma sencilla.
Carácter A 65 01000001 01100001 97 Carácter a
Carácter B 66 01000010 01100010 98 Carácter b
…
Carácter Z 90 01011010 01111010 122 Carácter z
El hecho de que las posiciones sean consecutivas permiten su ordenamiento
numérico o lexicográfico de forma sencilla.
76
Representación de caracteres
Caracteres: representación en C++
En C++ una declaración como
char c;
reservará espacio en memoria para la variable c, que será un carácter codificado
en ASCII, usando 1 byte para su almacenamiento.
Nótese la existencia de los caracteres no imprimibles, como el salto de línea, que
usaremos mucho en C++. Para lograr un salto de línea, C++ dispone de la
secuencia '\n'. Esto permite distinguir entre caracteres numéricos y valores
numéricos cuando formamos cadenas de caracteres (secuencia de caracteres
entre comillas dobles). Las estudiaremos más a fondo más adelante.
#include <iostream>
using namespace std;
int main() Salida:
{
char c=10; //Valor entero ASCII del retorno de línea
cout <<"Hola"<<c; //Forma correcta pero no se usa
cout <<"Hola\n"; //Forma preferida en C++
cout <<"Hola"<<endl; //Forma alternativa para el retorno de línea
cout <<"Hola10"; //Error: imprimiremos Hola10
}
77
Conversión entre tipos de datos
C++ es un lenguaje estáticamente tipado, lo que significa que los tipos
asignados a las variables se comprueban en tiempo de compilación.
Así, el compilador verifica que las operaciones que el programador ha escrito
en el código fuente están soportadas por el lenguaje. Si existe alguna
incompatibilidad, el compilador avisará con un mensaje de error.
Por ello, siempre deben declararse los tipos de las variables antes de
ser utilizadas.
No obstante, los lenguajes estáticamente tipados sí que permiten mezclar
tipos de datos en las expresiones a pesar de que sus representaciones
internas sean diferentes.
Para trabajar de forma cómoda con estas situaciones, los lenguajes
permiten que el programador adopte dos tipos de decisión:
• Conversión implícita: El compilador se encarga de forma automática
de adaptar las representaciones para poder efectuar los cálculos de
forma correcta.
• Conversión explícita: El programador escribe explícitamente en el
código fuente cómo quiere que se haga la conversión entre las
representaciones. 78
Conversión entre tipos de datos
Conversión implícita en C++
Asignaciones
En las asignaciones se evalúa la expresión a la derecha del operador de
asignación = y el resultado se convierte implícitamente al tipo de dato situado a la
izquierda del operador de asignación.
Cualquier asignación de un tipo de dato no booleano a bool(1) da un resultado
falso si el valor es 0. En caso contrario, el resultado de la asignación es cierto.
bool b=48.1; //b es cierto
En cualquier asignación de un tipo real a un tipo entero se trunca al entero
resultante de eliminar la parte fraccionaria.
int r=48.1; //r se almacenara como entero con valor 48
int s=-28.1; //r se almacenara como entero con valor -28
En cualquier asignación de un tipo entero a un tipo real éste se convertirá según
la norma IEEE 754. Puede conllevar la pérdida de precisión en números grandes
para los float, no así para los double, que tienen suficientes bits (una razón
más para usar siempre double).
float x=19999999; //x se almacenara como real 2.0e7
double y=19999999; //y se almacenara como real 19999999
(1) bool es un tipo de dato que almacena un valor cierto (true) o falso (false). 79
Conversión entre tipos de datos
Conversión implícita en C++
Operaciones
Cuando aparece una expresión con distintos tipos de datos mezclados, C++
promueve todos los tipos a un único tipo, el que tiene mas jerarquía de entre los
presentes. De esta forma, la operación (aritmética o lógica) se realiza según la
representación del tipo de mayor jerarquía.
Para los tipos de datos que vamos a manejar en la asignatura, la jerarquía de
menor a mayor en C++ es:
bool int
char int float double
int x=1;
double y=19999998;
//x+y es una expresión que se evalúa como double y se
//almacena en un registro interno. Al ejecutarse el
//programa, su valor será 19999999.
float w=x+y; //w se almacena con valor float 20000000
double z=x+y; //z se almacena con valor double 19999999
80
Conversión entre tipos de datos
Conversión explícita en C++
En ocasiones el programador necesita forzar la conversión.
Imaginemos un problema en el cual deseamos calcular la pendiente media de un
puerto de montaña. Para la longitud del puerto y para la altitud se han elegido
variables enteras que representan metros.
𝑎𝑙𝑡𝑖𝑡𝑢𝑑
La fórmula será: 𝑝𝑒𝑛𝑑𝑖𝑒𝑛𝑡𝑒 = 𝑙𝑜𝑛𝑔𝑖𝑡𝑢𝑑
Un programa ejemplo podría ser el siguiente:
#include <iostream>
using namespace std;
int main()
{
int longitud=18342;
int altitud=1123; //Respecto a la base del puerto
double pendiente=altitud/longitud;
#include <iostream>
using namespace std;
int main()
{
int longitud=18342;
int altitud=1123; //Respecto a la base del puerto
double pendiente=static_cast<double>(altitud)/longitud;
cout<<pendiente;
} Salida: 82
Conversión entre tipos de datos
Conversión explícita en C++
La conversión forzada de tipos static_cast<tipo_de_dato>(expresion)
convierte la representación interna de expresion a la representación marcada
por tipo_de_dato.
En nuestro ejemplo, forzamos a que la representación interna de la variable
altitud sea double. De esta forma, la expresión altitud/longitud se
convertirá implícitamente a double y obtendremos el resultado correcto.
Podréis encontrar código con conversiones forzadas tales como:
double pendiente=double(altitud)/longitud;
double pendiente=(double)altitud/longitud;//Estilo C
Aunque para el ejemplo que nos ocupa todas las opciones son válidas y
compilarán perfectamente, se recomienda usar static_cast.
Por otro lado, en la medida de lo posible, debemos evitar el uso de las
conversiones forzadas. En muchas ocasiones podemos evitar su uso. En el
ejemplo hubiese bastado con declarar:
double longitud=18342;
double altitud=1123;
83
Conversión entre tipos de datos
Las conversiones también conllevan graves riesgos. Un ejemplo clásico es el
ocurrido con el cohete Ariane, que se produjo por una conversión entre un
número en coma flotante de 64 bits (que era mayor de 32768) a un número
entero de 16 bits.
ariane 5 explosion.mp4
84
Temas de ampliación
Representación binaria de números reales
Coma flotante: norma IEEE 754
Procedimiento de cálculo general
Un número positivo 𝑥 podemos expresarle como:
𝑥 = 𝑚 ∙ 2𝑒
Tomando logaritmos en base 2 (valdría cualquier otra base):
log 2 𝑥 = log 2 (𝑚 ∙ 2𝑒 ) = log 2 𝑚 + e ∙ log 2 2 = log 2 𝑚 + 𝑒
Puesto que la mantisa normalizada es un valor positivo de la forma 1, …,
es decir, un número mayor o igual que 1 y menor que 2, log 2 𝑚 es un
valor mayor o igual que 0 y menor que 1, es decir, 0, …
Por tanto, si despreciamos log 2 𝑚, el exponente 𝑒 será siempre el entero
más próximo por defecto al valor obtenido en el cálculo de log 2 𝑥.
Ejemplo: Si log 2 𝑥=23.465, entonces 𝑒 = 23
Si log 2 𝑥=-23.465, entonces 𝑒 = −24
89
Representación binaria de números reales
Coma flotante: norma IEEE 754
Casos especiales: números desnormalizados simple precisión
Imaginemos que queremos representar en la norma IEEE 754 el número decimal
3 ∙ 2−130 |10 en simple precisión.
Siguiendo las pautas que hemos indicado para calcular el exponente
log 2 3 ∙ 2−130 = −128.415 …. e = −129
El exponente −129, esta fuera del rango [-127,128] que marca la norma.
Pero tenemos una alternativa:
• A un exponente con todo 0’s y mantisa no todos 0’s se le asigna el valor -126.
92