2012-05-02 11 views
5

Sì, sono a conoscenza dello standard di precisione a IEEE-754 e sì, sono a conoscenza del lavoro svolto sul campo. In parole semplici, sto cercando di salvare un semplice numero in virgola mobile (come 52.1 o 1.25) in soli 2 byte.Come si salva un numero in virgola mobile in 2 byte?

Ho provato alcune implementazioni in Java e in C# ma hanno rovinato il valore di input decodificando un numero diverso. Si nutre in 32.1 e dopo la codifica-decodifica si ottiene 32.0985.

C'è QUALUNQUE modo per memorizzare numeri in virgola mobile in soli 16 bit senza rovinare il valore di input?

Grazie mille.

+5

I punti di galleggiamento binari non possono codificare '32.1' – CodesInChaos

+2

Quale intervallo di numeri è necessario codificare e quante cifre significative hanno? Considerare i punti decimali fissi o mobili. – CodesInChaos

+0

Puoi memorizzarlo come un 'corto senza segno ', con alcuni bit usati per la parte esponenziale? Dovresti quindi riconvertire manualmente da questo formato a un normale 'float' di precisione singola. – Matthew

risposta

5

È possibile memorizzare tre cifre in BCD e utilizzare i restanti quattro bit per la posizione del punto decimale:

52.1 = 521 * 10^-1 => 0x1521 
1.25 = 125 * 10^-2 => 0x2125 

Questo darebbe una gamma 0,0000000000000001-999.Ovviamente si può aggiungere un offset per il punto decimale per ottenere ad esempio la gamma 0,0000,000001 millions al 999000000.


semplice implementazione di quattro bit utilizzato per il posizionamento del punto decimale, e il resto per il valore. Senza alcun controllo degli errori, e non accuratamente controllato. (Può avere problemi di precisione con alcuni valori quando si utilizza != per confrontare doppie.)

public static short Encode(double value) { 
    int cnt = 0; 
    while (value != Math.Floor(value)) { 
    value *= 10.0; 
    cnt++; 
    } 
    return (short)((cnt << 12) + (int)value); 
} 

public static double Decode(short value) { 
    int cnt = value >> 12; 
    double result = value & 0xfff; 
    while (cnt > 0) { 
    result /= 10.0; 
    cnt--; 
    } 
    return result; 
} 

Esempio:

Console.WriteLine(Encode(52.1)); 
Console.WriteLine(Decode(4617)); 

uscita:

4617 
52.1 
+0

@Geotarget: è possibile comprimere 4 cifre in due byte, ma in questo caso sono rimasti solo due bit per descrivere dove si trova il punto decimale. Per i numeri con meno cifre basta riempire con zeri, ad esempio '1.5' è uguale a' 001.5' o '1.500'. – Guffa

+0

Potete mostrare esempi di funzioni di codifica/decodifica binarie? Mi dispiace ma non capisco cosa stia accadendo. –

+0

@Geotarget: ho aggiunto una semplice implementazione sopra. – Guffa

3

Il problema è che non è possibile rappresentare con precisione 32.1 in qualsiasi tipo di binario a virgola mobile.

In precisione singola, il valore rappresentativo più vicino è 32.099998. A metà precisione, è apparentemente 32.0985.

È possibile considerare un tipo decimale a virgola mobile, ma questa soluzione non è esclusiva della precisione a metà.

+0

Un valore di precisione a metà utilizza 11 bit per il significando (il bit iniziale 1 è implicito). Nell'intervallo [32,64), 6 di questi bit vengono utilizzati per la parte intera, lasciando 5 bit per la parte frazionaria. Quindi in quel dominio [32,64), i valori rappresentabili sono esattamente i multipli di 1/(2 ** 5) = 1/32. Il più vicino a '32.1' sarà 32 + 3/32 (a.k.a. 1027/32) che è' 32.09375'. Quindi il tuo "apparentemente" non è corretto, dopotutto. Non so da dove il richiedente abbia tratto il suo esempio. Per un valore di precisione a metà, normalmente si genererebbero solo 3 cifre decimali, quindi "32.1" sarebbe la solita precisione. –

1

Dai propri esempi si desidera memorizzare 3 cifre e un punto decimale. Potresti semplicemente codificare il tuo "alfabeto" di 11 simboli in un codice a 4 bit e memorizzare 4 x 4 bit in 2 byte.

Scommetto che ora "spieghi" che il tuo requisito non è soddisfatto da questo approccio!

+0

sì, qualcosa come il decimale in codice binario funzionerebbe bene – Kell

6

C# non ha funzionalità incorporate per questo, ma è possibile provare un approccio a punto fisso.

Esempio di 8,8 punto fisso (8 prima della virgola, 8 dopo):

float value = 123.45; 
ushort fixedIntValue = (ushort)(value * 256); 

In questo modo, il numero viene memorizzato in questo modo: XXXXXXXX, XXXXXXXX

e si può recuperare il galleggiante nuovo di utilizzare questo:

float value = fixedIntValue/256f; 
+1

Anche questo ha una precisione limitata. 52.1 diventa 52.09765625. – Guffa

+0

Beh, non puoi avere tutto. Se vuoi di più, puoi provare 6,10 punti fissi o usare 4 byte. – bytecode77

+1

L'op non chiede tutto, solo per ottenere esattamente lo stesso valore. Questo non è affatto irragionevole, se un intervallo limitato è accettabile. Devi solo utilizzare un approccio diverso rispetto a un numero binario mobile/punto fisso. – Guffa

5

Sei sicuro avete bisogno di un tale micro-ottimizzazione, oltre semplicemente utilizzando un float o double?

Sarebbe meglio servire memorizzando un short e capendo che, ad esempio, è diviso per 100 per rendere il numero effettivo? (Ad esempio, i tuoi esempi di 52.1 e 1.25 potrebbero essere memorizzati come 5210 e 125). Penso che questa potrebbe essere la soluzione migliore per te.

Se si utilizza un numero a virgola mobile effettivo, è possibile prendere il numero decodificato e arrotondarlo a x cifre significative (dal proprio esempio, 3) che di solito dovrebbero riportare lo stesso numero iniziato con (si noti che sì, è intenzionalmente vago - non si può garantire l'ottenimento dell'originale se non si memorizza l'originale).

2

Ci sono 4.278.190,08 mila in virgola mobile a 32 bit valori, esclusi i NaN e gli infiniti. Ci sono 65.536 valori per i 16 bit in due byte. Chiaramente, è impossibile codificare univocamente tutti i valori a virgola mobile in due byte.

Quali vuoi codificare?

Anche per un singolo valore del segno e dell'esponente (ad esempio, tutti i valori in virgola mobile da 4 a 8, escluso 8), ci sono 8.388.608 valori a virgola mobile, quindi non è possibile nemmeno codificarli in due byte.

Devi limitarti a un piccolo sottoinsieme di valori da codificare. Dopo averlo fatto, le persone potrebbero avere suggerimenti su come codificarle. Qual è il vero problema che stai cercando di risolvere?