• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Научите считать float

nikolz

Well-known member
Ну как, если до этого число 12.3 это в int 0x4144cccd или1095027917 или x1=52429 x2=16708, и преобразование работает правильно, то просто присвоить тип float дает на выходе 1095027968.0
Ну все верно
Вы преобразовали число 1095027917 из формата int в формат float.
Число не изменилось, а изменилось его внутреннее представление. т е если посмотрите двоичное представление байт числа то обнаружите и мантиссу и порядок в доп коде с удаленным знаком. Т е внутреннее представление у Int и float этого числа разное.
Вы что хотите ?
------------------------------
 

Urbas81

Member
Ну все верно
Вы преобразовали число 1095027917 из формата int в формат float.
Число не изменилось, а изменилось его внутреннее представление. т е если посмотрите двоичное представление байт числа то обнаружите и мантиссу и порядок в доп коде с удаленным знаком. Т е внутреннее представление у Int и float этого числа разное.
Вы что хотите ?
------------------------------
А как внутреннее представление посмотреть? Мне нужно на вход функции подать 2 int на выходе получить float которое я могу записывать в файл или вывести в лог, именно в формате 12.3 так как это сделано тут IEEE-754 Floating Point Converter, только в обратную сторону, для тех int которые дают на выходе float >1 все OK, а если число меньше 1 зависает, скорее всего из-за нехватки времени на возведение в степень.


Код:
double pow(double x,double y)
{
    double z , p=1;
  if(y<0)
    z = fabs(y);
else
    z = y;
for(int i=0; i<z ; ++i)
{
    p *= x;
}
if(y<0)
   return 1/p;
else
   return p;
}



float ICACHE_FLASH_ATTR int_float(uint32 x1, uint32 x0)
{


            uint32 value = (x1<<16) | x0;
            uint32 b=value & 0x7fffff;
            double e=((value>>23) & 0xff)-127;
            double m=1+b*pow(2, -23);
           
            float p=pow(2.0, e);
            float result=m*p;
            if (value & 0x80000000) {
            result=-result;
            }
            return result;
    }
 
А как внутреннее представление посмотреть? Мне нужно на вход функции подать 2 int на выходе получить float которое я могу записывать в файл или вывести в лог, именно в формате 12.3 так как это сделано тут IEEE-754 Floating Point Converter, только в обратную сторону, для тех int которые дают на выходе float >1 все OK, а если число меньше 1 зависает, скорее всего из-за нехватки времени на возведение в степень.
Для начала, os_prinf в esp не поддерживает fp форматы, функцию вывода придется писать самому. Это раз. Два, возводить 2 в степень надо сдвигом влево, ну или вправо, если это отрицательная степень. Ну и три, зачем нужен этот "закат солнца вручную"? Связываться с fp для отсутствующего в библиотеке его вывода? Бессмысленно. Или считайте все в fp, или считайте в целых, а выводите отдельно целую, отдельно дробную части os_printf("%d.%d", mantissa, exponenet); Если считаете в fp, то вывод его не то чтобы сложен, но пописать придется. Я написал вывод вида "1.234k" для числа 1234.0, но там если посмотреть понятно как выводить и в других форматах. Ну оно в строку выводит, потом ее напечатать куда-то надо. Ну и преобразовать целое в fp надо не побитно руками, а просто double d = i+j/100.0; если i - целая часть, а j - сотые.
 

Вложения

nikolz

Well-known member
А как внутреннее представление посмотреть? Мне нужно на вход функции подать 2 int на выходе получить float которое я могу записывать в файл или вывести в лог, именно в формате 12.3 так как это сделано тут IEEE-754 Floating Point Converter, только в обратную сторону, для тех int которые дают на выходе float >1 все OK, а если число меньше 1 зависает, скорее всего из-за нехватки времени на возведение в степень.
Можете рассказать что Вы делаете?
---------------------------
Пока из Вашего смутного рассказа я понял, что у вас есть число записанное в формате float, но в программе вы его получили в виде uint32.
а вы хотите чтобы было float.
Если так, то просто смените тип
float y=(float)x; где х - это uint32 но в нем число в формате float.
т е у Вас код не меняется а меняется тип переменной в которой этот код.
------------------------
Вам это надо?
 

Urbas81

Member
Для начала, os_prinf в esp не поддерживает fp форматы, функцию вывода придется писать самому. Это раз. Два, возводить 2 в степень надо сдвигом влево, ну или вправо, если это отрицательная степень. Ну и три, зачем нужен этот "закат солнца вручную"? Связываться с fp для отсутствующего в библиотеке его вывода? Бессмысленно.
Все что надо и так выводится и печатается, я же написал для чисел >1 все норм.

Или считайте все в fp, или считайте в целых, а выводите отдельно целую, отдельно дробную части os_printf("%d.%d", mantissa, exponenet); Если считаете в fp, то вывод его не то чтобы сложен, но пописать придется. Я написал вывод вида "1.234k" для числа 1234.0, но там если посмотреть понятно как выводить и в других форматах. Ну оно в строку выводит, потом ее напечатать куда-то надо. Ну и преобразовать целое в fp надо не побитно руками, а просто double d = i+j/100.0; если i - целая часть, а j - сотые.
Да, это если есть целые и сотые, вот я и пытаюсь получить целые и сотые, 2 int это пара регистров Modbus в формате float, на их появление я не могу влиять.
По поводу сдвига влево/вправо эту информацию я и ждал, буду смотреть, спасибо.
 

