Return 语句有效但没有多大意义
我有以下功能:
int mult(int y, int z)
{
if (z == 0)
return 0;
else if (z % 2 == 1)
return mult(2 * y, z / 2) + y;
else
return mult(2 * y, z / 2);
}
我需要做的是通过归纳证明其正确性。现在我遇到的麻烦是,尽管我知道它自从运行以来就有效,但我无法遵循每个单独的步骤。
让我困惑的是 y 仅显示为参数,除了递归部分之外,它在任何地方都不会显示在返回中,但该函数实际上返回 y > 作为答案。
这是怎么发生的?我需要能够跟踪发生的一切,以便我可以对其进行迭代以进行证明。
I have the following function:
int mult(int y, int z)
{
if (z == 0)
return 0;
else if (z % 2 == 1)
return mult(2 * y, z / 2) + y;
else
return mult(2 * y, z / 2);
}
What I need to do is prove its correctness by induction. Now the trouble I'm having is that even though I know it works since I ran it I can't follow each individual step.
What is confusing me is that y
only shows up as an argument and in no place does it show up in a return except in the recursive part, and yet the function actually returns y
as the answer.
How does this happen? I need to be able to follow everything that happens so that I can do the iterations of it for the proof.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
因为这显然是一个家庭作业问题,所以我建议你做这项任务可能意味着你要做的事情。跟踪代码。
1) 给出 y 和 z 的起始值。
2)无论是在纸上还是在调试器中,跟踪调用该函数时发生的情况。
3) 使用当前的 y/z 值重复步骤 2,直到程序完成。
Since this is obviously a homework question, I recommend you do what the assinment was likely meant fot you to do. Trace through the code.
1) give a starting value for y and z.
2) either on paper or in a debugger, trace what happens when you call the function.
3) repeat step 2 with your current y/z values until program completion.
输出:
3 和 13 的工作原理:
偶数和奇数有一个开关(请参阅代码中的注释)。
当 z 为 null 时,递归“开始返回到初始调用”。如果数字 z 是奇数,则将 y 添加到递归调用的返回值中,如果数字 z 是偶数,则仅返回递归调用的值。
Output:
How it works for 3 and 13:
There's a switch for even and odd numbers (see comment in code).
When z is null, the recursion "starts to return to the initial call". If the number z is odd it adds y to the returned value of the recursive call, if it's even it justs returns the value from the recursive call.
逐步分析
step-by-step analisis
注意:如果这是家庭作业,请如此标记。
所以,我们基本上得到了三种递归情况。为了使一切更清楚,我将 C 代码重写为一些功能性伪代码。将
mult
替换为直观的运算符号,并找出低级表达式(如(z%2==1)
)的描述性解释。你会想出类似这样的话:
你现在明白了吗?
Note: If this is homework, tag it as such.
So, we basically got three recursive cases. To make it all clearer, I'd rewrite the C-code into some functional pseudo-code. Replace
mult
with an intuitive operator sign and figure out descriptive explanations of low-level expressions like(z%2==1)
.You'll come up with something like
Do you get the point now?
一种方法是将每一行翻译成“英语”。我的翻译是这样的:
如果 z 为零,则返回零
如果 z 为奇数,则返回 mult(y*2, z/2) + y
如果 z 为偶数,则返回 mult(y*2, z/2)
一般模式是递归调用 mult,第一个参数加倍,第二个参数减半。
请注意,这里您使用 z/2 调用 mult,但它的参数是整数,因此如果您的函数继续递归,第二个参数将每次减半,直到它降至 1,最后是 1/2,向下舍入到 0 - 此时递归将停止,因为 z==0。
有了这些线索,您应该能够理解该算法是如何工作的。
One approach would be to translate each line into "English". My translation would be something like this:
if z is zero, return zero
if z is odd, return mult(y*2, z/2) + y
if z is even, return mult(y*2, z/2)
The general pattern is to recursively call mult with the first parameter doubling, and the second parameter halving.
Note that here you're calling mult with z/2, but its arguments are integers, so if your function continues to recurse, the 2nd parameter will halve each time until it gets down to 1, and then finally 1/2 which rounds down to 0 - at which point recursion will stop because z==0.
With those clues, you should be able to understand how this algorithm works.
归纳论证的基础是证明结果对于第一个值是有效的,并且如果该原理对于泛型值
N
是正确的,则可以证明它对于N+1 成立
。为了简化,您可以首先证明它适用于
{ 0, 1, 2 }
中的z
,这对于手动测试来说应该是微不足道的。然后,为了演示归纳步骤,您从通用z=N
开始,并证明如果mult( y, N )
是有效结果,则mult ( y, N+1 )
就前一个结果而言也是有效的结果。由于偶数和奇数有不同的分支,因此您必须证明偶数和奇数N
的归纳步骤。Demonstrations by induction are based on proving that the result is valid for the first value, and that if the principle is correct for a generic value
N
, it is provable that it holds forN+1
.To simplify, you can start by proving that it works for
z
in{ 0, 1, 2 }
which should be trivial with a manual test. Then to demonstrate the induction step, you start with a genericz=N
, and prove that ifmult( y, N )
is a valid result, thenmult( y, N+1 )
is also a valid result in terms of the previous one. Since there are different branches for even and odd numbers, you will have to prove the induction step for both even and oddN
numbers.ya = ya
a = 偶数
b = 下一个奇数(换句话说 a + 1)
因此,如果您只想用偶数(一个 'a' ) 当给定一个奇数 (a 'b') 时,您可以执行以下操作:
yb = y(a+1) = y*a + y
现在将 'a' 写为 2 会让大家感到困惑*(z/2)。
y*a 变为 (2*y)*(z/2)
y*b 变为 ((2*y)*(z/2))+y
由于 'z' 出现在偶数和奇数的公式中,因此我们想认为代码告诉我们 (2*y)*(z/2) = (2*y)*(z/2) + y 这显然是疯狂的!
原因是我们忽略了 z/2 是整数这一事实,因此 z 永远不可能是奇数。当 z 为奇数时,编译器不会让我们将 z/2 分配给整数。如果我们尝试使“z”为奇数,那么我们真正使用的整数是 (z-1)/2 而不是 z/2。
为了解决这个问题,我们必须测试 z/2 是否为奇数,并据此选择我们的公式(例如,以“a”表示的 ya 或 yb)。
在 mult(y,z) 中,“y”和“z”都是整数。使用上面的符号 mult(2*y,b/2) 会变成 mult(2*y,a/2),因为 b/2 会被编译器截断为 a/2。
由于我们总是要获取“a”作为“mult”的参数,即使我们发送“b”,我们也必须确保只使用需要“a”的公式。因此,如上所述,我们使用 ya+1 代替 yb。
b/2 = a/2 + 1/2 但 1/2 不能表示为 int 的一部分。
ya = ya
a = an even number
b = the next odd number (in other words a + 1)
So, if you want the equation above in terms of only even numbers (an 'a') when given an odd number (a 'b') you can do the following:
yb = y(a+1) = y*a + y
Now confuse everyone by writing 'a' as 2*(z/2).
y*a becomes (2*y)*(z/2)
y*b becomes ((2*y)*(z/2))+y
Since 'z' appears in the formula for both even and odd numbers, we want to think that the code is telling us that (2*y)*(z/2) = (2*y)*(z/2) + y which is obviously MADNESS!
The reason is that we have snuck in the fact that z/2 is an integer and so z can never be odd. The compiler will not let us assign z/2 to an integer when z is odd. If we try to make 'z' odd, the integer we will really be using is (z-1)/2 instead of z/2.
To get around this, we have to test to see if z/2 is odd and pick our formula based on that (eg. either ya or yb in terms of 'a').
In mult(y,z) both 'y' and 'z' are both integers. Using the symbols above mult(2*y,b/2) becomes mult(2*y,a/2) because b/2 will be truncated to a/2 by the compiler.
Since we are always going to get an 'a' as a parameter to 'mult', even when we send a 'b', we have to make sure we are only using formulas that require 'a'. So, instead of yb we use ya+1 as described above.
b/2 = a/2 + 1/2 but 1/2 cannot be represented as part of an int.
并不是真正的答案,而是更多的建议。
您可能希望将递归调用从 2 次减少到 1 次:
这可以通过遵守“仅一个退出点”规则来再次简化:
虽然许多编译器会自动执行此简化,但当代码被简化时,调试通常会更容易。调试器将在单步执行时匹配代码。
有时简化会增加清晰度。此外,添加注释将帮助您了解您在做什么以及下一个阅读代码的人。
Not really an answer, but more of a suggestion.
You may want to reduce the recursion call from 2 to one:
This could be simplified once more by observing the rule "one exit point only":
Although many compilers will perform this simplification automatically, debugging is usually easier when the code is simplified. The debugger will match the code when single-stepping.
Sometimes simplifying will add clarity. Also, adding comments will help you figure out what you are doing as well as the next person who reads the code.