问题 为什么这个for循环会永远运行?

玻璃杯

知名会员
已加入
2019年11月22日
留言内容
126
编程经验
Beginner
这是我刚刚解决的问题,但我想知道为什么会首先发生。这是来自网络的控制台程序,该程序填充素数列表:

C#:
using System;
using System.Collections.Generic;

namespace PrimeFactorCalculator
{
    /// <summary>
    /// This program will calculate and populate a list of prime factors.
    /// </summary>
    class Program
    {
        private static List<long> _primes = new List<long>();

        static void Main(string[] args)
        {
            // Manually add the first prime number.
            _primes.Add(2);
            Console.WriteLine(2);

            for (long checkValue = 3; checkValue <= long.MaxValue; checkValue += 2)
            {
                if (IsPrime(checkValue))
                {
                    _primes.Add(checkValue);
                    Console.WriteLine(checkValue);
                }
            }
        }

        private static bool IsPrime(long checkValue)
        {
            bool isPrime = true;

            foreach (long prime in _primes)
            {
                if ((checkValue % prime) == 0 && prime <= Math.Sqrt(checkValue))
                {
                    isPrime = false;
                    break;
                }
            }
            return isPrime;        
        }
    }
}

它工作正常。我有一个程序,其中我手动填充了素数列表,并使用上面的代码替换了我的PrimeList.Add方法调用的庞大列表。这是代码的相关部分的外观,这是列表本身:

C#:
public static List<short> PrimeList { get; }

它在构造函数中实例化:

C#:
static NumberPropertiesModel()
{
    PrimeList = new List<short>();
    PopulatePrimeList();
    // more code
}

我将从网上获得的主要代码放入PopulatePrimeList()方法中:

C#:
public static void PopulatePrimeList()
{
    // Manually add the first prime number.
    PrimeList.Add(2);

    for (short checkValue = 3; checkValue <= short.MaxValue && checkValue > 0; checkValue += 2)
    {
        if (IsPrime(checkValue))
        {
            PrimeList.Add(checkValue);
        }
    }
}

private static bool IsPrime(short checkValue)
{
    bool isPrime = true;

    foreach (short prime in PrimeList)
    {
        if ((checkValue % prime) == 0 && prime <= Math.Sqrt(checkValue))
        {
            isPrime = false;
            break;
        }
    }

    return isPrime;
}

您可能会注意到,除了使用短裤而不是多头之外,我还为for循环添加了一个条件,即"&& checkValue > 0"。我必须添加它,因为循环将永远运行,我使用Debug.WriteLine来查看正在发生的事情,而checkValue变量最终会从其最大值的一端移到另一端,并不断循环。

当我看到此消息时,我想起checkValue最终会以其maxvalue-1结束,因此当它增加2时超过了限制,然后从另一端回绕。这给了我一个确保始终大于零的想法。但是,当我看到短裤的最大值是一个奇数时,我意识到我的想法是错误的,短裤的maxvalue-始终是偶数,并且因为checkValue从3开始并以2递增,所以永远不可能是偶数数字。因此,我对出现问题的想法本身就是错误的,但是我的解决方案确实有效。

我很好奇是否有人能告诉我为什么会这样?
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
您知道如何设置条件断点吗?如果没有,您应该阅读如何使用它,并在此处使用它。这样,您可以执行诸如循环运行之类的操作,直到接近您认为应该是最后一次迭代的位置,然后再中断,这样您就可以从那里一步一步地逐行查看实际发生的情况。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
如果您从逻辑上考虑问题,那么这个问题就很明显。您告诉循环只要继续 短的 变量小于或等于最大值a 短的 变量可以有。这意味着,要终止循环,您的 短的 变量必须大于可能的最大值,这是无稽之谈。

循环继续进行,直到变量等于或小于其最大可能值,然后将其加2。当您执行该加法时,您认为应该怎么办?显然,它不能创建一个大于最大可能值的值,因此只有两种可能:要么溢出并导致异常,要么不溢出,并且以某种方式对待最高位。显然,它不是前者,因此必须是后者。该最高位结束于用于表示符号的位置,这就是为什么它回绕为负数的原因。

如果您还不知道数字的补码表示形式,那么现在是研究它的好时机。
 

玻璃杯

知名会员
已加入
2019年11月22日
留言内容
126
编程经验
Beginner
如果您从逻辑上考虑问题,那么这个问题就很明显。您告诉循环只要继续 短的 变量小于或等于最大值a 短的 变量可以有。这意味着,要终止循环,您的 短的 变量必须大于可能的最大值,这是无稽之谈。

但是,为什么对于使用长变量而不是短变量的原始代码不发生这种情况呢?
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,525
地点
悉尼,澳大利亚
编程经验
10+
我不知道运行任何代码时发生了什么或没有发生什么,但是如果运行以下代码,您可以看到发生了什么:
C#:
static void Main(string[] args)
{
    short s = short.MaxValue;
    long l = long.MaxValue;

    Console.WriteLine(s);
    Console.WriteLine(l);

    Console.WriteLine(Convert.ToString(s, 2).PadLeft(16, '0'));
    Console.WriteLine(Convert.ToString(l, 2).PadLeft(64, '0'));

    s += 1;
    l += 1;

    Console.WriteLine(s);
    Console.WriteLine(l);

    Console.WriteLine(Convert.ToString(s, 2).PadLeft(16, '0'));
    Console.WriteLine(Convert.ToString(l, 2).PadLeft(64, '0'));

    Console.ReadLine();
}
 
最佳 底部