Арифметика с фиксированной точкой на микроконтроллерах

12

Часто мы используем микроконтроллеры, чтобы делать что-то в наших роботах, но нужно сделать некоторые вычисления в десятичном виде. Использование переменных с плавающей запятой очень медленное, потому что автоматически включается программная библиотека с плавающей запятой (если у вас нет высокопроизводительного микроконтроллера). Поэтому мы обычно используем арифметику с фиксированной точкой.

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

Я реализовал функцию atan2 с фиксированной точкой, но, поскольку я пытался сжать каждую последнюю каплю с ограниченной точностью (16 бит), я часто менял определение определения десятичной точки, и она менялась при настройке. Кроме того, у меня были бы некоторые константы, такие как квази-справочная таблица, у которых где-то есть подразумеваемая десятичная точка.

Я хочу знать, есть ли лучший способ. Существует ли библиотека или набор макросов, которые могут упростить использование переменных с фиксированной запятой, упростить умножение и деление между смешанными переменными и разрешить объявление десятичных чисел или константных выражений, но автоматически конвертировать в требуемое представление с фиксированной запятой при компиляции время?

ronalchn
источник
1
Я думаю, что на самом деле это лучше для стекового потока, так как решение является общим и не имеет ничего общего с робототехникой.
Шахбаз
1
@Jakob - Обратите внимание, что оба эти вопроса были закрыты как неконструктивные.
Марк Бут
1
Это то, что делает C ++ очень полезным для встраиваемых систем. Шаблоны будут генерировать правильный и оптимальный код автоматически.
Ракетный магнит
1
Могу ли я взглянуть на вашу функцию атана? Я пытаюсь решить проблему преобразования с плавающей точкой в ​​мои академические исследования, и я был бы рад ее решить.
Джо Хасс
1
@ronalchn Части Arduino (с микро AVR) языка реализуются в C ++. Существует также библиотека AVR C ++ . И этот поток, на котором компиляторы использовать.
embedded.kyle

Ответы:

7

Было бы неплохо, если бы мы могли сообщить компилятору диапазон и точность каждой входной переменной с фиксированной точкой (возможно, нет двух, имеющих основную точку в одном и том же месте), и она бы автоматически - во время компиляции - использовала правильный диапазон точность и масштабирование операций для промежуточных и конечных значений в серии вычислений. До меня дошли слухи, что это возможно сделать на языке программирования Ada или в шаблонах C ++.

Увы, самое близкое, что я видел, - это арифметические библиотеки с фиксированной точкой, которые требуют, чтобы вы, программист, вручную выбирали правильное представление и вручную проверяли, что каждая операция поддерживает достаточный диапазон и точность. Иногда они облегчают умножение и деление смешанных переменных. Такие как:

Дэвид Кэри
источник
Это почти наверняка возможно сделать с помощью шаблонов C ++.
Ракетный магнит
На самом деле я работаю над чем-то вроде вашего комментария "было бы неплохо, если бы ...". Это плагин для gcc, который преобразует код C с плавающей точкой в ​​фиксированную точку, оптимизируя все положения двоичной точки на этом пути. У меня есть документ, представленный в журнал ACM, а другой готовится. Если у вас есть C-код для функции atan, я был бы рад дать вам шанс ... Я мог бы вернуть вам C-код, который использует целочисленные переменные и выполняет все вещи с фиксированной запятой.
Джо Хасс
+1 за гораздо более полный ответ, чем мой. Я отредактировал ссылку в моей, чтобы включить ссылку на место, чтобы запросить исходный код, чтобы ответить на комментарий Марка Бута. Вы также можете обновить свою ссылку. Я бы сделал это сам, но предложенное редактирование находится в очереди и блокирует меня.
embedded.kyle
1
@Rocketmagnet Скорее всего, возможно реализовать фиксированные точки с помощью шаблонов, см. FixedPoints (заявление об отказе: я написал это, и он все еще очень «молодой»).
Pharap
gcc ссылка "a" не работает
Lesto
2

Я использовал библиотеку TI IQMath для реализации виртуальных операций с плавающей запятой на их DSP с фиксированной запятой.

