Calculating log2, with unions - c

I found the following code which calculates log2 of float x:
union { float f; unsigned int i; } vx = { x };
float y = vx.i;
y *= 1.0 / (1 << 23);
y = y - 126.94269504f;
return y;
The f parameter of union is initialized to input x and then it uses i? I can not understand how it uses something that is not initialized. And what vx.i value is actually? Thank you.

I can not understand how it uses something that is not initialized.
Actually vx.i is initialized. A union will occupy the same memory location. Therefore vx.i is initialized at the same time that vx.f is initialized.
And what vx.i value is actually?
To get the actual value of vx.i you need to understand how a float is stored in memory. Refer the excellent answer here How are floating point numbers are stored in memory?
From the answer linked,
If vx.f is 1.0 then vx.i will be 3f800000 (in hex)

Unions is something that comes from the time when memory was expensive. They are used to save memory.
When you declare a union, it will be large enough to hold the biggest member. So in this case, the size of vx will be max(sizeof(f), sizeof(i)).
So when you use vx = {x}, the value of x will be put in the memory that has been reserved for vx. When you are using vx.f, then whatever is in that memory will be interpreted as a float, but when you are using vx.i will instead be interpreted as an unsigned integer, but the raw binary data is the same.

union keyword basically means that float f and unsigned int i share the same memory.
initializing the union member f and then reading i is basically implementation defined.
What happens is that you get the binary representation of the float variable. The clever coder then uses that binary representation and scales the value so that you get log2 of the input value.

Your float and int share the same memory location. So the bytes occupied by the float are the same as the bytes of the int. But they mean something completelly different as the binary format of float is different than the int. So of you assign the float value it will change the int but the meaning of it will be completely different.

Related

Why do I get this output with a C union?

#include<stdio.h>
union U{
struct{
int x;
int y;
};
float xy;
};
int main(){
union U u;
u.x = 99;
printf("xy %f\n",u.xy); //output " 0 "
return 0;
}
I have figured out that it has something to do with how float is stored and read internally. Can someone explain it to me exactly?
Converting comments into an answer.
Printing with %f is not very useful; you should consider %g or %e. With %f, if the value is very small, it will be printed as 0.000000 even when it is not zero. (For example, any value smaller than 0.0000005 will be printed as 0.000000.) You need to read about IEEE 754 at Wikipedia, for example, to find out about how such values are represented.
For example, on a Mac running macOS Sierra 10.12.5 using GCC 7.2.0, printing with:
printf("xy %22.16g\n", u.xy);
produces:
xy 1.387285479681569e-43
The range of normal numbers in 4-byte float is normally 10⁺³⁸ to 10⁻³⁸, so a value 1.387…E-43 from a float is a subnormal value (though well within range of 8-byte double values). Remember that float values passed to printf() are promoted to a double automatically because of 'default argument promotions' — printf() never actually receives a float value.
The way float is represented is impacting the result. See How to represent FLOAT number in memory in C and https://softwareengineering.stackexchange.com/questions/215065/can-anyone-explain-representation-of-float-in-memory to see how the float is represented in the memory. You also did not initialize structure variable y. It can have any value in it. It may or may not be used. In your case, the value is very small and you are not printing full value. To see the value of float xy you need to print full value. As suggested in a comment here, if I use below statement in Codeblocks 16.1 on Windows( which contains MinGW compiler) I get value different than 0.000000.
printf("xy %.80f\n",u.xy);
gives me
xy 0.00000000000000000000000000000000000000000013872854796815689002144922874570169700
Yes, you're right, it has to do with the binary representation of a float value, which is defined in the standard document IEEE 754. See this great article by Steve Hollasch for an easy explanation. A float is a 32-bit value, and so is an int. So in your union U, xy falls exactly on the x member of the embedded struct, so when you set x to 99, the bits 1100011 (binary representation of 99) will be reinterpreted in xy as the mantissa of a float. As others have pointed out, this is a very small value, which may be printed as 0, depending on the printf format specifier.
Guessing from the naming of your union members (x, y, xy), I think you wanted to declare something different, e.g.:
union U
{
struct
{
short x;
short y;
};
float xy;
};
Or:
union U
{
struct
{
int x;
int y;
};
double xy;
};
In those declarations, both the x and y members are mapped onto the xy member.
The reason is that the value is very close to zero, so the default 6 digits
of precision isn't enough to display anything.
Try:
union { int i; float f; } u = {.i= 99};
printf("f %g\n", u.f);

How to convert int array (holding float value in Hex) back into float value in C

