Calculating with a float in macros in C - c

My colleague and I are studying for a test, where we have to analyze C Code. Looking through the tests from the previous years, we saw the following code, which we don't really understand:
#include <stdio.h>
#define SUM(a,b) a + b
#define HALF(a) a / 2
int main(int argc, char *argv[])
{
int big = 6;
float small = 3.0;
printf("The average is %d\n", HALF(SUM(big, small)));
return 0;
}
This code prints 0, which we don't understand at all... Can you explain this to us?
Thanks so much in advance!

The compiler's warnings (format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’) give more-than-enough information. You need to correct your format-specifier, which should be %lf, instead of %d, since you are trying to print a double value.
printf("The average is %lf\n", HALF(SUM(big, small)));
printf will treat the memory you point as however you tell it to. Here, it is treats the memory that represents the float as an int. Because the two are stored differently, you should get what is essentially a random number. It needs not be 0 always.

To get correct output
Add parentheses in macro
Use correct format specifier (%f)
Corrected Code
#include <stdio.h>
#define SUM(a, b) (a + b)
#define HALF(a) a / 2
int main() {
int big = 6;
float small = 3.0;
printf("The average is %f\n", HALF(SUM(big, small)));
return 0;
}
Output
The average is 4.500000
If you don't add parentheses, output will be 7.500000 due to operator precedence.
In case you need integer output, cast to int before printing.
printf("The average is %d\n", (int)HALF(SUM(big, small)));
Output
The average is 4

Related

why my printf is always repeating the first output [duplicate]

This question already has answers here:
Printing int as float in C
(7 answers)
Closed 1 year ago.
#include <stdio.h>
#include <math.h>
int main(void)
{
float a = 16777215;
int b = pow(2, 26);
float c = 22345678;
printf("%f\n", a);
printf("%f\n", b);
puts("---------------");
printf("%f\n", c);
printf("%f\n", b);
return 0;
}
output:
16777215.000000
16777215.000000
---------------
22345678.000000
22345678.000000
why the former printf output can have influence to the subsequent printf output?
b isn't a float. Try %i for integer or %d for decimal.
#include <stdio.h>
#include <math.h>
int main(void)
{
float a = 16777215;
int b = pow(2, 26);
float c = 22345678;
printf("%f\n", a);
printf("%i\n", b);
puts("---------------");
printf("%f\n", c);
printf("%i\n", b);
return 0;
}
You need to match the type or strange things can happen:
printf("%d\n", b);
Compiling the original code with clang gives helpful warnings:
pow.c:10:20: warning: format specifies type 'double' but the argument has type 'int' [-Wformat]
printf("%f\n", b);
~~ ^
%d
pow.c:13:20: warning: format specifies type 'double' but the argument has type 'int' [-Wformat]
printf("%f\n", b);
~~ ^
%d
varargs functions like printf have a hard time pinning down their type requirements, it's up to compilers like clang to go the extra mile and show hints like this. You'll need to be extra careful when calling functions of that sort and be sure you're doing it precisely as documented.
As to how this ended up happening, it's not clear, but it doesn't have to be. Undefined behaviour is just that: Anything can happen. It could print the same thing. It could work. It could crash. There doesn't have to be an explanation.
Undefined behavior as you try to print integer with %f
Try
printf("%d\n", b);
To answer your specific question, my guess is that, at the assembly level, if the conversion is not correctly indicated, it will jump to ret, using the value previously stored in eax register.

Arithmetic mean program in C

