Умножение с фиксированной запятой в известном диапазоне - PullRequest
3 голосов
/ 18 июля 2010

Я пытаюсь умножить A*B в 16-битной фиксированной точке, сохраняя при этом как можно большую точность. A - 16-разрядный в диапазоне целых чисел без знака, B делится на 1000 и всегда между 0.001 и 9.999. Прошло много времени с тех пор, как я имел дело с такими проблемами, поэтому:

  • Я знаю, что могу просто сделать A*B/1000 после перехода к 32-битным переменным, а затем вернуться к 16-битной
  • Я бы хотел сделать это быстрее, чем
  • Я бы хотел выполнить все операции, не переходя на 32-разрядные (поскольку у меня есть только 16-разрядное умножение)

Есть ли простой способ сделать это?

Редактировать: A будет в диапазоне от 0 до 4000, поэтому все возможные результаты также находятся в 16-битном диапазоне.

Редактировать: B исходит от пользователя, установить цифру за цифрой в маске X.XXX, поэтому операция /1000.

1 Ответ

3 голосов
/ 18 июля 2010

Нет, вам нужно перейти на 32 бит.В общем случае произведение двух 16-битных чисел всегда даст вам 32-битный результат.

Вам следует проверить набор команд ЦП того ЦПУ, над которым вы работаете, потому что большинство команд умножения на 16-битных машинах имеют возможность возвращать результат в виде 32-битного целого числа напрямую.

Этоочень поможет вам, потому что:

short testfunction (short a, short b)
{
  int A32 = a;
  int B32 = b;

  return A32*B32/1000
}

заставит компилятор сделать 32-битное * 32-битное умножение.На вашей машине это может быть очень медленным или даже выполнено в несколько шагов с использованием только 16-битных умножений.

Немного встроенной сборки или, что еще лучше, встроенная компилятор может значительно ускорить процесс.

Вот пример для Texas Instruments C64x + DSP с такими характеристиками:

short test (short a, short b) 
{
  int product = _mpy (a,b); // calculates product, returns 32 bit integer
  return product / 1000;
}

Еще одна мысль: вы делите на 1000. Была ли эта константа вашим выбором?Было бы намного быстрее использовать степень двух в качестве основы для ваших чисел с фиксированной точкой.1024 близко.Почему бы вам:

  return (a*b)/1024 

вместо этого?Компилятор может оптимизировать это, используя сдвиг вправо на 10 бит.Это должно быть намного быстрее, чем делать трюки с взаимным умножением.

...