Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Преобразование последовательности байтов во float


Автор: Hukuma 17.4.2009, 14:55
Здравствуйте!

Тема похожа на эту http://forum.vingrad.ru/topic-64014.html

Исходные данные - есть последовательность из 4ых байтов - это части числа в формате float. Т.е. знак экспоненты,экспонент, мантисса.
нужно из этих 4ых байтов собрать число в формате float.. я понял, что это можно сделать, использую побитовые операции, это как описано
в теме, на которую я сослался.. а вопрос такой - а нельзя это сделать проще? Очень туго въезжаю в формат IEEE754. Или нет других путей? 

Автор: UniBomb 17.4.2009, 15:04
Код

float  GetFloatFromFourBytes(char [] data)
 {
  union 
   {
     float num;
     char byte[4];
   } SimpleFloat;

  for(int i = 0; i < 4; i++)
   SimpleFloat.byte[i] = data[i];

  return SimpleFloat.num;
 }


как то так....

Автор: Hukuma 17.4.2009, 15:12
Unibomb,спасибо большое..интересный вариант, понравилс очень, сейчас попробую smile

Автор: InvalidProperty 17.4.2009, 15:12
только, наверное, порядок байт в слове еще нужно учитывать

Автор: GoldFinch 17.4.2009, 15:16
Цитата(UniBomb @  17.4.2009,  16:04 Найти цитируемый пост)
float  GetFloatFromFourBytes(char [] data)
 {
  union 
   {
     float num;
     char byte[4];
   } SimpleFloat;
  for(int i = 0; i < 4; i++)
   SimpleFloat.byte[i] = data[i];
  return SimpleFloat.num;
 }

Жесть какая, 4 байта копировать в 4 байта циклом %)

return (float)data[0];

Автор: UniBomb 17.4.2009, 16:22
Цитата(GoldFinch @  17.4.2009,  15:16 Найти цитируемый пост)
return (float)data[0];

А теперь спроси у компилятора (у лбого), что он думает по поводу этой строчки. Компилятор ответит, что результатом будет содержимое этой переменной (data[0]), пробразованное во float. 

А копировать ничего не придётся, если массив data объявить в составе объединения.

Автор: InvalidProperty 17.4.2009, 16:29
Цитата(UniBomb @  17.4.2009,  16:22 Найти цитируемый пост)
А копировать ничего не придётся, если массив data объявить в составе объединения. 

это истина, ибо union это не какой-то там struct. Его поля одинаковой длины ссылаются на одно и то же значение

Автор: GoldFinch 17.4.2009, 16:53
UniBomb, ок, return *(float*)data;

Автор: Rififi 17.4.2009, 23:00
GoldFinch, 
Жесть какая, 4 байта копировать в 4 байта циклом %)

return (float)data[0];

лучше жесть, чем неработающая кривизна ЖлолЖ

Автор: zim22 18.4.2009, 07:47
Код

