STM32 Ошибка вычисления числа с плавающей запятой - PullRequest
0 голосов
/ 03 мая 2019

Я должен выполнить вычисление с двумя числами с плавающей запятой, используя измерения, полученные от датчика расстояния с STM32.Расчет выполняется по следующему уравнению:

result = (df-ds) / ds * 10000;

, где df - первое измерение, а ds - второе измерение.

Пример значений для уравнения;

df = 26.6810;дс = 25,3270;

Моя проблема в том, что результат STM32 для этих значений равен 534.578247 , но когда я выполняю вычисления на калькуляторе Windows вручную, я получаю результат 534.607336 , которыйсильно отличается от расчета STM32.Я также использовал один ручной калькулятор, и ручной калькулятор выдает точно такой же результат с компьютером.

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

Заранее благодарен за любую помощь.

РЕДАКТИРОВАТЬ: Код, который я использую следующим образом;

 float result= 0;
 dmbres = 27.4587;
   int main()
   {
   while(1)
   {
   result= (float)((dmbres- res)/res)*10000;
   dmbres = res;
   sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
   monitor(datapackage);
   }

пакет данных состоит из 2 других сведений, которые мне нужны от MCU, и они не имеют отношения к вычислению result .

Я использую плату STM32F407 DISC-1.

Ответы [ 2 ]

1 голос
/ 03 мая 2019

У вас есть следующий код:

 float result= 0;
 dmbres = 27.4587;
   int main()
   {
   while(1)
   {
   result= (float)((dmbres- res)/res)*10000;
   dmbres = res;
   sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
   monitor(datapackage);
   }

И вы дали следующее уравнение:

результат = (df-ds) / ds * 10000;

со значениями:

df = 26,6810; дс = 25,3270;

И вы сообщили о следующем результате:

результат = 534,578247

Я предполагаю следующее:

  1. Значение, показанное для df ( 26.6810 ), получено в результате преобразования переменной res в строку:

    sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
    

    Поскольку эта выходная строка округляется до 4 десятичных знаков, полученное значение float res могло бы быть любым значением в диапазоне от 26.680950164794921875 до 26.6810474395751953125 . Это формирует значение dmbres для следующей итерации цикла.

  2. Значение, показанное для ds ( 25.3270 ), получено в результате преобразования переменной res в строку в следующей итерации цикла. Поскольку эта выходная строка также округляется до 4 десятичных знаков, значение float res, из которого она получена, могло быть любым значением в диапазоне от 25.3269500732421875 до 25.3270473480224609375 ).

  3. Значение, показанное для result ( 534.578247 ), получено в результате преобразования переменной result в строку на

    sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
    

    Эта строка вывода очень точна для float. Ближайшее сохраненное значение: 534.5782470703125 .

Для возможных значений df и ds наименьшее возможное значение для result = (df-ds)/ds*10000 задается как (26.680950164794921875 - 25.3270473480224609375) / 25.3270473480224609375 * 10000 , и дается наибольшее возможное значение по (26,6810474395751953125 - 25,3269500732421875) / 25,3269500732421875 * 10000 .

Ближайшие float значения, полученные из этих двух выражений, равны 534.5679931640625 и 534.6468505859375 соответственно. Ваш фактический результат 534.5782470703125 попадает в этот диапазон, поэтому не является неожиданным.

0 голосов
/ 04 мая 2019

Как уже упоминалось, цифры «слишком близки».32-разрядное число с плавающей запятой использует 23 бита для значащего, поэтому оно составляет всего около 7 значащих десятичных цифр.например, 1234567. Вы можете поместить десятичную точку где угодно, но любые цифры после 7 неточны, особенно если вы выполняете вычисления с ними.64-битный double использует 52 бита и содержит около 16 десятичных цифр.

Таким образом, вы можете объявить переменные как double.Это даст вам больший диапазон точности за счет (намного) более медленного выполнения.

...