Приведение битового потока к типу с плавающей запятой - PullRequest
1 голос
/ 18 февраля 2010

У меня проблемы с получением следующего кода для правильной работы. Используя онлайн-конвертер IEEE-754, я записал (вручную) в файл testData.txt, который читается со строкой битов, которая должна обозначать число с плавающей запятой 75,5; фактический cout.write действительно показывает, что битовая строка соответствует ожиданиям. Однако, когда я пытаюсь привести char * в число с плавающей точкой, используя объединение (как я видел, это типичный способ выполнить это преобразование), результирующее число с плавающей точкой не соответствует ожидаемому числу.

#include<climits>
#include<iostream>
#include<fstream>
#include<bitset>

int main( int, char** )
{

    std::ifstream inputFile( "testData.txt", std::ios_base::in | std::ios_base::binary );
    if( !inputFile ) std::cout << "Failed to open input file!" << std::endl;

    char buffer[ CHAR_BIT * sizeof(float) ];
    inputFile.read( buffer, CHAR_BIT * sizeof(float) );

    std::cout << "cout.write of input from file = ";
    std::cout.write( buffer, CHAR_BIT * sizeof(float) );
    std::cout << std::endl;

    union { float f; char* c; } fToCharStarUnion;

    fToCharStarUnion.c = buffer;
    std::bitset< sizeof(float) * CHAR_BIT > bits( std::string( fToCharStarUnion.c ) );
    std::cout << "fToCharStarUnion.f = " << fToCharStarUnion.f << " bits = " << bits << std::endl;

    inputFile.close();
    return 0;
}

Результат выполнения этого:

cout.write of input from file = 01000010100101110000000000000000
fToCharStarUnion.f = -1.61821e+38 bits = 01000010100101110000000000000000

Есть что-то фундаментальное, что я не делаю, чтобы это правильно работало?

Ответы [ 2 ]

4 голосов
/ 18 февраля 2010

Ваш союз должен включать массив char, а не указатель.

union { float f; char c[sizeof(float)]; } float2char;

Вам также придется беспокоиться о порядке байтов; является c [0] показателем конца поплавка или хвостом мантиссы. (Ответ будет зависеть от вашего оборудования - Intel против PPC или SPARC или ...)

3 голосов
/ 18 февраля 2010

Вы переводите ASCII в биты, используя конструктор bitset. Это приводит к тому, что ваши декодированные биты находятся в объекте bitset, а не union. Чтобы получить необработанные биты из набора битов, используйте метод to_ulong:

#include<climits>
#include<iostream>
#include<fstream>
#include<bitset>

int main( int, char** )
{

    std::ifstream inputFile( "testData.txt",
       std::ios_base::in | std::ios_base::binary );
    if( !inputFile ) std::cout << "Failed to open input file!" << std::endl;

    char buffer[ CHAR_BIT * sizeof(float) ];
    inputFile.read( buffer, CHAR_BIT * sizeof(float) );

    std::cout << "cout.write of input from file = ";
    std::cout.write( buffer, CHAR_BIT * sizeof(float) );
    std::cout << std::endl;

    union {
        float f[ sizeof(unsigned long)/sizeof(float) ];
        unsigned long l;
    } funion;

    funion.l = std::bitset<32>( std::string( buffer ) ).to_ulong();
    std::cout << "funion.f = " << funion.f[0]
       << " bits = " << std::hex <<funion.l << std::endl;

    inputFile.close();
    return 0;
}

Обычно это предполагает, что ваш FPU работает с тем же порядком байтов, что и целочисленная часть вашего ЦП, и что sizeof(long) >= sizeof(float)… менее гарантированно для double, и действительно, сложнее сделать перенос для 32-битных машин с 64-битные FPU.

Редактировать: Теперь, когда я сделал членов объединения равными по размеру, я вижу, что этот код чувствителен к порядку байтов. Декодированный float будет в последнем элементе массива на машине с прямым порядком байтов, первый элемент на младшем порядке. : v (. Возможно, лучшим подходом было бы попытаться дать целочисленному члену объединения столько же бит, сколько и члену FP, и выполнить сужающее приведение после получения to_ulong. Очень сложно поддерживать стандарт переносимости, который вам казался снимать в оригинальном коде.

...