2009-03-01 2 views
6

Скажем, у меня есть float в диапазоне [0, 1], и я хочу квантовать и хранить его в неподписанном байте. Похоже, никакой опасности, но на самом деле это довольно сложно:Convert/Quantize Float Range to Integer Диапазон

Очевидное решение выглядит следующим образом:

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

Это работает так далеко, что я получаю все цифры от 0 до 255, но распределение целых чисел нечетно. Функция возвращает 255, если а точно 1.0f. Нехорошее решение.

Если я правильное округление я просто перекладывать проблему:

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

Здесь результат 0 покрывает только половину флоат-диапазоне, чем любое другое число.

Как сделать квантование с равным распределением диапазона с плавающей запятой? В идеале я хотел бы получить равное распределение целых чисел, если я квантую равномерно распределенные случайные поплавки.

Любые идеи?


КВТ: Также мой код находится в языке C, проблема в языке-агностик. Для людей, не относящихся к C: Предположим, что float до int конверсия усекает поплавок.

EDIT: Так как мы имели некоторую путаницу здесь: мне нужно отображение, переводящее наименьший входной поплавок (0) до наименьшего неподписанные символ, и самый высокий поплавок моего диапазона (1.0f) до самого высокого знака байта (255).

ответ

10

Как насчет a * 256f с чеком, чтобы уменьшить 256 до 255? Так что-то вроде:

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

(для соответствующей функции мин на вашей платформе - Я не могу вспомнить функцию C для него.)

В основном вы хотите разделить диапазон на 256 равных частей, которые это то, что нужно делать. Крайный край для 1.0, идущий к 256 и требующий округления, только потому, что домен включен на обоих концах.

+0

ничего себе - да, это так! –

+0

Да - (unsigned char) (a * 256.0f) дает вам именно то, что вы хотите для каждого входного значения, кроме 1.0.C не имеет встроенной функции min, поэтому вам придется писать самостоятельно, если вы еще этого не сделали. –

+0

John, я придумал тот же результат, просто не смог перенести его из таблицы Excel. Я удалил свой смущающий ответ. – cdonner

1

Я думаю, что вы ищете это:

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

Это будет отображать единые значения с плавающей запятой в [0, 1] для однородных значений байтов в [0, 255]. Все значения в [i/256, (i + 1)/256 [(исключая (i + 1)/256) для i в 0..255 отображаются на i. Что может быть нежелательно, так это то, что 1.0f сопоставляется с 256.0f, который обертывается до 0.

0

Можно распространять одноразовую ошибку по всему диапазону, сохраняя при этом равное распределение, как если бы вы прыгали секунду через 31 декабря ,

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