float  GetFloatFromFourBytes(void *data)
 {
...
   SimpleFloat.num = *static_cast<float*>(data);


Автор: GoldFinch 18.4.2009, 10:15
Rififi, объясни, зачем читать через пост, а не все посты подряд?

Автор: mrbrooks 20.4.2009, 08:15
zim22, может все таки лучше через reinterpret_cast имхо.

по сабжу конечно объединения хороши, но и memcpy тоже не плохо.

Автор: Rickert 20.4.2009, 08:28
А memcpy никто не пробовал? smile 

Автор: zim22 20.4.2009, 08:29
Цитата(mrbrooks @  20.4.2009,  08:15 Найти цитируемый пост)
может все таки лучше через reinterpret_cast имхо.

я сначала сделал вариант с reinterpret_cast, но потом вспомнил, что это опасные преобразования.
а static_cast - безопаснее. тем более с ним работает тоже smile

Автор: mrbrooks 20.4.2009, 08:50
Цитата(zim22 @  20.4.2009,  08:29 Найти цитируемый пост)
я сначала сделал вариант с reinterpret_cast, но потом вспомнил, что это опасные преобразования.

опасные - для классов, для базовых типов - думаю не очень  smile 

Цитата(zim22 @  20.4.2009,  08:29 Найти цитируемый пост)
а static_cast - безопаснее. тем более с ним работает тоже 

если так - то и славно - еще одно решение в копилку.

Автор: Rickert 20.4.2009, 09:58
Ау, извращенцы!
Код
const size_t size = sizeof(float);
char d[size] = {0};
float dest;

//some data storing in "d";

memcpy(&dest, d, size);

Какие Reinterpret'ы и доп. классы, не сходите с ума smile 

Автор: mrbrooks 20.4.2009, 10:33
Цитата(Rickert @  20.4.2009,  09:58 Найти цитируемый пост)
Ау, извращенцы!
....
Какие Reinterpret'ы и доп. классы, не сходите с ума


сам извращенец. 

если внимательно почитаешь посты - то memcpy уже предложили, до такого гениального парня, как ты. 
 smile 

Автор: Hukuma 20.4.2009, 10:55
Огромное всем спасибо за участие! smile очень много нового узнал и вопрос тоже решён smile спасибо большое! smile

Автор: Rickert 20.4.2009, 11:11
mrbrooks, слеподыр! Не углядел! smile 

Автор: GoldFinch 20.4.2009, 11:40
Rickert, копировать 4 байта memcpy() - как минимум глупо

Автор: UniBomb 20.4.2009, 11:47
эх, тема была бы ещё интересней, если бы тут не занимались членомерством, а предлагали бы новые вариаты фразой "а ещё можно так", вместо "так делат глупо - надо вот так"....

Автор: Lazin 20.4.2009, 12:07
Цитата(UniBomb @  20.4.2009,  11:47 Найти цитируемый пост)
эх, тема была бы ещё интересней, если бы тут не занимались членомерством, а предлагали бы новые вариаты фразой "а ещё можно так", вместо "так делат глупо - надо вот так"....

а можно вот так: 
Код

float dest;
char data[4];
std::copy(data, data + 4, &dest);
 smile 

Автор: zim22 20.4.2009, 12:50
Цитата(Lazin @  20.4.2009,  12:07 Найти цитируемый пост)
а можно вот так: 

нельзя. я уже так пробовал smile

Автор: mrbrooks 20.4.2009, 13:14
Цитата(zim22 @  20.4.2009,  12:50 Найти цитируемый пост)
нельзя. я уже так пробовал

может он не в студии делал?

Автор: zim22 20.4.2009, 13:25
Цитата(mrbrooks @  20.4.2009,  13:14 Найти цитируемый пост)
может он не в студии делал?

в Code::blocks тоже не работает. Вы сами подумайте, как оно может работать!?

Автор: GoldFinch 20.4.2009, 13:28
Цитата(zim22 @  20.4.2009,  14:25 Найти цитируемый пост)
как оно может работать!?

нормально может работать
data, data + 4, &dest - указатели, должны неявно преобразовываться в итераторы

Автор: Lazin 20.4.2009, 13:33
не должно работать, так как у указателей разный тип, нужно &dest привести к char

Автор: zim22 20.4.2009, 13:37
Цитата(GoldFinch @  20.4.2009,  13:28 Найти цитируемый пост)
нормально может работать

нет. оно не будет нормально работать. оно будет криво работать.

Цитата(Lazin @  20.4.2009,  13:33 Найти цитируемый пост)
нужно &dest привести к char

теперь работает.
Код

std::copy(data, data + 4, (char*)&dest);

Автор: UnrealMan 20.4.2009, 13:38
Цитата(UniBomb @  20.4.2009,  11:47 Найти цитируемый пост)
эх, тема была бы ещё интересней, если бы тут не занимались членомерством, а предлагали бы новые вариаты фразой "а ещё можно так", вместо "так делат глупо - надо вот так".... 

Факт есть факт: самый простой и правильный способ - использование memcpy. Финт с объединением - это ненужное усложнение кода, а касты к float* не соблюдают выравнивание.

Автор: mrbrooks 20.4.2009, 13:47
Цитата(UnrealMan @  20.4.2009,  13:38 Найти цитируемый пост)
Финт с объединением - это ненужное усложнение кода

в чем усложнение то? в написание union. По мне так использование анонимного объединения ничем не хуже memcpy. 

Автор: UnrealMan 20.4.2009, 14:03
Цитата(mrbrooks @  20.4.2009,  13:47 Найти цитируемый пост)
По мне так использование анонимного объединения ничем не хуже memcpy.

А данные в объединении с воздуха берутся? Копировать байты по-любому приходится - либо циклом, как предложено выше, либо тем же memcpy, либо ещё чем-то аналогичным. Так зачем копировать данные в какое-то там объединение, если можно скопировать их сразу в переменную типа float? smile 

Автор: mrbrooks 20.4.2009, 14:09
Цитата(UnrealMan @  20.4.2009,  14:03 Найти цитируемый пост)
Копировать байты по-любому приходится - либо циклом, как предложено выше, либо тем же memcpy. Так зачем копировать данные в какое-то там объединение, если можно скопировать их сразу в переменную типа float?

с этим согласный   smile 

Автор: GoldFinch 20.4.2009, 14:21
Цитата(UnrealMan @  20.4.2009,  15:03 Найти цитируемый пост)
Копировать байты по-любому приходится - либо циклом, как предложено выше, либо тем же memcpy,

инструкцией mov
в 32 разрядных системах 4байтовые переменные должны копироваться 1 инструкцией mov (или m2m)
использование циклов, функций библиотек языка или апи для копирования 4 байт это бред %)

