C ++ binary float

I am wondering if there is a way to represent float using char in C ++?

For instance:

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

I read that maybe using a bitset, I can do this, but I'm not sure.

Suppose my float variable is 01001010 01001010 01001010 01001010 in binary format.

If I want a char array of 4 elements, the first element will be 01001010, the second: 01001010, etc.

Can I represent a float variable in a 4-element char array?

+4
source share
7 answers

I suspect you are trying to say:

 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 to add: all the people indicating that you cannot put a float in 8 bits are correct, of course, but in fact the OP is groping for the understanding that a float , like all atomic data types, is ultimately a simple continuous block bytes. This is not obvious to all beginners.

+8
source

using combining is clean and easy

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

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

Much safer from a compiler point of view than pointers. Memcpy works great too.

EDIT

Good, good, here are full-featured examples. Yes, you should use unions with caution if you do not follow how this compiler allocates the union and the pads or evens out that it can break, and therefore some / many say it is dangerous to use unions in this way. However, are alternatives considered safe?

Doing some C ++ readings has its problems with unions, and unification may very simply not work. If you really meant C ++, not C, this is probably bad. If you said kleenex and meant fabrics, then this might work.

 #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;
 }

And the result looks like this:

  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

You can check manually or look at this website, since I took examples directly from it, the result is as expected.

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

What you never want to do is point to a memory with a pointer to look at it with a different type. I never understood why this practice is used so often, especially for structures.

  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;
 }

This code will work 99% of the time, but not in 100% of cases. It will fail when you least expect it and at the worst of times, like the day after your most important customer receives it. Its an optimizer that eats your lunch with this coding style. Yes, I know that most of you do this, and they have been taught and probably never burned ... It just makes him more painful when he finally happens, because now you know that he can and failed (with popular compilers like gcc on regular computers like PCs).

After this method failed when using this method to test fpu, programmatically creating specific floating point numbers / patterns, I switched to an allied approach, which so far has never worked. By definition, elements in a union have the same piece of storage, and the compiler and optimizer are not confused with respect to two elements in this shared storage that ... are in the same shared storage. Using the code above, you rely on the assumption that non-register memory is saved for each use of the variables, and all variables are written back to this memory before the next line of code. Great if you never optimize or use a debugger. The optimizer in this case does not know that the result and the test have the same piece of memory, and this is the root of the problem / error. To make a game with a pointer, you have to fall into anything, like a union, you still need to know how the compiler aligns and pillows, you still have to deal with content.

The problem is that the compiler does not know that two elements have the same memory space. For a specific trivial example above, I observed how the compiler optimizes the assignment of a number to a floating point variable, since this value / variable is never used. The address for storing this variable is used, and if you tell printf the result data *, the compiler will not optimize the result pointer and thus will not optimize the address for testing, and thus will not optimize the storage for the test, but in this simple example it may have happened when the numbers 4.567 and 1.2345 never get into the compiled program. I also see that the compiler allocates storage for the test, but assigns numbers to the floating-point register, and then never uses this register and does not copy the contents of this register to the storage that it assigned. The reasons why this is unsuccessful for less trivial examples may be more difficult to fulfill, which is often associated with the allocation and eviction of registers, changing the line of code and its operation, changing the other and breaking it.

Memcpy,

 #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

I'm going to deal with the burning ones with my comments and depending on which side of the argument you decide to be included. Memcpy is probably your safest route. You still need to know the compiler well and manage your content. The compiler should not spoil memcpy, it should store registers in memory before calling and execute in order.

+2
source

the best you can create a custom float, byte size. or use char as a decimal point with a fixed point. in all cases, this will lead to a significant loss of accuracy.

+1
source

You can do this partially only in such a way as to prevent a complete restoration of the original float. In general, this is called Quantization , and depending on your requirements, there is the art of choosing good quantization. For example, the floating point values ​​used to represent R, G, and B in a pixel will be converted to char before being displayed on the screen.

Alternatively, it is easy to store the entire float as four characters, with each char storing some information about the original number.

0
source

You can create a fixed point value for this number using 2 bits for the whole number and 5 bits for the fractional part (or 6 if you want it to be unsigned). This would allow approximately 4.76 to be stored in terms of accuracy. You are not large enough to represent this number much more accurately - if you have not used the ROM search table of 256 entries, in which you store your information outside the number itself and in the translator.

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

If we ignore that your float is a float and converts 47567 to binary, we get 10111001 11001111. This is 16 bits, which is twice the size of a char (8 bits). The floats store their numbers, keeping the sign bit (+ or -), the indicator (where to put the decimal point, in this case 10 ^ -1), and then the significant digits (47567). There is not enough storage in the char store to store the float.

Alternatively, keep in mind that char can only store 256 different values. With four decimal places, there are more than 256 different values ​​from 1 to 4.7567 or even 4 and 4.7567. Since you cannot distinguish more than 256 different values, you do not have enough space to store it.

Perhaps you could write something that would "translate" from the float to char, limiting yourself to an extremely small range of values ​​and only one or two decimal places *, but I cannot think of any reason I would like.

* You can save any value from 0 to 256 in char, so if you always multiplied the value of char by 10 ^ -1 or 10 ^ -2 (you could use only one of these options, and not because there is no storage space exponents), you can save any number between 0 and 25.6 or 0 and 2.56. I do not know what to use it would be.

0
source

AC char - only 8 bits (on most platforms). The main problem that arises is twice. First, almost all existing FPUs support the IEEE floating point. This means that floating point values ​​require 32 bits or 64. Some support other non-standard sizes, but the only ones I know about are 80 bits. Not. I have never heard of supporting floats of only 8 bits. Thus, you could not have hardware support for an 8-bit float.

More importantly, you won’t be able to get many numbers from an 8-bit float. Remember that some bits are used to represent the exponent. You have almost no accuracy for your numbers.

Would you like to know about a fixed point ? That would be doable in bytes.

0
source

Source: https://habr.com/ru/post/1308486/


All Articles