Библиотека Texas Instruments TMS320C28x IQmath представляет собой набор высокооптимизированных и высокоточных математических функций для программистов на C / C ++, позволяющих легко переносить алгоритм с плавающей запятой в код с фиксированной запятой на устройствах TMS320C28x. Эти процедуры обычно используются в приложениях реального времени, требующих большого объема вычислений, где критически важны оптимальная скорость выполнения и высокая точность. Используя эти процедуры, вы можете достичь скорости выполнения значительно быстрее, чем эквивалентный код, написанный на стандартном языке ANSI C. Кроме того, предоставляя готовые к использованию высокоточные функции, библиотека TI IQmath может значительно сократить время разработки приложений DSP.

Это использует некоторые специфичные для TI вещи, но я также использовал этот код в качестве основы для реализации виртуальной математики с плавающей точкой на других микроконтроллерах. Для переноса требуется немного работы, но это намного проще, чем начинать с нуля.

embedded.kyle
источник
@ downvoter Хотите прокомментировать, что не так с моим ответом?
embedded.kyle
+1: эта библиотека лучше, чем та, которую он использует сейчас («просто используйте целое число»). Он не делает все, о чем просил исходный вопрос, но я думаю, что такой ответ (полезный, но не полное решение) не заслуживает отрицательного ответа - если только не существует законченного решения (что я сомневаюсь в этом случае ).
Дэвид Кэри
Мне кажется, что ответ, который относится только к одному диапазону устройств и является бесплатным, как в пиве, а не в речи, имеет ограниченное применение для будущих посетителей.
Марк Бут
@MarkBooth Я изменил ссылку с библиотеки C28x на библиотеку C64x. Если вы перейдете по этой ссылке, вы можете запросить исходный код. Вам нужна электронная почта компании или университета, чтобы получить доступ. Все так же свободно как в пиве и речи. Вам просто нужно поднять руку и подождать, пока вас вызовут, прежде чем вы сможете говорить. Немного раздражает, но когда у вас есть исходный код, его можно адаптировать к любому процессору, который вам нравится.
embedded.kyle
Благодаря @ Embedded.kyle исходный код определенно лучше, чем только двоичный, но все же он мало полезен, если лицензия позволяет использовать его ограниченным образом. Согласно странице библиотек программного обеспечения C6x, этот источник выпущен только под коммерческой лицензией TI , которая почти наверняка не является бесплатной, как в речи .
Марк Бут
1

Существует ряд реализаций (нет библиотек, о которых я сразу узнаю) Binary Scaling (иначе B-scaling)

При этом вы сохраняете мысленную заметку (или, что еще лучше, документируете код ...), где находится десятичная точка, используя сдвиги для перемещения десятичной точки вверх или вниз.

Я использовал B-scaling в ассемблере для оборонных проектов, даже на самых маленьких процессорах, поэтому могу поручиться за его пригодность для всего остального ...

Андрей
источник
Возможно, что-то вроде этого, но я никогда не видел, чтобы это называлось b-scaling. Я думаю об этом как о фиксированной точке - десятичная дробь никогда не плавает, потому что, хотя десятичная точка может измениться в ходе вычислений, любая переменная всегда имеет десятичную точку, фиксированную в определенном месте
ronalchn
0

Если вы используете целое число, чтобы помнить, где находится «точка», они как бы используют арифметику с плавающей запятой. Фиксированная точка, действительно имеет фиксированную точку.

atancosππ

Это зависит от диапазона значений, в котором нуждается ваше приложение, но вы можете полностью перейти к представлению с фиксированной точкой. То есть, например, вместо того, чтобы хранить число вроде этого:

struct num
{
    uint16_t number;
    uint16_t decimal_point;
};

где numberцелое число и decimal_pointговорит, где находится десятичная точка, вы можете сохранить его следующим образом:

struct num
{
    uint16_t integer;
    uint16_t fraction;
};

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

Shahbaz
источник
На самом деле хранение десятичной точки делает ее более похожей на число с плавающей запятой. Обычно десятичная точка определяется во время компиляции, и вы меняете представление в зависимости от вашей операции.
Якоб
Я не имею в виду, помните, как хранится в переменной, я имею в виду, помните, как я помню, как я помню, как интерпретировать результат (зная, где находится десятичная точка)
ronalchn
@ronalchn, я вижу. Вы имели в виду что-то вроде с #define, верно? Я думал, что вы на самом деле храните его, и оно может варьироваться в зависимости от того, насколько велико или мало ваше число.
Шахбаз
@ronalchn - ты думаешь о B-scaling? (см. мой ответ)
Андрей