如何快速对两个大数的位数做比较?

kenshu 2018-03-28 12:22:56
有一个类,它长度是400位的(也就是内存占50个字节,8*50=400)

比如
00010011 11001010 ...(这里是46个字节)... 00010011 11001010 (总共400位)


这个类两个实例的距离定义为,它们相同的位,如果一样,就是0,不一样就是1,把这个值加起来,就是它们的距离(也就是完全相同,就是0,完全不同,就是400)
也就是求两个400位的BIT数组的相似程度。

现在有个实例A。
还有个数组B(B大约是50万个),可以是事先排好序或做其它初始化的处理。

求A跟B中哪个元素的距离最小,

除了用A跟B中每个元素的每个位相比较,找到最小值。
有没有更快的办法?
...全文
936 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
kenshu 2019-07-19
  • 打赏
  • 举报
回复
引用 4 楼 赵4老师 的回复:
仅供参考:
#include <iostream>
#include <string>
using namespace std;
inline int compare(string str1,string str2) {//相等返回0,大于返回1,小于返回-1
if (str1.size()>str2.size()) return 1; //长度长的整数大于长度小的整数
else if (str1.size()<str2.size()) return -1;
else return str1.compare(str2); //若长度相等,则头到尾按位比较
}
string SUB_INT(string str1,string str2);
string ADD_INT(string str1,string str2) {//高精度加法
int sign=1; //sign 为符号位
string str;
if (str1[0]=='-') {
if (str2[0]=='-') {
sign=-1;
str=ADD_INT(str1.erase(0,1),str2.erase(0,1));
} else {
str=SUB_INT(str2,str1.erase(0,1));
}
} else {
if (str2[0]=='-') {
str=SUB_INT(str1,str2.erase(0,1));
} else { //把两个整数对齐,短整数前面加0补齐
string::size_type L1,L2;
int i;
L1=str1.size();
L2=str2.size();
if (L1<L2) {
for (i=1;i<=L2-L1;i++) str1="0"+str1;
} else {
for (i=1;i<=L1-L2;i++) str2="0"+str2;
}
int int1=0,int2=0; //int2 记录进位
for (i=str1.size()-1;i>=0;i--) {
int1=(int(str1[i])-'0'+int(str2[i])-'0'+int2)%10;
int2=(int(str1[i])-'0'+int(str2[i])-'0'+int2)/10;
str=char(int1+'0')+str;
}
if (int2!=0) str=char(int2+'0')+str;
}
}
//运算后处理符号位
if ((sign==-1)&&(str[0]!='0')) str="-"+str;
return str;
}
string SUB_INT(string str1,string str2) {//高精度减法
int sign=1; //sign 为符号位
string str;
int i,j;
if (str2[0]=='-') {
str=ADD_INT(str1,str2.erase(0,1));
} else {
int res=compare(str1,str2);
if (res==0) return "0";
if (res<0) {
sign=-1;
string temp =str1;
str1=str2;
str2=temp;
}
string::size_type tempint;
tempint=str1.size()-str2.size();
for (i=str2.size()-1;i>=0;i--) {
if (str1[i+tempint]<str2[i]) {
j=1;
while (1) {//zhao4zhong1添加
if (str1[i+tempint-j]=='0') {
str1[i+tempint-j]='9';
j++;
} else {
str1[i+tempint-j]=char(int(str1[i+tempint-j])-1);
break;
}
}
str=char(str1[i+tempint]-str2[i]+':')+str;
} else {
str=char(str1[i+tempint]-str2[i]+'0')+str;
}
}
for (i=tempint-1;i>=0;i--) str=str1[i]+str;
}
//去除结果中多余的前导0
str.erase(0,str.find_first_not_of('0'));
if (str.empty()) str="0";
if ((sign==-1) && (str[0]!='0')) str ="-"+str;
return str;
}
string MUL_INT(string str1,string str2) {//高精度乘法
int sign=1; //sign 为符号位
string str;
if (str1[0]=='-') {
sign*=-1;
str1 =str1.erase(0,1);
}
if (str2[0]=='-') {
sign*=-1;
str2 =str2.erase(0,1);
}
int i,j;
string::size_type L1,L2;
L1=str1.size();
L2=str2.size();
for (i=L2-1;i>=0;i--) { //模拟手工乘法竖式
string tempstr;
int int1=0,int2=0,int3=int(str2[i])-'0';
if (int3!=0) {
for (j=1;j<=(int)(L2-1-i);j++) tempstr="0"+tempstr;
for (j=L1-1;j>=0;j--) {
int1=(int3*(int(str1[j])-'0')+int2)%10;
int2=(int3*(int(str1[j])-'0')+int2)/10;
tempstr=char(int1+'0')+tempstr;
}
if (int2!=0) tempstr=char(int2+'0')+tempstr;
}
str=ADD_INT(str,tempstr);
}
//去除结果中的前导0
str.erase(0,str.find_first_not_of('0'));
if (str.empty()) str="0";
if ((sign==-1) && (str[0]!='0')) str="-"+str;
return str;
}
string DIVIDE_INT(string str1,string str2,int flag) {//高精度除法。flag==1时,返回商;flag==0时,返回余数
string quotient,residue; //定义商和余数
int sign1=1,sign2=1;
if (str2 == "0") { //判断除数是否为0
quotient= "ERROR!";
residue = "ERROR!";
if (flag==1) return quotient;
else return residue ;
}
if (str1=="0") { //判断被除数是否为0
quotient="0";
residue ="0";
}
if (str1[0]=='-') {
str1 = str1.erase(0,1);
sign1 *= -1;
sign2 = -1;
}
if (str2[0]=='-') {
str2 = str2.erase(0,1);
sign1 *= -1;
}
int res=compare(str1,str2);
if (res<0) {
quotient="0";
residue =str1;
} else if (res == 0) {
quotient="1";
residue ="0";
} else {
string::size_type L1,L2;
L1=str1.size();
L2=str2.size();
string tempstr;
tempstr.append(str1,0,L2-1);
for (int i=L2-1;i<L1;i++) { //模拟手工除法竖式
tempstr=tempstr+str1[i];
tempstr.erase(0,tempstr.find_first_not_of('0'));//zhao4zhong1添加
if (tempstr.empty()) tempstr="0";//zhao4zhong1添加
for (char ch='9';ch>='0';ch--) { //试商
string str;
str=str+ch;
if (compare(MUL_INT(str2,str),tempstr)<=0) {
quotient=quotient+ch;
tempstr =SUB_INT(tempstr,MUL_INT(str2,str));
break;
}
}
}
residue=tempstr;
}
//去除结果中的前导0
quotient.erase(0,quotient.find_first_not_of('0'));
if (quotient.empty()) quotient="0";
if ((sign1==-1)&&(quotient[0]!='0')) quotient="-"+quotient;
if ((sign2==-1)&&(residue [0]!='0')) residue ="-"+residue ;
if (flag==1) return quotient;
else return residue ;
}
string DIV_INT(string str1,string str2) {//高精度除法,返回商
return DIVIDE_INT(str1,str2,1);
}
string MOD_INT(string str1,string str2) {//高精度除法,返回余数
return DIVIDE_INT(str1,str2,0);
}
int main() {
char ch;
string s1,s2,res;

while (cin>>s1>>ch>>s2) {
switch (ch) {
case '+':res=ADD_INT(s1,s2);break;
case '-':res=SUB_INT(s1,s2);break;
case '*':res=MUL_INT(s1,s2);break;
case '/':res=DIV_INT(s1,s2);break;
case '%':res=MOD_INT(s1,s2);break;
default : break;
}
cout<<res<<endl;
}
return(0);
}


