2010-04-30 3 views
4

Мне интересно, есть ли способ представить float с использованием символа в C++?Float to binary in C++

Например:

int main() 
{ 
    float test = 4.7567; 
    char result = charRepresentation(test); 
    return 0; 
} 

я прочитал, что, вероятно, с помощью BitSet я могу это сделать, но я не уверен, что.

Предположим, что моя переменная float 01001010 01001010 01001010 01001010 в двоичном формате.

Если я хочу массив символов из 4 элементов, первый элемент будет 01001010, второй: 01001010 и так далее.

Могу ли я представить переменную float в массиве char из 4 элементов?

+3

Какое значение вы ожидаете от 'результата'? –

+3

То есть, чего вы пытаетесь достичь? – Potatoswatter

+0

Поплавок уже в «двоичном», между прочим. По крайней мере, с учетом любого практического компьютера, который использует OP. –

ответ

1

лучшее, что вы можете создать пользовательский плавающий размер байта. или использовать символ как десятичную точку с фиксированной точкой. во всех случаях это приведет к значительной потере точности.

+0

Хотя точность потерь может быть несущественной, в зависимости от требований к данным. Например. 8 бит могут представлять 1.0 и 0.0 и 254 шагов между ними, если это все, что вам нужно. –

0

Вы можете сделать это только частично, чтобы не допустить полного восстановления исходного поплавка. В общем, это называется Quantization, и в зависимости от ваших требований существует искусство выбора хорошего квантования. Например, значения с плавающей запятой, используемые для представления R, G и B в пикселе, будут преобразованы в символ перед отображением на экране.

В качестве альтернативы, можно легко хранить поплавок в виде четырех символов, причем каждый символ хранит некоторую информацию об исходном номере.

0

Вы можете создать для этого числа значение фиксированной точки, используя 2 бита для всего числа и 5 бит для дробной части (или 6, если вы хотите, чтобы она была без знака). Это позволило бы хранить примерно 4,76 с точки зрения точности. У вас недостаточно большого размера, чтобы представить это число гораздо точнее - если вы не использовали таблицу поиска ROM из 256 записей, в которой вы храните свою информацию вне самого номера и в переводчике.

8

Я подозреваю, что вы пытаетесь сказать:

int main() 
{ 
    float test = 4.7567; 
    char result[sizeof(float)]; 

    memcpy(result, &test, sizeof(test)); 

    /* now result is storing the float, 
      but you can treat it as an array of 
      arbitrary chars 

     for example: 
    */ 
    for (int n = 0; n < sizeof(float); ++n) 
     printf("%x", result[n]); 

    return 0; 
} 

Edited добавить: все люди, указывая на то, что вы не можете поместить float в 8 бит, конечно, правильно, но фактически ОП нащупывает понимание того, что float, как и все атомарные типы данных, в конечном счете представляет собой простой непрерывный блок байтов. Это не очевидно для всех новичков.

+0

Я бы добавил что-то к этому, чтобы объяснить, что «sizeof» разрабатывает, сколько символов вы можете поместить в float, и чтобы вы вернули несколько символов в качестве результата. – deworde

+3

Вы также можете использовать reinterpret_cast (тест) для аналогичного эффекта. – starblue

+0

Если float принимает 32 бита, а char принимает 8 бит, могу ли я разделить весь float на 4 части, я имею в виду, массив char из 4 элементов? – Eric

0
int main() 
{ 
    float test = 4.7567; 
    char result = charRepresentation(test); 
    return 0; 
} 

Если мы будем игнорировать, что ваш поплавок поплавок и конвертировать 47567 в двоичном, мы получаем 10111001 11001111. Это 16 бит, что в два раза превышает размер полукокса (8 бит). Поплавки хранят свои номера, сохраняя знаковый бит (+ или -), показатель (где положить десятичную точку, в данном случае 10^-1), а затем значимые цифры (47567). Просто не хватает места в чарке, чтобы хранить поплавок.

В качестве альтернативы учтите, что символ может хранить только 256 различных значений. С четырьмя десятичными знаками точности существует более 256 различных значений от 1 до 4.7567 или даже 4 и 4.7567. Поскольку вы не можете различать более 256 различных значений, у вас недостаточно места для его хранения.

Возможно, вы могли бы написать что-то, что «переводило бы» из поплавка в символ, ограничивая себя чрезвычайно небольшим диапазоном значений и только одним или двумя десятичными знаками *, но я не могу думать о какой-либо причине, хотеть.

* Вы можете сохранить любое значение между 0 и 256 в символе, поэтому, если вы всегда умножали значение в char на 10^-1 или 10^-2 (вы могли использовать только один из этих параметров, не оба поскольку для хранения экспонентов недостаточно места), вы можете сохранить любое число от 0 до 25.6 или 0 и 2.56. Я не знаю, что использовать это было бы.

