jueves, 6 de mayo de 2021

Cómo expresar en el sistema de numeración binario la parte fraccionaria de un número dado en el sistema de numeració decimal

En otras entradas del blog ya hemos hablado de cómo expresar en el sistema binario ( con unos y ceros, que es su expresión en el lenguaje máquina ) un número entero que venga dado en el sistema de numeración decimal. Consideremos por ejemplo el número $11_{10}$ ( en base $10$ ), resultando que $11_{10}=1011_{2}$ (en base binaria o base $2$, con tan sólo los símbolos $\{0,1\}$, a los que denominamos bits.

Ésto es así porqué, dividiendo sucesivamente por $2$ ( que es el número de símbolos del alfabeto de numeración binario ) el número en cuestión, y teniendo en cuenta el teorema de la división entera, al llevar a cabo las divisiones sucesivas de $11$ entre $2$:
$11=5 \cdot 2+\textbf{1}$
$5=2\cdot 2+\textbf{1}$
$2=\textbf{1}\cdot 2+\textbf{0}$
hasta llegar a una división con resto cero - en este caso, la tercera -, tomamos el bit menos significativa como el valor del último cociente, seguido por el bit que corresponde al resto de dicha división, y, así, siguiendo con las divisiones anteriores hasta obtener el bit más significativo, que corresponde al resto de la primera división. En efecto, al escribir el número en forma desarrollada, $1\cdot 2^3+0\cdot 2^2+1\cdot 2^1+ 1\cdot 2^0$, vemos que dicha suma, $8+2+1$, es igual a $11_{10}$

-oOo-

Ya sabemos hacer lo anterior; sin embargo, nos interesa también aprender a expresar en base binaria la parte fraccionaria de un número que viene dado en base diez. Consideremos pues la parte fraccionaria de un número dado en el sistema de numración decimal; por ejemplo, de $11,316_{10}$, esto es $\text{frac}(11,316_{10})=0,316_{10}$ . Veamos cómo podemos expresarla pues en el sistema de numeración binario ( con ceros y unos ).

Como observación preliminar - que tal vez resulte una obviedad al operar en base $10$, si bien nos guiará para hacer lo análogo al operar en base $2$ - démonos cuenta de que para obtener de manera mecánica las cifras decimales de dicho número podemos proceder de la siguiente manera ( pongamos que quién lo haga es un ordenador, y así deberíamos programarlo ):

i) Tomemos la parte fraccionaria, $0,316_{10}$, y multipliquémosla por la base de numeración - que es $10$ -, $0,316_{10} \cdot 10 =3,16_{10}$, lo cual, obviamente, nos proporciona la cifra de las décimas: $3$

ii) Tomamos ahora la parte fraccionaria de $3,16_{10}$, $\text{frac}(3,16_{10})=0,16_{10}$, y multipliquémosla por la base de numeración, $10$, así $0,16_{10} \cdot 10 =1,6_{10}$, lo cual nos proporciona la cifra de las centésimas: $1$

iii) Y, finalmente - puesto que sólo hay tres cifras decimales -, tomamos la parte fraccionaria de $1,6_{10}$, $\text{frac}(1,6_{10})=0,6_{10}$, y multipliquémosla por la base de numeración, $10$, así $0,6_{10} \cdot 10 =6_{10}$, lo cual nos proporciona la cifra de las milésimas: $6$

Fijémonos en el hecho de que, al escribir dicha cantidad en forma desarrollada: $$3\cdot 10^{-1}+1\cdot 10^{-2}+6\cdot 10^{-3}$$ obtenemos, como es bien claro, dicha parte fraccionaria:
$$0,3+0,01+0,006= 0,316$$

-oOo-

Pues bien, ahora vamos a proceder de manera análoga, con $0,632_{10}$ ( la parte decimal de $11,632_{10}$ ) pero expresándonos en base $2$, al objeto de ir obteniendo las cifras ( unos y ceros ) de las partes enteras que vayan resultando en los sucesivos cálculos, y que iremos concatenando desde el bit más significativo al menos significativo, $$.\square \,\square\, \ldots$$ en el orden que vayamos realizando dichas operaciones -- Nota: por $\text{ent}(.)$ nos referiremos a la cifra que quede a la izquierda de la coma/punto decimal, que será un uno o bien un cero --:

