Перейти к содержанию
    

аппроксимация деления

У меня стоит задача нормировки потока чисел (поток пикселей изображения) на некоторое переменное значение (например разницу максимальной и минимальной яркости изображения). Соответственно без деления не обойтись. Те алгоритмы, которые используются чаще всего, делятся на два типа: либо тупо LUT с забитой таблицей 1/х, либо итеративные алгоритмы, имитирующие деление в столбик, с различной степенью оптимизации. Еще можно складывать делитель, пока результат не превзойдет делимое и посчитать количество таких операций, но это совсем плохой алгоритм.

 

Почему никто не использует тупо полиномиальную аппроксимацию 1/х? Вот здесь всего навсего полином 3-й степени, 100 слайсов на 3-ем Спартане и при этом точность 11 бит. Мне так кажется, что я здесь что-то не понимаю, это же так просто, почему так не делают?

Еще и конкретно для моей задачи - даже при точности 11 бит, я мог бы получить приемлемый результат, забив на линейность нормировки.

 

Спасибо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня стоит задача нормировки потока чисел (поток пикселей изображения) на некоторое переменное значение (например разницу максимальной и минимальной яркости изображения). Соответственно без деления не обойтись. Те алгоритмы, которые используются чаще всего, делятся на два типа: либо тупо LUT с забитой таблицей 1/х, либо итеративные алгоритмы, имитирующие деление в столбик, с различной степенью оптимизации. Еще можно складывать делитель, пока результат не превзойдет делимое и посчитать количество таких операций, но это совсем плохой алгоритм.

 

Почему никто не использует тупо полиномиальную аппроксимацию 1/х? Вот здесь всего навсего полином 3-й степени, 100 слайсов на 3-ем Спартане и при этом точность 11 бит. Мне так кажется, что я здесь что-то не понимаю, это же так просто, почему так не делают?

Еще и конкретно для моей задачи - даже при точности 11 бит, я мог бы получить приемлемый результат, забив на линейность нормировки.

 

Спасибо.

Вот например целочисленное деление не подходит?

Какая частота съема пикселей? Разрядность пикселей? Какая плис?

PS в крайнем случае можно сделать pipeline деление...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

собственно вот и ответ на ваш вопрос.

 

ЗЫ. деление в столбик будет делить точно, при конвейере будет 1 слово за такт. и для ваших 11 бит составит немногим больше 100 слайсов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот например целочисленное деление не подходит?

Какая частота съема пикселей? Разрядность пикселей? Какая плис?

PS в крайнем случае можно сделать pipeline деление...

Частота - 50МГц, 14бит, плис - 7я серия xilinx. На данный момент для деления использую корку DividerGenerator в режиме Radix-2. Хавает более 2000 FF... pipeline нужен обязательно, а вот latency роли не играет, хоть 1000 тактов пойдет. Ваш алгоритм, насколько я понимаю, несколько тактов на деление требует? Я боюсь, что если его конвейеризировать, то слайсов будет прилично занимать...

И все-таки в аппроксимации меня привлекает то, что результат-то можно получать гораздо большей разрядности, чем наихудшую точность (ну как в АЦП - есть разрядность, а есть нелинейность и в плохом АЦП может быть 16 эффективных разрядов, но линейными могут быть только 14). Т.е. можно получить монотонную 16-битную функцию на выходе, у которой только первые 11 бит будут всегда точно соответствовать 1/х, что вполне может сгодиться. Делением в столбик такого не получишь...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Частота - 50МГц, 14бит, плис - 7я серия xilinx. На данный момент для деления использую корку DividerGenerator в режиме Radix-2. Хавает более 2000 FF... pipeline нужен обязательно, а вот latency роли не играет, хоть 1000 тактов пойдет. Ваш алгоритм, насколько я понимаю, несколько тактов на деление требует? Я боюсь, что если его конвейеризировать, то слайсов будет прилично занимать...