0

A C char всего 8 бит (на большинстве платформ). Основная проблема, которая возникает, - в два раза. Во-первых, почти все существующие FPU поддерживают плавучую точку IEEE. Это означает, что для значений с плавающей запятой требуется 32 бита или 64. Некоторые поддерживают другие нестандартные размеры, но единственные, о которых я знаю, - 80 бит. Нет. Я никогда не слышал о поддерживающих поплавках всего 8 бит. Таким образом, у вас не было аппаратной поддержки для 8-битного поплавка.

Что еще более важно, вы не сможете получить много цифр из 8-битного поплавка. Помните, что некоторые биты используются для представления экспоненты. У вас почти нет точности для ваших цифр.

Возможно, вы хотите узнать о Неподвижная точка? Это можно было бы сделать в байте.

+0

Стандартные (IEEE 754-2008) размеры также включают полуточную (16-разрядную) и четырехкратную точность (128 бит). Однако нет 8-битных. – dan04

2

используя союз является чистым и легко

 
union 
{ 
    float f; 
    unsigned int ul; 
    unsigned char uc[4]; 
} myfloatun; 

myfloatun.f=somenum; 
printf("0x%08X\n",myfloatun.ul); 

Гораздо безопаснее с точки зрения компилятора, чем указатели. Memcpy отлично работает.

EDIT

Хорошо, хорошо, здесь полностью функциональные примеры. Да, вы должны с осторожностью использовать профсоюзы, если не будете следить за тем, как этот компилятор выделяет союз и пэды или выравнивает его, что он может сломаться, и поэтому некоторые/многие говорят, что опасно использовать профсоюзы таким образом. Однако альтернативы считаются безопасными?

Проведение чтения С ++ имеет свои проблемы с профсоюзами, и объединение может очень просто не работать. Если вы действительно имели в виду C++, а не C, это, вероятно, плохо. Если вы сказали kleenex и означали ткани, тогда это может сработать.

 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

typedef union 
{ 
    float f; 
    unsigned char uc[4]; 
} FUN; 

void charRepresentation (unsigned char *uc, float f) 
{ 
    FUN fun; 

    fun.f=f; 
    uc[0]=fun.uc[3]; 
    uc[1]=fun.uc[2]; 
    uc[2]=fun.uc[1]; 
    uc[3]=fun.uc[0]; 
} 

void floatRepresentation (unsigned char *uc, float *f) 
{ 
    FUN fun; 
    fun.uc[3]=uc[0]; 
    fun.uc[2]=uc[1]; 
    fun.uc[1]=uc[2]; 
    fun.uc[0]=uc[3]; 
    *f=fun.f; 
} 