Автор: vinter 20.4.2009, 14:31
GoldFinch,  в С\С++ нет инструкции mov, там вообще нет никаких инструкций  smile 

Автор: Irdis 20.4.2009, 18:18
 я тоже умею  smile, (оч. часто юзаю)
Код

float ConvertCharToFloat(char* a)
{
    float n;
    char* n1;
    float* n2=&n;
    n1=(char *) n2;
    for (int i=0;i<4;i++)
        n1[i]=a[i];
    return n;
}


Автор: zim22 20.4.2009, 18:33
Цитата(Irdis @  20.4.2009,  18:18 Найти цитируемый пост)
я тоже умею  , (оч. часто юзаю)

тогда уж так. хотя как уже выяснилось в этой теме - вариант с memcpy - оптимальный.
Код

float ConvertCharToFloat(char* a)
{
    float result;
    for (int i = 0; i != 4; ++i)
        ((char*)&result)[i] = a[i];
    return result;
}

Автор: GoldFinch 20.4.2009, 18:54
zim22, в каком месте он оптимальный? по скорости? по объему кода? про числу строчек исходника? да ниразу

Автор: zim22 20.4.2009, 19:10
GoldFinch, предлагайте тогда альтернативные варианты. не словом, а делом.

Автор: mes 20.4.2009, 19:23
Цитата(zim22 @  20.4.2009,  18:10 Найти цитируемый пост)
GoldFinch, предлагайте тогда альтернативные варианты. не словом, а делом. 

 a он разве не предложил ?
Цитата(GoldFinch @  17.4.2009,  15:53 Найти цитируемый пост)
*(float*)data

 и даже обосновал, почему этот вариант ему кажется самым привлекательным:
Цитата(GoldFinch @  20.4.2009,  13:21 Найти цитируемый пост)
в 32 разрядных системах 4байтовые переменные должны копироваться 1 инструкцией mov (или m2m)

ну и не забыл охарактеризовать  другие подходы :

Цитата(GoldFinch @  20.4.2009,  13:21 Найти цитируемый пост)
использование циклов, функций библиотек языка или апи для копирования 4 байт это бред %)

Как видите и словом и делом smile

Автор: zim22 20.4.2009, 20:03
Цитата(GoldFinch @  20.4.2009,  18:54 Найти цитируемый пост)
в каком месте он оптимальный? по скорости? по объему кода? про числу строчек исходника? да ниразу

Цитата(GoldFinch @  20.4.2009,  14:21 Найти цитируемый пост)
в 32 разрядных системах 4байтовые переменные должны копироваться 1 инструкцией mov (или m2m)

Поставьте бряк на строке с memcpy и войдите внуть функции. Вас перекинет в файл memcpy.asm. Это же ваш любимый ассемблер! Ваши любимые команды! Мечты сбываются  smile 

