Числа внутри типичных микроконтроллеров вообще не имеют десятичных знаков. Это двоичные целые числа. Внутри машины нет десятичной дроби. Компилятор или ассемблер может позволить вам указать константы таким образом, но они преобразуются в двоичные, прежде чем машина их увидит.
Однако вы можете выбрать любые единицы измерения для целочисленных значений. Например, предположим, что вы хотите представить доллары внутри микро. Изначально он не может заработать 3,21 доллара, но может сделать 321 цент. Микро работает только со значением 321, но вы знаете, что оно представляет собой единицы по 1/100 долларов.
Это всего лишь один пример, иллюстрирующий концепцию произвольных единиц. Часто числа представлены несколькими битами двоичной дроби. Это то же самое, что сказать, что каждый счет представляет значение 2 -N , где N - количество битов дроби. Это представление называется «фиксированной точкой». Вы заранее решаете, какое разрешение вам нужно, и делаете вид, что справа от воображаемой двоичной точки достаточно битов для поддержки этого разрешения. Например, допустим, вам нужно представить что-то с разрешением не менее 1/100. В этом случае вы использовали бы по крайней мере 7 битов дроби, так как 2 7 = 128. Это фактически даст вам разрешение 1/128.
Машина не имеет ни малейшего представления, что это происходит. Он сложит и вычтет эти числа как обычные целые числа, но все по-прежнему работает. Это становится немного сложнее, когда вы умножаете и делите значения с фиксированной точкой. Произведение двух значений с фиксированной точкой с N битами дроби будет иметь 2N битов дроби. Иногда вы просто отслеживаете тот факт, что новое число имеет 2N битов дроби, или иногда вы можете сдвинуть его вправо на N битов, чтобы вернуться к тому же представлению, что и раньше.
Плавающая точка - это то же самое, но число битов дроби сохраняется вместе с целочисленной частью, так что эту настройку можно выполнить во время выполнения. Выполнение математических операций над числами с плавающей запятой может занять несколько циклов. Аппаратные средства с плавающей точкой делают все это для вас, чтобы операции завершались быстро. Однако те же манипуляции могут быть выполнены и в программном обеспечении. Нет причины, по которой вы не можете написать подпрограмму для добавления двух чисел с плавающей запятой, просто это займет гораздо больше времени, чем выделенное оборудование, выполняющее ту же самую вещь.
Я определил 3-байтовый формат с плавающей запятой для 8-битных PIC и написал несколько подпрограмм для управления ими. Микроконтроллеры обычно работают с реальными значениями с точностью до 10 или 12 бит. Мой формат с плавающей запятой использует 16 бит точности, что достаточно для нескольких промежуточных вычислений.
У меня также есть 32-битный формат для 16-битных PIC. Это использует одно 16-битное слово для мантиссы, что ускоряет вычисления, поскольку эти PIC могут работать с 16 битами одновременно.
Эти процедуры включены в мою версию PIC Development Tools . После установки посмотрите на файлы с «fp24» в их имени в каталоге SOURCE> PIC и «fp32f» в каталоге SOURCE> DSPIC.
Арифметика с фиксированной запятой обычно используется для выполнения дробных вычислений в микроконтроллерах.
Хитрость заключается в том, чтобы сказать, что (например) старшие 16 битов
uint32_t
перед десятичной запятой и младшие 16 после, то есть. сохраненное целое число находится в 1/2 ^ 16ths. С некоторыми небольшими оговорками обычная арифметика «просто работает».Вот обзор .
источник
Если ваш MCU не является DSP с множителем с плавающей запятой, все сохраняется как 16-битные (или 8 или 32 в зависимости от вашей платформы) числа. Это все, что знает настоящий MCU.
Выше этого у вас есть код "C" и компилятор C. Компилятор «знает» о различных типах данных, таких как char, int, uint, float, double и так далее.
Наиболее распространенное представление поплавков на оборудовании - в формате IEEE. Это отделяет мантиссу от показателя степени и использует два 16-битных слова для хранения информации. Ознакомьтесь с этой вики-статьей о форматах номеров IEEE.
Таким образом, именно компилятор знает, где находится мантисса и показатель степени, и применяет к нему математические вычисления. Помните, узнать о логарифмах? как они упростили математику, прибавив силу, когда вы хотели сделать несколько? хорошо, компилятор c делает нечто похожее с показателями степени и умножает мантиссу, чтобы вычислить ответ. Таким образом, для умножения с плавающей запятой компилятор создаст ассемблерный код, который добавляет показатели и выполняет умножение мантиссы.
MCU ничего не знает о числе !!! только то, что сказано, загрузить память в регистр, добавить память в регистр и установить флаг переноса, если это необходимо, и так далее, пока умножение не будет завершено.
Именно компилятор C и ваш код "абстрагируют" понятие чисел, десятичных точек и т. Д. От MCU.
Кроме того, некоторые языки также поддерживают «десятичный» тип данных, который полезен для финансовых систем, что не распространено на встраиваемых платформах, поскольку плавающие объекты используют меньше памяти и эффективно работают.
источник
Точно так же, как полноценные процессоры без процессора (например, большинство ARM) работают с плавающей точкой. С программным обеспечением фпу. Есть библиотека, которая выполняет математические / побитовые операции. Если вы помните, как выполняли сложение, умножение и т. Д. В начальной школе карандашом и бумагой, мало что изменилось за день перехода с целых чисел на числа с десятичной точкой. Вы делали математику так же, как вы просто настраивали числа так, чтобы десятичные точки выстраивались в линию до начала (сложение и вычитание) или после того, как вы закончили (умножение или деление). Жесткий и мягкий fpus ничем не отличаются, они корректируют биты до и после операции, но операция в основном представляет собой целую операцию.
Я не помню точно, где его найти сейчас, но у инструментов Техаса был очень хороший документ, связанный с их продуктами DSP. Он объяснил их формат с плавающей запятой и зашел так далеко, что объяснил, как работают операции. Их формат не имеет округления и денормализации, бесконечности, тишины и сигнализации, таких как IEEE, поэтому его гораздо легче понять, а также значительно быстрее, чем форматы IEEE. Однажды увидев этот формат в действии, вы сделали свой первый шаг к формату IEEE. Округление требует некоторого объяснения и размышления, но в остальном основы знака, экспоненты и мантиссы одинаковы.
Использование библиотек с плавающей запятой очень дорого, с точки зрения ресурсов (память, флэш-память, циклы процессора), и я бы не рекомендовал использовать их во встроенной системе или микроконтроллере. 12.3 и 24.5 довольно легко управлять, например, целыми числами 123 и 245, если вы помните или, возможно, если вы убедитесь, что все ваши математические вычисления понимают, что все числа умножены на десять, и если / когда вы отображаете в Пользователь в этом преобразовании вы добавляете десятичную точку. Экономит тонны кода и производительности. Конечно, целочисленное деление - это плохо для микроконтроллеров и встроенных систем, так как большинство процессоров не имеют инструкции деления, и это включает деление на 10 для преобразования в десятичную форму для отображения пользователю. И тот же ответ, деление, которое вы получаете из своего кода на C, выполняется с использованием библиотеки.
источник
Плавающие значения хранятся в двоичном 32-битном формате, и 1-й бит должен указывать, является ли значение с плавающей запятой положительным / отрицательным числом, следующие 8 битов имеют показатель -127, тогда есть 23 бита, которые являются полным числом, включая десятичное место, т.е. :
1 00010001 00010001000000000000000
Так что 1 является то , что она отрицательна, следующие 8 битов , чтобы указать показатель в этом случае:
0001 0001 = 17 (17-127 = -110)
Тогда мантисса делится:
(1+1/4+1/128)2^5
2^5
было движение десятичного разряда, когда поплавок был перемещен в двоичную. В результате при преобразовании теряются некоторые цифры, но они близки.1.5ex10-110
Возможно, я допустил ошибки, следуя другим, но это общее представление о том, как поплавки сохраняются в памяти.
источник