I'm trying to write a automated test program that requires me to generate an int array datastream (which actually holds float data)
To generate that int array, i try to
write a floating number into char byte array, and then
convert the char byte array into an int array, which later
convert back the number from the int array to floating point ( without losing the decimal points).
I was able to do step 1 & 2 without issue, but I can't convert the int array back to floating point using ( float)(*int_ptr).
My code:
int ibuff[10];
int *int_ptr;
float f=0.1;
char c [sizeof(float)];
memcpy(c, &f, sizeof(float)); //now c is 0x3f800000;
ibuff[0]=(c[3]<<24 | c[2]<<16 | c[1]<<8 | c[0]); //ibuff[0] is now also 0x3f800000
int_ptr=&ibuff[0];
printf("%f\n", (float)(*int_ptr)); //this will print out 1065353216.0000, and not 1.0 as I expected
Your direct problem comes from casting the dereferenced integer pointer int_ptr to a float and then attempting to print that value as a float. You are currently attempting:
printf("%f\n", (float)(*int_ptr));
which as you have found will not work. What you want to do is interpret the value at the address held by int_ptr as a float. To accomplish that, you will need:
printf("%f\n", *(float*)(int_ptr));
While you can view the address as anything your like, you must make sure you do not run afoul of the strict-aliasing rules set forth in the C-standard at rules 6.5 (6) and 6.5 (7). There are limited exceptions specified, but as stated: "The intent ... is to specify those circumstances in which an object may or may not be aliased." Technically your cast from int to float is a violation which is masked by the use of a pointer (arrived at through the intervening use of a character array, which muddies the water a bit further).
In your print statement:
(float)(*int_ptr)
You are casting an int to a float, ie (float)(int)(x) will be the value of x as a float instead of an int. What you want is the memory of the location to be interperated as a float, so you need:
*(float *)(int_ptr)

Copying data from float to an int, without the data being casted

