/*
寻找与一个给定的数目有相同数目的1位的下一个大数的问题
它在使用位串来表示子集是有用。把一个集合的所有可能元素列成一个线性序列,
使用字或字的序列来表示子集,当集合的成员i属于该子集时设置字或字序列的第i位为1
R. W. Gosper [HAK, item 175]
按32位无符号数算 33 = 32 + 1
s = x & -x
r = s + x
y = r | ((x^r) >> 2)/s)
或
y = r | ((x^r) >> (2+ntz(x)))
y = r | ((x^r) >> (33-nlz(s)))
y = r | ((1 << (pop(x^r)-2))-1)
*/
#include "iostream"
#include "bitset"
#include "limits"
using namespace std;
#define out2(T) cout<<bitset<numeric_limits<unsigned short>::digits>(T)<<endl
#define SIZE(T) (numeric_limits<unsigned T>::digits)
unsigned short snoob(unsigned short x)
{
unsigned short smallest, ripple, ones;
// XXX 表示任意
// x = XXX0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // XXX1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
ones = (ones >> 2)/smallest; // 0000 0000 0111
return ripple | ones; // XXX1 0000 0111
}
unsigned short snoob1(unsigned short x)
{ unsigned short ntz(unsigned short x);
unsigned short smallest, ripple, ones;
// XXX 表示任意
// x = XXX0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // XXX1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
return ripple | (ones >> (2 + ntz(x)));
}
unsigned short snoob2(unsigned short x)
{ unsigned short nlz(unsigned short x);
unsigned short smallest, ripple, ones;
int t = SIZE(short)+1;
// XXX 表示任意
// x = XXX0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // XXX1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
return ripple | (ones >> (t-nlz(smallest)));
}
unsigned short snoob3(unsigned short x)
{ unsigned short pop(unsigned short x);
unsigned short smallest, ripple, ones;
// XXX 表示任意
// x = XXX0 1111 0000
smallest = x & -x; // 0000 0001 0000
ripple = x + smallest; // XXX1 0000 0000
ones = x ^ ripple; // 0001 1111 0000
return ripple | ( (1<<(pop(ones)-2)) - 1 );
}
unsigned short ntz(unsigned short x) //计算后缀0数目
{
int s = SIZE(short);
int i = 0; while ( !(x&(unsigned short)(1)) && i < s) { x>>=1; i++; }
return i;
}
unsigned short nlz(unsigned short x) //计算前导0数目
{
int s = SIZE(short);
int L = (unsigned short)(1) << (s-1);
int i = 0; while ( !(x&L) && i < s) {x<<=1; i++;}
return i;
}
unsigned short pop(unsigned short x) //种群计数函数
{
int s = SIZE(short);
int i = 0; while(s--) { (x&(unsigned short)(1)) ? ++i : 0; x>>=1; }
return i;
}
void main()
{
out2( snoob(0xF0) );
out2( snoob1(0xF0) );
out2( snoob2(0xF0) );
out2( snoob3(0xF0) );
cout << ntz(0x17A0) <<endl;
cout << nlz(0x17F0) <<endl;
cout << pop(0x359D) <<endl;
}