【发布时间】:2020-01-11 11:06:45
【问题描述】:
我正在解决一些算法测试,它是Collatz conjecture。
总之,
1-1. if the number is even, divide it by 2
1-2. if odd, multiply it by 3 and plus 1
2. repeat the same process 1(1-1 or 1-2), until the number become 1.
例如, 6 变为 1,经过 8 次尝试(6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1)。
在测试中,应该以500次尝试结束,并返回尝试次数。 如果失败 500 次,则返回 -1。
这是我的代码。
using System;
public class Program {
public int Main(int num) {
int answer = -1;
int maxTry = 500;
int count = 0;
if (num == 1)
return count;
for (count = 0; count < maxTry; count++)
{
// 1-1
if (num % 2 == 0)
{
num /= 2;
}
// 1-2
else
{
num = num * 3 + 1;
}
if (num == 1)
{
answer = count + 1;
break;
}
}
Console.Write(answer);
return answer;
}
}
在遇到“626331”之前,它运行良好! 在解释中,626331 不可能是 500 次中的 1。 但是使用我的代码,它返回 488,这意味着它在 488 次尝试时变为 1。 当我重复打印过程时,它看起来运行良好。
经过所有尝试,发现分割是问题所在。
我改变了这个
if (num % 2 == 0)
...
else
...
进入
if (num % 2 == 0)
...
else if (num % 2 == 1)
...
现在每个案例都可以完美运行! 但我对这种情况没有任何线索。
这是在线编码测试,编译选项是 C# Mono C# Compiler 5.14.0.177
【问题讨论】:
-
你的程序溢出了int范围,即
-2,147,483,648 to 2,147,483,647。而您的“修复”仅有效,因为现在您可以获得 0、1 或 -1。处理 long 而不是 int 以获得正确的行为。 -
@PeterDeniho 虽然它在某种意义上有点重复,但核心问题不是代码中没有覆盖 mod 负数,而是溢出本身。因此,我认为这不是链接问题的欺骗
-
在循环过程中,变量
num最终得到1069967879的值。将其乘以 3,结果为3209903637,超出了int类型的范围(2147483647的最大值)。溢出导致负数-1085063659。添加== 1子句隐藏了这个事实,但并没有真正解决问题,因为计算仍然没有产生算法预期范围内的数字。有关 C# 中模运算的更多详细信息,请参阅标记的重复项。 -
@Andrei:帖子的标题是 _"(num % 2) 会导致 0、1 和更多?从
%得到一个结果,而不是0或1。也就是说,我还添加了指向重复帖子的链接,该帖子涉及int和 C# 中其他基本类型的值范围。 -
@PeterDuniho,我现在也明白这一点,谢谢。但是,op 没有意识到的核心问题是溢出。可以在这里附上两个骗子吗?