¿Cómo se calcula el punto flotante en una base distinta de 10?
-
06-09-2019 - |
Pregunta
Dado el artículo de Wikipedia sobre Punto de base, ¿cómo se calcularía el equivalente binario de 10,1 o el equivalente hexadecimal de 17,17?Para el primero, ¿cuál es el equivalente binario de un décimo?Para este último, ¿la representación hexadecimal de 17/100?
Estoy buscando más un algoritmo que soluciones solo para esos dos ejemplos.
Solución
Para convertir el decimal 10.1 a binario, separe las partes entera y fraccionaria y convierta cada una por separado.
Para convertir la parte entera, use la división entera repetida por 2 y luego escriba los restos en orden inverso:
10/2 = 5 resto 0
5/2 = 2 resto 1
2/2 = 1 resto 0
1/2 = 0 resto 1
Respuesta:1010
Para convertir la parte fraccionaria, usa la multiplicación repetida por 2, restando la parte entera en cada paso.Las partes enteras, en orden de generación, representan su número binario:
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
...(el ciclo se repite para siempre)
Entonces el decimal 0,1 es el binario 0,000110011001100...
(Para una explicación más detallada vea las rutinas dec2bin_i() y dec2bin_f() en mi artículo http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ .)
Para hexadecimal, utilice el mismo procedimiento, excepto con un divisor/multiplicador de 16 en lugar de 2.Los restos y las partes enteras mayores que 9 deben convertirse directamente a dígitos hexadecimales:10 se convierte en A, 11 se convierte en B, ..., 15 se convierte en F.
Otros consejos
Un número de terminación (un número que puede ser representado por un número finito de dígitos) n 1 en base b 1 , puede llegar a ser un número no termina en una base diferente b 2 . A la inversa, un número no termina en una base b 1 puede llegar a ser un número de terminación en base b 2 .
El número 0.1 10 cuando se convierte a binario es un número no termina, como es 0.17 10 cuando se convierte a un número hexadecimal. Pero el número de terminación 0.1 3 en la base 3, cuando se convierte a la base 10 es la no terminación, repitiendo número 0. (3) 10 (que significa que el número 3 repeticiones ). Del mismo modo, la conversión de 0,1 10 a binario y 0,17 10 a hexadecimal, uno termina con la no terminación, números 0.0 (0011) repetir 2 y 0,2 (B851E) 16
Debido a esto, al convertir un número tal de una base a otra, se puede notar que tiene para aproximar el número en lugar de tener una representación que es completamente exacta.
El algoritmo es bastante simple, pero en la práctica se puede hacer un montón de ajustes tanto con tablas de búsqueda y los registros para acelerarlo. Pero para el algoritmo básico, puede intentar algo como esto:
shift=0;
while v>=base, v=v/base, shift=shift+1;
Next digit:
if v<1.0 && shift==0, output the decimal point
else
D=floor(v)
output D
v=v-D
v=v*base
shift = shift-1
if (v==0) exit;
goto Next Digit
También se puede poner una prueba en la que hay que parar la impresión después de n dígitos durante más tiempo decimales periódicos.
El 'equivalente binario' de un décimo es una media, es decir en lugar de 1/10 ^ 1, que es 1/2 ^ 1.
Cada dígito representa una potencia de dos. Los dígitos detrás de la coma de la base son los mismos, es sólo que ellos representan 1 sobre la potencia de dos:
8 4 2 1 . 1/2 1/4 1/8 1/16
Así que para 10.1, es obvio que necesita un '8' y '2' para hacer que la parte 10. Un medio (0,5) es demasiado, 1/4 (0,25) es demasiado, 1/8 (0,125) es demasiado. Necesitamos 1/16 (0,0625), lo que nos dejará con 0,0375. 1/32 es 0,03125, así que puede tomar eso también. Hasta el momento tenemos:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32
1 0 1 0 0 0 0 1 1
Con un error de 0,00625. 1/64 (0.015625) y 1/128 (0,0078125) son a la vez demasiado, 1/256 (0,00390625) funcionará:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
1 0 1 0 0 0 0 1 1 0 0 1
Con un error de 0,00234375.
El 0.1 no se puede expresar exactamente en binario (al igual que 1/3 no se puede expresar exactamente en decimal). Dependiendo de donde usted pone su raíz, que finalmente tiene que parar, probablemente redonda, y aceptar el error.
Antes de girar con esto a la luz de mi librería GMP, aquí es donde tengo que tratar de hacer que el código PHP de Rick Regan genérico para cualquier base de 2 a 36.
Function dec2base_f(ByVal ddecimal As Double, ByVal nBase As Long, ByVal dscale As Long) As String
Const BASES = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'up to base 36
Dim digitCount As Long
Dim wholeNumber As Double
Dim digit As String * 1
digitCount = 0
dscale = max(dscale, Len(CStr(ddecimal)) - Len("0."))
Dim baseary_f As String
baseary_f = "0."
Do While ddecimal > 0 And digitCount < dscale
ddecimal = ddecimal * nBase
digit = Mid$(BASES, Fix(ddecimal) + 1)
baseary_f = baseary_f & digit '"1"
ddecimal = ddecimal - Fix(ddecimal)
digitCount = digitCount + 1
Loop
dec2base_f = baseary_f
End Function
Function base2dec_f(ByVal baseary_f As String, nBase As Double) As Double
Const BASES As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim decimal_f As Double
Dim i As Long
Dim c As Long
For i = Len(baseary_f) To Len("0.") + 1 Step -1
c = InStr(BASES, Mid$(baseary_f, i, 1)) - 1
decimal_f = decimal_f + c
decimal_f = decimal_f / nBase
Next
base2dec_f = decimal_f
End Function
Debug.Print base2dec_f(dec2base_f(0.09, 2, 200), 2) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 8, 200), 8) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 16, 200), 16) --> 0.09