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.
Related
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.
This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 6 years ago.
I have a friend who is getting different output than I do for the following program:
int main() {
int x = 20, y = 35;
x = y++ + x++;
y = ++y + ++x;
printf("%d%d", x, y);
return 0;
}
I am using Ubuntu, and have tried using gcc and clang. I get 5693 from both.
My friend is using Visual Studio 2015, and gets 5794.
The answer I get (5693) makes most sense to me, since:
the first line sets x = x + y (which is x = 20+35 = 55) (note: x was incremented, but assigned over top of, so doesn't matter)
y was incremented and is therefore 36
next line increments both, adds the result and sets it as y (which is y = 37 + 56 = 93)
which would be 56 and 93, so the output is 5693
I could see the VS answer making sense if the post-increment happened after the assignment. Is there some spec that makes one of these answers more right than the other? Is it just ambiguous? Should we fire anyone who writes code like this, making the ambiguity irrelevant?
Note: Initially, we only tried with gcc, however clang gives this warning:
coatedmoose#ubuntu:~/playground$ clang++ strange.cpp
strange.cpp:8:16: warning: multiple unsequenced modifications to 'x' [-Wunsequenced]
x = y++ + x++;
~ ^
1 warning generated.
The Clang warning is alluding to a clause in the standard, C++11 and later, that makes it undefined behaviour to execute two unsequenced modifications to the same scalar object. (In earlier versions of the standard the rule was different although similar in spirit.)
So the answer is that the spec makes all possible answers equally valid, including the program crashing; it is indeed inherently ambiguous.
By the way, Visual C++ actually does have somewhat consistent and logical behaviour in such cases, even though the standard does not require it: it performs all pre-increments first, then does arithmetic operations and assignments, and then finally performs all post-increments before moving on to the next statement. If you trace through the code you've given, you'll see that Visual C++'s answer is what you would expect from this procedure.
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().
Consider the following snippets:
C++:
#include <iostream>
using namespace std;
int main()
{
int x = 10, y = 20;
y = x + (x=y)*0;
cout << y;
return 0;
}
which gives a result of 20, because the value of y is assigned to x since the bracket is executed first according to the Operator Precedence Table.
VB.NET:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim x As Integer = 10
Dim y As Integer = 20
y = x + (x = y) * 0
MsgBox(y)
End Sub
which instead gives a result of 10.
What is the reason for this difference?
What is the order of execution of operators in VB.NET?
Unlike in C++, VB.NET's = is not always an assignment. It can also be the equality comparison operator (== in C++) if it appears inside an expression. Therefore your two expressions are not the same. They are not even equivalent. The VB.NET code does not do what you might think it does.
First to your C++ code: Like you're saying, the assignment x=y happens first; thus your code is roughly equivalent to this: (It seems that was incorrect; see Jens' answer.) Since you end up with y being 20, it is likely that your C++ compiler evaluated your code as if you had written this:
int x = 10, y = 20;
x = y;
y = x + x*0; // which is equivalent to `y = 20 + 20*0;`, or `y = 20 + 0;`, or `y = 20;`
In VB.NET however, because the = in your subexpression (x=y) is not actually interpreted as an assignment, but as a comparison, the code is equivalent to this:
Dim x As Integer = 10
Dim y As Integer = 20
y = 10 + False*0 ' which is equivalent to `y = 10 + 0*0`, or `y = 10` '
Here, operator precedence doesn't even come into play, but an implicit type conversion of the boolean value False to numeric 0.
(Just in case you were wondering: In VB.NET, assignment inside an expression is impossible. Assignments must always be full statements of their own, they cannot happen "inline". Otherwise it would be impossible to tell whether a = inside an expression meant assignment or comparison, since the same operator is used for both.)
Your C++ snippet is undefined behavior. There is no sequence point between using x as the first argument and assigning y to x, so the compiler can evaluate the sub-expressions in any order. Both
First evaluate the left side: y = 10 + (x=y) * 0 -> y = 10 + (x=20) * 0 -> y = 10 + 20*0
First evaluate the right side: y = x + (x=20) * 0 -> y = 20 + 20 * 0
It is also generally a very bad style to put assignments inside expressions.
This answer was intended as a comment, but its length quickly exceeded the limit. Sorry :)
You are confusing operator precedence with evaluation order. (This is a very common phenomenon, so don't feel bad). Let me try to explain with a simpler example involving more familiar operators:
If you have an expression like a + b * c then yes, the multiplication will always happen before the addition, because the * operator binds tighter than + operator. So far so good? The important point is that C++ is allowed to evaluate the operands a, b and c in any order it pleases. If one of those operands has a side effect which affects another operand, this is bad for two reasons:
It may cause undefined behavior (which in your code is indeed the case), and more importantly
It is guaranteed to give future readers of your code serious headaches. So please don't do it!
By the way, Java will always evaluate a first, then b, then c, "despite" the fact that multiplication happens before addition. The pseudo-bytecode will look like push a; push b; push c; mul; add;
(You did not ask about Java, but I wanted to mention Java to give an example where evaluating a is not only feasible, but guaranteed by the language specification. C# behaves the same way here.)
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I found a interesting quize today about gcc http://ridiculousfish.com/blog/posts/will-it-optimize.html
How come this code
int factorial(int x) {
if (x > 1) return x * factorial(x-1);
else return 1;
}
can be translated by compiler into
int factorial(int x) {
int result = 1;
while (x > 1) result *= x--;
return result;
}
Is this true? How gcc does it?
You already know that gcc can optimize a tail-recursive function into a loop. The other thing that gcc can do (and is mentioned in your link) is try to optimize a non-tail-recursive function into a tail-recursive function.
Your factorial function is here:
int factorial(int x) {
if (x > 1) return x * factorial(x-1);
else return 1;
}
Now I'm going to try to make as few changes as possible and rewrite this as tail-recursive. First, I'll flip the if test:
int factorial(int x) {
if (!(x > 1)) return 1;
else return x * factorial(x-1);
}
Next, I'll remove the unneeded else:
int factorial(int x) {
if (!(x > 1)) return 1;
return x * factorial(x-1);
}
This is almost tail-recursive, but it is returning x * factorial() and not just factorial(). The typical way to make this tail recursive is to include a second parameter, which is an accumulator.
int factorial(int x, int accumulator = 1) {
if (!(x > 1)) return accumulator;
return factorial(x - 1, x * accumulator);
}
Now this is a tail-recursive function, and it can be optimized into a loop.
The compiler could transform that code into something tail-call optimisable by putting the multiplication before the recursive function call:
int factorial(int x) {
return factorial_tail_call(x, 1);
}
int factorial_tail_call(int x, int result) {
if (x > 1) return factorial_tail_call(x-1, result*x);
return result;
}
By performing the evaluation of result*x before factorial_tail_call is called recursively, the compiler can determine that x and result are no longer needed. Hence, it can pop them from the stack. This forms proof that the stack doesn't need to grow.
Can you see any resemblance between the transformed-to code? The 1 is in the same place, the condition x > 1 is in the same place and return result; is in the same place. It's all just a different way of expressing the same algorithm, providing the compiler implements tail call optimisation. By moving the multiplication expression into an argument and putting in comments the code from your post to the right, you might be able to see some resemblance of functionality, and how the compiler managed to make the remainder of the transformation:
int factorial(int x) {
return factorial_tail_call(x, 1); // int result = 1;
}
int factorial_tail_call(int x, int result) {
if (x > 1) return factorial_tail_call(x-1, result*x); // while (x > 1) result *= x--;
return result; // return result;
}
§5.1.2.3p4 of n1570.pdf
In the abstract machine, all expressions are evaluated as specified by
the semantics. An actual implementation need not evaluate part of an
expression if it can deduce that its value is not used and that no
needed side effects are produced (including any caused by calling a
function or accessing a volatile object).
Compilers are smart things, written by far better programmers than most of us. If the compiler can figure out that two pieces of code are equivalent, then it can choose whichever of the two it wishes (with some restrictions, described in the quotation below). For example, it could replace a loop that calculates and prints the first thousand primes with a single printf expression.
§5.1.2.3p6 of n1570.pdf
The least requirements on a conforming implementation are:
— Accesses to volatile objects are evaluated strictly according to the
rules of the abstract machine.
— At program termination, all data written into files shall be
identical to the result that execution of the program according to the
abstract semantics would have produced.
— The input and output dynamics of interactive devices shall take
place as specified in 7.21.3. The intent of these requirements is that
unbuffered or line-buffered output appear as soon as possible, to
ensure that prompting messages actually appear prior to a program
waiting for input.
This is the observable behavior of the program.
That's one reason why micro-optimisation is futile.
If another thread modifyies a string that strlen is processing, that's a race condition. Race conditions are undefined behaviour. You need to guard the string with a mutex to ensure this doesn't happen, or learn better multi-threading paradigms. Which book are you reading?
§5.1.2.4p25 of n1570.pdf
The execution of a program contains a data race if it contains two
conflicting actions in different threads, at least one of which is not
atomic, and neither happens before the other. Any such data race
results in undefined behavior.