int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int x = 5;
cout << f(x,5);
In the example above the four possible answers to choose from are:
3024
6561
55440
161051
Function f(int &x, int c) is called four times after the first call before it reaches the base case where it returns the result which is 6561. My guess was 3024 but I was wrong. Even if the x variable which is passed by reference increments in each call of f(int &x, int c) and takes the values 6->7->8->9 respectively the final result of this recursion is equal to 9^4.
So my question is: Variable x is passed by reference and is equal to 9 when it reaches the base case. Does that mean that all the stages of recursion will have this value for variable x even if they had a different value when they've been called?
No, there are more than four answers to choose from.
The fetch of x for the recursive function call, and the fetch of x for the right hand side of multiplication, is not sequenced with each other; and as such the evaluation order is unspecified.
This doesn't mean that the evaluation order would be some particular evaluation order, and it's only necessary to figure it out. This means that the final results can:
Vary depending on the compiler.
Vary each time this program executes.
The evaluation order may also be different for each individual recursive call. Each recursive call can end up using a different evaluation order, too. "Unspecified" means "unspecified". Any possibility can happen. Each individual time.
I didn't bother to calculate all actual possibilities here. It's better to invest one's own time on something that should work properly, instead of on something that obviously can never work properly.
If you want a specific evaluation order, it's going to be either this:
int y=x;
return f(x, c) * y;
Or this:
int y=f(x, c);
return y * x;
This evaluation order is now specified.
Related
This question already has an answer here:
Use pass by reference in recursion
(1 answer)
Closed 1 year ago.
I came across the following question:
#include <stdio.h>
int f(int &x, int c)
{
c = c - 1;
if (c == 0) return 1;
x = x + 1;
return f(x, c) * x;
}
int main()
{
int p = 5;
printf("%d", f(p, p));
}
As far as I have worked out, the recursion calls should work, and with each recursion call, value of c should reduce by 1 and value of x should increase by 1 . However, if I calculate it that way, the answer comes out to be 3024. However, on executing, the output comes out to be 6561. I am not really sure how this answer is coming.
I have the link to the article from where this question is taken, but I fail to understand how x will remain constant as is described in this link: https://www.geeksforgeeks.org/c-references-question-1/
Can someone help me with the working behind this code?
There can be any result, due to Undefined behavior.
Since the x is passed by reference, the last assign will matter. Thus, we have:
9*9*9*9*1=6561
We delay the evaluation of the f(x, c) * x, where all the subsequent recursive calls will have access to the x. We increment the x this way until the c is equal to 0, means we increment the x up to it being 9.
When we hit the base case (the c == 0), the current call returns 1, while the x is already 9.
Then we evaluate the multiplication 1 * x * x * x * x, where x is equal to 9. Thus, the 6561.
Flawless explanation? Not so much.
The fun part is that there is no concept of left-to-right or right-to-left evaluation in C++:
Order of evaluation of any part of any expression, including order of
evaluation of function arguments is unspecified (with some exceptions
listed below). The compiler can evaluate operands and other
subexpressions in any order, and may choose another order when the
same expression is evaluated again.
Means, that though this logic gets a pass this time, it may won't be this way next time for me or if you run it yourself.
Will the machine or compiler make use of the property that zero multiplied with an integer must always be zero? Consider
int f(int c, int d, int e, int f)
{
// some complex calculations here...
}
int foo(int a, int b, int c, int d, int e, int f)
{
return (a - b) * f(c, d, e, f);
}
In run time, if we pass some arguments where a == b, then mathematically there is no need to calculate the result of f() (assuming no undefined or strange behavior). The result must always be 0.
I am not quite sure if there is any possibility that the machine / compiler might use some optimizing technique to skip the calculation of f(). Or, asked the other way round, is it guaranteed that f() will be always called no matter what values of a and b are?
I am tagging this question with both C and C++ to avoid the slight chance that rules differ in C and C++ in this case. If so, please elaborate respectively.
Update Thanks for the discussion. From what I gather up to now, the possible existence of a function's side-effect would certainly be a factor to consider. However, I would like to clarify that the helper function f() is not a must in my intention. Code like
int foo(int a, int b, int c, int d, int e, int f)
{
return (a - b) * /* some complex expression with c, d, e, f */;
}
would also qualify. Apologies for not making it clear at the beginning.
Compiler
The compiler usually (meaning most compilers) optimizes arithmetic calculations if they consist of constants. For example i = 1 + 3; will be optimized to i = 4; but the more complex the calculation, fewer the compilers that will be able to optimize it. Compilers usually work recursively with tree structures and search them to find possible optimizations. So it makes no difference if you add 2 or 20 constants, but it makes a difference if the additions are inside a loop. In this case calling foo(a, a, x, y, z); is a bit less likely to be optimized that calling foo(1, 1, x, y, z);.
If the compiler first inlines small functions, and searches for arithmetic optimizations after, then it is quite likely that if the parameters are determined at compile time, the compiler will be able to optimize out all the extra instructions. After all this is what it boils down to, can the compiler be sure that the result of foo is 0 without running the program?
Two things to note:
Compilers can selectively optimize different things (for gcc using -O0, -O1, -O2, -O3 and other more specific commands)
Compilers themselves are written programmes and not a magic black box. For the compiler to optimize foo, a developer must write somewhere in there: check if a subtraction is about the same variable and if so substitute the result with 0. And somewhere near that: check if you multiply with zero and substitute that with 0. All that at compile time.
For the compiler to optimize at run time, then instead of multiplying a and b, the produced assembly will contain checks for each variable to check for any one zeros. I don't think any compiler does that.
Processor
The processor is for the most part a dumb machine that does exactly what its told. The multiplication is done by hardware that carries some bitwise logic. For the processor to optimize this multiplication, the circuits that do that calculation must also have a part that says the following: if one of the multiplicants is 0 then the result is 0 and we need not do the multiplication. If someone has programmed the processor to do that, then it is optimized. Depends on implementation but I think it's quite unlikely.
This would require the compiler to generate branching, which it generally doesn't like to do. If you want the branching, make it explicit:
int f(int c, int d, int e, int f)
{
// some complex calculations here...
}
int foo(int a, int b, int c, int d, int e, int f)
{
if (a == b) return 0;
return (a - b) * f(c, d, e, f);
}
As noted in the comments, f may also have side effects, in which case it is guaranteed not to be "optimized" away.
Unless the compiler can determine, at compile time, that (a - b) will always evaluate to 0, it won't try to add code to perform the evaluation at runtime.
The main reason is what it has been discussed in other answers: the function that provides one of the operands can have side effects, and you don't normally want to avoid them to happen (if you would want it, you would have to add the evaluation by yourself).
The other reason is that the hardware already does that, and multiplications in which one of the operands is 0 normally takes much less cycles than a regular one.
Note that this is different to what happens with short circuit evaluation in conditional expressions: if ( (a - b) == 0 || f(c, d, e, f) == 0 ) . In this case, the first condition may avoid the second one from executing f() at runtime.
This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 8 years ago.
I am trying to learn the basics of C/C++ right now. I am going through a course on Lynda.com
My questions deals with a sequence of code from Chapter 4 "Macro caveats from the Course C/C++ Essential Training". I have followed all the setup procedures to get Xcode and Eclipse setup correctly on a Mac and Eclipse on a PC. When I run this code on a MAC and PC I get different results. Just trying to understand why that is happening and what I can do to get the same result on both.
Here is the code:
// working.c by Bill Weinman <http://bw.org/>
#include <stdio.h>
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int increment() {
static int i = 42;
i += 5;
printf("increment returns %d\n", i);
return i;
}
int main( int argc, char ** argv ) {
int x = 50;
printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment()));
return 0;
}
On a PC I get this result:
increment returns 47
increment returns 52
max of 50 and 52 is 50
increment returns 57
increment returns 62
increment returns 67
max of 50 and 67 is 62
On a MAC (both Xcode and Eclipse) I get this result:
increment returns 47
increment returns 52
increment returns 57
max of 50 and 47 is 57
increment returns 62
increment returns 67
increment returns 72
max of 50 and 62 is 72
Why is this happening and what can I do to make sure the results are the same?
You have unspecified results here.
Order of evaluation within printf() is not defined.
Once you have multiple increment() calls within the same printf then you never know which once gets executed first and how they are evaluated.
The order in which all elements in a full-expression get evaluated is not defined. All that is required is that each sub-expression have its operands fully evaluated before it is evaluated. In the case of a function call, the arguments can be evaluated in any order, and in fact one argument might only be partially evaluated at the moment another argument becomes fully evaluated.
First, let's expand the macro:
printf("max of %d and %d is %d\n", x,
increment(),
((x) > (increment()) ? (x) : (increment()));
(Oops, there is another problem here: if increment() is larger than x then it gets called again. Make the MAX macro a function instead so the arguments are only evaluated once!)
All of the following sequences are possible. I omit the evaluation of x here because it doesn't change.
The second argument increment() is evaluated, followed by x > increment(), finally followed by whichever ?: operand is selected. (This is likely the sequence you were expecting.)
x > increment() is evaluated, followed by whichever ?: operand is selected, finally followed by the second argument increment().
x > increment() is evaluated, followed by the second argument increment(), finally followed by whichever ?: operand is selected.
These may all yield different results, and they are all a correct interpretation of your code.
When you call multiple functions in a single full-expression, you should ensure that these functions either don't have any side-effects, or that the side-effects of each function do not change the behavior of any of the other functions. Otherwise, compiling on a different compiler (or a different version of the same compiler!) could change the result.
As an additional example, even the simple-looking expression increment() > increment() has an unspecified result, because the order in which the operands are evaluated is not defined; if the left operand is evaluated first then the result will be false, otherwise it will be true.
In the more complicated example ((a + b) * (c + d)) the compiler can evaluate a, b, c, and d in any order that it pleases. All that is required is that a and b must be evaluated before a + b can be, c and d must be evaluated before c + d can be, and a + b and c + d must be evaluated before the final operator * can be.
There are two problems here.
You are relying on whatever the compiler chooses for evaluating the arguments to printf(). The statements evaluated first modify the values of later statements. Move the increment() calls out of the argument list. Store the results of increment() in variables instead and pass those variables to printf().
Also, the macro expansion of MAX can cause either argument to be evaluated once or twice. So even on the same OS and compiler, you can get awkward results. To fix this, do the same as I suggested for storing the increment() results. Pass those variables to MAX().
I recently got confused by the following c++ snippet:
#include <cstdio>
int lol(int *k){
*k +=5;
return *k;
}
int main(int argc, const char *argv[]){
int k = 0;
int w = k + lol(&k);
printf("%d\n", w);
return 0;
}
Take a look at line:
int w = k + lol(&k);
Until now I thought that this expression would be evaluated from left to right: take current value of k (which before calll to lol function is 0) and then add it to the result of lol function. But compiler proves me I'm wrong, the value of w is 10. Even if I switch places to make it
int w = lol(&k) + k;
the result would be still 10. What am I doing wrong?
Tomek
This is because the parameters in an expression are not specified to be evaluated in any particular order.
The compiler is free to execute either parameter k or lol(&k) first. There are no sequence points in that expression. This means that the side-effects of the parameters can be executed in any order.
So in short, it's not specified whether the code prints 5 or 10. Both are valid outputs.
The exception to this is short-circuiting in boolean expressions because && and || are sequence points. (see comments)
This code either yields 5 or 10 depending on the choice of evaluation oder of the function call relative to that of the left side of +.
Its behavior is not undefined because a function call is surrounded by two sequence points.
Plus is by definition commutative, so the order in your example is totally implementation-defined.
Mysticial is right when mentioning sequence points. Citing Wikipedia article (don't have C++ standard at hand):
A sequence point in imperative programming defines any point in a
computer program's execution at which it is guaranteed that all side
effects of previous evaluations will have been performed, and no side
effects from subsequent evaluations have yet been performed. They are
often mentioned in reference to C and C++, because the result of some
expressions can depend on the order of evaluation of their
subexpressions. Adding one or more sequence points is one method of
ensuring a consistent result, because this restricts the possible
orders of evaluation.
The article also has a list of sequence point in C++.
Here is my function:
void abc(char *def, unsigned int w, unsigned int x, unsigned int y, unsigned int z)
{
printf("val 1 : %d\n", w);
printf("val 2 : %d\n", x);
printf("val 3 : %d\n", y);
printf("val 4 : %d\n", z);
}
and here is where I call this function:
unsigned int exp[4] = { 1, 2, 3, 4 };
unsigned short count = 0;
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);
and here is the output that I expect:
val1 : 1
val2 : 2
val3 : 3
val4 : 4
but what I get is completely reverse of it:
val1 : 4
val2 : 3
val3 : 2
val4 : 1
I don't know why? Any help would be appreciated.
From standard docs, 5.4
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions,
and the order in which side effects take place, is unspecified58) Between the previous and next sequence point a
scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior
value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for
each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.
An example from the Standard docs itself,
i = v[i ++]; / / the behavior is undefined
And it is for the very same reason that
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]); is undefined..
You should not use the ++ operator, operating on the same variable, more than once in the same statement. The order in which the operation will be performed is not defined.
Try:
abc(anyarray, exp[count], exp[count+1], exp[count+2], exp[count+3]);
count += 4;
You've invoked undefined behavior, by modifying count more than once without an intervening sequence point.
You are counting on the parameters being evaluated left to right. You can't make any assumptions about the order that they're evaluated. In this case, it looks like the compiler is evaluating them right-to-left.
Also, you may want to look up sequence points, because it may be that you shouldn't use the ++ operator in this way.
abc(anyarray, exp[count++], exp[count++], exp[count++], exp[count++]);
The order of evaluation of arguments of abc is unspecified but the expression invokes undefined behaviour because you are trying to modify a variable count more than once between two sequence points.
Furthermore using incorrect format specifier in printf() also invokes UB. Please make sure you have used correct format specifiers(i.e %u for unsigned int) in printf().
You got this because you called adb(exp,a,b,c,d) according to your problem, but during call of function d is pushed first on stack and then c ,b relatively. As you passed exp[count++] at last argument which will process first to push over stack means 1 is pushed first then 2 then 3 then 4. And in called function pop performed so you get w=4 x=3 y=2 z=1 that's it.
This is because of the calling convention. In _cdecl, the default calling convention for c/c++ programs (according to microsoft), the parameters are passed on the stack to the function in reverse order. Because of this, the parameters are also evaluated in reverse order.