I wanted to ask you because when I run my program, I get that the arithmetic mean of 5 and 18 is 11, not 11.5? I put my program in C:
#include <stdio.h>
int main(void) {
int a,b;
a = 5;
b = 18;
printf("La media aritmética de %d i %d es %d\n", a, b, (a+b)/2);
return 0;
}
Thanks
Modify your code like below -
#include <stdio.h>
int main(void) {
float a,b;
a = 5;
b = 18;
printf("La media aritmética de %.f i %.f es %f\n", a, b,(a+b)/2);
return 0;
}
Currently, you are getting 11. Because when this operation (a+b)/2 is happening, it is saving the result in an integer. Which is ignoring the floating point value.
EDIT: If you want to print only 2 floating points then do the following -
printf("La media aritmética de %.f i %.f es %%0.2f\n", a, b,(a+b)/2);
For more info please see this Floating point rounding
This is because you are using int instead of float or double. Integer division in C will provide only integer result by rounding off the output. Please use float instead of int or typecast the solution with float.
float c;
c = (float)(a+b)/2
However these are very basic C questions. Please go through C tutorial or C books for these kind of answers.
Change the data type of a and b to float/double.
#include
int main(void)
{
float a,b,c;
a = 5.0;
b = 18.0;
c=(a+b)/2;
printf("La media aritmética de %f i %f es %f\n", a, b,c );
return 0;
}
Problem in your code is data type.When dividing any numbers, sometimes it return whole or decimal value.
For eg,
Let divide 10/2=5 and 10/4=2.5.
Thus,be aware in allocate datatypes.
For your problem,there are lot of ways to solve,
1.Change data type of particular answer storing variable
2.Change data type for all process involving variables
3.Change format specifier
4.Typecasting

Calculating the range of long in C

I am writing a program in C to calculate the range of different data types. Please look at the following code:
#include <stdio.h>
main()
{
int a;
long b;
for (a = 0; a <= 0; --a)
;
++a;
printf("INT_MIN: %d\n", a);
for (a = 0; a >= 0; ++a)
;
--a;
printf("INT_MAX: %d\n", a);
for (b = 0; b <= 0; --b)
;
++b;
printf("LONG_MIN: %d\n", b);
for (b = 0; b >= 0; ++b)
;
--b;
printf("LONG_MAX: %d\n", b);
}
The output was:
INT_MIN: -32768
INT_MIN: 32767
LONG_MIN: 0
LONT_MAX: -1
The program took a long pause to print the long values. I also put a printf inside the third loop to test the program (not mentioned here). I found that b did not exit the loop even when it became positive.
I used the same method of calculation. Why did it work for int but not for long?
You are using the wrong format specifier. Since b is of type long, use
printf("LONG_MIN: %ld\n", b);
In fact, if you enabled all warnings, the compiler probably would warn you, e.g:
t.c:19:30: warning: format specifies type 'int' but the argument has type 'long' [-Wformat]
printf("LONG_MIN: %d\n", b);
In C it is undefined behaviour to decrement a signed integer beyond its minimum value (and similiarly for incrementing above the maximum value). Your program could do literally anything.
For example, gcc compiles your program to an infinite loop with no output.
The proper approach is:
#include <limits.h>
#include <stdio.h>
int main()
{
printf("INT_MIN = %d\n", INT_MIN);
// etc.
}
In
printf("LONG_MIN: %d\n", b);
the format specifier is %d which works for integers(int). It should be changed to %ld to print long integers(long) and so is the case with
printf("LONG_MAX: %d\n", b);
These statements should be
printf("LONG_MIN: %ld\n", b);
&
printf("LONG_MAX: %ld\n", b);
This approach may not work for all compilers(eg gcc) and an easier approach would be to use limits.h.
Also check Integer Limits.
As already stated, the code you provided invokes undefined behavior. Thus it could calculate what you want or launch nuclear missiles ...
The reason for the undefined behavior is the signed integer overflow that you are provoking in order to "test" the range of the data types.
If you just want to know the range of int, long and friends, then limits.h is the place to look for. But if you really want ...
[..] to calculate the range [..]
... for what ever reason, then you could do so with the unsigned variant of the respective type (though see the note at the end), and calculate the maximum like so:
unsigned long calculate_max_ulong(void) {
unsigned long follow = 0;
unsigned long lead = 1;
while (lead != 0) {
++lead;
++follow;
}
return follow;
}
This only results in an unsigned integer wrap (from the max value to 0), which is not classified as undefined behavior. With the result from above, you can get the minimum and maximum of the corresponding signed type like so:
assert(sizeof(long) == sizeof(unsigned long));
unsigned long umax_h = calculate_max_ulong() / 2u;
long max = umax_h;
long min = - max - 1;
(Ideone link)
Assuming two's complement for signed and that the unsigned type has only one value bit more than the signed type. See §6.2.6.2/2 (N1570, for example) for further information.