И все-таки в аппроксимации меня привлекает то, что результат-то можно получать гораздо большей разрядности, чем наихудшую точность (ну как в АЦП - есть разрядность, а есть нелинейность и в плохом АЦП может быть 16 эффективных разрядов, но линейными могут быть только 14). Т.е. можно получить монотонную 16-битную функцию на выходе, у которой только первые 11 бит будут всегда точно соответствовать 1/х, что вполне может сгодиться. Делением в столбик такого не получишь...

думаю будет меньше чем 2000 FF

 

upd

 

для 16 битных данных

Flow Status Successful - Thu May 14 14:49:58 2015

Quartus II 64-Bit Version 13.0.1 Build 232 06/12/2013 SP 1 SJ Full Version

Family Stratix IV

Logic utilization < 1 %

Combinational ALUTs 46 / 58,080 ( < 1 % )

Memory ALUTs 0 / 29,040 ( 0 % )

Dedicated logic registers 85 / 58,080 ( < 1 % )

Total registers 85

Total pins 67 / 584 ( 11 % )

Device EP4SGX70HF35C2

Timing Models Final

 

таймквет показывает частоту выше 300 МГц

 

Как вариант можно блок деления запустить на частоте эдак 300МГц.

 

300МГц/50МГц = 6

 

Ставим 3 (с запасом) модуля и переиспользуем ресурсы.

Таким образом, Вы получаете на 3 модулях pipeline на 3*6=18 тактов

Минимизация ресурсов налицо за счет временного мультиплексирования и переиспользования ресурса (модуля деления)...

------------------------------------------------------------------------------------------------------------------------------------------------------------

Даже если просто (для работы на одной тактовой частоте 50МГц)

85 регистров *16 = 1 360

то и здесь получается экономия

 

только что увидел у Вас не 16 бит а 14 бит данные, тогда еще больше экономии...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если в a/b делитель не так часто меняется, посчитайте как угодно медленно один раз с=(2^n)/b и потом множьте на него за такт и сдвигайте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если в a/b делитель не так часто меняется, посчитайте как угодно медленно один раз с=(2^n)/b и потом множьте на него за такт и сдвигайте.

С нормировкой кадра такое прокатит, а вот когда множитель для каждого пикселя меняется (а такое тоже надо) - уже нет

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Почему никто не использует тупо полиномиальную аппроксимацию 1/х? Вот здесь всего навсего полином 3-й степени. Мне так кажется, что я здесь что-то не понимаю, это же так просто, почему так не делают?
Наверное потому, что x должно быть в пределах от 1 до 2х (в той же статье написано). Может не хватить диапазона.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Наверное потому, что x должно быть в пределах от 1 до 2х (в той же статье написано). Может не хватить диапазона.

 

Да, есть такое. Адекватно аппроксимировать 1/х и возле нуля и на хвосте невозможно... Хотя, как в той же статье, можно попытаться разбить область определения на несколько сегментов и в каждом сегменте использовать свои коэффициенты для полинома... Считать полиномы посложнее будет - надо концы сегментов согласовывать, т.е. решать задачу с закрепленными концами, но все-таки мне кажется такой поход интересным...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для вычисления 1/x есть еще итерационные алгоритмы, для них характерна очень быстрая сходимость, в том числе и на больших разрядностях

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для вычисления 1/x есть еще итерационные алгоритмы, для них характерна очень быстрая сходимость, в том числе и на больших разрядностях

например? (хорошие по Вашему мнению - 32/64 бит)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

например? (хорошие по Вашему мнению - 32/64 бит)

Ну можно, наверное, методом Ньютона попробовать.. :biggrin:

 

Главное - выбрать правильное начальное приближение.. ;)

 

Например, мы хотим найти частное от деления: A/B = D, где A = 555555, B = 11 и, соответственно, D = 50505.

 

Тогда:

 

A/B = [(A*232/B)>>32] = D.

 

Введем обозначение:

 

x = 232/B.

 

Это равносильно:

 

232/x = B.

 

Или:

 

f(x) == 232/x - B = 0.

 

Находим производную:

 

f'(x) = -232/x2.

 

