2009-03-01 17 views
6

Supponiamo di avere un valore float nell'intervallo [0, 1] e di voler quantizzare e memorizzarlo in un byte senza segno. Suona come un gioco da ragazzi, ma in realtà è piuttosto complicato:Converti/Quantizza intervallo float su intero Intervallo

La soluzione più ovvia è simile al seguente:

unsigned char QuantizeFloat(float a) 
{ 
    return (unsigned char)(a * 255.0f); 
} 

Questo funziona nella misura che ho tutti i numeri da 0 a 255, ma la distribuzione degli interi non è pari. La funzione restituisce solo 255 se a è esattamente 1.0f. Non è una buona soluzione.

Se faccio corretto arrotondamento me a spostare il problema:

unsigned char QuantizeFloat(float a) 
{ 
    return (unsigned char)(a * 255.0f + 0.5f); 
} 

Qui il risultato 0 copre solo metà del galleggiante gamma di qualsiasi altro numero.

Come si effettua una quantizzazione con distribuzione equa dell'intervallo di virgola mobile? Idealmente mi piacerebbe ottenere una distribuzione equa degli interi se quantizzo equamente i float casuali distribuiti equamente.

Qualche idea?


Btw: Anche il mio codice è in C il problema è linguistico-indipendente. Per le persone che non fanno parte di C: supponiamo che la conversione da float a int tronca il float.

EDIT: Dato che avevamo una certa confusione qui: ho bisogno di una mappatura che mappa il galleggiante di ingresso più piccolo (0) al più piccolo unsigned char, e il più alto galleggiante della mia fascia (1.0f) al più alto byte senza segno (255).

risposta

10

Che ne dici di a * 256f con un controllo per ridurre 256 a 255? Quindi, qualcosa di simile a:

return (unsigned char) (min(255, (int) (a * 256f))); 

(Per una opportuna funzione min sulla vostra piattaforma - non riesco a ricordare la funzione C per esso.)

In sostanza si vuole dividere la gamma in 256 parti uguali, che è quello che dovrebbe fare. Il caso limite per 1.0 che va a 256 e che richiede arrotondamento è solo perché il dominio è inclusivo alle due estremità.

+0

wow - sì, è proprio così! –

+0

Sì - (unsigned char) (a * 256.0f) fornisce esattamente ciò che si desidera per ogni valore di input ad eccezione di 1.0.C non ha una funzione min integrata, quindi dovrai scrivere la tua se non lo hai già fatto. –

+0

John, mi è venuta in mente lo stesso risultato, non è stato in grado di trasferirlo correttamente dal foglio di calcolo di Excel. Ho cancellato la mia risposta imbarazzante. – cdonner

1

penso che quello che stai cercando è questo:

unsigned char QuantizeFloat (float a) 
{ 
    return (unsigned char) (a * 256.0f); 
} 

Ciò mappare valori float uniformi in [0, 1] per valori di byte uniformi in [0, 255]. Tutti i valori in [i/256, (i + 1)/256 [(che è escluso (i + 1)/256), per i in 0..255, sono mappati a i. Quello che potrebbe essere indesiderabile è che 1.0f è mappato a 256.0f che si avvolge attorno a 0.

0

Uno può diffondere l'errore una tantum su tutto l'intervallo mantenendo la stessa distribuzione come si farebbe con un balzo secondo il 31 dicembre .

limit = 4 
maxi = limit - 1 

n = 16 
for i in range(n): 
    x = i/(n - 1) 

    a = x * maxi # Wrong distribution 
    b = x * limit # One off 
    c = x * (limit - 1/limit) 

    print(f"{x:.3f} | {a:.3f} | {b:.3f} | {c:.3f}") 

-

0.000 | 0.000 | 0.000 | 0.000 
0.067 | 0.200 | 0.267 | 0.250 
0.133 | 0.400 | 0.533 | 0.500 
0.200 | 0.600 | 0.800 | 0.750 
0.267 | 0.800 | 1.067 | 1.000 
0.333 | 1.000 | 1.333 | 1.250 
0.400 | 1.200 | 1.600 | 1.500 
0.467 | 1.400 | 1.867 | 1.750 
0.533 | 1.600 | 2.133 | 2.000 
0.600 | 1.800 | 2.400 | 2.250 
0.667 | 2.000 | 2.667 | 2.500 
0.733 | 2.200 | 2.933 | 2.750 
0.800 | 2.400 | 3.200 | 3.000 
0.867 | 2.600 | 3.467 | 3.250 
0.933 | 2.800 | 3.733 | 3.500 
1.000 | 3.000 | 4.000 | 3.750 
Problemi correlati