Синус, косинус, квадртаный корень FixedPoint
Вероятно, в сети, можно найти множество статей, касательно вычислениям с фиксированной точкой. По роду своей деятельности, я разработчик электроники и программист микроконтроллеров. Математика, с фиксированной точкой в моих задачах практически не встерчалась.
Имеется фрезерный станок ЧПУ. Было принято решение, переделать его систему управления, используя ядро Cortex M3. Вобщем и целом, существуют программные пакеты, позволяющие сделать это. Например GRBL. Однако, у меня своя специфика. Для реализации ПО, потребовались математичесике операции sin (x), cos (x), sqrt (x). И я задумался над их реализацией в формате фиксированной точки.
Для начала приступил к реализации функций sin (x), cos (x). Да, конечно, можно использовать табличные методы, но я пошел другим путем и решил реализовать апроксимацию, используя ряд Тейлора. Оценил участок, на котором буду раскладывать в ряд и приступил к реализации. Для разложения в ряд был выбран отрезок [0…PI/4], так как на этом отрезке, значение аргумента функции укладывается в промежуток [0…1], так и результат функции укладывается в отрезок от 0 до 1, таким образом со всеми числами можно работать как с 32-битными положительными дробными числами на интервале [0…0.9999(9)]. Единственное, значение cos (0), принимает значение 1.0., но я ограничился значением 0.9999(9). Таким образом удалось расширить диапазон значений на два бита. Бит знака и бит единичного разряда.Т.е. при вычислениий sin (x), cos (x), на этом отрезке, эффективно используются все 32-бита.
Поскольку sin (x) и cos (x), должны быть реализованы на интервале [-PI…PI] или [0…2*PI], задумался над их склеиванием в единую функцию. В ходе размышлений, появилась одна идея. Все равно, при большинстве вычислений, происходит масштабирование аргумента функций до 2*PI. почему бы не сделать это сразу, внутри функции. Подобное масштабирование приводит к одному интересному эффекту. Старшие биты числа можно использовать для выбора интервала на котором будет происходить вычисление функции. Т.е. старшие три быта просто определеяют какая из функиций будет выполнена. Это позволяет избавиться от операции сравнения. Кроме того, аргумент функции может принимать как отрицательные так и положительные значения, и это практически не повлияет результат вычислений. Так устроен формат чисел.
Затем приступил к реализации вычисления корня квадратного. При вычислении корня, тоже подошел к вопросу нестандартно, и стал аппроксимировать функцию на отрезках кратных степкни двойки. Обнаружил ошибка аппроксимации, носит квадратичный характер. Однако, оказалось, что апроксисмирующая ошибку порабола сдвинута относительно центра. Я нашел коэффициенты, используя квадратичную апроксимаци. сдвига по оси X, и получил точность апроксимации порядка 6, при извлечении квадратного корня из 32-битного числа.
После чего, решил повысить точность апроксимации, апроксимировав остаточную ошибку. И это привело к точности порядка 0.15, для 32-битного аргумента. Т.е. извлечение квадратного корня из целого 32-битного числа, до целого 16-битного результата происходит без использования итераций. Причем расчеты ошибки могут быть распараллелены (например в FPGA). После, добавил итеративную часть.
Вычисление тригонометрических функций:
https://github.com/hwswdev/FixedPoint/blob/68d436b97e57184b0f05ecba72bc365ebf1e79ae/Math/SinCosFixed.s
Вычисление корня квадратного:
https://github.com/hwswdev/FixedPoint/blob/68d436b97e57184b0f05ecba72bc365ebf1e79ae/Math/Sqrt.s
Habrahabr.ru прочитано 8463 раза
