微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用C在一个数字中找到零的前导数

如何解决如何使用C在一个数字中找到零的前导数

|| 例如,如果我有数字64,那么它的二进制表示形式将是0000 0000 0000 0000 0000 0000 0000 0100 0000,所以零的前导数字是25。 请记住,我必须在O(1)时间中进行计算。 请告诉我正确的方法。即使您的复杂度> O(1),也请发布答案。谢谢     

解决方法

        我只是在搜索结果和以下代码的顶部发现了此问题:
int pop(unsigned x) {
    unsigned n;
    n = (x >> 1) & 033333333333;
    x = x - n;
    n = (n >> 1) & 033333333333;
    x = x - n;
    x = (x + (x >> 3)) & 030707070707;
    return x % 63;
}

int nlz(unsigned x) {
    x = x | (x >> 1);
    x = x | (x >> 2);
    x = x | (x >> 4);
    x = x | (x >> 8);
    x = x | (x >>16);
    return pop(~x);
}
pop的位数为1位,比第一个(推荐的)答案快几倍。 我没有注意到,问题是关于64位数字,所以在这里:
int nlz(unsigned long x) {
    unsigned long y;
    long n,c;
    n = 64;
    c = 32;
    do {
        y = x >> c;
        if (y != 0) {
            n = n - c;
            x = y;
        }
        c = c >> 1;
    } while (c != 0);
    return n - x;
}
是64位算法,比上述速度快几倍。     ,        右移是您的朋友。
    int input = 64;
    int sample = ( input < 0 ) ? 0 : input;
    int leadingZeros = ( input < 0 ) ? 0 : 32;

    while(sample) {
        sample >>= 1;
        --leadingZeros;
    }
    printf(\"Input = %d,leading zeroes = %d\\n\",input,leadingZeros);
    ,        有关32位版本和其他出色的技巧,请参见此处。
// this is like doing a sign-extension
// if original value was   0x00.01yyy..y
// then afterwards will be 0x00.01111111
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
之后,您只需要返回64-numOnes(x)。 一个简单的方法是numOnes32(x)+ numOnes32(x >> 32),其中numOnes32定义为:
int numOnes32(unsigned int x) {
    x -= ((x >> 1) & 0x55555555);
    x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
    x = (((x >> 4) + x) & 0x0f0f0f0f);
    x += (x >> 8);
    x += (x >> 16);
    return(x & 0x0000003f);
}
我还没有尝试过这段代码,但这应该直接执行numOnes64(在更少的时间内):
int numOnes64(unsigned long int x) {
     x = ((x >> 1) & 0x5555555555555555L) + (x & 0x5555555555555555L);
     x = ((x >> 2) & 0x3333333333333333L) + (x & 0x3333333333333333L);
     // collapse:
     unsigned int v = (unsigned int) ((x >>> 32) + x);
     v = ((v >> 4) + v) & 0x0f0f0f0f) + (v & 0x0f0f0f0f);
     v = ((v >> 8) & 0x00ff00ff) + (v & 0x00ff00ff);
     return ((v >> 16) & 0x0000ffff) + (v & 0x0000ffff);
}
    ,        我会去:
unsigned long clz(unsigned long n) {
    unsigned long result = 0;
    unsigned long mask = 0;
    mask = ~mask;
    auto size = sizeof(n) * 8;
    auto shift = size / 2;
    mask >>= shift;
    while (shift >= 1) {
        if (n <= mask) {
            result += shift;
            n <<= shift;
        }
        shift /= 2;
        mask <<= shift;
    }
    return result;
}
    ,        因为以2为底的对数粗略表示代表一个数字所需的位数,所以在回答中可能会很有用:
irb(main):012:0> 31 - (Math::log(64) / Math::log(2)).floor()
=> 25
irb(main):013:0> 31 - (Math::log(65) / Math::log(2)).floor()
=> 25
irb(main):014:0> 31 - (Math::log(127) / Math::log(2)).floor()
=> 25
irb(main):015:0> 31 - (Math::log(128) / Math::log(2)).floor()
=> 24
当然,使用
log(3)
的一个缺点是它是浮点例程。可能有一些非常聪明的位技巧可以找到整数前导零位的数量,但我想不出一个...     ,        使用浮点数不是正确的答案。 这是我用来计算TRAILING 0的算法...将其更改为Leading ... 该算法在O(1)中(将始终在同一时间甚至在某些CPU上同时执行)。
int clz(unsigned int i)
{
  int zeros;
  if ((i&0xffff)==0) zeros= 16,i>>= 16; else zeroes= 0;
  if ((i&0xff)==0) zeros+= 8,i>>= 8;
  if ((i&0xf)==0) zeros+= 4,i>>= 4;
  if ((i&0x3)==0) zeros+= 2,i>>= 2;
  if ((i&0x1)==0) zeros+= 1,i>>= 1;
  return zeroes+i;
}
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。