查了一下,你还被禁止过回贴啊?还敢喊冤?

一句话,
不懂你可以装懂,那叫装逼。
不懂你还可以鄙视人,最多只能证明你是一坨屎。
但不懂,你还要故意误导人,你就是人渣中的人渣啊。
kenshu 2019-07-19
  • 打赏
  • 举报
回复
我为什么会看不起4楼这种人?

我在CSDN的那几年,随便看到个贴子都有他的份(不管是我发的还是我回的)。

我记得的,他回贴只有两种情况:
1.“你自己百度”
2.他自己随便百度一大段东西出来。

------

像我上一个帖,
https://bbs.csdn.net/topics/392351026

自从GOOGLE离开中国以后,我为了方便,并且完全合法地上GOOGLE,会租一部境外的主机,就是为了上GOOGLE.
那个贴,不敢说,尽了所有的努力。
但至少,我能力范围内,想得出的关键字,全部百度或GOOGLE,并且从结果的第一页,看到最后一页。
当时是找不到方法的。
我确信没办法才问的。


另一种情况,像这个贴,
他妈你随便自己百度一个“VC大数算法”之类的,就贴上来。
还好我一眼就看得懂,要是人家看不懂,得花多少时间?后面回贴的人,又得花多少时间?
长时间以来,我看到他的大量回复,都是故意误导人。

