Archivo de la categoría: Programación

La programación es el proceso de diseñar, codificar, depurar y mantener el código fuente de programas

Sistema Hexadecimal

Sistema Hexadecimal

El sistema hexadecimal tiene base 16 y se representa por el conjunto {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}

Muchos valores en informática se representan en hexadecimal

El valor de un byte se puede representar con dos cifras hexadecimales. Desde el valor 0 decimal como 00, hasta el valor 255 como FF

Cada cuatro cifras binarias se corresponden con una cifra hexadecimal, por eso también corresponde con el valor de un nibble

Conversiones

Convertir de sistema decimal a hexadecimal

La representación hexadecimal de un número decimal (el paso de un número en base 10 a su correspondiente en base 16), se calcula dividiendo sucesivamente el cociente de la división del numero por el divisor 16, hasta obtener un cociente menor a 16. La representación en base 16 será, el último cociente seguido del ultimo resto seguido del resto anterior seguido del resto anterior y así hasta el primer resto obtenido

Para conseguir la conversión, además se utiliza esta tabla para representar los valores:

Tabla de conversión
Decimal Hexadecimal
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 A
11 B
12 C
13 D
14 E
15 F

Ejemplo: Convertir 3737 a representación hexadecimal

Numero Cociente Resto
\frac{3737}{16} 233 9
\frac{233}{16} 14 9

14\rightarrow E
9\rightarrow 9

Entonces tenemos que:

