运行和调试之间的控制流程不同

时间:2017-10-04 17:09:55

标签: c# debugging control-flow

我正在编写一个程序,其行为我设计为来自用户的单个文本输入的功能而没有别的。没有使用系统时钟,没有引用外部文件,没有多线程。但是,当我运行它时,程序执行的控制流程与我调试时的控制流程不同,我认为在这种情况下应该是不可能的。

它不会自行编译,但这是一个意外行为的函数:

static public Dictionary<ComplexNumber, int> getFactorization(ComplexNumber xGaussian)
        {
            Dictionary<ComplexNumber, int> factors = new Dictionary<ComplexNumber, int>();
            int sumOfRealAndImaginary = 2;
            while (true)
            {
                Console.WriteLine(sumOfRealAndImaginary);//test
                int realPart = sumOfRealAndImaginary / 2;
                int imaginaryPart = sumOfRealAndImaginary - realPart;
                for (int i = 0; realPart - i >= 0;) 
                {
                    if ((realPart - i) * (realPart - i) +
                        (imaginaryPart + i) * (imaginaryPart + i) >
                        xGaussian.getRealPart().getNumerator() *
                        xGaussian.getRealPart().getNumerator() +
                        xGaussian.getImaginaryPart().getNumerator() *
                        xGaussian.getImaginaryPart().getNumerator())
                    {
                        if (factors.ContainsKey(xGaussian))
                            factors[xGaussian] += 1;
                        else
                            factors.Add(xGaussian, 1);
                        return factors;
                    }
                    ComplexNumber factor =
                        new ComplexNumber(realPart - i, imaginaryPart + i);
                    ComplexNumber quotient = (ComplexNumber)(xGaussian / factor);
                    quotient.getRealPart().reduce();
                    quotient.getImaginaryPart().reduce();
                    if (quotient.getRealPart().getDenominator() == 1 &&
                        quotient.getImaginaryPart().getDenominator() == 1) 
                    {
                        if (factors.ContainsKey(factor))
                            factors[factor] += 1;
                        else
                            factors.Add(factor, 1);
                        xGaussian = (ComplexNumber)(xGaussian / factor);
                        continue;
                    }
                    factor = new ComplexNumber(realPart - i, -imaginaryPart - i);
                    quotient = (ComplexNumber)(xGaussian / factor);
                    quotient.getRealPart().reduce();
                    quotient.getImaginaryPart().reduce();
                    if (quotient.getRealPart().getDenominator() == 1 &&
                        quotient.getImaginaryPart().getDenominator() == 1)
                    {
                        if (factors.ContainsKey(factor))
                            factors[factor] += 1;
                        else
                            factors.Add(factor, 1);
                        xGaussian = (ComplexNumber)(xGaussian / factor);
                        continue;
                    }
                    ++i;
                }
                ++sumOfRealAndImaginary;
            }
        }

ComplexNumber类型的设计方式与复数在数学中的行为相同,但仅限于有理的实部和虚部,因此我将以与复数中的复数相同的方式键入ComplexNumber对象的值。数学。这个版本的getFactorization()假设两个部分的分母都是1,为简单起见。

注意sumOfRealAndImaginary如何初始化为2,并且它唯一被改变的地方是它在while循环的底部递增的位置。在调试模式下,当我传递getFactorization()值3 + 4i并以足够中等的速度逐步执行代码时,它会在sumOfRealAndImaginary = 3时返回。这就是我所期望的。但是,当我运行程序时,也使用3 + 4i作为函数参数,直到sumOfRealAndImaginary = 126才会返回,这可以从while循环顶部的WriteLine()调用中看出。特别是,while循环中的第一个if语句,其代码块包含函数的return语句,在运行时需要更多的传递来评估为true,而不是在调试时。它不仅应该对期望的sumOfRealAndImaginary值为3,而且对于大于该值的每个值都要求为true。此外,当我在调试模式下快速单步执行代码 时,if语句将继续评估为false,直到我减速为止,此时它会在下一次传递时计算为true。因此,似乎if语句是否正确评估取决于代码的执行速度。什么可能导致这种行为?

我可以枚举更多不同的意外行为案例,但也许这足以启动。

编辑:根据PawełŁukasik的要求,ComplexNumber类。分数是一个类似的类,也是从Number类派生的,它是抽象的。