int main() 
{ 
    unsigned int ra; 
    float test; 
    char result[4]; 
    FUN fun; 

    if(sizeof(fun)!=4) 
    { 
     printf("It aint gonna work!\n"); 
     return(1); 
    } 

    test = 4.7567F; 
    charRepresentation(result,test); 
    for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 

    test = 1.0F; 
    charRepresentation(result,test); 
    for(ra=0;ra<;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 

    test = 2.0F; 
    charRepresentation(result,test); 
    for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 

    test = 3.0F; 
    charRepresentation(result,test); 
    for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 

    test = 0.0F; 
    charRepresentation(result,test); 
    for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 


    test = 0.15625F; 
    charRepresentation(result,test); 
    for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n"); 

    result[0]=0x3E; 
    result[1]=0xAA; 
    result[2]=0xAA; 
    result[3]=0xAB; 
    floatRepresentation(result,&test); 
    printf("%f\n",test); 

    return 0; 
} 

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

 
gcc fun.c -o fun 
./fun 
0x40 0x98 0x36 0xE3 
0x3F 0x80 0x00 0x00 
0x40 0x00 0x00 0x00 
0x40 0x40 0x00 0x00 
0x00 0x00 0x00 0x00 
0x3E 0x20 0x00 0x00 
0.333333 

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

http://en.wikipedia.org/wiki/Single_precision

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

 
int broken_code (void) 
{ 
    float test; 
    unsigned char *result 

    test = 4.567; 
    result=(unsigned char *)&test; 

    //do something with result here 

    test = 1.2345; 

    //do something with result here 

    return 0; 
} 

Этот код будет работать в 99% случаев, но не в 100% случаев. Он потерпит неудачу, когда вы меньше всего этого ожидаете и в самое худшее время, как на следующий день после того, как ваш самый важный клиент получит его. Его оптимизатор, который ест ваш обед с этим стилем кодирования. Да, я знаю, что большинство из вас это делают, и их учили и, возможно, никогда не сжигали ....Это просто делает его более болезненным, когда он, наконец, происходит, потому что теперь вы знаете, что он может и не справился (с популярными компиляторами, такими как gcc, на обычных компьютерах, таких как ПК).

После того, как этот метод был неудачным при использовании этого метода для тестирования fpu, программно построив определенные числа/шаблоны с плавающей запятой, я переключился на союзный подход, который до сих пор не сработал. По определению элементы в объединении имеют один и тот же кусок хранилища, а компилятор и оптимизатор не путаются в отношении двух элементов в этом общем хранилище, которые ... находятся в том же разделяемом хранилище. С помощью вышеприведенного кода вы полагаетесь на предположение, что за каждым использованием переменных сохраняется нерегистровая память, а все переменные записываются обратно в эту память перед следующей строкой кода. Отлично, если вы никогда не оптимизируете или используете отладчик. Оптимизатор в этом случае не знает, что результат и тест имеют один и тот же кусок памяти, и это корень проблемы/ошибки. Чтобы сделать игру с указателем, вы должны попасть во все, что угодно, как союз, вам все равно нужно знать, как компилятор выравнивает и прокладывает подушки, вам все равно придется иметь дело с контентами.

Проблема заключается в том, что компилятор не знает, что два элемента имеют одинаковое пространство памяти. Для конкретного тривиального примера выше я наблюдал, как компилятор оптимизирует присвоение числа переменной с плавающей запятой, поскольку это значение/переменная никогда не используется. Адрес для хранения этой переменной используется, и если вы скажете printf данные результата *, компилятор не будет оптимизировать указатель результата и, таким образом, не будет оптимизировать адрес для тестирования и, таким образом, не будет оптимизировать хранилище для теста, но в этом простом примере он может и произошел, когда числа 4.567 и 1.2345 никогда не попадают в скомпилированную программу. Я также вижу, что компилятор выделяет хранилище для теста, но присваивает числа регистру с плавающей запятой, а затем никогда не использует этот регистр и не копирует содержимое этого регистра в хранилище, которое он назначил. Причин, по которым он не подходит для менее простых примеров, может быть труднее следовать, что часто связано с распределением регистров и выселением, изменяет строку кода и работает, меняет другую, и она ломается.

тетсру,

 

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

void charRepresentation (unsigned char *uc, float *f) 
{ 
    memcpy(uc,f,4); 
} 

void floatRepresentation (unsigned char *uc, float *f) 
{ 
    memcpy(f,uc,4); 
} 

int main() 
{ 
    unsigned int ra; 
    float test; 
    unsigned char result[4]; 

    ra=0; 
    if(sizeof(test)!=4) ra++; 
    if(sizeof(result)!=4) ra++; 
    if(ra) 
    { 
     printf("It aint gonna work\n"); 
     return(1); 
    } 

    test = 4.7567F; 
    charRepresentation(result,&test); 
    printf("0x%02X ",(unsigned char)result[3]); 
    printf("0x%02X ",(unsigned char)result[2]); 
    printf("0x%02X ",(unsigned char)result[1]); 
    printf("0x%02X\n",(unsigned char)result[0]); 

    test = 0.15625F; 
    charRepresentation(result,&test); 
    printf("0x%02X ",(unsigned char)result[3]); 
    printf("0x%02X ",(unsigned char)result[2]); 
    printf("0x%02X ",(unsigned char)result[1]); 
    printf("0x%02X\n",(unsigned char)result[0]); 

    result[3]=0x3E; 
    result[2]=0xAA; 
    result[1]=0xAA; 
    result[0]=0xAB; 
    floatRepresentation(result,&test); 
    printf("%f\n",test); 

    return 0; 
} 
 
gcc fcopy.c -o fcopy 
./fcopy 
0x40 0x98 0x36 0xE3 
0x3E 0x20 0x00 0x00 
0.333333 

С пламенным я собираюсь получить о моих вышеизложенных замечаний, и в зависимости от того, какая сторона аргумента вы решили быть. Возможно, memcpy - ваш самый безопасный маршрут. Вы все еще должны хорошо знать компилятор и управлять своими контентами. Компилятор не должен испортить memcpy, он должен хранить регистры в памяти до вызова и выполнять в порядке.

+1

Использование 'union' таким образом - неопределенное поведение. – Cubbi

+0

У меня есть ошибка? это не был полностью протестированный код, просто «попробуй что-то вроде этого без ошибок» вроде кода, как и плакаты, вроде как, но проигнорируйте код ошибок. Я использую объединение для изучения бит с плавающей запятой в течение многих лет, различных компиляторов, различных платформ, никогда не было одной проблемы. По крайней мере, в C, не работают ли объединения с C++? –

+0

На самом деле подход memcpy может завершиться неудачно по той же причине, что подход с указателем на память может завершиться неудачно, если вы хотите избежать неопределенного поведения в компиляторах, вам нужно выйти за пределы компилятора, например, писать в файл. Если вам комфортно с надежностью менее 100%, любой из этих подходов будет работать. –