$\text{frac}(0,632_{10})\cdot 2=0,316_{10}\cdot 2=0,632 \rightarrow \text{ent}(\textbf{0},632_{10})=\textbf{0} \rightarrow \;.\textbf{0} \square \, \square \, \ldots_{2}$
$\text{frac}(0,632_{10})\cdot 2=0,632_{10}\cdot 2=1,264 \rightarrow \text{ent}(\textbf{1},264_{10})=\textbf{1} \rightarrow \;.0\textbf{1} \square \, \square \, \ldots_{2}$
$\text{frac}(1,264_{10})\cdot 2=0,264_{10}\cdot 2=0,528 \rightarrow \text{ent}(\textbf{0},528_{10})=\textbf{0} \rightarrow \;.01\textbf{0} \square \, \square \, \ldots_{2}$
$\text{frac}(0,528_{10})\cdot 2=0,528_{10}\cdot 2=1,056 \rightarrow \text{ent}(\textbf{1},056_{10})=\textbf{1} \rightarrow \;.010\textbf{1} \square \, \square \, \ldots_{2}$
$\text{frac}(1,056_{10})\cdot 2=0,056_{10}\cdot 2=0,112 \rightarrow \text{ent}(\textbf{0},112_{10})=\textbf{0} \rightarrow \;.0101\textbf{0} \square \, \square \, \ldots_{2}$
$\text{frac}(0,112_{10})\cdot 2=0,112_{10}\cdot 2=0,224 \rightarrow \text{ent}(\textbf{0},224_{10})=\textbf{0} \rightarrow \;.01010\textbf{0} \square \, \square \, \ldots_{2}$
$\text{frac}(0,224_{10})\cdot 2=0,224_{10}\cdot 2=0,448 \rightarrow \text{ent}(\textbf{0},448_{10})=\textbf{0} \rightarrow \;.010100\textbf{0} \square \, \square \, \ldots_{2}$
$\text{frac}(0,448_{10})\cdot 2=0,448_{10}\cdot 2=0,896 \rightarrow \text{ent}(\textbf{0},896_{10})=\textbf{0} \rightarrow \;.0101000\textbf{0} \square \, \square \, \ldots_{2}$
$\vdots$

-oOo-

Nos encontramos ahora con la necesidad de reflexionar acerca del error de representación finita de dicha cantidad (en los registros binarios de un computador, que, naturalmente, son de longitud finita), puesto que, al tener ésta infinitos bits, necesariamente debe ser aproximada para poder ser representada (con el número finito de bits de los registros de memoria de datos de la máquina).

Démonos cuenta de que el proceso no termina nunca, esto es, la parte decimal del número expresada en el sistema binario tiene infinitas cifras, a pesar de que al expresarse en el sistema decimal dicha parte decimal sea finita. Ésto plantea un problema importante: a la hora de representar en los registros del computador dicha cantidad - que tienen una longitud finita - deberemos cortar la parte decimal en algún lugar, lo cual introduce un inevitable error (de representación).

En la representación finita ( de la máquina ) en coma flotante en lo que viene a llamarse "simple precisión", la mantisa - que es el número decimal del tipo $.01010000 \ldots$ - tiene una longitud de $23$ bits. Así que podríamos continuar el proceso anterior hasta sacar $15$ cifras binarias (bits) más. Sin embargo, veamos que sucede con el error de representación si nos quedásemos sólo con $8$ bits, esto es $0,632_{10} \approx .01010000_{2}$ [ Nota: Al expresar la cantidad en el sistema binario, suele utilizarse el punto decimal (en lugar de la coma, usada en nuestro país habitualmente en la expresiones en el sistema de numeración decimal) para indicar que a su derecha escribiremos las cifras binarias correspondientes a la parte fraccionaria del número en cuestión ].

La representación finita $.01010000_{2}$ corresponde a la siguiente cantidad
$0\cdot 2^{-1}+1\cdot 2^{-2}+0\cdot 2^{-3}+1\cdot 2^{-4}+0\cdot 2^{-5}+0\cdot 2^{-6}+0\cdot 2^{-7}+0\cdot 2^{-8}=$
$=2^{-2}+2^{-4}$
$=1/4+1/16$
$=5/16$
$=0,3125_{10} \neq 0,316_{10}$

Así pues, el error absoluto de la aproximación es $|0,316-0,3125|=0,0035$, y por tanto el error relativo es de $\dfrac{0,0035}{0,316}\approx 0,00111 = 1,11\,\%$. Es claro que para aumentar la precisión debemos aumentar el número de bits de la representación, por lo que con $23$ bits, el error relativo es, seguro, muchísimo menor. Dejo a la persona lectora el interesante ejercicio de calcularlo, retomando los cálculos donde los he dejado ( en el octavo bit ).
$\square$

No hay comentarios:

Publicar un comentario