#include<stdio.h>
int main()
{
float a;
printf("Enter a number:");
scanf("%f",&a);
printf("%d",a);
return 0;
}
I am running the program with gcc
in Ubuntu.
For values--
3.3 it gives value 1610612736
3.4 it gives value 1073741824
3.5 it gives value 0
3.6 it gives value -1073741824
4 it gives value 0
5 it gives value 0
What is happening? Why are these values printed? I'm doing this intentionally, but would like to understand why this is happening. Details are appreciated!
The printf
function does not know the type of format you passed in, because that part is variadic.
int printf(const char* format, ...);
// ^^^
In the C standard, passing a float
will be automatically promoted to a double
(C11§6.5.2.2/6), and nothing else will be done in the caller side.
Inside printf
, since it doesn't know the type of that ...
thingie (§6.7.6.3/9), it has to use the hint from elsewhere — the format string. Since you've passed "%d"
, it is telling the function that, an int
is expected.
According to the C standard, this leads to undefined behavior (§7.21.6.1/8–9), which includes the possibility of printing some weird number, end of story.
But what is really happening? In most platforms, a double
is represented as "IEEE 754 binary64" format, and a float
in binary32 format. The numbers you've entered are converted to a float, which only has 23 bits of significance, which means the numbers will be approximated like this:
3.3 ~ (0b1.10100110011001100110011) × 2¹ (actually: 3.2999999523162842...)
3.4 ~ (0b1.10110011001100110011010) × 2¹ (actually: 3.4000000953674316...)
3.5 = (0b1.11 ) × 2¹ (actually: 3.5)
3.6 ~ (0b1.11001100110011001100110) × 2¹ (actually: 3.5999999046325684...)
4 = (0b1 ) × 2² (actually: 4)
5 = (0b1.01 ) × 2² (actually: 5)
Now we convert this to double, which has 53 bits of significance, which we have to insert 30 binary "0"'s at the end of these numbers, to produce e.g.
3.299999952316284 = 0b1.10100110011001100110011000000000000000000000000000000 ×2¹
These are mainly to derive the actual representation of those numbers, which are:
3.3 → 400A6666 60000000
3.4 → 400B3333 40000000
3.5 → 400C0000 00000000
3.6 → 400CCCCC C0000000
4 → 40100000 00000000
5 → 40140000 00000000
I recommend using http://www.binaryconvert.com/convert_double.html to see how this breaks down to the ±m × 2e format.
Anyway, I suppose your system is an x86/x86_64/ARM in normal setting, which means the numbers are laid out in memory using little-endian format, so the arguments passed will be like
byte
#0 #1 ... #4 ... #8 ....
+----+----+----+----+ +----+----+----+----+----+----+----+----+
| 08 | 10 | 02 | 00 | | 00 | 00 | 00 | 60 | 66 | 66 | 0A | 40 | ....
+----+----+----+----+ +----+----+----+----+----+----+----+----+
address of "%d" content of 3.299999952316284
(just an example)
Inside the printf
, it consumes the format string "%d"
, parses it, and then finds out that an int
is needed because of %d, so 4 bytes are taken from the variadic input, which is:
byte
#0 #1 ... #4 ... #8 ....
+ - -+ - -+ - -+ - -+ +====+====+====+====+ - -+ - -+ - -+ - -+
: 08 : 10 : 02 : 00 : | 00 | 00 | 00 | 60 | 66 : 66 : 0A : 40 : ....
+ - -+ - -+ - -+ - -+ +====+====+====+====+ - -+ - -+ - -+ - -+
address of "%d" ~~~~~~~~~~~~~~~~~~~
this, as an 'int'
so, printf will receive 0x60000000, and display it as a decimal integer, which is 1610612736, which is why you see that result. The other numbers can be explained similarly.
3.3 → ... 60000000 = 1610612736
3.4 → ... 40000000 = 1073741824
3.5 → ... 00000000 = 0
3.6 → ... C0000000 = -1073741824 (note 2's complement)
4 → ... 00000000 = 0
5 → ... 00000000 = 0
I'm assuming that the other answers so-far posted are missing the point: I think you're deliberately using different conversions for scanning and printing, and want to understand the results. If, indeed, you just made a mistake, then you can ignore my answer.
Basically, you need to read this article, which will explain how the bit patterns for floating-point numbers are defined, then write out the bit patterns for each of those numbers. Given that you understand how integers are stored, you should then have your answers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With