реклама на сайте
подробности

 
 
> Float To Str, очень быстренькое преобразование
cf7k
сообщение Sep 25 2007, 12:27
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227



А не сталкивался ли кто-либо с потребностью преобразования вещественно числа в строку?
Понятное дело - sprintf (&buf, "%F",....) в большинстве случаев эту проблему решает. Но есть несколько "но": эта ф-ция тянет за собой много математики и работает достаточно неспешно smile.gif

нашел даже красивый вариант:
http://lua-users.org/lists/lua-l/2004-11/msg00466.html

Но все это тянет математику...

Я готов пожертвовать пару килобайт ПЗУ под таблички для ускорения процесса smile.gif

А моя идея такова:

из IEEE-754 взять показатель степени (2^N), вычислить его в формате К*10^Y и хранить две таблички: K и Y, а вся математика сведется к умножению 2х fixed-point чисел.

Z=A*2^N; 2^N = K*10^Y => Z=A*K*10^Y.

и далее домножать на 10 и вытаскивать из старших разрядов очередную цифру.

только вот мои эксперименты к успешному результату никак не хотят приводить.
(в примере ниже все экспериментально)

Код
typedef union _floats {
  unsigned long u;
  float f;
  struct {
    unsigned ml : 16;
    unsigned mh : 7;
    signed   e  : 8;
    unsigned s  : 1;
  };
} floats;


void convert1 (float in, char *dst)
{
#define shift 24
#define mask 0x00FFFFFF;

  floats intf;
  float lg10;
  floats exp2;
  unsigned long ires;
  unsigned char i;

  intf.f = in;
  exp2.u = 0;                         //заземлить :)
  exp2.e = intf.e;

  exp2.f = log10(exp2.f);         //Ex: 2^-17 = 10^-5.11751
  lg10   = floorf(exp2.f);          //10^-5.11751 = (10^-6)*(10^0.88249)
  exp2.f = exp2.f - lg10;
  exp2.f = powf(10, exp2.f);    //10^.088249 = 7.629395
  
  unsigned long long res, mul1, mul2;

  mul1 = intf.u & 0x00FFFFFF;    //1.23
  mul1 = mul1 | 0x800000;       //set hidden "1"
  mul1 = mul1 << 1;                //1.24

  mul2 = exp2.u & 0x00FFFFFF;  //1.23
  mul2 = mul2 | 0x800000;       //set hidden "1"
  mul2 = mul2 << 1;                //1.24

  res = mul1 * mul2;                //целая часть IN [1,2,...,9]
  ires = res >> 24;

   ires = ires * 10;
  i = ires >> shift;
  *dst++ = i + '0';
  
  *dst++ = '.';

  ires &= mask;
  ires = ires * 10;
  i = ires >> shift;
  *dst++ = i + '0';

  ires &= mask;
  ires = ires * 10;
  i = ires >> shift;
  *dst++ = i + '0';
}


Где ж все-таки собака порылась ?

Эти чудеса нацелены на PIC24.
(меня устраивает, что это только для чисел одинарной точности, не универсально; нечисла мне по барабану)
Прикрепленные файлы
Прикрепленный файл  Table2Calc.rar ( 19.64 килобайт ) Кол-во скачиваний: 51
 
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
cf7k
сообщение Sep 26 2007, 15:10
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 82
Регистрация: 14-03-06
Из: Санкт-Петербург
Пользователь №: 15 227



Цитата(Kolia @ Sep 26 2007, 13:55) *
Ну если вы переходите на такие заморочки 07.gif . Я бы порекомендовал вам вообще отказаться от FLOAT математики и перейти к чисмам INT, LONG и т.д. ... и жизнь покажется вам сказкой beer.gif


Я бы с радостью wink.gif Только вот трудоемкость перевода всей математики, калибровочных кривых, и пр. никак не сделают жизнь сказкой. Вся математика уже написана и не мной.

Цитата(zltigo @ Sep 26 2007, 14:35) *
Поскольку человек считывает значения еще более неспешно, то одним из вероятных путей решения этой проблемы является пересмотр построения системы, дабы эта неспешность не находилась в узком месте.


Тут я уже пооптимиздил smile.gif В принципе даже с sprintf'ом на полной частоте можно конвертировать до сотни измерений в сек. Но задача в другом - вписаться в бюджет по питанию, дабы не ставить еще один (или более мощный) DC-DC. Вся обработка одного канала измерений занимает времени столько же сколько и конвертирование float в строку. А у меня еще виртуальная машина кушать хочет smile.gif


Цитата(alexander55 @ Sep 26 2007, 15:42) *
Сталкивался.
Пусть надо 2 знака после запятой. Решал примерно так.

float a=1.23;
int b=(int)(a*100);
cout <<"a=" <<b/100 <<"," <<b%100 ;

Получается полегче.


Спасибо. Идея ясна. Но пусть float a = 1.23e-7 smile.gif В приведенном в исходном посте примере я не показал вывод показателся степени, но он подразумевается.
Когда числа "похожи" на целые двузначные (примерно от 0.1 до 99) - ту все понятно, ну а если динамический диапазон немножко шире - приходится выводить в экспоненциальной форме.

для простоты выпендрежа я делал так:
Код
//-------------------------------------------------------------------------------------------------
//описание формата 3хкомпонентного представления числа
//-------------------------------------------------------------------------------------------------
typedef struct _Value3{
  char  Exp;      //кол-во порядков
  char  M_int;          //целая часть мантиссы
  char  M_1;        //первая цифра дробной части мантиссы
  float Tens;
}Value3, *PValue3;


void FloatToNum3 ( float Num, PValue3 Num3)
{
  float Mantissaf, Expf, M_intf;
  Expf        = floorf( log10f( Num ) );     //целое количество порядков в числе
  Num3->Exp   = (char)Expf;
  Num3->Tens  = powf( 10, Expf );
  Mantissaf   = Num/(Num3->Tens);                //исх. число в формате [1.0..9.9)
  M_intf      = floorf( Mantissaf );    
  Num3->M_int = (char) M_intf;
  Num3->M_1   = (char)floorf( (Mantissaf - M_intf)*10 );
}


Но это по производительности соизмеримо с библиотечым sprintf'ом.

Хотя бы ткните в линк, где бы подробненько были разжеваны правила работы с fixed-point, а то между двух чисел блуждаю... в 23х битах заблудился... клинит меня wacko.gif
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th August 2025 - 15:15
Рейтинг@Mail.ru


Страница сгенерированна за 0.01379 секунд с 7
ELECTRONIX ©2004-2016