2009-03-01 15 views
6

Angenommen, ich habe eine Gleitkommazahl im Bereich von [0, 1] und möchte sie in einem Byte ohne Vorzeichen quantisieren und speichern. Klingt wie ein Kinderspiel, aber es ist ziemlich kompliziert in der Tat:Convert/Quantize Float Range zu Integer Range

Die offensichtliche Lösung sieht wie folgt aus:

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

Dies funktioniert so weit, dass ich alle Zahlen von 0 bis 255, aber die Verteilung der ganzen Zahlen ist nicht einmal. Die Funktion gibt nur 255 zurück, wenn a genau 1.0f ist. Keine gute Lösung.

Wenn ich die richtige Rundung kann ich verschieben nur das Problem:

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

Hier ist das das Ergebnis 0 deckt nur die Hälfte des Schwimmers-Bereich als jede andere Zahl.

Wie mache ich eine Quantisierung mit gleicher Verteilung des Fließkommabereichs? Idealerweise würde ich gerne eine gleiche Verteilung von ganzen Zahlen erhalten, wenn ich gleichmäßig verteilte zufällige Gleitkommazahlen quantisiere.

Irgendwelche Ideen?


Btw: Auch mein Code ist in C das Problem ist Sprache-agnostic. Für die Nicht-C-Leute: Gehen Sie einfach davon aus, dass float bis int Konvertierung den Float abschneidet.

EDIT: Da wir einige Verwirrung hier hatten: Ich brauche eine Abbildung, die den kleinsten Eingang Schwimmer abbildet (0) auf den kleinsten unsigned char und den höchsten Schwimmer meiner Reichweite (1.0f) mit dem höchsten Byte ohne Vorzeichen (255).

Antwort

10

Wie wäre es mit a * 256f mit einem Scheck um 256 auf 255 zu reduzieren? So etwas wie:

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

(Für eine geeignete min Funktion auf Ihrer Plattform - Ich kann die C-Funktion für sie erinnern.)

Grundsätzlich Sie den Bereich in 256 gleiche Abschnitte geteilt werden soll, die ist das, was das tun sollte. Der Kantenfall für 1.0, der zu 256 geht und abgerundet werden muss, ist nur, weil die Domäne an beiden Enden eingeschlossen ist.

+0

wow - ja, das ist es! –

+0

Ja - (unsigned char) (a * 256.0f) gibt Ihnen genau das, was Sie für jeden Eingabewert mit Ausnahme von 1.0 möchten.C hat keine eingebaute Min-Funktion, also müssen Sie Ihre eigene schreiben, wenn Sie es nicht schon getan haben. –

+0

John, kam ich mit dem gleichen Ergebnis nach oben, nur nicht in der Lage war, es zu übertragen korrekt aus der Excel-Tabelle. Ich habe meine peinliche Antwort gelöscht. – cdonner

1

Ich denke, was Sie suchen ist dies:

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

Diese einheitliche Float-Werte abbildet in [0, 1], um einheitliche Byte-Werte in [0, 255]. Alle Werte in [i/256, (i + 1)/256 [(also ohne (i + 1)/256) für i in 0..255 werden auf i abgebildet. Was vielleicht unerwünscht sein könnte, ist, dass 1.0f auf 256.0f abgebildet wird, das auf 0 umläuft.

0

Man kann den einmaligen Fehler entlang der gesamten Bandbreite verteilen, während man die gleiche Verteilung wie bei einer Schaltsekunde über den 31. Dezember behält .

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