【问题标题】:Can someone find the error in calculating number of 1's in binary representation?有人能在二进制表示中找到计算 1 的数量的错误吗?
【发布时间】:2014-07-16 20:56:53
【问题描述】:

此代码为除 1 以外的所有值输出 0。对于 1,它输出 1。看起来它正在执行 else 语句,因为“temp”值没有被打印(所有额外的打印语句已添加用于调试)。请帮忙。

#include<stdio.h>
#include<math.h>
int binarysum(long long int p);
int main(){
    int r;
    long long int x;
    scanf("%lld",&x);
    r=binarysum(x);
    printf("%d",r);
    return 0;
}
int binarysum(long long int p){
    int result;
    int j;
    long long int check=pow(2,30),temp;
    printf("%lld p %lld check\n",p,check);
    if(p==0)
        result=0;
    else if(p==1)
        result=1;
    else{
        for(j=31;j>=2;j--){
            temp=check/2;
            if(p>=temp){
                printf("%lld temp\n",temp);
                result=1+binarysum(p-temp);
                break;
            }
        } 
    }
    printf("%d result\n",result);
    return result;
}

【问题讨论】:

  • 首先想到的是在你的 for 循环中 temp 每次都是一样的,因为 check 永远不会改变。
  • 你的包围是错误的;也就是说,您的 sn-p 中的 }{ 多一个。我不确定您是否遗漏了代码,或者只是在您的printf("%d result\n, result); 行之前放了太多}。无论哪种方式,这都是您应该正确缩进代码的原因。
  • 不,他有正确数量的括号,每个 5 个。缩进让人很难分辨。
  • 第五个{在哪里?我看到main 前面一个,binarysum 前面一个,else 前面一个,for 前面一个。
  • 有史以来最复杂的popcount计算方式?

标签: c debugging error-handling


【解决方案1】:

问题是 check 在 for 循环中永远不会更新。

for(j=31;j>=2;j--){
    temp=check/2;
    if(p>=temp){
        printf("%lld temp\n",temp);
        result=1+binarysum(p-temp);
        break;
    }
} 

temp 每次都使用检查设置,但由于check 不会更改,temp 也不会更改。 将其切换为temp /= 2;,或使用check 而不是temp

【讨论】:

    【解决方案2】:

    pow 是一个浮点函数。因此,除了速度非常慢之外,pow (2, 30) 可能存在舍入误差,使其比 2 的 30 次方略小,将其分配给 long long 会将其舍入为 0x3fffffff 而不是 0x40000000。另一方面, (1ll

    check 在循环中永远不会被修改,这就是它不起作用的原因。

    您认为数字-1 中设置了多少位?

    您认为数字 1234567890123456 中设置了多少位?你为什么不为那个数字给出正确的结果?

    我想说你需要一些练习才能找到解决问题的最直接和最简单的方法。

    int bitcount = 0; 
    for (long long mask = 1ll << 62; mask != 0; mask >>= 1)
        if ((p & mask) != 0)
            ++bitcount;
    

    这是最简单的方法。你真的应该使用未签名的,未签名的那种操作。有一些聪明的技巧可以给你更快的代码,但不是我期望任何人自己想出来的。

    【讨论】:

    • pow(2, 30) 中的舍入错误是不可能的。此外,我认为没有理由询问 -1 和 1234567890123456 的“多少位”。(虽然代码很好,所以没有反对)
    【解决方案3】:

    那么,您想计算二进制数的人口数吗?
    怎么了

    int popcount(unsigned long long a)
    {
        int retval = 0;
        size_t i;
        unsigned long long b = 1;
        for (i = 0; i<(CHAR_BIT*sizeof(unsigned long long); i++)
        {
            if (a & b<<i)
               retval++;
        }
        return retval;
    }
    

    如果您觉得这太慢了,您可以使用“bit twiddling hacks”的相应部分(自己用 Google 搜索,或在此网站上搜索)。 或者,您知道,查找在一个周期内执行此操作的编译器内在函数。英特尔 x86(-64):

    int64_t _mm_popcnt_u64(unsigned __int64 a);
    

    gcc:

    int __builtin_popcountll(unsigned long long)
    

    【讨论】:

      【解决方案4】:

      主要错误是您的递归函数不起作用。 试着仔细看看:

      if(p==0)
          result=0;
              else if(p==1)
          result=1;
      else{
          for(j=31;j>=2;j--){
              temp=check/2;
              printf("temp=%lld\n",temp);
              if(p>=temp){
                  printf("%lld temp\n",temp);
                  result=1+binarysum(p-temp);
              }
          }
      }
      

      如果假设 p=6 那么你的温度是 2^30 显然 p 小于温度。所以你的递归不起作用。 声明:

      result=1+binarysum(p-temp);
      

      从不执行。所以你得到result 为零,因为零是存储在变量result 中的垃圾值。 如果您将代码更改为:

      else{
          temp=check;
          for(j=31;j>=2;j--){
              temp=temp/2;
              printf("temp=%lld\n",temp);
              if(p>=temp){
                  printf("%lld temp\n",temp);
                  result=1+binarysum(p-temp);
              }
          }
      }
      

      这是解决问题的简单方法

      #include<stdio.h>
      int main(){
          long long number;
          scanf("%lld",&number);
          int result=0;
          while(number>0){
              if(number&1){
                  result++;
              }
              number=number>>1;
          }
          printf("%d\n",result);
      }
      

      【讨论】:

      • 注意:我编辑了误导性的表达number&amp;1==1
      • 这两种方式都是正确的。我写 number&1==1 的主要原因是强调 bitwise and 返回数字的二进制表示的最后一位。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-01
      • 2018-07-31
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多