3737_{(10} = E99_{(16}

Convertir de sistema decimal a hexadecimal con decimales

La representación hexadecimal de un número decimal con decimales (el paso de un número en base 10 a su correspondiente en base 16), se calcula multiplicando sucesivamente el número (después los resultados) sin su parte entera por 16, hasta obtener un número sin decimales, hasta una cantidad que se repita periódicamente (en el caso de números periódicos), o hasta un número de dígitos predefinido por la precisión de la máquina. La representación en base 16 será, la parte entera sin modificaciones, después se le añade la coma y por último la parte entera del resultado de las multiplicaciones sucesivas

Ejemplo: Convertir 56,75 a representación hexadecimal con decimales

Número Cociente Resto
\frac{56}{16} 3 8

3\rightarrow 3
8\rightarrow 8

Entonces tenemos que la parte entera es:

56_{(10} = 38_{(16}

Número Resultado Parte entera
0,75 \cdot 16 12 12

12\rightarrow C

Entonces tenemos que la parte decimal es:

0,75_{(10} = C_{(16}

Entonces tenemos que:

56,75_{(10} = 38,C_{(16}

Convertir de sistema hexadecimal a decimal

La representación decimal de un número binario, correspondería a aplicar la fórmula:

b_1 \cdot 16^{(n - 1)} + \cdots + b_n \cdot 16^0

Donde n seria la longitud de la cadena, y b_i el valor correspondiente a la posición i-ésima de la ristra, empezando de izquierda a derecha

Ejemplo: Convertir E99 a representación decimal

E\rightarrow 14
9\rightarrow 9

E99_{(16}=E \cdot 16^2 + 9 \cdot 16^1 + 9 \cdot 16^0 = 14 \cdot 256 + 9 \cdot 16 + 9 \cdot 1 = 3584 + 144 + 9 = 3737_{(10}

Entonces tenemos que:

E99_{(16}=3737_{(10}

Convertir de sistema hexadecimal a decimal con decimales

Si el número tiene además decimales, se expresará con la siguiente fórmula:

b_1 \cdot 16^{(n - 1)} + \cdots + b_n \cdot 16^0 + b_{(n + 1)} * 16^{-1} + \cdots+ b_{(n + m)} \cdot 16^{-m}

Donde n seria la longitud de la cadena sin decimales, m la longitud de la cadena con decimales, b_i el valor correspondiente a la posición i-ésima de la ristra, empezando de izquierda a derecha

Ejemplo: Convertir 38,C a representación decimal

3\rightarrow 14
8\rightarrow 9
C\rightarrow 12

38,C_{(16}=3 \cdot 16^1 + 8 \cdot 16^0 + C \cdot 16^{-1} = 3 \cdot 16 + 8 \cdot 1 + 12 \cdot 0,0625 = 48 + 8 + 0,75 = 56,75_{(10}

Entonces tenemos que:

38,C_{(16}=56,75_{(10}

Signo-Magnitud

Signo-Magnitud

La representación signo-magnitud usa el bit más significativo como bit de signo, facilitando la comprobación de si el entero es positivo o negativo

Existen varias convenciones para representar en una máquina los números enteros en su forma binaria, tanto positivos como negativos

Todas tratan implicar el bit más significativo (el que está más a la izquierda) de la palabra (1 palabra equivale a 8 bits) como un bit de signo

En una palabra de n bits, los n-1 bits de la derecha representan la magnitud del entero

El caso general correspondería a aplicar la fórmula:

A=\begin{cases}\sum\limits_{i=0}^{n} 0^{n-2} \cdot a_i & \text{si }a_{n-1}=0 \\ -\sum\limits_{i=0}^{n} 0^{n-2} \cdot a_i & \text{si }a_{n-1}=1 \end{cases}

La representación signo-magnitud posee varias limitaciones:

  • La suma y la resta requieren tener en cuenta tanto los signos de los números como sus magnitudes relativas para llevar a cabo la operación en cuestión
  • Hay dos representaciones para el número 0:

    \begin{cases} +0_{(10}=00000000_{(2} \\ -0_{(10}=10000000_{(2} \end{cases}

Debido a estas limitaciones, raramente se usa la representación en signo-magnitud para representar los números enteros en una máquina

En su lugar, el esquema más común es la representación en complemento a dos

Conversiones

Ejemplo: Convertir de decimal a signo-magnitud

Vamos a convertir \pm 18 a signo-magnitud, primero lo convertimos a binario

Número Cociente Resto
\frac{18}{2} 9 0
\frac{9}{2} 4 1
\frac{4}{2} 2 0
\frac{2}{2} 1 0

Entonces tenemos que la parte binaria es:

18_{(10} = 10010_{(2}

Ahora le aplicamos la distinción por signo dentro de 1 palabra (recordemos que son 8 bits), entonces tenemos:

\begin{cases} +18_{(10}=00010010_{(2} \\ -18_{(10}=10010010_{(2} \end{cases}

Complemento a dos

Complemento a dos

La representación en complemento a dos, al igual que la representación en signo-magnitud, usa 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 en signo-magnitud en la forma de interpretar los bits restantes

Consideremos un entero A de n bits representado en complemento a dos. Si A es positivo, el bit de signo, a_{n-1} es 0. Los restantes bits representan la magnitud del número de la misma forma que en la representación signo-magnitud, es decir:

\sum\limits_{i=0}^{n} 0^{n-2} \cdot a_i\text{ si }A\geq 0

El número 0 se identifica como positivo y tiene, por tanto, un bit de signo 0 y una magnitud de todo ceros. El rango de los enteros positivos que pueden representarse es, desde 0 (todos los bits son 0) hasta 2^{n-1}-1 (todos los bits son 1). Cualquier número mayor requeriría más bits

Para un número A negativo, el bit de signo, a_n-1 es 1. Los n-1 bits restantes pueden tomar cualquiera de las 2^{n-1} combinaciones. Por lo tanto, los enteros negativos pueden representarse desde -1 hasta (-2)^{n-1}, es decir:

A=(-2)^{n-1}\cdot a_{n-1}

Sería deseable asignar los bits de los enteros negativos de tal manera que su manipulación aritmética pudiera efectuarse de una forma directa, similar a la de los enteros sin signo. En la representación sin signo, para calcular el valor de un entero a partir de su expresión en bits, el peso más significativo es 2^{n-1}

El caso general correspondería a aplicar la fórmula:

A=(-2)^{n-1} \cdot a_{n-1} + \sum\limits_{i=0}^{n} 0^{n-2} \cdot a_i

Propiedades

  • Rango de valores
    (-2)^{n-1}\text{ a } 2^{n-1}-1
  • Número de representaciones del 0
    Única
  • Negación
    Ejecutar el complemento booleano de cada bit y sumar 1 al patrón de bits resultante
  • Ampliación de la longitud en bits
    Las posiciones extra se añaden a la izquierda, rellenandolas con el valor del bit de signo original
  • Regla del desbordamiento
    Si se suman dos números de igual signo (ambos positivo ó negativos), hay desbordamiento si y sólo si, el resultado tiene signo opuesto
  • Regla para la resta
    Para restar B de A, se toma el complemento a dos de B y se suma a A

Conversiones

Ejemplo: Convertir de decimal a complemento a dos

Vamos a convertir \pm 18 a complemento a dos, primero lo convertimos a binario

Número Cociente Resto
\frac{18}{2} 9 0
\frac{9}{2} 4 1
\frac{4}{2} 2 0
\frac{2}{2} 1 0

Entonces tenemos que la parte binaria es:

18_{(10} = 10010_{(2}

Para hallar el -18 hay que utilizar la negación del 18

Se ejecuta el complemento booleano de cada bit dentro de 1 palabra (recordemos que son 8 bits), entonces tenemos:

18_{(10} = 00010010_{(2}
00010010 \rightarrow 11101101

Se le suma 1 al patrón de bits resultante

11101101+1=11101110

Entonces tenemos que:

\begin{cases} 18_{(10} = 00010010_{(2} \\ -18_{(10} = 11101110_{(2} \end{cases}

Coma flotante

Coma flotante

La representación en coma flotante más importante es la definida en la norma 754 IEEE (ANSI/IEEE Std 754-1985)

Este estándar se desarrolló para facilitar la portabilidad de los programas de un procesador a otro y para alentar el desarrollo de programas numéricos sofisticados

Este estándar ha sido ampliamente adoptado y se utiliza prácticamente en todos los procesadores y coprocesadores aritméticos actuales

Hay dos representaciones en coma flotante:

  • Formato simple (32 bits)
  • Formato doble (64 bits)

Formato simple (32 bits)

En el formato simple se utiliza el siguiente formato para almacenar una palabra (32 bits):

Bit de signo Exponente Mantisa
1 bit 8 bits 23 bits

Dado un E_1=\text{ exponente } + 127 (127 es el máximo número positivo del exponente) tenemos que:

00000000_{(2}\leq E_1\leq 11111111_{(2}

Si denotamos (E1)_{(10} a la conversión decimal de E_1, tenemos que:

0\leq (E1)_{(10}\leq 2^7+2^6+2^5+2^4+2^3+2^2+2^1+2^0=255

O lo que seria lo mismo:

-127\leq (E_1)_{(10} -127\leq 128

Si denotamos \alpha=(E_1)_{(10} -127 tenemos que:

-127\leq\alpha\leq 128
(E_1)=\alpha+127

Denotamos s como el bit de signo y M como la mantisa. A raíz de esto, surgen dos tipos de números:

  • Números normales
    -127 < \alpha < 128

    Conversión a número normal: (-1)\cdot s \cdot 1,M \cdot 2^\alpha

  • Números subnormales
    \alpha = (-127)

    Conversión a número subnormal: (-1)\cdot s \cdot 0,M \cdot 2^{-126}

  • \alpha = 128

    Da lugar a excepciones del tipo +\infty, -\infty\text{ y NaN} (no es un número, Not a Number del inglés)

Se utiliza un bit escondido (hidden bit del inglés) en la mantisa. Se toma el primer dígito que siempre es a_1 = 1. Este bit escondido no hará falta almacenarlo, consiguiendo así unos cuantos números más

Número Decimal Binario
\tiny \text{Máximo número normal positivo} \tiny 3,40282347 \cdot 10^{38} \tiny\text{0 11111110 11111111111111111111111}
\tiny \text{Máximo número normal negativo} \tiny -3,40282347 \cdot 10^{38} \tiny \text{1 11111110 11111111111111111111111}
\tiny \text{Mínimo número normal positivo} \tiny 1,17549435 \cdot 10^{-38} \tiny \text{0 00000001 00000000000000000000000}
\tiny \text{Mínimo número normal negativo} \tiny -1,17549435 \cdot 10^{-38} \tiny \text{1 00000001 00000000000000000000000}
\tiny \text{Máximo número subnormal positivo} \tiny 1,17549421 \cdot 10[{-38} \tiny \text{0 00000000 11111111111111111111111}
\tiny \text{Máximo número subnormal negativo} \tiny -1,17549421 \cdot 10[{-38} \tiny \text{1 00000000 11111111111111111111111}
\tiny \text{Mínimo número subnormal positivo} \tiny 1,40129846 \cdot 10^{-45} \tiny \text{0 00000000 00000000000000000000001}
\tiny \text{Mínimo número subnormal negativo} \tiny -1,40129846 \cdot 10^{-45} \tiny \text{1 00000000 00000000000000000000001}
\tiny \text{+0} \tiny 0,0 \tiny \text{0 00000000 00000000000000000000000}
\tiny \text{-0} \tiny -0,0 \tiny \text{1 00000000 00000000000000000000000}
\tiny +\infty \tiny +\infty \tiny \text{0 11111111 00000000000000000000000}
\tiny -\infty \tiny -\infty \tiny \text{1 11111111 00000000000000000000000}
\tiny \text{NaN} \tiny NaN \tiny \text{(0 }\acute{o}\text{ 1) 11111111 (alg}\acute{u}\text{n 1)}

Conversiones

Ejemplo: convertir el 3737 a formato simple (32 bits)

Es positivo, por tanto el signo es 0

Número Cociente Resto
\frac{3737}{2} 1868 1
\frac{1868}{2} 934 0
\frac{934}{2} 467 0
\frac{467}{2} 233 1
\frac{233}{2} 116 1
\frac{116}{2} 58 0
\frac{58}{2} 29 0
\frac{29}{2} 14 1
\frac{14}{2} 7 0
\frac{7}{2} 3 1
\frac{3}{2} 1 1

Entonces tenemos que la parte binaria es:

3737_{(10} = 111010011001_{(2}

Para el exponente vamos a necesitar mover 12 cifras decimales, por tanto debemos hacer 127 + 11 = 138 (sumamos 11 porque el bit escondido no se cuenta)

Número Cociente Resto
\frac{138}{2} 69 0
\frac{69}{2} 34 1
\frac{34}{2} 17 0
\frac{17}{2} 8 1
\frac{8}{2} 4 0
\frac{4}{2} 2 0
\frac{2}{2} 1 0

Entonces tenemos que el exponente es:

138_{(10} = 10001010_{(2}

Entonces tenemos que:

3737_{(10} = \text{0 10001010 11010011001000000000000}_{(2}

Formato doble (64 bits)

En el formato simple se utiliza el siguiente formato para almacenar dos palabras (64 bits):

Bit de signo Exponente Mantisa
1 bit 11 bits 52 bits

Dado un E_1=\text{ exponente } + 1023 (1023 es el máximo número positivo del exponente) tenemos que:

00000000000_{(2}\leq E_1\leq 11111111111_{(2}

Si denotamos (E1)_{(10} a la conversión decimal de E_1, tenemos que:

0\leq (E1)_{(10}\leq 2^{10}+2^9+2^8+2^7+2^6+2^5+2^4+2^3+2^2+2^1+2^0=2047

O lo que seria lo mismo:

-1023\leq (E_1)_{(10} -1023\leq 1024

Si denotamos \alpha=(E_1)_{(10} -1023 tenemos que:

-1023\leq\alpha\leq 1024
(E_1)=\alpha+1023

Denotamos s como el bit de signo y M como la mantisa. A raíz de esto, surgen dos tipos de números:

  • Números normales
    -1023 < \alpha < 1024

    Conversión a número normal: (-1)\cdot s \cdot 1,M \cdot 2^\alpha

  • Números subnormales
    \alpha = (-1023)

    Conversión a número subnormal: (-1)\cdot s \cdot 0,M \cdot 2^{-1022}

  • \alpha = 1024

    Da lugar a excepciones del tipo +\infty, -\infty\text{ y NaN} (no es un número, Not a Number del inglés)

Se utiliza un bit escondido (hidden bit del inglés) en la mantisa. Se toma el primer dígito que siempre es a_1 = 1. Este bit escondido no hará falta almacenarlo, consiguiendo así unos cuantos números más

Número Decimal Binario
\tiny \text{Máximo número}\\ \text{normal positivo} \tiny 1,7976931 \cdot 10^{308} \tiny \text{0 11111111110 1111111111111111111111111111111111111111111111111111}
\tiny \text{Máximo número}\\ \text{normal negativo} \tiny -1,7976931 \cdot 10^{308} \tiny \text{1 11111111110 1111111111111111111111111111111111111111111111111111}
\tiny \text{Mínimo número}\\ \text{normal positivo} \tiny 2,2250738 \cdot 10^{-308} \tiny \text{0 00000000001 0000000000000000000000000000000000000000000000000000}
\tiny \text{Mínimo número}\\ \text{normal negativo} \tiny -2,2250738 \cdot 10^{-308} \tiny \text{1 00000000001 0000000000000000000000000000000000000000000000000000}
\tiny \text{Máximo número}\\ \text{subnormal positivo} \tiny 2,2250738 \cdot 10^{-308} \tiny \text{0 00000000000 1111111111111111111111111111111111111111111111111111}
\tiny \text{Máximo número}\\ \text{subnormal negativo} \tiny -2,2250738 \cdot 10^{-308} \tiny \text{1 00000000000 1111111111111111111111111111111111111111111111111111}
\tiny \text{Mínimo número}\\ \text{subnormal positivo} \tiny 4,9406564 \cdot 10^{-324} \tiny \text{0 00000000000 0000000000000000000000000000000000000000000000000001}
\tiny \text{Mínimo número}\\ \text{subnormal negativo} \tiny -4,9406564 \cdot 10^{-324} \tiny \text{1 00000000000 0000000000000000000000000000000000000000000000000001}
\tiny +0 \tiny 0,0 \tiny \text{0 00000000000 0000000000000000000000000000000000000000000000000000}
\tiny -0 \tiny -0,0 \tiny \text{1 00000000000 0000000000000000000000000000000000000000000000000000}
\tiny +\infty \tiny +\infty \tiny \text{0 11111111111 0000000000000000000000000000000000000000000000000000}
\tiny -\infty \tiny -\infty \tiny \text{1 11111111111 0000000000000000000000000000000000000000000000000000}
\tiny \text{NaN} \tiny \text{NaN} \tiny \text{(0 }\acute{o}\text{ 1) 11111111111 (alg}\acute{u}\text{n 1)}

Conversiones

Ejemplo: convertir el 3737 a formato doble (64 bits)

Es positivo, por tanto el signo es 0

Número Cociente Resto
\frac{3737}{2} 1868 1
\frac{1868}{2} 934 0
\frac{934}{2} 467 0
\frac{467}{2} 233 1
\frac{233}{2} 116 1
\frac{116}{2} 58 0
\frac{58}{2} 29 0
\frac{29}{2} 14 1
\frac{14}{2} 7 0
\frac{7}{2} 3 1
\frac{3}{2} 1 1

Entonces tenemos que la parte binaria es:

3737_{(10} = 111010011001_{(2}

Para el exponente vamos a necesitar mover 12 cifras decimales, por tanto debemos hacer 1023 + 11 = 1034 (sumamos 11 porque el bit escondido no se cuenta)

Número Cociente Resto
\frac{1034}{2} 517 0
\frac{517}{2} 258 1
\frac{258}{2} 129 0
\frac{129}{2} 64 1
\frac{64}{2} 32 0
\frac{32}{2} 16 0
\frac{16}{2} 8 0
\frac{8}{2} 4 0
\frac{4}{2} 2 0
\frac{2}{2} 1 0

Entonces tenemos que el exponente es:

138_{(10} = 10000001010_{(2}

Entonces tenemos que:

\tiny 3737_{(10} = \text{0 10000001010 1101001100100000000000000000000000000000000000000000}_{(2}

Álgebra de Boole

Álgebra de Boole

El álgebra de Boole es una disciplina que analiza los circuitos digitales y otros sistemas digitales

Recibe su nombre en honor al matemático inglés George Boole, que propuso los principios básicos de este álgebra en 1854 en su tratado An investigation of the laws of thought on wich to found the mathematical theories of logic and probabilities

En 1938, Claude Shannon, un investigador asistente en el Departamento de Ingeniería Eléctrica del M.I.T., sugirió que el álgebra de Boole podría usarse para resolver problemas de circuitos de conmutación

Las técnicas de Shannon se usaron, consecuentemente en el análisis y diseño de circuitos digitales. El álgebra de Boole resulta una herramienta útil en dos áreas:

  • Análisis
    Es una forma concisa de descubrir el funcionamiento de los circuitos digitales
  • Diseño
    Dada una función deseada, se puede aplicar el álgebra de Boole para desarrollar una implementación de complejidad simplificada de esa función

El álgebra de Boole usa variables y operaciones lógicas. Una variable puede tomar el valor 1 cuando es verdadero ó 0 cuando es falso. Tiene únicamente tres operaciones lógicas básicas (AND, OR y NOT), que se representan simbólicamente:

AND OR NOT
A AND B A OR B NOT A
A\wedge B A\vee B \neg A

Tablas de verdad

La tabla de verdad define las operaciones lógicas básicas, enumerando el valor para cada combinación posible de los valores de los operandos. Además de los operadores básicos del álgebra de Boole, también se suelen enumerar tres operadores útiles: XOR, XNOR, NAND y NOR. Los cuales se pueden obtener haciendo operaciones con los operadores básicos

Tabla AND

La operación AND es verdadera si y sólo si los dos operandos son verdaderos

A B A\wedge B
0 0 0
0 1 0
1 0 0
1 1 1

Tabla OR

La operación OR es verdadera si y sólo si los uno o ambos operandos son verdaderos

A B A\vee B
0 0 0
0 1 1
1 0 1
1 1 1

Tabla NOT

La operación NOT invierte el valor del operando

A \neg A
0 1
1 0

Tabla XOR

La operación XOR es verdadera si y sólo uno de los operandos es verdadero

Equivale a realizar:

(A \wedge \neg B) \vee (\neg A \wedge B) \equiv (A \vee B) \wedge (\neg A \vee \neg B)

A B A\oplus B
0 0 0
0 1 1
1 0 1
1 1 0

Tabla XNOR

La operación XNOR es la negación de la operación XOR

Equivale a realizar:

(A \wedge B) \vee (\neg A \wedge \neg B)

A B \neg(A\oplus B)
0 0 1
0 1 0
1 0 0
1 1 1

Tabla NAND

La operación NAND es la negación de la operación AND

Equivale a realizar:

\neg(A \wedge B)

A B \neg(A \wedge B)
0 0 1
0 1 1
1 0 1
1 1 0

Tabla NOR

La operación NOR es la negación de la operación OR

Equivale a realizar:

\neg(A \vee B)

A B \neg(A \vee B)
0 0 1
0 1 0
1 0 0
1 1 0

Identidades básicas

Hay dos clases de identidades:

  • Reglas básicas (postulados)
    Se afirman sin demostración
  • Otras identidades
    Se pueden derivar de los postulados básicos

Los postulados definen la manera en la que las expresiones booleanas se interpretan

Reglas básicas
A \wedge B = B \wedge A A \vee B = B \vee A Ley conmutativa
A \wedge (B \vee C) = (A \wedge B) \vee (A \wedge C) A \vee (B \wedge C) = (A \vee B) \wedge (A \vee C) Ley distributiva
1 \wedge A = A 0 \vee A = A Elemento neutro
A \wedge \neg A = 0 A \vee \neg A = 1 Elemento complementario
Otras identidades
0 \wedge A = 0 1 \vee A = 1
A \wedge A = A A \vee A = A
A \wedge (B \wedge C) = (A \wedge B) \wedge C A \vee (B \vee C) = (A \vee B) \vee C Ley asociativa
\neg (A \wedge B) = \neg A \vee \neg B \neg (A \vee B) = \neg A \wedge \neg B Teorema de Morgan

Qubits

Qubits

Un qubits es un sistema cuántico con dos estados propios y que puede ser manipulado arbitrariamente

Solo puede ser descrito correctamente mediante la mecánica cuántica, y solamente tiene dos estados bien distinguibles mediante medidas físicas

También se entiende por qubits la información que contiene ese sistema cuántico de dos estados posibles

En esta acepción, el qubits es la unidad mínima y por lo tanto constitutiva de la teoría de la información cuántica

Es un concepto fundamental para la programación cuántica y para la criptografía cuántica, el análogo cuántico del bit en informática

Estos qubits ya no toman simplemente valores enteros (0 ó 1)

Sino que ahora son representados por entidades matemáticas llamadas vectores de estado |\psi\succ

Que vamos a representar usando la notación de Dirac:

\begin{matrix} |0\succ&=\binom{1}{0}\\ |1\succ&=\binom{0}{1} \end{matrix}

Que define los estados base de un qubit

Como vector, el estado |\psi\succ de cada qubit pertenece a un espacio vectorial particular llamado espacio de Hilbert

Físicamente, podemos medir el estado |\psi\succ en dos estados básicos ortogonales, que por convención se llaman |0\succ y |1\succ

Esto implica que el espacio de Hilbert es de 2 dimensiones

Por lo que se pueden elegir los vectores \left \{ |0\succ, 1\succ \right \} como base del espacio vectorial

De esta forma, cualquier vector de estado |\psi\succ de un qubit es una combinación lineal de los vectores base (que en el lenguaje de la mecánica cuántica se llama estado de superposición cuántica)

|\psi\succ=\alpha|0\succ+\beta|1\succ

Que define la combinación lineal de los estados base de un qubit

El espacio de Hilbert de cada qubit es un espacio complejo

Esto quiere decir que \alpha y \beta son números complejos

Además, no pueden tomar cualquier valor

Deben cumplir que:

\left\|\alpha\right\|^{2}+\left\|\beta\right\|^{2}=1

Es decir, que el vector de estado de un qubit |\psi\succ está normalizado, (su norma es igual a 1)

Puertas cuánticas

Las puertas cuánticas son transformaciones lineales entre los vectores de estado |\psi\succ

Pero no sirve realizar cualquier transformación lineal

Sólo pueden ser consideradas las transformaciones que no cambien la norma del vector |\psi\succ

Aquellas que tomen un vector cuya norma sea 1 y lo conviertan en otro vector de norma igual a 1

Este tipo de transformaciones se llaman Transformaciones unitarias, o en el lenguaje de la mecánica cuántica, Operadores Unitarios

Por lo tanto, las puertas cuánticas son operadores unitarios

Los operadores unitarios pueden ser representados como matrices

La aplicación de un operador unitario A a un vector de estado |b\succ, puede ser representada como una multiplicación de una matriz de 2x2 por un vector columna, dando como resultado otro vector columna

\begin{pmatrix} A_{11} & A_{12} \\ A_{21} & A_{22} \end{pmatrix} \cdot \begin{pmatrix} b_{1}\\ b_{2} \end{pmatrix} = \begin{pmatrix} c_{1}\\ c_{2} \end{pmatrix}

Puertas cuánticas de un qubit en Qiskit

Qiskit es una herramienta creada por IBM para desarrollar software para procesadores cuánticos

Está implementado en el lenguaje de programación Python, y disponible para que el público en general para empezar a experimentar y probar nuestros algoritmos

A continuación voy a representar las puertas cuánticas más utilizadas que se aplican a un qubit, así como su representación matricial y su forma de implementarla en Qiskit

Para saber como instalar Qiskit en tu ordenador, puedes revisarlo en su documentación

Puerta Identidad

La puerta identidad representa a la matriz identidad y se llama así porque representa a la aplicación identidad que va de un espacio vectorial de dimensión finita a sí misma

I=\begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}

Y cuya representación en notación de Dirac es:

\begin{matrix} I|0\succ=|0\succ\\ I|1\succ=|1\succ \end{matrix}

Código Qiskit de la puerta identidad:

Matrices de Pauli

Las matrices de Pauli, deben su nombre a Wolfgang Ernst Pauli

Son matrices usadas en física cuántica en el contexto del momento angular intrínseco o espín

Matemáticamente, las matrices de Pauli constituyen una base vectorial del álgebra de Lie del grupo especial unitario SU\left(2\right), actuando sobre la representación de dimensión 2

Puerta X (matriz X de Pauli)

I=\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}

Y cuya representación en notación de Dirac es:

\begin{matrix} I|0\succ=|1\succ\\ I|1\succ=|0\succ \end{matrix}

Código Qiskit de la puerta X:

Puerta Y (matriz Y de Pauli)

I=\begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}

Y cuya representación en notación de Dirac es:

\begin{matrix} I|0\succ=i|1\succ\\ I|1\succ=-i|0\succ \end{matrix}

Código Qiskit de la puerta Y:

Puerta Z (matriz Z de Pauli)

I=\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}

Y cuya representación en notación de Dirac es:

\begin{matrix} I|0\succ=|0\succ\\ I|1\succ=|-1\succ \end{matrix}

Código Qiskit de la puerta Z:

Puerta Hadamard

La puerta de Hadamard, deben su nombre a Jacques Salomon Hadamard

No son más que la representación de un qubit de la transformada cuántica de Fourier

Como las filas de la matriz son ortogonales, dónde {\displaystyle H} es una matriz unitaria

H=\frac{1}{\sqrt{2}}\cdot \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}

Y cuya representación en notación de Dirac es:

\begin{matrix} H|0\succ=\frac{1}{\sqrt{2}}\cdot \left(|0\succ+|1\succ\right)\\ H|1\succ=\frac{1}{\sqrt{2}}\cdot \left(|0\succ-|1\succ\right) \end{matrix}

Código Qiskit de la puerta H:

Puertas U (Universales)

En versiones anteriores de qiskit existían las denominadas puertas U1, U2 y U3

Pero estas puertas han desaparecido en versiones posteriores de qiskit

Se pueden construir con puertas P y U mediante las siguientes equivalencias:

\left\{\begin{matrix} U_{1}\left(\lambda\right)=P\left(\lambda\right)\\ U_{2}\left(\Phi,\lambda\right)=U\left(\Phi,\lambda,\frac{\pi}{2}\right)\\ U_{3}\left(\theta,\Phi,\lambda\right)=U\left(\theta,\Phi,\lambda\right) \end{matrix}\right.

Se define como

U\left(\theta,\Phi,\lambda\right)= \begin{pmatrix} \cos{\frac{\theta}{2}} & -\exp^{i\cdot\lambda}\cdot\sin{\frac{\theta}{2}} \\ \exp^{i\cdot\Phi}\cdot\sin{\frac{\theta}{2}} & \exp^{i\cdot\left(\Phi+\lambda\right)}\cdot\cos{\frac{\theta}{2}} \end{pmatrix}

Hay dos casos específicos en los que obtenemos las siguientes equivalencias:

\left\{\begin{matrix} H=U\left(\frac{\pi}{2},0,\pi\right)= \frac{1}{\sqrt{2}}\cdot \begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}\\ P=U\left(0,0,\lambda\right)= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\lambda} \end{pmatrix} \end{matrix}\right.

Puerta P

P\left(\Phi\right)= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\Phi} \end{pmatrix}

Código Qiskit de la puerta P:

Puerta U1

U_{1}\left(\lambda\right)= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\lambda} \end{pmatrix} =P\left(\lambda\right)

Código Qiskit de la puerta U1 en versiones anteriores:

Puerta U2

U_{2}\left(\Phi,\lambda\right)= \frac{1}{\sqrt{2}}\cdot\begin{pmatrix} 1 & -\exp^{i\cdot\lambda} \\ \exp^{i\cdot\Phi} & \exp^{i\cdot\left(\Phi+\lambda\right)} \end{pmatrix} =U\left(\Phi,\lambda,\frac{\pi}{2}\right)

Código Qiskit de la puerta U2 en versiones anteriores:

Puerta U3

U_{3}\left(\theta,\Phi,\lambda\right)= \begin{pmatrix} \cos{\frac{\theta}{2}} & -\exp^{i\cdot\lambda}\cdot\sin{\frac{\theta}{2}} \\ \exp^{i\cdot\Phi}\cdot\sin{\frac{\theta}{2}} & \exp^{i\cdot\left(\Phi+\lambda\right)}\cdot\cos{\frac{\theta}{2}} \end{pmatrix} =U\left(\theta,\Phi,\lambda\right)

Código Qiskit de la puerta U3 en versiones anteriores:

Puerta S

Da un cuarto de vuelta alrededor de la esfera de Bloch

Se define como \Phi =\frac{\pi}{2} y por esa razón es equivalente a una puerta U_{1}\left(\frac{\pi}{2}\right)

S= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\frac{\pi}{2}} \end{pmatrix} = U_{1}\left(\frac{\pi}{2}\right)

Y cuya representación en notación de Dirac es:

SS|q\succ=\mathbb{Z}|q\succ

Código Qiskit de la puerta S:

Puerta S

Surge a partir de una puerta S negativa

Se define como \Phi =-\frac{\pi}{2} y por esa razón es equivalente a una puerta U_{1}\left(\frac{-pi}{2}\right)

S= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{-i\cdot\frac{\pi}{2}} \end{pmatrix} = U_{1}\left(\frac{-pi}{2}\right)

Código Qiskit de la puerta S:

Puerta T

Es similar a la puerta S y también es conocida como la puerta \sqrt[4]{\mathbb{Z}}

Se define como \Phi =\frac{\pi}{4} y por esa razón es equivalente a una puerta U_{1}\left(\frac{\pi}{4}\right)

T= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\frac{\pi}{4}} \end{pmatrix} = U_{1}\cdot\left(\frac{\pi}{4}\right)

Código Qiskit de la puerta T:

Puerta T

Surge a partir de una puerta T negativa

Se define como \Phi =-\frac{\pi}{4} y por esa razón es equivalente a una puerta U_{1}\left(\frac{-\pi}{4}\right)

T= \begin{pmatrix} 1 & 0 \\ 0 & \exp^{i\cdot\frac{\pi}{4}} \end{pmatrix} = U_{1}\cdot\left(\frac{-\pi}{4}\right)

Código Qiskit de la puerta T:

Puertas de rotación estándar

Estas puertas representan un tipo particular de rotación, derivadas de las matrices de Pauli

De manera general se definen como:

R_{p}\left(\theta\right)=\exp\left(-\frac{i\cdot\theta}{2}\right)=\cos\left(\frac{\theta}{2}\right)\cdot I-i\cdot \sin\left(\frac{\theta}{2}\right)\cdot P

Puerta Rx (Rotación estándar alrededor del eje-x)

La Puerta Rx es equivalente a U\left(\theta,\frac{-\pi}{2},\frac{\pi}{2}\right)

R_{x}\left(\theta\right)= \begin{pmatrix} \cos\left(\frac{\theta}{2}\right) & -i\cdot\sin\left(\frac{\theta}{2}\right) \\ -i\cdot\sin\left(\frac{\theta}{2}\right) & \cos\left(\frac{\theta}{2}\right) \end{pmatrix} = U\left(\theta,\frac{-\pi}{2},\frac{\pi}{2}\right)

Código Qiskit de la puerta Rx:

Puerta Ry (Rotación estándar alrededor del eje-y)

La Puerta Ry es equivalente a U\left(\theta,0,0\right)

R_{y}\left(\theta\right)= \begin{pmatrix} \cos\left(\frac{\theta}{2}\right) & -\sin\left(\frac{\theta}{2}\right) \\ \sin\left(\frac{\theta}{2}\right) & \cos\left(\frac{\theta}{2}\right) \end{pmatrix} = U\left(\theta,0,0\right)

Código Qiskit de la puerta Ry:

Puerta Rz (Rotación estándar alrededor del eje-z)

La Puerta Rz es equivalente a P\left(\phi\right)

R_{z}\left(\phi\right)= \begin{pmatrix} \exp^{-i\cdot \frac{\phi}{2}} & 0 \\ 0 & \exp^{i\cdot \frac{\phi}{2}}\end{pmatrix} = P\left(\phi\right)

Código Qiskit de la puerta Rz:

Lenguaje de programación

Lenguaje de programación

Un lenguaje de programación puede ser cualquier lenguaje artificial que pueda utilizarse para definir una secuencia de instrucciones para su procesamiento en una máquina (maquinaria industrial, un ordenador, una tablet, un móvil)

Se asume generalmente que la traducción de las instrucciones a un código que comprende la máquina debe ser completamente sistemática. Normalmente es la máquina quien realiza la traducción

Lenguaje de bajo nivel

A muy bajo nivel, los microprocesadores procesan exclusivamente señales electrónicas binarias. Dar una instrucción a un microprocesador supone en realidad enviar series de unos y ceros espaciados en el tiempo de una forma determinada. Esta secuencia de señales se denomina código máquina

El código representa normalmente datos e instrucciones para manipularlos. Un modo más fácil de comprender el código máquina es dando a cada instrucción un mnemónico, como por ejemplo STORE, ADD o JUMP. Esta abstracción da como resultado el ensamblador, un lenguaje de muy bajo nivel que es específico de cada microprocesador

Los lenguajes de bajo nivel permiten crear programas muy rápidos, pero que son difíciles de comprender. Lo más importante es el hecho de que los programas escritos en bajo nivel son prácticamente específicos para cada procesador. Si se quiere ejecutar el programa en otra máquina con otra tecnología, será necesario reescribir el programa desde cero

Lenguaje de alto nivel

Por lo general se piensa que las máquinas realizan tareas de cálculos o procesamiento de textos. La descripción anterior es sólo una forma muy esquemática de ver como trabajan. Existe un alto nivel de abstracción entre lo que se le pide a la máquina y lo que realmente comprende. Existe también una relación compleja entre los lenguajes de alto nivel y el código máquina

Los lenguajes de alto nivel son más fáciles de comprender que el código máquina porque están formados por elementos de lenguajes naturales, como el inglés. En BASIC (uno de los lenguajes de alto nivel más conocidos por su sencillez de aprendizaje), los comandos como ‘IF CONTADOR = 10 THEN STOP’ pueden utilizarse para pedir a la máquina que pare si la variable CONTADOR es igual a 10. Por desgracia para muchas personas esta forma de trabajar es un poco frustrante, dado que a pesar de que las máquinas parecen comprender un lenguaje natural, lo hacen en realidad de una forma rígida y sistemática

Interpretes y compiladores

La traducción de una serie de instrucciones en lenguaje ensamblador (el código fuente) a un código máquina (o código objeto) no es un proceso muy complicado y lo realiza normalmente un programa especial llamado compilador. La traducción de un código fuente de alto nivel a un código máquina también se realiza con un compilador, en este caso este programa será más complejo, o mediante un intérprete

Un compilador crea una lista de instrucciones de código máquina, el código objeto, basándose en un código fuente. El código objeto resultante es un programa ejecutable que ya puede funcionar en la máquina, pero que puede hacer que se bloquee si no está bien diseñado

Los intérpretes, por otro lado, son más lentos que los compiladores ya que no producen un código objeto, sino que recorren el código fuente una línea cada vez. Cada línea se traduce a código máquina y se ejecuta. Cuando la línea se lee por segunda vez, como en el caso de los programas en que se reutilizan partes del código, debe compilarse de nuevo. Aunque este proceso es más lento, es menos susceptible de provocar bloqueos indeseados en la máquina

Ensamblador

Ensamblador

El lenguaje ensamblador es un lenguaje de bajo nivel cuyas instrucciones se suelen corresponder una a una con las instrucciones del ordenador, y con la posibilidad de poder definir, por ejemplo, macroinstrucciones

Este lenguaje es totalmente dependiente del modelo de procesador

Para poder estudiar este lenguaje con un microprocesador real se ha elegido el 8086, ya que es uno de los más utilizados en la actualidad en ordenadores de tipo PC

La principal característica de ese microprocesador es que es capaz de trabajar con operandos de 16 bits

Los ordenadores de tipo PC usan las operaciones básicas en 16 bits del 8086 y si el procesador es de 32 bits se le añaden un repertorio nuevo de operaciones en 32 bits. Si es de 64 bits entonces el repertorio de operaciones incluidas son de 16 bits, de 32 bits y un nuevo repertorio de 64 bits

Arquitectura básica del 8086

La arquitectura interna del 8086 se compone de dos partes diferenciadas: la Unidad de Ejecución y la Unidad de Interfaz con el bus

La tarea principal de la Unidad de Ejecución es ejecutar las instrucciones que extrae de la cola de espera, a donde llegan procedentes de la MP (Memoria Principal)

El trabajo principal de la Unidad de Interfaz con el bus es buscar y traer las instrucciones de la MP. Para ello tendrá que generar la dirección de la instrucción a ejecutar

Registros generales o de datos

Hay 4 registros de 16 bits y cada uno tiene una utilidad concreta:

  • AX
    Registro acumulador, se utiliza con las operaciones aritméticas
  • BX
    Registro de base, se utiliza para acceder a vectores, tablas, etc
    Mediante el uso de una dirección base que indica cual es el primer elemento y una dirección de desplazamiento que es el valor que se le suma a la dirección base para poder alcanzar el elemento deseado
  • CX
    Registro contador, se utiliza para contar en bucles e instrucciones de tipo repetitivo
  • DX
    Registro de datos, tiene dos usos particulares

    1. Complementar al registro AX en las operaciones aritméticas multiplicación y división
    2. Contiene direcciones de puerto para instrucciones de entrada / salida

Estos 4 registros tiene la siguiente propiedad común, aunque son de 16 bits, se pueden considerar cada uno de ellos como 2 registros independientes de 8 bits. De este modo podemos designar los bits más altos o significativos como Hight (al registro se le renombra con H al final: AH, BH, CH, DH) y los más bajos o menos significativos como Lower (al registro se le renombra con L al final: AL, BL, CL, DL)

Registros de segmento: Segmentación

Hay 4 registros de 16 bits y cada uno tiene una utilidad concreta:

  • CS
    Segmento de código, es el que define la zona de memoria donde se encuentran las instrucciones a ejecutar o de programa
  • DS
    Segmento de datos, es el que define la zona donde se encuentran los datos que van a ser usados en el programa
  • SS
    Segmento de stack o pila, define la zona de memoria que se va a utilizar como una pila
  • ES
    Segmento extra, como su nombre indica contiene la dirección del segmento extra, que se utiliza cuando se sobrepasa la capacidad de 64 kbytes del segmento de datos y para realizar determinadas transferencias de datos entre segmentos

Bus de datos: lineas por las que se transmiten los datos

Anchura del bus de datos: número de lineas eléctricas del bus por las que se transmiten los datos, en el 8086 son de 16 bits

Bus de direcciones: lineas por las que se transmiten las direcciones

Anchura del bus de direcciones: número de lineas eléctricas del bus por las que se transmiten las direcciones, en el 8086 son de 16 bits

Por tanto, las direcciones deberían ser de 16 bits, sin embargo, en el 8086 son de 20 bits. Esto es debido a que el número de direcciones distintas sería 2^{16}=64K, pero como son muy pocas, nos interesa que sean de 20 bits, ya que 2^{10}=1M

Para calcular la dirección física necesitamos un segmento y un desplazamiento, usando siempre valores en hexadecimal, con lo que tendremos un primer registro de 16 bits al que se añadirá un 0 a su derecha y un segundo registro de 16 bits

Como notación se usa Segmento:Desplazamiento

El cálculo de la dirección física se realizará:
Segmento x 10(h) + Desplazamiento

Ejemplos de Segmento:Desplazamiento

  • 0000:1050\Rightarrow 0000\cdot 10+1050=0150
  • 0010:0F50\Rightarrow 0010\cdot 10+0F50=0150
  • 0100:0050\Rightarrow 0100\cdot 10+0050=0150
  • 0105:0000\Rightarrow 0105\cdot 10+0000=0150

Como puede apreciarse en los ejemplos, distintas combinaciones de segmentos y desplazamientos pueden darnos la misma dirección física. Esta situación no es un error, es debido a que las direcciones de los segmentos se solapan entre sí

Podemos tener tantos números de segmentos distintos como combinaciones distintas puedan hacerse con la dirección base de segmento. Como tiene 16 bits entonces tenemos 2^{16} combinaciones por lo que tenemos 64\cdot K direcciones distintas

Podemos tener tantos números de direcciones distintas en cada segmento como combinaciones distintas puedan hacerse con el desplazamiento. Como tiene 16 bits entonces tenemos 2^{16} combinaciones por lo que tenemos 64\cdot K direcciones distintas

Se podría pensar que como tenemos 64\cdot K segmentos y 64\cdot K direcciones, tendríamos 64\cdot 64=2G direcciones físicas. Sin embargo, como las direcciones están solapadas este número de direcciones es incorrecto

Las direcciones válidas de comienzo de segmento tienen la propiedad de acabar en 0. Por tanto, ya que en hexadecimal son 10, al pasar de hexadecimal a decimal obtenemos que el número de direcciones es 16

SQL

SQL

Al gestionar bases de datos el modelo de datos más utilizado es el modelo relacional y para comunicarse con el gestor se puede utilizar el lenguaje SQL

NO es un lenguaje de programación, sino un lenguaje de gestión de bases de datos que presenta las siguientes características:

  • LDD (Lenguaje de definición de datos)

    El LDD de SQL proporciona comandos para la definición de esquemas de relación, borrado de relaciones y modificación de los esquemas de relación

  • LMD (Lenguaje interactivo de manipulación de datos)

    El LMD de SQL incluye un lenguaje de consultas basado tanto en el álgebra relacional como en el cálculo relacional de tuplas. También incluye comandos para insertar, borrar y modificar tuplas

  • Integridad

    El LDD incluye comandos para especificar restricciones de integridad que deben cumplir los datos almacenados en la base de datos. Las actualizaciones que violan las restricciones de integridad se rechazan

  • Definición de vistas

    El LDD de SQL incluye comandos para la definición de vistas

  • Control de transacciones

    SQL incluye comandos para especificar el comienzo y el final de transacciones

  • SQL incorporado y SQL dinámico

    SQL incorporado y SQL dinámico define cómo se pueden incorporar las instrucciones de SQL en lenguajes de programación de propósito general como C, C++, Java, PL/L, Cobol, Pascal o Fortran, entre otros

  • Autorización
    El LDD de SQL incluye comandos para especificar los derechos de acceso a las relaciones y a las vistas

Evolución del SQL

IBM desarrolló la versión original de SQL, denominado Sequel, como parte del proyecto System R a principios de 1970 por el grupo de San José, California

El lenguaje Sequel ha evolucionado desde entonces y su nombre ha pasado a ser SQL (lenguaje estructurado de consultas, Structured Query Language)

Hoy en día, muchos lenguajes de programación son compatibles con el lenguaje SQL y se ha establecido como el lenguaje estándar para el uso de bases de datos relacionales

1981, IBM lanzó el primer programa comercial basado en SQL

1986, ANSI (Instituto nacional americano de normalización, American National Standards Institute) publicó una norma SQL, denominada SQL-86 o SQL1 y fue confirmada por ISO (Organización internacional de normalización, International Standards Organization) en 1987

1989, ANSI publicó una extensión de la norma para SQL denominada SQL-89

1992, apareció una nueva versión de la norma denominada SQL-92 o SQL2

1999, apareció una nueva versión denominada SQL:1999 o SQL2000. En la cual se agregaron expresiones regulares, consultas recursivas (para relaciones jerárquicas), triggers y algunas características orientadas a objetos

2003, apareció una nueva versión denominada SQL:2003. En la cual se agregaron algunas características de XML, cambios en las funciones, estandarización del objeto sequence y de las columnas autonuméricas

2005, apareció una nueva versión denominada SQL:2005 y se corresponde con la norma ISO/IEC 9075-14:2005. Definiendo cómo SQL puede utilizarse conjuntamente con XML:

  • Importar y guardar datos XML en una base de datos SQL, manipulándolos dentro de la base de datos y publicando el XML y los datos SQL convencionales en forma XML
  • Facilidades que permiten a las aplicaciones integrar dentro de su código SQL el uso de XQuery, lenguaje de consulta XML publicado por el W3C (World Wide Web Consortium) para acceso concurrente a datos ordinarios SQL y documentos XML

2008, apareció una nueva versión denominada SQL:2008. En la cual se agregó el uso de la cláusula ORDER BY fuera de las definiciones de los cursores. Incluyendo disparadores del tipo INSTEAD OF. Y la inclusión de la sentencia TRUNCATE

2011, apareció una nueva versión denominada SQL:2011. En la cual se agregaron los datos temporales (PERIOD FOR) y mejoras en las funciones de ventana y de la cláusula FETCH

2016, apareció una nueva versión denominada SQL:2016. En la cual se agregó la búsqueda mediante patrones, funciones de tabla polimórficas y compatibilidad con los ficheros JSON

LDD

Lenguaje de definición de datos (LDD)

El lenguaje de definición de datos (LDD), es el que se encarga de la modificación de la estructura de los objetos de la base de datos

Incluye órdenes para modificar, borrar o definir las relaciones (tablas) en las que se almacenan los datos de la base de datos

Existen cuatro operaciones básicas:

Definición de los datos

El conjunto de relaciones de cada base de datos debe especificarse en el sistema en términos de un lenguaje de definición de datos (LDD)

El LDD de SQL no sólo permite la especificación de un conjunto de relaciones, sino también de la información relativa a esas relaciones, incluyendo:

  • El esquema de cada relación
  • El dominio de valores asociado a cada atributo
  • Las restricciones de integridad
  • El conjunto de índices que se deben mantener para cada relación
  • La información de seguridad y de autorización de cada relación
  • La estructura de almacenamiento físico de cada relación en el disco

Tipos básicos de dominios

La norma SQL soporta gran variedad de tipos de dominio predefinidos:

  • CHAR(n)

    Una cadena de caracteres de longitud fija, con una longitud n especificada por el usuario. También se puede utilizar la palabra completa character

  • VARCHAR(n)

    Una cadena de caracteres de longitud variable con una longitud máxima n especificada por el usuario. La forma completa, character varying, es equivalente

  • INT

    Un entero (un subconjunto finito de los enteros dependiente del ordenador). La palabra completa, integer, es equivalente

  • SMALLINT

    Un entero pequeño (un subconjunto dependiente del ordenador del tipo de dominio entero)

  • NUMERIC(p, d)

    Un número en coma fija, cuya precisión la especifica el usuario. El número está formado por p dígitos (más el signo) y de esos p dígitos, d pertenece a la parte decimal

  • DOUBLE

    Un número en coma flotante y números en coma flotante de doble precisión, con precisión dependiente del ordenador

  • FLOAT(n)

    Un número en coma flotante cuya precisión es, al menos, de n dígitos

  • DATE

    Dato de tipo fecha, con una precisión de hasta segundo

Definición básica de esquemas

CREATE TABLE

Las relaciones se definen mediante el comando CREATE TABLE:

\text{CREATE TABLE r} (\\ A_1 D_1, \cdots, A_n D_n,\\ \{rest-integridad_1\}, \cdots, \{rest-integridad_k\} )

Donde r es el nombre de relación, cada Ai es el nombre de un atributo del esquema de la relación r y Di es el tipo de dominio de los valores del dominio del atributo Ai

Hay varias restricciónes de integridad válidas

Una de las más usadas es la de clave primaria (primary key), que adopta la siguiente forma:

\text{primary key}(A_{j1}, \cdots, A_{jm})

La especificación de clave primaria determina los atributos A_{j1}, \cdots, A_{jm} forman la clave primaria de la relación

Los atributos de la clave primaria tienen que ser no nulos y únicos; es decir, ninguna tupla puede tener un valor nulo para un atributo de la clave primaria y ningún par de tuplas de la relación puede ser igual en todos los atributos de la clave primaria

Aunque la especificación de clave primaria es opcional, suele ser una buena idea especificar una clave primaria para cada relación

En el ejemplo se ha creado una relación llamada cuenta en la cual se han definido los atributos:

numero_cuenta, que puede guardar una palabra de hasta 10 carácteres
nombre_sucursal, que puede guardar una palabra de hasta 15 carácteres
saldo, que puede guardar un número decimal con 12 enteros y 2 decimales
Y con la restricción sobre numero_cuenta como clave primaria de la relación

Si una tupla recién insertada o recién modificada de una relación contiene valores nulos para cualquiera de los atributos que forman parte de la clave primaria, o si tienen el mismo valor que otra tupla de la relación, SQL notificará el error e impedirá la actualización

En el ejemplo se ha creado otra relación llamada cliente en la cual se han definido los atributos:

numero_cuenta, que puede guardar una palabra de hasta 10 carácteres
nombre_cliente, que puede guardar una palabra de hasta 15 carácteres
Y con la restricción sobre numero_cuenta como clave primaria de la relación

Como puede verse podemos crear más de una relación

DROP TABLE

Para eliminar una relación de la base de datos se utiliza el comando DROP TABLE

Este comando elimina de la base de datos toda la información sobre la relación

En el ejemplo se ha elimina de la base de datos toda la información sobre la relación cuenta

Este comando es más drástico que DELETE, que sólo borra sus tuplas manteniendo el esquema de la relación

Sin embargo, DROP, si se elimina cuenta, no se podrá volver a insertar ninguna tupla en dicha relación, a menos que se vuelva a crear con el comando CREATE TABLE

ALTER TABLE

El comando ALTER TABLE se utiliza para añadir atributos a una relación existente

Como valor del nuevo atributo se asigná a todas las tuplas de la relación el valor nulo

En el ejemplo se ha añadido un nuevo atributo

Donde cuenta es el nombre de la relación existente, ano es el nombre del atributo que se desea añadir y DATETIME es el dominio del atributo añadido

También se pueden eliminar atributos usando ALTER TABLE

En el ejemplo se ha eliminado el atributo que añadimos antes

Donde cuenta es el nombre de la relación existente y ano es el nombre del atributo que se desea eliminar

En este caso no es necesario declarar el dominio del atributo a borrar

Muchos sistemas de bases de datos no permiten el borrado de atributos, aunque sí que permiten el borrado de tablas completas

TRUNCATE

Este comando solo se aplica a tablas y su función es borrar el contenido completo de la relación especificada

La ventaja sobre el comando DELETE, es que si se quiere borrar todo el contenido de la relación, es mucho más rápido, especialmente si la relación es muy grande

La desventaja es que TRUNCATE sólo sirve cuando se quiere eliminar absolutamente todas las tuplas, ya que no se permite la cláusula WHERE

Si bien, en un principio, esta sentencia parecería ser LMD (Lenguaje de Manipulación de Datos), es en realidad una LDD, ya que internamente, el comando TRUNCATE borra la tabla y la vuelve a crear y no ejecuta ninguna transacción

En el ejemplo hemos borrado todo el contenido de la relación llamada cuenta