Теперь подставляем всё это в формулу Ньютона и находим:

 

xn+1 = xn - f(xn)/f'(xn), или

 

xn+1 = xn + [232/xn - B]/[232/xn2], или

 

xn+1 = 2*xn - B*xn2/232, или

 

xn+1 = 2*xn - [(B*xn*xn)>>32].

 

Начальное приближение для x0 выбираем равным:

 

x0 = 232-m, где m - максимальная степень двойки в двоичном представлении числа B..

 

То есть, для B = 11 это дает:

 

B = 11d = 1011b = 1*23 + 0*22 + 1*21 + 1*20.

 

Откуда находим, что m = 3, и:

 

x0 = 229.

 

Тогда:

 

x1 = 230 - 11*226 = 335544320;

 

x2 = 2*335544320 - (11*335544320*335544320)>>32 = 382730240;

 

x3 = 2*382730240 - (11*382730240*382730240)>>32 = 390298880;

 

x4 = 2*390298880 - (11*390298880*390298880)>>32 = 390451513;

 

x5 = 2*390451513 - (11*390451513*390451513)>>32 = 390451572;

 

x6 = 2*390451572 - (11*390451572*390451572)>>32 = 390451572;

 

После чего находим:

 

A/B = [(A*x)>>32] = [(555555*390451572)>>32] = 50505 = D.

 

Но в целом, все эти "быстро сходящиеся итерации" не слишком то оптимальны для FPGA, КМК..

 

Как-то так..

 

:biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну можно, наверное, методом Ньютона попробовать.. :biggrin:

 

Главное - выбрать правильное начальное приближение.. ;)

 

Например, мы хотим найти частное от деления: A/B = D, где A = 555555, B = 11 и, соответственно, D = 50505.

 

Тогда:

 

A/B = [(A*232/B)>>32] = D.

 

Введем обозначение:

 

x = 232/B.

 

Это равносильно:

 

232/x = B.

 

Или:

 

f(x) == 232/x - B = 0.

 

Находим производную:

 

f'(x) = -232/x2.

 

Теперь подставляем всё это в формулу Ньютона и находим:

 

xn+1 = xn - f(xn)/f'(xn), или

 

xn+1 = xn + [232/xn - B]/[232/xn2], или

 

xn+1 = 2*xn - B*xn2/232, или

 

xn+1 = 2*xn - [(B*xn*xn)>>32].

 

Начальное приближение для x0 выбираем равным:

 

x0 = 232-m, где m - максимальная степень двойки в двоичном представлении числа B..

 

То есть, для B = 11 это дает:

 

B = 11d = 1011b = 1*23 + 0*22 + 1*21 + 1*20.

 

Откуда находим, что m = 3, и:

 

x0 = 229.

 

Тогда:

 

x1 = 230 - 11*226 = 335544320;

 

x2 = 2*335544320 - (11*335544320*335544320)>>32 = 382730240;

 

x3 = 2*382730240 - (11*382730240*382730240)>>32 = 390298880;

 

x4 = 2*390298880 - (11*390298880*390298880)>>32 = 390451513;

 

x5 = 2*390451513 - (11*390451513*390451513)>>32 = 390451572;

 

x6 = 2*390451572 - (11*390451572*390451572)>>32 = 390451572;

 

После чего находим:

 

A/B = [(A*x)>>32] = [(555555*390451572)>>32] = 50505 = D.

 

Но в целом, все эти "быстро сходящиеся итерации" не слишком то оптимальны для FPGA, КМК..

 

Как-то так..

 

:biggrin:

спасибо...

 

PS метод Ньютон работает для нахождения практически любых функций и как Вы правильно заметили для FPGA в чистом виде плохо подходят

 

я думал, что есть уже какие-то модификации, которые лучше подходят для FPGA и менее итерационные...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вообще Ньютон как раз может и быть интересен. По крайней мере в алгоритме быстрого вычисления обратного корня именно он и используется. Кстати интересно, есть ли готовые корки, реализующие быстрый инверсный корень?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...