#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);
Related
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.
Sorry if this is already been asked, and I've seen other way of extracting the exponent of a floating point number, however this is what is given to me:
unsigned f2i(float f)
{
union {
unsigned i;
float f;
} x;
x.i = 0;
x.f = f;
return x.i;
}
I'm having trouble understanding this union datatype, because shouldn't the return x.i at the end always make f2i return a 0?
Also, what application could this data type even be useful for? For example, say I have a function:
int getexponent(float f){
}
This function is supposed to get the exponent value of the floating point number with bias of 127. I've found many ways to make this possible, however how could I manipulate the f2i function to serve this purpose?
I appreciate any pointers!
Update!!
Wow, years later and this just seem trivial.
For those who may be interested, here is the function!
int getexponent(float f) {
unsigned f2u(float f);
unsigned int ui = (f2u(f)>>23) & 0xff ;//shift over by 23 and compare to 0xff to get the exponent with the bias
int bias = 127;//initialized bias
if(ui == 0) return 1-bias; // special case 0
else if(ui == 255) return 11111111; //special case infinity
return ui - bias;
}
I'm having trouble understanding this union datatype
The union data type is a way for a programmer to indicate that some variable can be one of a number of different types. The wording of the C11 standard is something like "a union contains at most one of its members". It is used for things like parameters that may be logically one thing or another. For example, an IP address might be an IPv4 address or an IPv6 address so you might define an address type as follows:
struct IpAddress
{
bool isIPv6;
union
{
uint8_t v4[4];
uint8_t v6[16];
} bytes;
}
And you would use it like this:
struct IpAddress address = // Something
if (address.isIPv6)
{
doSomeV6ThingWith(address.bytes.v6);
}
else
{
doSomeV4ThingWith(address.bytes.v4);
}
Historically, unions have also been used to get the bits of one type into an object of another type. This is because, in a union, the members all start at the same memory address. If I just do this:
float f = 3.0;
int i = f;
The compiler will insert code to convert a float to an integer, so the exponent will be lost. However, in
union
{
unsigned int i;
float f;
} x;
x.f = 3.0;
int i = x.i;
i now contains the exact bits that represent 3.0 in a float. Or at least you hope it does. There's nothing in the C standard that says float and unsigned int have to be the same size. There's also nothing in the C standard that mandates a particular representation for float (well, annex F says floats conform to IEC 60559 , but I don't know if that counts as part of the standard). So the above code is, at best, non portable.
To get the exponent of a float the portable way is the frexpf() function defined in math.h
how could I manipulate the f2i function to serve this purpose?
Let's make the assumption that a float is stored in IEC 60559 format in 32 bits which Wkipedia thinks is the same as IEEE 754. Let's also assume that integers are stored in little endian format.
union
{
uint32_t i;
float f;
} x;
x.f = someFloat;
uint32_t bits = x.i;
bits now contains the bit pattern of the floating point number. A single precision floating point number looks like this
SEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMM
^ ^ ^
bit 31 bit 22 bit 0
Where S is the sign bit, E is an exponent bit, M is a mantissa bit.
So having got your int32_t you just need to do some shifting and masking:
uint32_t exponentWithBias = (bits >> 23) & 0xff;
Because it's a union it means that x.i and x.f have the same address, what this allows you to do is reinterpret one data type to another. In this scenario the union is first zeroed out by x.i = 0; and then filled with f. Then x.i is returned which is the integer representation of the float f. If you would then shift that value you would get the exponent of the original f because of the way a float is laid out in memory.
I'm having trouble understanding this union datatype, because shouldn't the return x.i at the end always make f2i return a 0?
The line x.i = 0; is a bit paranoid and shouldn't be necessary. Given that unsigned int and float are both 32 bits, the union creates a single chunk of 32 bits in memory, which you can access either as a float or as the pure binary representation of that float, which is what the unsigned is for. (It would have been better to use uint32_t.)
This means that the lines x.i = 0; and x.f = f; write to the very same memory area twice.
What you end up with after the function is the pure binary notation of the float. Parsing out the exponent or any other part from there is very much implementation-defined, since it depends on floating point format and endianess. How to represent FLOAT number in memory in C might be helpful.
That union type is strongly discouraged, as it is strongly architecture dependant and compiler implementation dependant.... both things make it almost impossible to determine a correct way to achieve the information you request.
There are portable ways of doing that, and all of them have to deal with the calculation of logarithm to the base ten. If you get the integer part of the log10(x) you'll get the number you want,
int power10 = (int)log10(x);
double log10(double x)
{
return log(x)/log(10.0);
}
will give you the exponent of 10 to raise to get the number to multiply the mantissa to get the number.... if you divide the original number by the last result, you'll get the mantissa.
Be careful, as the floating point numbers are normally internally stored in a power of two's basis, which means the exponent you get stored is not a power of ten, but a power of two.
I'm trying to express a fractional number in binary and then have it print out as a float. I've done the fixed point to floating point conversion.
The number in decimal: -342.265625
fixed point: -101010110.010001
32-bit float: 11000011101010110010001000000000
64-bit float (double): 1100000001110101011001000100000000000000000000000000000000000000
*I've double checked with an IEEE 754 Converter
*I'm also aware that printf changes floats into doubles to print them, but declaring it as a double should work? I thought...?
Code:
int main()
{
float floaty = 0b11000011101010110010001000000000;
double doubley = 0b1100000001110101011001000100000000000000000000000000000000000000;
printf("Float: %f\n", floaty);
printf("Double: %lf\n", doubley);
}
Output:
Float: 3282772480.000000
Double: 13868100853597995008.000000
The compiler is gcc and the standard is c99
From gcc's documentation:
The type of these constants follows the same rules as for octal or
hexadecimal integer constants, so suffixes like ‘L’ or ‘UL’ can be
applied.
So, the binary numbers you assign to float and double are actually of integer types and don't directly map to the bit pattern of the underlying types you assign to.
In other words, this:
float floaty = 0b11000011101010110010001000000000;
double doubley = 0b1100000001110101011001000100000000000000000000000000000000000000;
is equivalent to:
float floaty = 3282772480;
double doubley = 13868100853597995008;
The problem is that the compiler is trying to help you out. Your literals (0b1...), which by the way is a non-standard extension and should be written as (0x...), are treaded as literals. The compiler then tries its very best to fit those values into the variables you cast them to. As such it produces very big values that are equal to the integer value of your literals.
To directly assign the value of a variable, you have to use unions (or pointers if you don't mind losing a bit of portability). This code works:
#include <stdint.h>
union floatint {
float f;
uint32_t i;
};
union doubleint {
double d;
uint64_t i;
};
int main()
{
floatint floaty;
doubleint doubley;
floaty.i = 0xC3AB2200;
doubley.i = 0xC075644000000000;
printf("Float: %f\n", floaty.f); // implementation-defined, in your case IEEE 754
printf("Double: %lf\n", doubley.d); // ditto
}
Note that this is the very definition of a union, two (or more) types that share the same representation, but are treated differently.
You can use the binary constants with some more work.
We will have to assume the floating point represented using IEEE 754, and the system is in little endian:
uint32_t value = 0b11000011101010110010001000000000;
float f;
memcpy( &f , &value , sizeof( f ) );
printf( "%f\n" , f );
Below is some code that i wrote to understand typecasting but I do not understand why the value of float or double is being printed as "0.000000" even if i type cast from as array of integers or try to interpret from a union's address.
#include <stdio.h>
union test1
{
int x;
float y;
double z;
};
int main()
{
int x[2]={200,300};
float *f;
f=(float*)(x);
printf("%f\n",*f); /*(1)why is this value 0.0*/
*f=(float)(x[0]); /*(2)this works as expected and prints 200.00000*/
printf("%f\n",*f);
union test1 u;
u.x=200;
/*(3)this line give compilation error why*/
//printf ("sizeof(test1) = %d \n", sizeof(test1));
/*(4) this line also prints the value of float and double as 0.0000 why*/
printf ("sizeof(test1) = %lu u.x:%d u.y:%f u.z:%lf \n", sizeof(u), u.x, u.y, u.z);
return 0;
}
First and foremost, int and float are not compatible types.
In your code, by saying
f=(float*)(x);
you're breaking the strict aliasing rule. Any further usage invokes undefined behavior.
To put in simple words, you cannot just take a pointer to a float, cast that to an int * and dereference that int * to get an int value. To quote the wikipedia article,
[..] pointer arguments in a function are assumed to not alias if they point to fundamentally different types, [...]
For a much detailed description, please see the already linked FAQ answer.
printf("%f\n",*f); /*(1)why is this value 0.0*/
You are taking the address of an int and treating it like it contains a float. That is undefined behavior.
printf("%f\n",*f); /*(1)why is this value 0.0*/
This is effectively undefined behavior, but saying this doesn't explain why you have 0.0 in your case. The result could have been anything because it is undefined behavior, but with a given compiler and a given machine, the behavior, while not specified, produced something.
You are reading as a float a memory that contains the encoding of an int; it is highly probable that the encoding of 200 as int, is read as a very small value (a denormalized small float number) as a float and written as 0.0. On my machine, denormalized float numbers are printed as 0.0 with printf (don't know if it is a standard printf behavior).
For float encoding, read IEEE 754.
Couldnt understand how numbers are handled in C. Could anyone point to a good tutorial.
#include<stdio.h>
main()
{
printf("%f",16.0/3.0);
}
This code gave: 5.333333
But
#include<stdio.h>
main()
{
printf("%d",16.0/3.0);
}
Gave some garbage value: 1431655765
Then
#include<stdio.h>
main()
{
int num;
num=16.0/3.0;
printf("%d",num);
}
Gives: 5
Then
#include<stdio.h>
main()
{
float num;
num=16/3;
printf("%f",num);
}
Gives: 5.000000
printf is declared as
int printf(const char *format, ...);
the first arg (format) is string, and the rest can be anything. How the rest of the arguments will be used depending on the format specifiers in format. If you have:
printf("%d%c", x, y);
x will be treated as int, y will be treated as char.
So,
printf("%f",16.0/3.0);
is ok, since you ask for float double (%f), pass float double(16.0/3.0)
printf("%d",16.0/3.0);
you ask for int(%d), you pass float double (double and int have different internal representation) so, the bit representation of 16.0/3.0 (double) corresponds to bit representation of 1431655765(int).
int num;
num=16.0/3.0;
compiler knows that you are assigning to int, and converts it for you. Note that this is different than the previous case.
Ok, the first 1 is giving correct value as expected.
Second one you are passing a float while it is treating it as an int (hence the "%d" which is for displaying int datatypes, it is a little complicated to explain why and since it appears your just starting I wouldn't worry about why "%d" does this when passed a float) reading it wrong therefore giving you a wierd value. (not a garbage value though).
Third one it makes 16.0/3.0 an int while assigning it to the int datatype which will result in 5. Because while making the float an int it strips the decimals regardless of rounding.
In the fourth the right hand side (16/3) is treated as an int because you don't have the .0 zero at the end. It evaluates that then assigns 5 to float num. Thus explaining the output.
It is because the formatting strings you are choosing do not match the arguments you are passing. I suggest looking at the documentation on printf. If you have "%d" it expects an integer value, how that value is stored is irrelevant and likely machine dependent. If you have a "%f" it expects a floating point number, also likely machine dependent. If you do:
printf( "%f", <<integer>> );
the printf procedure will look for a floating point number where you have given an integer but it doesn't know its and integer it just looks for the appropriate number of bytes and assumes that you have put the correct things there.
16.0/3.0 is a float
int num = 16.0/3.0 is a float converted to an int
16/3 is an int
float num = 16/3 is an int converted to a float
You can search the web for printf documentation. One page is at http://linux.die.net/man/3/printf
You can understand numbers in C by using concept of Implecit Type Conversion.
During Evaluation of any Expression it adheres to very strict rules of type Conversion.
and your answer of expression is depends on this type conversion rules.
If the oparands are of different types ,the 'lower' type is automatically converted into the 'higher' type before the operation proceeds.
the result is of the higher type.
1:
All short and char are automatically converted to int then
2:
if one of the operands is int and the other is float, the int is converted into float because float is higher than an ** int**.
if you want more information about inplicit conversion you have to refer the book Programming in ANSI C by E Balagurusamy.
Thanks.
Bye:DeeP
printf formats a bit of memory into a human readable string. If you specify that the bit of memory should be considered a floating point number, you'll get the correct representation of a floating point number; however, if you specify that the bit of memory should be considered an integer and it is a floating point number, you'll get garbage.
printf("%d",16.0/3.0);
The result of 16.0/3.0 is 5.333333 which is represented in Single precision floating-point format as follows
0 | 10101010 | 10101010101010101010101
If you read it as 32bit integer value, the result would be 1431655765.
num=16.0/3.0;
is equivalent to num = (int)(16.0/3.0). This converts the result of float value(5.33333) to integer(5).
printf("%f",num);
is same as printf("%f",(float)num);