Понимание дробной части с фиксированной точкой

Итак, я пытаюсь разобраться с числами с фиксированной точкой. Все идет нормально. Единственное, что меня смутило, так это «дробная» часть числа.

Мое понимание чисел с фиксированной точкой состоит в том, что они разбивают двоичное число в соответствии со шкалой (которая в данном случае равна восьми битам). В левой части будет целая часть, а в правой — дробь. XXX.Y, где XXX — три байта для целой/целой части, а Y — один байт для дробной части (пожалуйста, поправьте меня, если я ошибаюсь).

Возьмем следующие макросы:

#define FIX_SCALE 8
#define FIX_FRACTION_MASK ((1 << FIX_SCALE) - 1)
#define FIX_WHOLE_MASK ~FIX_FRACTION_MASK
#define FIX_FROM_FLOAT(X) ((X) * (1 << FIX_SCALE))
#define FIX_TO_FLOAT(X) ((float)(X) / (1 << FIX_SCALE))
#define FIX_TO_INT(X) ((X) >> FIX_SCALE)
#define FIX_FROM_INT(X) ((X) << FIX_SCALE)
#define FIX_FRACTION(X) ((X) & FIX_FRACTION_MASK)
#define FIX_WHOLE(X) ((X) & FIX_WHOLE_MASK)

Рассмотрим следующий пример:

int Fixed = FIX_FROM_FLOAT(2.5f);

Результирующее целочисленное значение равно 640, 0x280 в шестнадцатеричном формате и 0000 0000 0000 0000 0000 0010 1000 0000 в двоичном формате.

Возьмем первые два байта: 0000 0010 1000 0000

Я понимаю, откуда 0000 0010, это целая часть (2). Но чего я не понимаю, так это 1000 0000, который является дробной частью. Я просто не понимаю, как это связано с числом 5 (которое в двоичном формате равно 0101). Я ожидал что-то вроде 0101 0000 или 0000 0101 -- Очевидно, я неправильно понимаю здесь фундаментальную концепцию.

Если я напишу:

int Fraction = FIX_FRACTION(Fixed);

Я бы получил 128 (0x80 в шестнадцатеричном формате. Имеет смысл, потому что он маскирует целую часть, которая равна 2). В первый раз я написал, что рассчитывал получить 5 обратно.

Я получаю 0.5, если напишу:

float Fraction = FIX_TO_FLOAT(FIX_FRACTION(Fixed));

Может ли кто-нибудь прояснить эту путаницу для меня? Почему в дроби номер 0000 1000 не было 101? Почему мы должны были сделать FIX_TO_FLOAT на FIX_FRACTION, чтобы получить правильную дробь?

Спасибо.


person vexe    schedule 16.04.2016    source источник


Ответы (3)


Сравнение шаблонов чисел в десятичном и двоичном представлении не работает. Давайте на мгновение забудем о числах с фиксированной точкой и посмотрим на двоичные представления 5 и 50:

 5: 0000'0101
50: 0011'0010

Как видите, двоичный образец десятичного числа 5 также нельзя найти в двоичном представлении десятичного числа 50.

Теперь, чтобы понять, почему десятичное число 0,5 равно ..00'1000'0000 в двоичном формате Q23.8, вам нужно следовать правилу преобразования двоичного кода в десятичное:

Замените каждую 1 на 2 ^ позицию и сложите числа

position:      7 6 5 4  3 2 1 0  -1-2-3-4 -5-6-7-8
binary number: 0 0 0 0  0 0 1 0 . 1 0 0 0  0 0 0 0

2^1 + 2^-1 = 2 + 0.5 = 2.5

person maniacmic    schedule 27.04.2016

Целые числа представляют различные степени числа 10:

Десятичное представление целочисленных столбцов (источник)

So 10203 = 1×10000 + 0×1000 + 2×100 + 0×10 + 3×1

И десятичные дроби продолжают этот шаблон, представляя отрицательные степени числа 10:

Десятичное представление дробных столбцов

So 0.10203 = 1/10 + 0/100 + 2/1000 + 0/10000 + 3/100000

Десятичное число 2,5 имеет «2» в столбце 2 и «5» в столбце 1/10, поэтому сумма равна 2 × 1 + 5/10.

Двоичная фиксированная точка работает точно так же, за исключением степени 2 вместо 10. Целая часть — это столбец 1, столбец 2, столбец 4, столбец 8 и т. д., а дробная часть — столбец 1/2. , 1/4 столбца, 1/8 столбца и т. д.

Так, например, если число имеет формат 4.4, где первый полубайт является целой частью без знака, а второй полубайт является дробной частью, для двоичного числа 1010 1001 целая часть представляет собой

1×8 + 0×4 + 1×2 + 0×1

Дробная часть представляет

1/2 + 0/4 + 0/8 + 1/16

Таким образом, десятичный эквивалент будет

1×8 + 0×4 + 1×2 + 0×1 + 1/2 + 0/4 + 0/8 + 1/16

= 10.5625

Подписанная версия аналогична:

знаковое двоичное представление 4.4 (источник)

Итак, в вашем двоичном формате, где 2.5 равно 0b0000 0010 1000 0000, первый байт имеет 1 в столбце 2s, 0 в столбце 1s, так что это

... + 0×4 + 1×2 + 0×1 + 1/2 + 0/4 + 0/8 + ...

person endolith    schedule 24.10.2019

Двоичные значения справа от . 1/2 1/4 1/8 и т. д. Следовательно, 10,1 двоичного числа равно 2,5

person B Ramsay    schedule 16.04.2016
comment
Чтобы расширить мой ответ, двоичный код - это система счисления, а не кодировка. Это основание два вместо основания десять. 0,5d 1/2 0,1b - person B Ramsay; 16.04.2016
comment
Я не уверен, что вы имеете в виду под 0,5 d 1/2 0,1b? Не могли бы вы подробнее рассказать? - person vexe; 17.04.2016
comment
извините, что медленно. двоичные числа имеют двоичные веса (показатели) по обе стороны от десятичной точки. 1/2 равно 0,1 в двоичном формате, потому что значение первого десятичного разряда равно 1/2. В десятичной математике значение справа от десятичной точки равно 1/10. 1/2 = 5/10 = 0,5 десятичного числа - person B Ramsay; 18.10.2017