【问题标题】:Computing square-root with bit shifting algorithm always outputs the same number用位移算法计算平方根总是输出相同的数字
【发布时间】:2019-04-07 21:31:34
【问题描述】:

我正在努力使用用于计算大数平方根的位移算法。我有 32 位字的数组,输入无关紧要,输出总是相同的数字。以前,该算法在每个数组单元格中使用 1 位,但是当我切换到单元格中的单词时,它不再起作用了。
我编写了完全独立工作的方法(添加单词、减去单词、向右移动位),但整个程序并没有达到我的预期。
当输入数字的第一个位置为 0 时,输出为 0,当它有任何数字但数组的第一个单元格不是 0 时,输出始终相同。

变量:

uint32_t var[4] = {0,0,0,0};
uint32_t w_number[word_len] = {1, 0,0,234324};
uint32_t one[word_len]      = {0,0,0,0};
uint32_t var[word_len]      = {0,0,0,0};
uint32_t buff[word_len]     = {0,0,0,0};
uint32_t result[word_len]   = {0,0,0,0};

代码:

一个[0] = 1L

while (isBigger(one, input))
{
    shiftR_word(one);
    shiftR_word(one);
}

while (!isZero(one))
{
    add_word(result, one, var); //the result of one+result is put in Var. 

    if ((isBigger(input, var) || equals(input, var))) // if (input >= var) 
    {       
        subtract_word(input, var, input); // input-=var
        shiftR_word(result);
        add_word(result, one, result);          
    }
    else
    {
        shiftR_word(result);            
    }
    shiftR_word(one);
    shiftR_word(one);
}

std::cout << "\nOut: ";
printAsBit(result);
std::cout << std::endl;

这是我正在使用的可能导致问题的移位算法。

    void shiftR_word(uint32_t w_number[], int n=4)
    {
      // n - how many words
      //(n*32b word) >> 1
      bool* odd = new bool[n];

        for (int i = 0; i < n; i++)
        {
          if( w_number[i] & 1 )
            odd[i]=true;
          else
            odd[i]=false;
        }


        for (int i = 0; i < n; i++)
          w_number[i] >>= 1;

        for (int i = 0; i <= n-1; i++)
        {
          if(odd[i])
          {
            w_number[i+1] = w_number[i+1] | 1 << 31;
          }
        }

      delete[] odd;
    }

添加函数:

void add_word(uint32_t a[], uint32_t b[], uint32_t result[], int len=4)
{
  int carry=0;

  for (int i = len-1; i >=0; i--)
  {
    result[i]=a[i]+b[i]+carry;
    carry = (a[i]>result[i] || b[i]>result[i]) ? 1 : 0;

  } 
}

isBigger 方法:

bool isBigger(uint32_t a[],uint32_t b[] ,int len=4)
{
    for (int i = 0; i < len; i++)
    {
      if (a[i]>b[i])
      {
        return true;
      }
    }
    return false;
}

我无法发现代码中的错误,尤其是当我单独测试所有方法时,它们似乎都有效。

【问题讨论】:

  • 请发帖minimal reproducible example。这里没有足够的代码和变量声明来了解发生了什么。 所有方法都有效 不,它们没有。 add_word 没有正确计算进位(2 ^ 32 是 34,并且您使用的方法由于溢出而不起作用)。
  • @1201ProgramAlarm 是的,我不小心复制了错误版本的add_word 方法。现在我编辑并发布了我正在使用的那个。
  • 您可以使用二进制搜索来计算平方根。这将需要O(log(n))。
  • @AtulKumar 我已经阅读了所有算法并选择了这个,因为一旦它在 c++ 中工作,我将不得不在汇编中编写它,而这个似乎是最容易在汇编中实现的。

标签: c++ algorithm square-root


【解决方案1】:

isBigger 不起作用。如果 a 的 (长度 2) 值为 {2, 5},b 的值为 {6, 3},它将返回 true,而它应该返回 false。在循环内部,如果a[i] &lt; b[i],您希望返回false,并且仅在两个值相等时才检查下一个值。

bool isBigger(const uint32_t a[], const uint32_t b[], int len = 4)
{
    for (int i = 0; i < len; i++)
    {
      if (a[i] > b[i])
        return true;
      if (a[i] < b[i])
          return false;
    }
    // Only get here if `a` and `b` are equal
    return false;
}

此外,shiftR_word 具有未定义行为,因为w_number[i+1] 可以超出数组的末尾(当i == n-1 时,您将访问w_number[n - 1 + 1] 或w_number[n])。在这种情况下,您的循环条件应该是i &lt; n-1。但是,该功能相当低效。它可以重写为只需要一个循环并且不需要内存分配,但这留给读者作为练习。

【讨论】:

  • 我已经改变了这两件事,现在输出总是这样的'0000...10101010100'。它适用于具有完美根的小数(例如 16),但似乎不适用于更大的数。 100 的输出是 20,而 1000 甚至更多的输出是相同的……我一直在寻找不同的单词转换方法,但没有找到比这更好的方法。
  • 好吧,没关系,输出仍然是错误的,我得到 16 的 7,输出始终是 ` 0....1111 `。
猜你喜欢
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多