Я пытаюсь реализовать процедуру с фиксированной запятой, которая включает вычисление значения для малого которое приближается к . Целевая архитектура - FPGA. Одна из проблем заключается в том, что эта функция не может легко использоваться для расширения Тейлора. Можно видеть, что для малых значений x наклон стремится к бесконечности, когда приближается к , поэтому оценка функции с использованием степенного ряда включает умножение огромных коэффициентов на маленький . Поэтому этот метод численно нестабилен.
Используя итерационный подход, Ньютон-Рафсон дает следующее итеративное уравнение: , где мы находимся пытаясь приблизить . Но еще раз, поскольку мала, также должен быть маленьким, чтобы решение сходилось. Так как уравнение включает в себя деление небольшого числа на другое небольшое число, есть вероятность, что арифметика с фиксированной точкой потерпит неудачу.
При этом я хотел бы знать, как реализовать приближение малых значений для используя арифметику с фиксированной точкой, используя предварительно вычисленные коэффициенты или итерационные методы.
Ответы:
Подпрограмма, которую я использовал ранее (я не знаю, является ли она «правильной» или нет), является подходом «разделяй и властвуй».
Вы начинаете с произвольного верхнего и нижнего значения (скажем, 5 и 0 соответственно - самый высокий и самый низкий квадратные корни, которые вы хотите найти) и находите среднюю точку между ними. Квадрат это значение.
Если значение в квадрате больше, чем ваша цель, установите верхнее значение в качестве значения в квадрате. Если оно ниже, установите меньшее значение.
Повторяйте до тех пор, пока либо квадратное значение не совпадет с вашим значением поиска, либо вы выполнили достаточно итераций, чтобы быть настолько точными, насколько вам нравится.
Вот небольшая версия, которую я собрал в perl:
Это, конечно, использует с плавающей запятой, но можно легко адаптировать к фиксированной точке. Вы можете изменить точность, изменив предел итерации. Каждая итерация становится немного более точной, чем предыдущая.
Например: - найти квадратный корень из 9:
Если бы он нашел значение 3, он бы остановился рано, конечно.
Дайте ему достаточно итераций, и он должен получиться очень точным:
источник
Вот некоторые идеи и процедуры от Вознесенного Трансцендентного Мастера / Гуру Скотта Даттало здесь .
Это, конечно, шутка, кроме части гуру (Гуру?). Скотт великолепен.
Актуальное обсуждение. 2005 и PIC, а некоторые - C, но могут иметь значение.
Скотт снова - 2003
Два Мастера !!!
Датталло и Головченко.
Диапазон методов
источник
Вы не указали, что вы подразумеваете под «малым значением» или «приближением». Так что то, что я собираюсь предложить, может не сработать, но здесь идет.
Самым простым было бы составить справочную таблицу. По сути это ПЗУ, в котором адресная шина - это число, которое вы хотите получить в квадратном корне, а вывод данных - это результат. С одним BRAM вы можете сделать 9-битный, 8-битный LUT. Конечно, больше БРАМов даст вам больший стол.
(BRAM = термин Xilinx для Block RAM, который также может использоваться в качестве ROM. Другие FPGA имеют аналогичные вещи.)
Если вам нужна большая точность, чем дает BRAM, вы можете выполнить простую линейную интерполяцию двух записей LUT. Например, предположим, что вы хотите 12-битный вход, но у вас есть только BRAM для 10 бит. Вы берете первые 10 бит вашего ввода и смотрите это в LUT. Добавьте 1 к этим 10 битам и посмотрите это значение тоже. Затем вы выполняете простую линейную интерполяцию между двумя результатами, используя нижние 2 бита, чтобы определить пропорцию одного значения к другому. Конечно, это только даст вам приближение, но я думаю, что если вы сделаете математику, вы обнаружите, что она может быть достаточно хорошей.
Этот метод является наименее точным с числами с низким значением, но поскольку входные данные переходят к более высоким значениям, точность повышается.
Оптимизация вышеупомянутого метода будет заключаться в использовании BRAM в качестве двухпортового ПЗУ. Таким образом, вы можете прочитать два значения без увеличения количества используемых BRAM. Это также позволит вам рассчитать SQRT для каждого тактового цикла с некоторыми задержками в конвейере.
Кстати, этот метод работает и для SINE / COSINE!
источник
Попробуйте следующий подход
x <<= 2
в C), пока оно не окажется в вышеуказанном диапазоне.источник
Пытатьсях = ( у+ д)2≈Y2+ 2 дY
так что давайте d= ( х -Y2) / 2 у= ( х / у- у) ≫ 1
и следующий Yзнак равно у+д,
Если MSb n справа, пусть сначалаY= 1 ≪ ( н / 2 ) , Сходится за <4 итерации.
источник
Попробуйте: улучшенное гадание для 1-й переменной
Ваше число может быть рассмотрено: A * 2 ^ n
1-е приближение тогда: A * 2 ^ (n / 2)
Допустим, вы используете 32-разрядное число, а 24-разрядные используются для хранения дробей. Для чисел> 1:
1. Подсчитать количество битов, используемых в целочисленной части (N)
2. Половину этого числа (N '= N / 2, т. Е. 1 бит со
смещением вправо ) 3. Смещение вправо исходного числа на N' Это ваше первое предположение.
В этом формате наименьшее число, которое вы можете иметь, составляет 2 ^ -24. Квадратный корень будет около 2 ^ -12. Итак, для чисел <1:
1. Подсчитайте количество «нулевых» битов в дроби, пока не достигнете установленного бита (N)
2. Половину этого числа (N '= N / 2, т. Е. 1 бит, сдвинутый вправо)
3. ВЛЕВО сдвиньте оригинальное число на пересмотренный счет: это ваше первое предположение.
Пример:
0,0000 0000 0000 0000 1 [16 ведущих нулей] приближается к: 0,0000 0000 1
Наконец, если у вас все еще есть проблемы с маленьким А: можете ли вы рассчитать 1 / А?
Если это так, то инвертируйте свой номер и попробуйте использовать алгоритм обратного квадратного корня:
x' = 0.5x * (3 - Ax^2)
источник