In the following code I try to copy data from a float f to an int i, bit for bit, without any conversion of the data. I cast the address of f to (int*), and dereference this address when I assign it to i. The thinking is that if the program sees &f as an int pointer, it won't do a type conversion when (int*) f is dereferenced and assigned to i. But this isn't working and I do not understand why.
void main(){
float f=3.0;
int i;
/* Check to make sure int and float have the same size on my machine */
printf("sizeof(float)=%d\n",sizeof(float)); /* prints "sizeof(float)=4" */
printf("sizeof(int)=%d\n",sizeof(int)); /* prints "sizeof(int)=4" */
/* Verify that &f and (int*) &f have the same value */
printf("&f = %p\n",&f); /* prints &f = 0x7ffc0670dff8 */
printf("(int*) &f = %p\n",(int*) &f); /* prints (int*) &f = 0x7ffc0670dff8 */
i=*((int*) &f);
printf("%f\n", i); /* prints 0.000000 (I would have expected 3.000000) */
return;
}
By assigning via typecasting you are copying the raw 4 bytes of data from one variable to another. The problem is that a 3 in a 32-bit floating point variable isn't stored like a 3 in an integer variable.
For example, a 3 in 64-bit float format on a Mac is stored as 0x4e808000. Assigning that into an integer will produce 1077936128.
See https://en.wikipedia.org/wiki/IEEE_floating_point or http://www.madirish.net/240 or https://users.cs.duke.edu/~raw/cps104/TWFNotes/floating.html
Creating two pointers of unrelated types to the same object violates the strict aliasing rule. You want to avoid this, as in complicated code it can cause the compiler to produce binaries that don't do what you want. It's also undefined behaviour.
The correct way to change the type of a bit pattern in C between int and float is to avoid pointers completely, and use a union:
union int_float { int i; float f; };
int ival = (union int_float){ .f = 4.5 }.i;
float fval = (union int_float){ .i = 45 }.f;
Results may vary slightly. Be sure to check that the sizes of your floating type and your integer type are identical, or data will be lost/garbage data generated.
Note that it is possible to produce values in this way that are not valid elements of the destination type (this is more or less what you're seeing above when non-zero integer values get interpreted as floating-point zeroes despite not having all-zero bit patterns), which could lead to undefined or unexpected behaviour further down the line. Be sure to verify the output.
after the conversion you obtain an integer stored in the variable i.
So if you wannt to print such a value you have to use:
printf("%d\n", i); /* prints 1077936128 */
Now the printf will interprets correctly the memory bits and print the correct value.
This is not a cast but a bit copy like you said.
Remember that ((int)&f) dereference that pointer into an int value. It won't do what you believe on machines where int and float have different sizes.
A different way to copy, if the sizes of int and float are identical, is:
memcpy(&i, &f, sizeof f);
After copying the four bytes contained in the memory area if we try to print the content as a sequence of four decimal values we can appreciate the redistribution just happened:
for floating:
3 160 0 3
for integer
0 204 204 0
This means that the four bytes are managed differently from the computer according to the type of rapresentation: int or float.

Float or Char. Types confusion

I have a struct like this:
typedef struct tic {
char * close_ts;
float * close;
float * open;
}
open and close are float values (like 11.4, 33.5 etc), will be copied from stream but i don't really need to make any computation on them. I just need to extract them and write somewhere else.
Would be better in this case to use char instead of float?
I will disagree with the answers before me.
If you do not need to perform any computation on those number, and want to remain as you read them, you should use strings.
Why:
Floating point values are imprecise. If you read 1.0f and store it as a float, it might get stored as 0.99999998 (not those exact values mind you). It gets more imprecise as the magnitude of the number increases. If you want to store big numbers, it will only get worse.
There is a good article on wikipedia about why this is the case - http://en.wikipedia.org/wiki/Floating_point
If those values are something like money (they look like that from the naming), even if you need to do computations on them, I would advise against float, and would recommend you use some library that can do fixed point math.
I see no reason why to use char*.
The reasons to use float:
sizeof(float) = 4 bytes is less than sizeof("1.234567f") = 9 bytes.
It is natural to use float, so the program will be more readable.
If you want to store float as float it cannot be:
float *open;
//or
float *close;
but
float open;
//or
float close;
If you do not need to perform any operations on these floats - you may also store them as literal character string in an array but its length will depend on your float literal length etc so array may sometimes occupy more space than regular float so float should be ok here.
First of all, char *close_ts, float *close, and float *open are pointers. You should not assign anything to them but the address of a like variable type. For example:
float num = 5;
float *pNum = &num;
In this case, pNum holds the address of num (&num). If you dereference pNum (*pNum), you get the value of num (5).
You should decide which variable type you use depending on what it'll be used for. Will you be storing a character in it, such as 'A'? If so, use a char. Will you be storing a number with a fractional part, such as 3.14? If so, use a float.

A small program for understanding unions in C [duplicate]

Suppose I define a union like this:
#include <stdio.h>
int main() {
union u {
int i;
float f;
};
union u tst;
tst.f = 23.45;
printf("%d\n", tst.i);
return 0;
}
Can somebody tell me what the memory where tst is stored will look like?
I am trying to understand the output 1102813594 that this program produces.
It depends on the implementation (compiler, OS, etc.) but you can use the debugger to actually see the memory contents if you want.
For example, in my MSVC 2008:
0x00415748 9a 99 bb 41
is the memory contents. Read from LSB on the left side (Intel, little-endian machine), this is 0x41bb999a or indeed 1102813594.
Generally, however, the integer and float are stored in the same bytes. Depending on how you access the union, you get the integer or floating point interpretation of those bytes. The size of the memory space, again, depends on the implementation, although it's usually the largest of its constituents aligned to some fixed boundary.
Why is the value such as it is in your (or mine) case? You should read about floating-point number representation for that (look up ieee 754)
The result is depends on the compiler implementation, But for most x86 compilers, float and int will be the same size. Wikipedia has a pretty good diagram of the layout of a 32 bit float http://en.wikipedia.org/wiki/Single_precision_floating-point_format, that can help to explain 1102813594.
If you print out the int as a hex value, it will be easier to figure out.
printf("%x\n", tst.i);
With a union, both variables are stored starting at the same memory location. A float is stored in an IEEE format (can't remember the standard number, you can look that up[edit: as pointed out by others, IEEE 754]). But, it will be a two's complement normalized (mantissa is always between 0 and 10, exponent can be anything) floating point number.
you are taking the first 4 bytes of that number (again, you can look up what bits go where in the 16 or 32 bits that a float takes up, can't remember). So it basically means nothing and it isn't useful as an int. That is, unless you know why you would want to do something like that, but usually, a float and int combo isn't very useful.
And, no, I don't think it is implementation defined. I believe that the standard dictates what format a float is in.
In union, members will be share the same memory. so that we can get the float value as integer value.
Floating number format will be different from integer storage. so that we can understand the difference using the union.
For Ex:
If I store the 12 integer value in ( 32 bits ). we can get this 12 value as floating point format.
It will stored as signed(1 bit), exponent(8 bits) and significant precision(23 bits).
I wrote a little program that shows what happens when you preserve the bit pattern of a 32-bit float into a 32-bit integer. It gives you the exact same output you are experiencing:
#include <iostream>
int main()
{
float f = 23.45;
int x = *reinterpret_cast<int*>(&f);
std::cout << x; // 1102813594
}

Resources