The very simple Java code as follows has the weird output, but the same logic code in C and C++ has the right output. I try with the JDK 1.7 and JDK 1.3 (relative JRE), the weird output is always there.
public class Test {
public static int sum=0;
public static int fun(int n) {
if (n == 1)
return 1;
else
sum += fun(n - 1); // this statement leads to weird output
// { // the following block has right output
// int tmp = fun(n - 1);
// sum += tmp;
// }
return sum;
}
public static void main(String[] arg) {
System.out.print(fun(5));
}
}
The output is 1 which should be 8. Relative C/C++ code is as follows:
#include<stdio.h>
int sum=0;
int fun(int n) {
if (n == 1)
return 1;
else
sum += fun(n - 1);
return sum;
}
int main()
{
printf("%d",fun(5));
return 0;
}
Adding test java code:
class A {
public int sum = 0;
public int fun(int n) {
if(n == 1) {
return 1;
} else {
sum += fun(n - 1);
return sum;
}
}
}
public class Test {
public static void main(String arg[]){
A a = new A();
System.out.print(a.fun(5));
}
}
I'm going to run through this for fun(3) for the sake of giving a complete answer. For those of you who are not interested why this works for C++ but not for Java, please ignore my answer.
Here is what Java is doing:
inside fun(3)
sum += sum + fn(n-1) // sum is 0
becomes
sum = 0 + fun(2) // sum is 0
Then inside fun(2)
sum = 0 + fun(1) // sum is 0
Then inside fun(1)
return 1 // sum is 0
Back inside fun(2)
sum = 0 + 1; // sum is 0
becomes
sum = 1; // sum will soon become 1
Back inside fun(3)
sum = 0 + 1; // sum is 1
becomes
sum = 1; // sum gets reset to 1
Here is what C++ is doing:
inside fun(3)
sum += fn(n-1) // sum is 0
becomes
sum = sum + fn(2) // sum is 0
Then inside fun(2)
sum = sum + fn(1) // sum is 0
Then inside fun(1)
return 1 // sum is 0
Back inside fun(2)
sum = sum + 1 // sum is 0
Becomes
sum = 0 + 1 => sum = 1 // sum will soon become 1
Back inside fun(3)
sum = sum + 1 // sum is 1
Becomes
sum = 1 + 1 // sum will soon become 2
What you should do:
I do not know why C++ evaluates sum
after making the function call rather than before. I do not know if this is in the specifications. But I do know that you should not be depending on this in any language. A correct solution would be:
int fun(int n) {
if (n == 1)
return 1;
else
return n + f(n - 1);
}
The problem is this line:
sum += fun(n - 1);
which is updating the variable sum
.
Assuming that you are simply trying to sum the numbers from 1 to N, then it should be doing the calculation that calculates f(N)
in terms of f(N - 1)
. That doesn't require you to refer to sum
... and certainly it doesn't require you to update it.
(I'm being careful NOT to tell you what the answer is ... because it you will learn more if you figure it out yourself.)
By the way, there is nothing Java specific about the flaw in your algorithm ...
It is worth noting that the real issue is not to do with static versus instance variables. The real issue is that a recursive function like this shouldn't be using either kind of variable. Now in this example you can possibly get away with it, but if the recursion involves something like this: f(N) = f(N-1) + f(N-2)
you are liable to find that the different call trees interfere with each other.
A more correct solution in this case is to write the method as:
int fun(int n) {
if (n == 1)
return 1;
else
return n + f(n - 1);
}
As I said, you don't need to refer to, or update the sum
variable.
The current answers to this question do not get to the root of the issue. The behavior in Java is due to the fact that:
sum += fun(n - 1);
is equivalent to:
sum = sum + fun(n - 1);
where sum
is evaluated before fun(n - 1)
and the value is stored. We can see this by going to the JLS section 15.26.2. Compound Assignment Operators which says:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2))
and then the left hand operand is evaluated and then the right hand operand is evaluated and the operation is performed. So sum
is evaluated before each iteration of the recursion and is 0
all the way back.
It also means that if you switched the line to this:
sum = fun(n - 1) + sum ;
it would produce the effect you desire since fun
would be evaluated first.
In C++:
sum += fun(n - 1);
is also equivalent to:
sum = sum + fun(n - 1);
this is covered in the draft C++ standard section 5.17
Assignment and compound assignment operators which says:
The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once.[...]
The major different is that the order of evaluation of the left and right hand side is unspecified which is covered in section 1.9
Program execution paragraph 15 which says:
Except where noted, evaluations of operands of individual operators and of subexpressions of individualexpressions are unsequenced.[...]
and so 1
and 8
would both be valid results in C++. We can see this live gcc gives us 8 and clang gives us 1.
Try this:
public class Test {
public static int fun(int n) {
System.out.println("processing n " + n );
if (n == 1)
return 1;
else{
return n + fun(n - 1);
}
}
public static void main(String[] arg) {
System.out.print(fun(5));
}
}
public static int fun(int n) {
if (n == 1)
return 1;
else
return n + fun(n - 1);
}
BTW if you want to do it in the same way as in C code, just define sum as "Integer" instead of "int"
return n <= 1 ? n : n + fun(n-1);
Try this
static int getsum(int num){
int sum = 0;
if(num == 1){
return num;
}else{
sum = num+getsum(num-1);
}
return sum ;
}
You really need to step through your logic there. It doesn't make any sense. Is the "weird" output that f(5) = 8? (you've actually accidentally written a function which computes 2^(n-2), but that seems beside the point)
I can't explain to you where any syntax is wrong - its the algorithm itself. It just doesn't do what you intended it to do. A big red flag that should stand out to you: the variable n isn't even directly added to sum anywhere! When you call fun(5), that 5 isn't even used. It's just passed into f(4).
It seems to me that your logic was this: recursively loop from n->1, and add that to sum. In which case, your function should have been:
void fun(int n){
if(n == 0)
return;
sum += n;
fun(n-1);
}
or something like that. But that isn't a very...recursive-y way to do things. You'd be much better off with no variables at all. Non-base-case: return n+fun(n-1).
Also in the future, when you say that some code has "weird output", you should probably provide both 1) the weird output and 2) what you expected the output to be. We're all just guessing at what you wanted to write.
来源:https://stackoverflow.com/questions/11813692/different-results-in-java-and-c-using-in-recursion