I was reading this question on SO. After reading the first answer I was unable to understand the reason for -5 >> 1 = -3. I also tweaked a little bit more around it.
You can also see the code and output here.
Here is what I did:
#include<stdio.h>
int main(){
printf("5/2 = %d\n",5/2);
printf("5 >> 1 = %d\n",5 >> 1);
printf("5/2 = %lf\n",5/2);
printf("5 >> 1 = %f\n",5 >> 1);
printf("-5/2 = %d\n",-5/2);
printf("-5 >> 1 = %d\n",-5 >> 1);
printf("-5/2 = %f\n",-5/2);
printf("-5 >> 1 = %f\n",-5 >> 1);
return 0;
}
Output :
5/2 = 2
5 >> 1 = 2
5/2 = 2.168831
5 >> 1 = 2.168831
-5/2 = -2
-5 >> 1 = -3
-5/2 = 2.168833
-5 >> 1 = 2.168833
I am unable to understand 5/2 == 2.168831, 5 >> 2 == 2.168831, 5 >> 1 == -3.
Why this is happening? (It may be possible that the answer is very basic and I am missing some basic things, so pls guide me).
The reason you see the results you do is:
When you pass an
intargument but use a printf specifier fordouble(remember that afloatis converted to adoublein this situation), then most C implementations pass theintargument according to their usual rules for passing aintargument to a variadic function (a function that accepts diverse argument types), but theprintfroutine interprets the machine state as if it were passed adoubleargument, as described below. (This is not necessarily what always happens; once you leave the behavior defined by the C standard, a C implementation may do other things. In particular, there can be complex interactions with the optimizer that cause surprising results. However, this is what happens most commonly. You cannot rely on it.)Each computing platform has some rules for how arguments are passed. One platform might specify that all arguments are pushed onto the stack, from right to left, and that each argument is put onto the stack using only as many bytes as it needs. Another platform might specify that arguments are pushed onto the stack left to right or that arguments are padded up to the next multiple of four bytes, to keep the stack nicely aligned. Many modern platforms specify that integer arguments under a certain size are passed in general registers, floating-point arguments are passed in floating-point registers, and other arguments are passed on the stack.
When
printfsees%fand looks for adoubleargument, but you have passed anint, what doesprintffind? If this platform pushes both arguments onto the stack, thenprintffinds the bits for yourint, but it interprets those bits as if they were adouble. This results inprintfprinting a value determined by yourint, but it bears no obvious relationship to yourintbecause the bits have entirely different meanings in the encodings forintand fordouble.If this platform puts an
intargument in one place but adoubleargument in another place, thenprintffinds some bits that have nothing at all to do with yourintargument. They are bits that just happened to be left over in, for example, the floating-point register where thedoubleargument should be. Those bits are just the residue of previous work. The value you get will be essentially random with respect to theintyou have passed. You can also get a mix, withprintflooking for eight bytes of adoubleby taking four bytes of theintyou passed along with four bytes of whatever else was nearby.When you run the program multiple times, you will often see the same value printed. This happens for two reasons. First, computers are mechanical. They operate in largely deterministic ways, so they do the same things over and over again, even if those things were not particularly designed to be used the way you are using them. Second, the environment the operating system passes to the program when it starts is largely the same each time you start the program. Most of its memory is either cleared or is initialized from the program file. Some of the memory or other program state is initialized from other environment in the computer. That data can be different from run to run of the program. For example, the current time obviously changes from run to run. So does your command history, plus values the command shell has placed in its environment variables. Sometimes running a program multiple times will produce different results.
When you use code whose behavior is not defined by some specification (which may be the C specification, a compiler specification, a machine and operating system specification, or other documents), then you cannot rely on the behavior of that code. (It is possible to rely on the behavior of code compiled by a particular C compiler that is specified by that C compiler even though it is not fully specified by the C standard.)