【问题标题】:Why is this variably turning negative? [closed]为什么这会变负? [关闭]
【发布时间】:2016-01-07 21:48:57
【问题描述】:

所以我的错误表明我无权访问此内存。 这是它的代码,我正在尝试让 collaz 系列工作。 但是我的n 变得消极,即使它不应该。

const int number = 1000000;

//Chain Vars-------------------
int chainLength = 0;
int startingNumber = 0;
int chain = 0;
int n = 0;
//----------------------------

for (int i = 2; i <= 1000000; i++)
{
    n = i;
    chain = 0;

    while (n != 1 && n >= i)
    {
        chain++;
        if ( (n % 2) == 0)
        {
            n = n / 2;
        }
        else
        {
            n = n * 3 + 1;
        }
    }
}

【问题讨论】:

  • Pastebin:坏 - 在 SO 上发布代码:好。发布所有代码:坏 - 发布与问题相关的代码:好
  • 同样的代码在 c# 中也可以正常工作。 -- C# 不是 C++
  • 关闭一个错误。数组的索引从 0 开始,而不是 1。如果它在 C# 中工作,那么你很幸运 - 即使它看起来适用于您选择的测试用例,代码在 C# 中也会有缺陷。
  • 错误信息到底说了什么?
  • @PaulMcKenzie 算法就是算法。数组边界是数组边界。两者都与语言无关。

标签: c++ collatz


【解决方案1】:

在您的 for 循环中,您可以:

for (int i = 2; i <= 1000000; i++)
{
    n = i;
    chain = 0;

    while (n != 1 && n >= i)
    {
        chain++;
        if ( (n % 2) == 0)
        {
            n = n / 2;
        }
        else
        {
            n = n * 3 + 1;
        }
    }

    //Store the chain length in cache
    cache[i] = chain + cache[n];
    //-------------------------------

    if (cache[i] > chainLength)
    {
        chainLength = cache[i];
        startingNumber = i;
    }
}

在某些时候while (n != 1 &amp;&amp; n &gt;= i) 很可能以n 大于1000000 结束。然后,您将越界访问cache(当您将访问cache[n])(即[0:1000000])。

while 循环之前添加std::cout &lt;&lt; "i is " &lt;&lt; i &lt;&lt; std::endl;。添加 std::cout &lt;&lt; "n is " &lt;&lt; n &lt;&lt; std::endl; 之后。运行程序,你会得到(几秒钟后):

...
i is 113381
n is 85036
i is 113382
n is 56691
i is 113383
n is -1812855948
Erreur de segmentation (core dumped)

给你。现在,您可以使用调试器、识别错误、修复错误(很可能重新设计循环)并使其工作! ;-)

提示:当n 变为负数时,可能它达到了int 的最大值......然后只需使用错误类型(如long long int 或uint64_t)。然后,你很可能不会得到任何过低(除非你让number 臭虫)。

C# 不像 C++ 那样管理内存。如果在此处访问数组越界,您可能不会收到任何错误(或者,如上所述,您很幸运)。我对 C# 不熟悉。必须始终避免访问数组,因为它可能具有不确定的行为(可能导致崩溃)。

【讨论】:

  • 我自己没有运行它,但我可以 100% 确定循环退出后 n 将是 == 1 或
  • 我认为“n!= 1”只有在它是 1 时才会结束……我该如何解决这个问题?我似乎找不到修复方法:/
  • @sLowDowN - 或者.. 如果n 得到否定 - 请参阅我的帖子 :)
  • @Danny_ds 我是支持您的答案的人,因为它是迄今为止唯一正确的答案。但你为什么说“不是这样”?我知道 n 变为负数,并且我 100% 确定当 n 为负数时 n == 1 或
  • @KlitosKyriacou - 好吧,你说得对,n cache[] 的范围。它只会因为太高而变得消极。我将删除该评论。感谢您的支持。
【解决方案2】:

就像jpo38说的:

提示:当 n 变为负数时,它可能已达到 int 的最大值...使用调试器验证这一点,只需在 while 循环之前执行:

那是我的问题,然后我将“int n”更改为“long long n”,因为“long n”仍然很小,现在它给了我正确的答案。谢谢大家 :) 很简单,但有时是你看不到的小东西。

【讨论】:

  • 该死的......我在我的帖子中提到了溢出,但为什么我没有得到更多的声誉! :-(
  • 这让我思考:是否可以在数学上证明使用 64 位整数时 n 不会溢出?
【解决方案3】:

程序运行调试后:

    //Store the chain length in cache
    cache[i] = chain + cache[n];

n 似乎是 0x93f20374i113383)这是负数 -1812855948,或者是正数 2482111348 - 但溢出成为 -1812855948

while (n != 1 && n >= i)

循环以负数n 结束,导致cache[n] 崩溃。

【讨论】:

  • 如何才能得到负数?因为 n 只除以 2 或乘以 3 +1 ...这应该是一个非常简单的解决方案,但我看不到它:D
  • @sLowDowN - 因为它溢出了n 是一个有符号整数,并得到+2482111348(无符号),它转换为带有int 的-1812855948。
猜你喜欢
  • 1970-01-01
  • 2021-12-22
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
  • 2013-02-04
  • 2016-01-08
  • 2023-03-31
  • 1970-01-01
相关资源
最近更新 更多