Urbas81

Member
Можете рассказать что Вы делаете?
---------------------------
Пока из Вашего смутного рассказа я понял, что у вас есть число записанное в формате float, но в программе вы его получили в виде uint32.
Наоборот, есть два регистра Modbus в формате int являющиеся передаваемой переменной в формате float, и из них надо собрать float.
 

nikolz

Well-known member
Наоборот, есть два регистра Modbus в формате int являющиеся передаваемой переменной в формате float, и из них надо собрать float.
union {
uint32 i[2];
double a;
}x;
x.i[0]=reg1; x.i[1]=reg2;
x.a -это double (8байт)
========================
если надо float (4 байта то)

union {
uint16 i[2];
float a;
}x;
 

Urbas81

Member
union {
uint32 i[2];
double a;
}x;
x.i[0]=reg1; x.i[1]=reg2;
x.a -это double (8байт)
========================
если надо float (4 байта то)

union {
uint16 i[2];
float a;
}x;
Да, это оно спасибо, уже и с отрицательными заработало, единственно заметил не всегда корректно "-" отображает и иногда разряды теряются, подскажите как правильно перевести в строку, до этого я делал так:
Код:
char*  fts(char* buffer, float value)
{
  os_sprintf_fd(buffer, "%d.%d,", (int)(value),(int)(fabs((value - (int)value)*1000)));
  return buffer;
}
 

nikolz

Well-known member
Да, это оно спасибо, уже и с отрицательными заработало, единственно заметил не всегда корректно "-" отображает и иногда разряды теряются, подскажите как правильно перевести в строку, до этого я делал так:
Код:
char*  fts(char* buffer, float value)
{
  os_sprintf_fd(buffer, "%d.%d,", (int)(value),(int)(fabs((value - (int)value)*1000)));
  return buffer;
}
-------------------------------
хорошо бы проверить правильно ли вы поняли формат регистров.
В некоторых датчиках используется формат в виде целой (один регистр) и дробной части(второй регистр) это не формат float.
и его надо преобразовывать иначе.
--------------------------------------
 
Все что надо и так выводится и печатается, я же написал для чисел >1 все норм.
Да, это если есть целые и сотые, вот я и пытаюсь получить целые и сотые, 2 int это пара регистров Modbus в формате float, на их появление я не могу влиять.
Если в modbus это 32хбитные float, то это тип float у ESP, скорее всего стандартный IEEE-754, просто делаете

union
{
float f;
uint32_t i;
} v;

пишите v.i = modbus[n]; (если у вас там 32хбитное целое) и v.f - ваш float. Если 2 16тибитных, то v.i = ((uint32_t)modbus[n]<<16) +modbus[n+1]; (ну или наоборот, если порядок другой) Если битовый тип в modbus другой, тогда да, придется манипулировать этими битами, запихивать мантиссу, знак, порядок и его знак на свои места. Но обычно 32битный fp везде стандартный.
 
Да, это оно спасибо, уже и с отрицательными заработало, единственно заметил не всегда корректно "-" отображает и иногда разряды теряются, подскажите как правильно перевести в строку, до этого я делал так:
Я пару сообщений назад прицепил код для перевода fp в строки. Там есть с округлением тонкости, надо на один десятичный разряд вперед смотреть, чтобы правильно округлять.
 

Urbas81

Member
Я пару сообщений назад прицепил код для перевода fp в строки. Там есть с округлением тонкости, надо на один десятичный разряд вперед смотреть, чтобы правильно округлять.
Добрый день, использую Ваш функцию для печати float все норм, но на определенных значениях есть провалы/выбросы значений, я так понимаю это и есть "тонкость" как это обойти, я использую задание кол-ва знаков после запятой в диапазоне от 0 до 3, вчера попробовал стороннее решение, на нем все норм, но иногда появляются буквы/знаки после запятой.
 
Добрый день, использую Ваш функцию для печати float все норм, но на определенных значениях есть провалы/выбросы значений, я так понимаю это и есть "тонкость" как это обойти, я использую задание кол-ва знаков после запятой в диапазоне от 0 до 3, вчера попробовал стороннее решение, на нем все норм, но иногда появляются буквы/знаки после запятой.
Там, вроде, все просто и прозрачно, можно примеры чисел, на которых возникают проблемы?
 

Urbas81

Member
Там, вроде, все просто и прозрачно, можно примеры чисел, на которых возникают проблемы?
Насколько я понял, это может происходить на разных числах, как пример первый график, на нем четко видно округление до целых чисел, прямо "забор" прослеживается, на синусоиде все более предсказуемо, я выделил красным одну из частей где это происходит. Возможно это связано с точностью самого float. Для проверки нашел другой пример по выводу float, на нем эта же синусоида без искажений, но там количество знаков после запятой не регулируется.
 

Вложения

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

Код:
#include <stdio.h>
#include <math.h>
#include "strnum.h"

void main(void)
{ 
char str1[256];
char str2[256];
FILE *fo = fopen("sin.txt", "wt");
if (fo)
  {
   for(int i = 0; i<360; i++)
    {
     float f = sin(i*M_PI/180.0);
     d2scistrup(str1, f, "", 3, 0);
     sprintf(str2, "%1.3f", f);
     fprintf(fo, "%i;%s;%s;\n", i, str1, str2);
    }
   fclose(fo);
}  
}
Вроде, проблем не вижу. Проверял в bcb6.
 

Вложения

Сверху Снизу