public class ComplexNumber : Number
        {
            Fraction m_real;
            Fraction m_imaginary;
            public ComplexNumber(Fraction real, Fraction imaginary)
            {
                m_real = real;
                m_imaginary = imaginary;
            }
            public ComplexNumber(int real, int imaginary)
            {
                m_real = new Fraction(real, 1);
                m_imaginary = new Fraction(imaginary, 1);
            }
            public Fraction getRealPart()
            {
                return m_real;
            }
            public Fraction getImaginaryPart()
            {
                return m_imaginary;
            }
            protected override Number add(Number number)
            {
                if (number is Fraction)
                {
                    Fraction fraction = (Fraction)number;
                    return new ComplexNumber((Fraction)(m_real + fraction), m_imaginary);
                }
                ComplexNumber complexNumber = (ComplexNumber)number;
                return new ComplexNumber((Fraction)(m_real + complexNumber.m_real),
                    (Fraction)(m_imaginary + complexNumber.m_imaginary));
            }
            protected override Number subtract(Number number)
            { 
                if (number is Fraction)
                {
                    Fraction fraction = (Fraction)number;
                    return new ComplexNumber((Fraction)(m_real - fraction), m_imaginary);
                }
                ComplexNumber complexNumber = (ComplexNumber)number;
                return new ComplexNumber((Fraction)(m_real - complexNumber.m_real),
                    (Fraction)(m_imaginary - complexNumber.m_imaginary));
            }
            protected override Number multiply(Number number)
            {
                if (number is Fraction)
                {
                    Fraction fraction = (Fraction)number;
                    return new ComplexNumber((Fraction)(m_real * fraction),
                        (Fraction)(m_imaginary * fraction));
                }
                ComplexNumber complexNumber = (ComplexNumber)number;
                return new ComplexNumber((Fraction)(m_real * complexNumber.m_real - m_imaginary *
                    complexNumber.m_imaginary), (Fraction)(m_real * complexNumber.m_imaginary +
                    m_imaginary * complexNumber.m_real));
            }
            protected override Number multiply(int scalar)
            {
                    return new ComplexNumber((Fraction)(m_real * scalar),
                        (Fraction)(m_imaginary * scalar));
            }
            protected override Number divide(Number number)
            {
                if (number is Fraction)
                {
                    Fraction fraction = (Fraction)number;
                    return new ComplexNumber((Fraction)(m_real / fraction),
                        (Fraction)(m_imaginary / fraction));
                }
                ComplexNumber complexNumber = (ComplexNumber)number;
                return new ComplexNumber((Fraction)((Fraction)(m_real * complexNumber.m_real +
                    m_imaginary * complexNumber.m_imaginary) / (Fraction)(complexNumber.m_real *
                    complexNumber.m_real + complexNumber.m_imaginary * complexNumber.m_imaginary)),
                    (Fraction)((Fraction)(m_imaginary * complexNumber.m_real -
                    m_real * complexNumber.m_imaginary) / (Fraction)(complexNumber.m_real
                    * complexNumber.m_real + complexNumber.m_imaginary * complexNumber.m_imaginary)));
            }
            public override string ToString()
            {
                StringBuilder output = new StringBuilder();
                if (m_imaginary.getNumerator() != 0)
                {
                    m_imaginary.reduce();
                    if (m_imaginary.getNumerator() > 0)
                    {
                        if (m_real.getNumerator() != 0)
                        {
                            output.Append(m_real.ToString());
                            output.Append("+");
                        }
                        if (m_imaginary.getNumerator() != 1)
                            output.Append(m_imaginary.getNumerator());
                    }
                    else if (m_imaginary.getNumerator() < 0)
                    {
                        if (m_real.getNumerator() != 0)
                            output.Append(m_real.ToString());
                        output.Append("-");
                        if (m_imaginary.getNumerator() != -1)
                            output.Append(-m_imaginary.getNumerator());
                    }
                    output.Append("i");
                    if (m_imaginary.getDenominator()!=1)
                    {
                        output.Append("/");
                        output.Append(m_imaginary.getDenominator());
                    }
                }
                else if (m_real.getNumerator() != 0)
                    output.Append(m_real.ToString());
                else
                    return "0";
                return output.ToString();
            }
            public override bool Equals(object obj)
            {
                if (obj is ComplexNumber)
                {
                    ComplexNumber complexNumber = (ComplexNumber)obj;
                    return m_real.Equals(complexNumber.m_real) &&
                        m_imaginary.Equals(complexNumber.m_imaginary);
                }
                return false;
            }
            public override int GetHashCode()
            {
                return m_real.GetHashCode() | m_imaginary.GetHashCode();
            }
        }

再次编辑:a link to a text file of the whole program,就此而言。

1 个答案:

答案 0 :(得分:0)

其他人建议问题与我为Fraction类定义的ToString()的重载具有调用reduce()的副作用这一事实有关,并且因为调试器使用ToString()以便显示变量的值,调试器可能一直在搞乱我的Fraction对象执行中的内部。有几个原因导致我觉得这不是问题的原因,其中最重要的是我希望它能使调试行为异常,但让运行不受影响而不是另一种方式,但我听从他们的建议,并安排在Fraction构造函数中发生所有减少,这确实解决了问题。如果有人对这是如何工作有更明确的解释,我将不胜感激。