mercoledì 6 ottobre 2010

Conversione numeri decimali in IEEE-754-32bit

Per un pò di teoria sullo standard IEEE-754 rimando alla pagina di Wikipedia. Qui posto solamente la funzione per effettuare la conversione in R.


Innanzitutto scriviamo alcune funzioni per eseguire la conversione dei numeri decimali in numeri binari:


decInt_to_8bit <- function(x, precs) {
q <- c()
r <- c()
xx <- c()
for(i in 1:precs){
xx[1] <- x
q[i] <- xx[i] %/% 2
r[i] <- xx[i] %% 2
xx[i+1] <- q[i]
}
rr <- rev(r)
return(rr)
}

devDec_to_8bit <- function(x, precs) {
nas <- c()
nbs <- c()
xxs <- c()
for(i in 1:precs)
{
xxs[1] <- x*2
nas[i] <- (xxs[i]) - floor(xxs[i])
nbs[i] <- trunc(xxs[i], 1)
xxs[i+1] <- nas[i]*2
}
return(nbs)
}


La prima funzione permette di convertire numeri interi (o prima della virgola) in codice binario, mentre la seconda permette di eseguire la conversione dei numeri decimali (dopo la virgola).
Il parametro precs indica il numero di bit da utilizzare.

Ad esempio:


decInt_to_8bit(11, 8)
[1] 0 0 0 0 1 0 1 1


Il numero 11, in codice binario a 8 bit è: 00001011.


devDec_to_8bit(0.625, 8)
[1] 1 0 1 0 0 0 0 0


Il numero 0.625 in codice binario a 8 bit è 10100000. Aumentando la precisione, nel primo caso permettiamo il calcolo di numeri superiori a 256 (limite massimo per gli 8-bit), mentre nel secondo caso permette di aumentare la precisione dopo la virgola:


devDec_to_8bit(0.3, 8)
[1] 0 1 0 0 1 1 0 0
devDec_to_8bit(0.3, 16)
[1] 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0


Ritornando ai primi due esempi, possiamo eliminare gli zeri in abbondanza con le seguenti due funzioni:


remove.zero.aft <- function(a) {
n <- length(a)
for(i in n:1){
if (a[n]==0) a <- a[-n]
else return(a)
n <- n-1
}
}

remove.zero.bef <- function(a) {
n <- length(a)
for(i in 1:n){
if (a[1]==0) a <- a[-1]
else return(a)
}
}


Abbiamo quindi:


remove.zero.bef(decInt_to_8bit(11, 8))
[1] 1 0 1 1

remove.zero.aft(devDec_to_8bit(0.625, 8))
[1] 1 0 1


Possiamo unire le due funzioni per crearne una che converte numeri decimali con la virgola in numeri binari:


dec.to.nbit <- function(x,n) {
aa <- abs(trunc(x, 1))
bb <- abs(x) - abs(trunc(x))

q <- c()
r <- c()
xx <- c()
for(i in 1:n){
xx[1] <- aa
q[i] <- xx[i] %/% 2
r[i] <- xx[i] %% 2
xx[i+1] <- q[i]
}
rr <- rev(r)

nas <- c()
nbs <- c()
xxs <- c()
for(i in 1:n)
{
xxs[1] <- bb*2
nas[i] <- (xxs[i]) - floor(xxs[i])
nbs[i] <- trunc(xxs[i], 1)
xxs[i+1] <- nas[i]*2
}

bef <- paste(remove.zero.bef(rr), collapse="")
aft <- paste(remove.zero.aft(nbs), collapse="")
bef.aft <- c(bef, aft)
strings <- paste(bef.aft, collapse=".")
return(strings)
}


Abbiamo quindi:


dec.to.nbit(11.625,8)
[1] "1011.101"





Imparato quindi a convertire i numeri decimali in numeri binari, possiamo passare alla conversione in IEEE-754 single precision (ossia 32bit), utilizzando la seguente funzione:


dec.to.ieee754 <- function(x) {
aa <- abs(trunc(x, 1))
bb <- abs(x) - abs(trunc(x))

rr <- decInt_to_8bit(aa, 32)

ppc <- 24 - length(remove.zero.bef(rr))

nbs <- devDec_to_8bit(bb, ppc)

bef <- remove.zero.bef(rr)
aft <- remove.zero.aft(nbs)

exp <- length(bef) - 1
mantissa <- c(bef[-1], aft)

exp.bin <- decInt_to_8bit(exp + 127, 16)
exp.bin <- remove.zero.bef(exp.bin)

first <- c()
if (sign(x)==1) first=c(0)
if (sign(x)==-1) first=c(1)

ieee754 <- c(first, exp.bin, mantissa, rep(0, 23-length(mantissa)))
ieee754 <- paste(ieee754, collapse="")

return(ieee754)
}


Il numero 11.625 in IEEE-754 è:


dec.to.ieee754(11.625)
[1] "01000001001110100000000000000000"


Per utilizzare la funzione dec.to.ieee754 servono le funzioni scritte sopra: decInt_to_8bit, devDec_to_8bit, remove.zero.bef, remove.zero.aft.

Per sicurezza potete confrontare questo output con quello che si ottiene da questo convertitore online

Nessun commento:

Posta un commento