他妈你不帮人可以,甚至鄙视人也没问题,但你不能故意害人。

类似的伤害,我受过最严重的一次,
02/03年的样子,要写个工具,网上到处找算法。
找到一个评教授职称的论文,如获至宝。

为什么?因为大量的名词看不懂。所以我以为很牛逼。

我一字一句地百度GOOGLE,看不懂的词还要再找下去,总共花了我一个多两个星期。

最后才发现那就是一堆垃圾,根本就是故意堆砌晦涩的词语。因为他要评职称啊。

最后,那个工具写完了。
你当然不知道是哪个软件,对吧?
那你自己百度一下。

你这么会教人百度,不会找不到吧?

我敢保证,我至少有三个软件,你百度或GOOGLE得出来的,从第一页翻到最后一页,它是相关领域里最好的。(它们不一定排在第一位,但肯定是你找得到的最好的)
kenshu 2019-07-18
  • 打赏
  • 举报
回复
对不起,太久没来CSDN了,我都不记得当时问这个问题是关于什么事了。

所以也就不记得要算什么了。

平均给吧。4楼这种,我最看不起,就给1分吧。给1分是为了提醒你,我要来羞辱你。

每个贴都关你的事。
要不就回一个上网查(我找得到还来这里请教),要不就随便贴个不知道哪里百度来的代码。

worldy 2018-05-04
  • 打赏
  • 举报
回复
BYTE a[416],b[416];//将数组扩大2个字节,是的能被32整除,将其作为13个INT类型,最后两个字节都赋值为0,不影响结果
int CalcDis()
{

	UINT* pA=(UINT*)&a[0];
	UINT* pB=(UINT*)&b[0];
	int n=0;

	for (int i=0;i<13;i++)
	{
		UINT x=(*pA) ^( *pB);//每4个字节做一个UINT处理,
		for(int j=0;j<32;j++)
		{
			n+=(x & 0x01);
			x>>1; 
		}
		pA++;
		pB++;
		 
	}
	return n;
}
worldy 2018-05-04
  • 打赏
  • 举报
回复
#9L 的BYTE a[416],b[416];===> BYTE a[52],b[52];
hhhh63 2018-05-03
  • 打赏
  • 举报
回复
我把这个表整理成下面的样子,发现很有规律,应该可以用数列的方法直接算出来。效率更高。不过还没有总结出来。 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4, 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5, 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7, 1,2,2,3, 2,3,3,4, 2,3,3,4, 3,4,4,5, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7, 2,3,3,4, 3,4,4,5, 3,4,4,5, 4,5,5,6, 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7, 3,4,4,5, 4,5,5,6, 4,5,5,6, 5,6,6,7, 4,5,5,6, 5,6,6,7, 5,6,6,7, 6,7,7,8
hhhh63 2018-05-03
  • 打赏
  • 举报
回复
建一个256长度的表 int a[256]={0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4, 4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5, 4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4, 4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6, 4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4, 4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5, 4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4, 4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 }; 每个字节异或,再查这个表,重复50次相加,等到距离。 参考:https://www.douban.com/note/274239939/
worldy 2018-04-10
  • 打赏
  • 举报
回复
【这个类两个实例的距离定义为,它们相同的位,如果一样,就是0,不一样就是1,把这个值加起来】 将两个数的对应字节(可以组成UINT类型数)分别进行异或,然后将异或的结构每位值相加,就是你所谓的距离
worldy 2018-04-10
  • 打赏
  • 举报
回复
for(INT i=0;i<8;i++){ n+= a & 1 ; a >>=1; } 即可简单的得到1的位数
waterx 2018-04-08
  • 打赏
  • 举报
回复
1楼正解,不过可以优化下,先异或再查表,这样表长只有256,省了好多预计算。查表是经常用的空间换时间做法。
赵4老师 2018-03-28
  • 打赏
  • 举报
