Масштабирование с фиксированной точкой и точность умножения

Мне нужно выполнить операцию умножения над переменной с фиксированной точкой x (16-разрядное целое число без знака [U16] с двоичной точкой 6 [BP6]) с коэффициентом A, который, как я знаю, всегда будет между 0 и 1. Код написан на C для 32-битной встроенной платформы.

Я знаю, что если бы я также сделал этот коэффициент U16 BP6, то я получил бы U32 BP12 от умножения. Я хочу масштабировать этот результат обратно до U16 BP6, поэтому я просто отсекаю первые 10 бит и последние 6.

Однако, поскольку точность коэффициента ограничена количеством дробных битов, и мне не обязательно нужны полные 10 бит целого числа, я подумал, что могу просто сделать переменную коэффициента A U16 BP15, чтобы получить более точный результат. .

Я разработал следующий пример (потерпите меня):

Допустим, что x = 172.0 (десятичный) и я хочу использовать коэффициент A = 0.82 (десятичный). Идеальный десятичный результат будет 172,0 * 0,82 = 141,04.

В двоичном формате x = 0010101100.000000.

Если я использую BP6 для A, двоичное представление будет либо

    A_1 = 0000000000.110100 = 0.8125 or
    A_2 = 0000000000.110101 = 0.828125

(в зависимости от того, основано ли значение на полу или на потолке).

Выполнение двоичного умножения между x и любым значением A дает (без учета начальных нулей):

    A_1 * x = 10001011.110000000000 = 139.75 
    A_2 * x = 10001110.011100000000 = 142.4375

В обоих случаях удаление последних 6 бит не повлияет на результат.

Теперь, если я расширил A до BP15, то

    A_3 = 0.110100011110110 = 0.82000732421875

и результирующее умножение дает

    A_3 * x = 10001101.000010101001000000000 = 141.041259765625

При обрезке дополнительных 15 дробных битов результат

    A_3 * x = 10001101.000010 = 141.03125

Итак, здесь довольно ясно, что расширение коэффициента, чтобы иметь больше дробных битов, дает более точный результат (по крайней мере, в моем примере). Это что-то, что будет иметь место в целом? Хорошо/плохо ли это использовать на практике? Я что-то упускаю или неправильно понимаю?

РЕДАКТИРОВАТЬ: я должен был сказать "точность" вместо "точность" здесь. Я ищу результат, который ближе к моему ожидаемому значению, а не результат, содержащий больше дробных битов.


person djentastic    schedule 27.09.2013    source источник


Ответы (1)


Сделав аналогичный код, я бы сказал, что то, что вы делаете, в целом будет верным со следующими проблемами.

  1. Очень легко получить неожиданное переполнение при перемещении вокруг вашей двоичной точки. Рекомендуется тщательное тестирование/анализ и/или обнаружение кода. Заметный провал: Ariane_5

  2. Вам нужна точность, поэтому я не согласен с «обрезать ... последние 6». Вместо этого я рекомендую округлить ваши результаты, если позволяет время обработки. Используйте обрезанный MSBbit, чтобы, возможно, скорректировать результат.

person chux - Reinstate Monica    schedule 27.09.2013
comment
Спасибо за отзыв. В этом случае никогда не должно быть проблемы с переполнением, так как я буду проверять, что коэффициент никогда не будет больше 1,0. Кроме того, я уменьшаю результат до 6 дробных битов, так как он будет использоваться в последующих вычислениях с другими переменными BP6. Так что может не обязательно точность в результате, но хотя бы в расчете. Даже с удалением дробных битов в результате последнее вычисление намного ближе к моему желаемому результату. - person djentastic; 27.09.2013
comment
Также спасибо за редактирование, чтобы включить эту заметную ошибку. Хорошо знать. - person djentastic; 27.09.2013
comment
C предоставляет удивительную возможность кодировать действительно гладкие решения. Также в SDK входит достаточно веревки, чтобы повеситься. :-) - person chux - Reinstate Monica; 27.09.2013