2012-03-15 12 views
9

Ho bisogno di memorizzare i valori in un intervallo compreso tra -10000 e 10000. Ai margini dell'intervallo, la precisione necessaria non è molto alta (forse circa 64, vedrò come si adatta), intorno allo zero la precisione deve essere 1 o migliore.Ricerca di una libreria half float o quarter float

Purtroppo lo spazio è molto limitato, non più di 12 bit, meno sarebbe anche meglio. In senso stretto, anche half floats sono fuori. Esiste una libreria open source che gestisce alcuni formati float molto brevi con mantissa breve e lunghezza esponenziale? Come la mantissa a 8 bit e l'esponente a 3 bit.

È richiesta solo la conversione da/verso i formati più grandi, non viene eseguita alcuna operazione aritmetica.

+0

Con un esponente di 3 bit si avrebbe una precisione minima di 128. – xanatos

+0

Sì, molto probabilmente finirò per cucinare qualcosa da solo usando bitfield. Ma sono interessato a vedere le soluzioni che altri hanno trovato - se ce ne sono. – hirschhornsalz

+0

@xanatos: solo se ci si attiene a una radice di 2. Se si passa a una radice di 10, ha solo bisogno di mantissa a 9 bit, radix a 2 bit. (Precisione di 39 vicino a 10000) –

risposta

3

Forse μ-law o A-law potrebbe essere utile per voi.

+1

oh, pensiero interessante. Dovresti espandere questa risposta. Un sacco. –

+0

Se è preciso al più vicino 1 da 0-12, precisione 2 da 13-25, precisione 3 da 26-38 ... è la precisione 39 da 9671-10139 e si adatta a 9 bit! (lasciando 10 bit per segno) Non ho idea di come fare la matematica per questo però. –

+0

Molto interessante. Ho implementato qualcosa di pratico con solo 4 intervalli nel mio vecchio codice. Ora cercherò di trovare un'efficace generalizzazione o astrazione e vedere quale rapporto di intervalli/valori si adatta meglio. – hirschhornsalz

4

Se non si sta eseguendo alcun calcolo, non c'è quasi bisogno di una libreria. frexp, ldexp e un po 'di smarrimento dovrebbe fare il lavoro.

2

Utilizziamo libHalf fornito con openexr. Non ne sono un grande fan in quanto la qualità del codice non è esattamente stellare (anche se non è seriamente rotto). Cerca la directory denominata Half nelle origini estratte: dovrebbe essere indipendente.

1

Estrapolando dalla risposta di Jens Björnhager, ho ottenuto questo:

double from_storage(unsigned short bits) { //only lowest 10 bits read 
     double a = bits&0x1FF; 
     a /= 5.11967985; 
     a = a*a; 
     return double(bits&0x200 ? -a : a); 
} 

unsigned short to_storage(double a) { //only lowest 10 bits set/relevant 
     assert(a<=10000.0); 
     assert(a>=-10000.0); 
     if (a >= 0) { 
       a = std::pow(a, .5); // inverse of number in from_storage 
       a *= 5.11967985; 
       unsigned short b = ((unsigned short)(a)); 
       assert((b&0x200)==0); 
       return b; 
     } else { 
       a = std::pow(-a, .5); 
       a *= 5.11967985; 
       unsigned short b = ((unsigned short)(a)); 
       assert((b&0x200)==0); 
       return b | 0x200; 
     } 
} 

come dimostrato in http://ideone.com/DLTUn. Questo può contenere in modo univoco ciascuno dei valori compresi tra -10 e 10 e i valori superiori sono solo 39. (Ci sono anche 3 valori tra 0 e 1). Qualcuno più math potrebbe probabilmente ottenere il positivo e il negativo a più di un formato "complimento di due", che ridurrebbe il codice to_storage a metà.

+1

Grazie per l'input. Penso che userò qualche variante di μ-Law (che è molto simile a un quarto di float) estesa a 11 o 12 bit. Ho bisogno di memorizzare diversi 10^9 di questi valori (il più, meglio è), questo è il motivo principale per cui voglio salvare ogni bit. La velocità di conversione è un'altra preoccupazione: la capacità di rallentare è più probabile, ma un approccio basato su tabelle andrà bene. – hirschhornsalz

+0

@drhirsch: funziona sulla stessa falsariga di μ-Law, tranne che con una curva morbida. Un approccio basato su tabelle potrebbe essere più veloce, ma sarebbe più complicato.Penso che il tavolo sia la risposta migliore in assoluto. –