回复
仅供参考:
#include <iostream>
#include <string>
using namespace std;
inline int compare(string str1,string str2) {//相等返回0,大于返回1,小于返回-1
         if (str1.size()>str2.size()) return 1; //长度长的整数大于长度小的整数
    else if (str1.size()<str2.size()) return -1;
    else                              return str1.compare(str2); //若长度相等,则头到尾按位比较
}
string SUB_INT(string str1,string str2);
string ADD_INT(string str1,string str2) {//高精度加法
    int sign=1; //sign 为符号位
    string str;
    if (str1[0]=='-') {
        if (str2[0]=='-') {
            sign=-1;
            str=ADD_INT(str1.erase(0,1),str2.erase(0,1));
        } else {
            str=SUB_INT(str2,str1.erase(0,1));
        }
    } else {
        if (str2[0]=='-') {
            str=SUB_INT(str1,str2.erase(0,1));
        } else { //把两个整数对齐,短整数前面加0补齐
            string::size_type L1,L2;
            int i;
            L1=str1.size();
            L2=str2.size();
            if (L1<L2) {
                for (i=1;i<=L2-L1;i++) str1="0"+str1;
            } else {
                for (i=1;i<=L1-L2;i++) str2="0"+str2;
            }
            int int1=0,int2=0; //int2 记录进位
            for (i=str1.size()-1;i>=0;i--) {
                int1=(int(str1[i])-'0'+int(str2[i])-'0'+int2)%10;
                int2=(int(str1[i])-'0'+int(str2[i])-'0'+int2)/10;
                str=char(int1+'0')+str;
            }
            if (int2!=0) str=char(int2+'0')+str;
        }
    }
    //运算后处理符号位
    if ((sign==-1)&&(str[0]!='0')) str="-"+str;
    return str;
}
string SUB_INT(string str1,string str2) {//高精度减法
    int sign=1; //sign 为符号位
    string str;
    int i,j;
    if (str2[0]=='-') {
        str=ADD_INT(str1,str2.erase(0,1));
    } else {
        int res=compare(str1,str2);
        if (res==0) return "0";
        if (res<0) {
            sign=-1;
            string temp =str1;
            str1=str2;
            str2=temp;
        }
        string::size_type tempint;
        tempint=str1.size()-str2.size();
        for (i=str2.size()-1;i>=0;i--) {
            if (str1[i+tempint]<str2[i]) {
                j=1;
                while (1) {//zhao4zhong1添加
                    if (str1[i+tempint-j]=='0') {
                        str1[i+tempint-j]='9';
                        j++;
                    } else {
                        str1[i+tempint-j]=char(int(str1[i+tempint-j])-1);
                        break;
                    }
                }
                str=char(str1[i+tempint]-str2[i]+':')+str;
            } else {
                str=char(str1[i+tempint]-str2[i]+'0')+str;
            }
        }
        for (i=tempint-1;i>=0;i--) str=str1[i]+str;
    }
    //去除结果中多余的前导0
    str.erase(0,str.find_first_not_of('0'));
    if (str.empty()) str="0";
    if ((sign==-1) && (str[0]!='0')) str ="-"+str;
    return str;
}
string MUL_INT(string str1,string str2) {//高精度乘法
    int sign=1; //sign 为符号位
    string str;
    if (str1[0]=='-') {
        sign*=-1;
        str1 =str1.erase(0,1);
    }
    if (str2[0]=='-') {
        sign*=-1;
        str2 =str2.erase(0,1);
    }
    int i,j;
    string::size_type L1,L2;
    L1=str1.size();
    L2=str2.size();
    for (i=L2-1;i>=0;i--) { //模拟手工乘法竖式
        string tempstr;
        int int1=0,int2=0,int3=int(str2[i])-'0';
        if (int3!=0) {
            for (j=1;j<=(int)(L2-1-i);j++) tempstr="0"+tempstr;
            for (j=L1-1;j>=0;j--) {
                int1=(int3*(int(str1[j])-'0')+int2)%10;
                int2=(int3*(int(str1[j])-'0')+int2)/10;
                tempstr=char(int1+'0')+tempstr;
            }
            if (int2!=0) tempstr=char(int2+'0')+tempstr;
        }
        str=ADD_INT(str,tempstr);
    }
    //去除结果中的前导0
    str.erase(0,str.find_first_not_of('0'));
    if (str.empty()) str="0";
    if ((sign==-1) && (str[0]!='0')) str="-"+str;
    return str;
}
string DIVIDE_INT(string str1,string str2,int flag) {//高精度除法。flag==1时,返回商;flag==0时,返回余数
    string quotient,residue; //定义商和余数
    int sign1=1,sign2=1;
    if (str2 == "0") {  //判断除数是否为0
        quotient= "ERROR!";
        residue = "ERROR!";
        if (flag==1) return quotient;
        else         return residue ;
    }
    if (str1=="0") { //判断被除数是否为0
        quotient="0";
        residue ="0";
    }
    if (str1[0]=='-') {
        str1   = str1.erase(0,1);
        sign1 *= -1;
        sign2  = -1;
    }
    if (str2[0]=='-') {
        str2   = str2.erase(0,1);
        sign1 *= -1;
    }
    int res=compare(str1,str2);
    if (res<0) {
        quotient="0";
        residue =str1;
    } else if (res == 0) {
        quotient="1";
        residue ="0";
    } else {
        string::size_type L1,L2;
        L1=str1.size();
        L2=str2.size();
        string tempstr;
        tempstr.append(str1,0,L2-1);
        for (int i=L2-1;i<L1;i++) { //模拟手工除法竖式
            tempstr=tempstr+str1[i];
            tempstr.erase(0,tempstr.find_first_not_of('0'));//zhao4zhong1添加
            if (tempstr.empty()) tempstr="0";//zhao4zhong1添加
            for (char ch='9';ch>='0';ch--) { //试商
                string str;
                str=str+ch;
                if (compare(MUL_INT(str2,str),tempstr)<=0) {
                    quotient=quotient+ch;
                    tempstr =SUB_INT(tempstr,MUL_INT(str2,str));
                    break;
                }
            }
        }
        residue=tempstr;
    }
    //去除结果中的前导0
    quotient.erase(0,quotient.find_first_not_of('0'));
    if (quotient.empty()) quotient="0";
    if ((sign1==-1)&&(quotient[0]!='0')) quotient="-"+quotient;
    if ((sign2==-1)&&(residue [0]!='0')) residue ="-"+residue ;
    if (flag==1) return quotient;
    else         return residue ;
}
string DIV_INT(string str1,string str2) {//高精度除法,返回商
    return DIVIDE_INT(str1,str2,1);
}
string MOD_INT(string str1,string str2) {//高精度除法,返回余数
    return DIVIDE_INT(str1,str2,0);
}
int main() {
    char ch;
    string s1,s2,res;

    while (cin>>s1>>ch>>s2) {
        switch (ch) {
            case '+':res=ADD_INT(s1,s2);break;
            case '-':res=SUB_INT(s1,s2);break;
            case '*':res=MUL_INT(s1,s2);break;
            case '/':res=DIV_INT(s1,s2);break;
            case '%':res=MOD_INT(s1,s2);break;
            default :                   break;
        }
        cout<<res<<endl;
    }
    return(0);
}
ssbqrm 2018-03-28
  • 打赏
  • 举报