C the same output different results

#include<stdio.h>
int main(void) {
int m=2, a=5, b=4;
float c=3.0, d=4.0;
printf("%.2f,%.2f\n", (a/b)*m, (a/d)*m);
printf("%.2f,%.2f\n", (a/d)*m, (a/b)*m);
return 0;
}
The result is:
2.50,0.00
2.50,-5487459522906928958771870404376799406808566324353377030104786519743796498661129086808599726405487030183023928761546165866809436788166721199470577627133198744209879004896284033606071946689658593354711574682628407789000148729336462084532657713450945423953627239707603534923756075420253339949731915621203968.00
I want to know what cause this difference.
However, if I change int to float, the answer is the same as I expect.
The result is:
2.50,2.50
2.50,2.50
You are using wrong format specifiers, try this:
#include<stdio.h>
int main(void)
{
int m=2,a=5,b=4;
float fm=2,fa=5,fb=4;
float c=3.0,d=4.0;
//First expression in this printf is int and second is float due to d
printf("%d , %.2f\n\n",(a/b)*m,(a/d)*m);
//Second expression in this printf is int and first is float due to d
printf("%.2f , %d\n\n",(a/d)*m,(a/b)*m);
printf("%.2f , %.2f\n\n",(fa/b)*fm,(fa/d)*fm);
printf("%.2f , %.2f\n\n",(fa/d)*fm,(fa/b)*fm);
return 0;
}
Output:
2 , 0
0 , 1074003968
2.50 , 2.50
2.50 , 2.50
Section 7.19.6.1 p9 of the C99 standard says:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
Note that a/b is int if both are ints and is float if at least one is float, and similarly for other arithmetic operators. Thus in a/b, if they both are ints then 5/4 = 1; if at least one is float, then 5/4.0 = 5.0/4.0 = 1.25, because the compiler automatically converts an int into a float before any arithmetics with another float. So your results were expected to be different.
But in your case you seem to use the %.2f format even when you output ints. So print takes the four bytes that have your int and tries to decode those four bytes as if they had some float encoded. Flot numbers are encoded very differently in memory from ints -- it's like taking a Hungarian text and tryint to interpret it as if it was written in English, even if the letters are the same -- the resulting "interpretation" will be just garbage.
What you need to do: any int should be output with %d and any float with %f or similar formats.
If you want the result to be in float cast them:
#include <stdio.h>
int main(void) {
// your code goes here
int m=2,a=5,b=4;
float c=3.0,d=4.0;
printf("%.2f,%.2f\n",(float)(a/b)*m,(float)(a/d)*m);
printf("%.2f,%.2f\n", (float) (a/d)*m,(float)((a/b)*m));
return 0;
}
Hope this helps..:)
You are trying to print integer values
printf("%d,%.2f\n",(a/b)*m,(a/d)*m);
printf("%.2f , %d\n\n",(a/d)*m,(a/b)*m);
In order to print integer values you should use %d using wrong format specifier lead to undefined behavior

C math not respecting declared constants

Stackoverflow,
I'm trying to write a (very) simple program that will be used to show how machine precision and flops effect functions around their root. My code is as follows:
#include <stdio.h>
#include <math.h>
int main(){
const float x = 2.2;
float sum = 0.0;
sum = pow(x,9) - 18*pow(x,8) + 144*pow(x,7) - 672*pow(x,6) + 2016*pow(x,5) -
4032*pow(x,4) + 5376*pow(x,3) - 4608*pow(x,2) + 2304*x - 512;
printf("sum = %d", sum);
printf("\n----------\n");
printf("x = %d", x);
return 0;
}
But I keep getting that sum is equal to zero. At first I thought that maybe my machine wasn't respecting the level of percision, but after printing x I discovered that the value of x is changing each time I run the program and is always huge (abs(x) > 1e6)
I have it declared as a constant so I'm even more confused as to whats going on...
FYI I'm compiling with gcc -lm
printf("sum = %d", sum);
sum is a float, not an int. You should use %f instead of %d. Same here:
printf("x = %d", x);
Reading about printf() format specifiers may be a good idea.

Resources