Автор: vinter 20.4.2009, 20:35
Цитата(mes @  20.4.2009,  20:23 Найти цитируемый пост)
и даже обосновал, почему этот вариант ему кажется самым привлекательным:

Цитата(mes @  20.4.2009,  20:23 Найти цитируемый пост)
ну и не забыл охарактеризовать  другие подходы :

круто, а когда надо будет строку с цифрами выражение парсить будем lua предлагать?

Автор: UnrealMan 20.4.2009, 21:53
Цитата(zim22 @  20.4.2009,  20:03 Найти цитируемый пост)
Поставьте бряк на строке с memcpy и войдите внуть функции. 

Это не самый лучший способ увидеть результат оптимизации компилятора smile Не знаю, как гнусь, а более-менее новые VC++ и IC++ умеют вместо вызова memcpy делать те же mov:

Код
void binary_to_float(const char* data, float& result)
004043C0  mov         eax,dword ptr [data] 
004043C4  mov         ecx,dword ptr [result] 
{
    std::memcpy(&result, data, sizeof(result));
004043C8  mov         edx,dword ptr [eax] 
004043CA  mov         dword ptr [ecx],edx 
}

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

Автор: GoldFinch 20.4.2009, 22:27
Цитата(UnrealMan @  20.4.2009,  22:53 Найти цитируемый пост)
004043C8  mov         edx,dword ptr [eax] 
004043CA  mov         dword ptr [ecx],edx 

для этого используют push\pop, твой оптимизатор гуан*

Добавлено через 6 минут и 13 секунд
алсо такой код должен инлайниться, а идея использования отдельный функции для копирования 4 байт в 4 байта ничем не лучше чем если бы memcpy была отдельной функцией

Автор: mes 20.4.2009, 22:46
Цитата(GoldFinch @  20.4.2009,  21:27 Найти цитируемый пост)
для этого используют push\pop, твой оптимизатор гуан*

Добавлено через 6 минут и 13 секунд
алсо такой код должен инлайниться, а идея использования отдельный функции для копирования 4 байт в 4 байта ничем не лучше чем если бы memcpy была отдельной функцией 

сорри, но не уловил смысла, нельзя ли иначе (попроще) изъясниться ?

Автор: UnrealMan 21.4.2009, 01:44
Цитата(mes @  20.4.2009,  22:46 Найти цитируемый пост)
сорри, но не уловил смысла, нельзя ли иначе (попроще) изъясниться ?

Смысл примерно следующий: операции со стеком push и pop выполняются типа быстрее, чем простые mov с дополнительным регистром, только вот тупые разработчики компиляторов в Intel и Microsoft об этом не знают. А ещё mov (в отличие от push и pop) занимает страшно много места (вынуждая несчастных пользователей покупать терабайтные винчестеры для хранения полученных таким варварским способом исполнительных файлов). Короче, продемонстрированная оптимизация - полный песец, и, поэтому, ясень пень, тут нужно скорей хвататься за ассемблер, чтобы на нём родить самый оптимальный по своему количеству, скорости и переносимости исходный код.

Добавлено @ 01:45
Что касается приведённого мной кода, то он специально подобран так, чтобы всем сразу было видно, во что компилятор может превратить memcpy. Это не было предложением использовать на практике именно такой код.

Автор: Rickert 21.4.2009, 02:31
Цитата(GoldFinch @  20.4.2009,  11:40 Найти цитируемый пост)
Rickert, копировать 4 байта memcpy() - как минимум глупо

А вот теперь я слушаю оргаменты.

Автор: xvr 21.4.2009, 10:54
Цитата(GoldFinch @ 20.4.2009,  22:27)
Цитата(UnrealMan @  20.4.2009,  22:53 Найти цитируемый пост)
004043C8  mov         edx,dword ptr [eax] 
004043CA  mov         dword ptr [ecx],edx 

для этого используют push\pop, твой оптимизатор гуан*

Рукоблудием надо меньше заниматься - инструкции PUSH/POP выполняются ВДВОЕ/ВТРОЕ медленне, чем MOV  smile 
Источник - Intel 64 and IA-32 Architectures Optimization reference manual (248966-016), таблица C-12

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)