回复
你的用异或再加_mm_popcnt_u32(统计有多少个“为1的位”), 都是位运算很快的,我这边差不多例子一个1024bit的和1000万的比较在1秒钟之内计算完所有相似度 ----------------------------------------------------------- 我自己一个程序的例子,我是对应位都是1才算1,用& for(int j=0; j<featDim; j++) { int vec1=_featsMatGlobal.at<int>(i,j); int vec2= queryVec.at<int>(0,j); //按位与运算 &后统计1的个数,就是点积啊. dotMul +=_mm_popcnt_u32( vec1&vec2 ); sum1 += _mm_popcnt_u32(vec1); sum2 += _mm_popcnt_u32(vec2); //cout<<sum1<<" "<<sum2<<endl; }
kenshu 2018-03-28
  • 打赏
  • 举报
回复
引用 1 楼 ckc 的回复:
...... 可以预先建立一个256*256的表格,这样就可以快速查询两个字节的距离,然后50个字节的距离相加得到最后结果 ......
这一句看不懂.具体应该怎么做?谢谢!
ckc 2018-03-28
  • 打赏
  • 举报
回复
总共50个字节,这个是可以拆分来计算再相加的 可以预先建立一个256*256的表格,这样就可以快速查询两个字节的距离,然后50个字节的距离相加得到最后结果 在计算A跟B中每个比较的时候还可以加上判断,如果计算出来的结果已经大于以前的最小值,就不需要再计算下去了 另外我怀疑cpu的多媒体指令里有些指令也许可以在这个过程中加快处理 你这个事情如果需要经常执行可以从更底层,从汇编那一级想想办法。

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