2009-03-01 18 views
6

Disons que j'ai un flottant dans la plage de [0, 1] et que je veux quantifier et stocker dans un octet non signé. Sonne comme une évidence, mais en fait, il est assez compliqué:Convertir/Quantifier la plage flottante en entier Nombre

La solution évidente ressemble à ceci:

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

Cela fonctionne dans la mesure que je reçois tous les chiffres de 0 à 255, mais la distribution des entiers n'est pas pair. La fonction renvoie uniquement 255 si a est exactement 1.0f. Pas une bonne solution.

Si je fais l'arrondissement bon je déplace simplement le problème:

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

Voici le résultat 0 ne couvre que la moitié de la gamme float que tout autre nombre.

Comment effectuer une quantification avec une distribution égale de la plage de virgule flottante? Idéalement, j'aimerais obtenir une distribution égale des entiers si je quantifie des flottants aléatoires également distribués.

Des idées? Btw: Aussi mon code est en C le problème est indépendant de la langue. Pour les personnes non-C: Supposons simplement que la conversion float en int tronque le flotteur.

EDIT: Depuis que nous avons eu une certaine confusion ici: je besoin d'une carte qui associe le flotteur d'entrée le plus petit (0) au unsigned char le plus petit et le plus haut flotteur de ma gamme (1.0f) au plus haut octet non signé (255).

Répondre

10

Que diriez-vous de a * 256f avec une vérification pour réduire de 256 à 255? Donc, quelque chose comme:

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

(Pour une fonction appropriée min sur votre plate-forme - je ne me souviens pas de la fonction C pour elle.)

Fondamentalement, vous voulez diviser la gamme en 256 parties égales, ce qui est ce que cela devrait faire. Le cas limite pour 1.0 allant à 256 et nécessitant un arrondi vers le bas est juste parce que le domaine est inclusif aux deux extrémités.

+0

wow - oui, voilà! –

+0

Oui - (caractère non signé) (a * 256.0f) vous donne exactement ce que vous voulez pour chaque valeur d'entrée sauf pour 1.0.C n'a pas de fonction min intégrée, vous devrez donc écrire le vôtre si vous ne l'avez pas déjà fait. –

+0

John, j'ai trouvé le même résultat, mais je n'ai pas réussi à le transférer correctement depuis la feuille de calcul Excel. J'ai supprimé ma réponse embarrassante. – cdonner

1

Je pense que ce que vous cherchez est le suivant:

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

Cela carte des valeurs flottantes uniformes dans [0, 1] aux valeurs d'octets uniformes dans [0, 255]. Toutes les valeurs de [i/256, (i + 1)/256 [(c'est-à-dire excluant (i + 1)/256), pour i dans 0..255, sont mappées à i. Ce qui peut être indésirable, c'est que 1.0f est mappé à 256.0f qui s'enroule autour de 0.

0

On peut répartir l'erreur unique sur toute la plage tout en maintenant une distribution égale comme une seconde intercalaire jusqu'au 31 décembre .

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