文件中比特1的个数计算~~急求高人~~高人请进

weixiaoshashou 2011-05-25 05:01:45
要求如下,计算任意一个文件里面的比特1的个数,要求计算的时候另外在一个线程下面进行计算。
我自己写了一个类,把线程当做静态成员函数了。
我的思路是这样子的:定义一个文件流对象,然后以二进制的形式打开文件,然后用一个字符数组进行读取,然后用STL中的bitset进行存储字符数组中的字符,然后调用bitset的count函数即可计算比特1的个数,可是没有成功。想请叫一下大家,我应该怎么的去实现这个要求呢?
函数如下:

DWORD WINAPI CMyDlg::CountBit(LPVOID lpParameter)
{
DWORD dwRead=0;
std::fstream mystream;
mystream.open(m_filename,std::ios::binary|std::ios::in);
char str[4096];
while(mystream.getline(str,4096))
{
std::string s(str[0],4096);//这里有问题,暂时没有想好
std::bitset<4096> f(s);
dwRead += f.count();
}
return dwRead;
}
//这个按钮点击就会进行计算
void CMyDlg::OnBnClickedCalc()
{
// TODO: 在此添加控件通知处理程序代码
HANDLE hThread;
hThread = CreateThread(NULL,0,CountBit,NULL,0,NULL);
CString str;
str.Format(L"比特数:%d,耗时:%ms,文件名:%d",CountBit(0),0,m_filename);
CloseHandle(hThread);
}
...全文
270 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
luciferisnotsatan 2011-05-26
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 luciferisnotsatan 的回复:]

记得 编程珠玑 里有个单核并发求 1 位的。看过忘了。
不过就算自己写个遍历,也比先转成字符串,再转bitset,再count快。
vc里的count用的是一个查表,4位4位 计算
[/Quote]

记错书名了,是 代码之美。
下面的代码是,32位机器上,int为32bit。如果你是64位程序,可以再加一个等式。


	char buf[4096] = {5};
buf[2] = -1;
buf[4095] = 5;

unsigned int *p = (unsigned int *)buf;
unsigned int *pend = p + 1024;
unsigned int tmp;
unsigned int sum = 0;
while(p < pend)
{
tmp = *p;
tmp = (tmp & 0x55555555) + ((tmp>>1) & 0x55555555);
tmp = (tmp & 0x33333333) + ((tmp>>2) & 0x33333333);
tmp = (tmp & 0x0f0f0f0f) + ((tmp>>4) & 0x0f0f0f0f);
tmp = (tmp & 0x00ff00ff) + ((tmp>>8) & 0x00ff00ff);
tmp = (tmp & 0x0000ffff) + ((tmp>>16) & 0x0000ffff);
sum += tmp;
++p;
}
cout<<sum;


上面的代码大致就是,
先计算相邻两比特位一个分组,将两bit相加,统计有几个1(实际上就是1为1,0为0)。
tmp 0 1 1 1 1 0 0 0
0+1=1 1+1=10 1+0=1 0+0=0
tmp 0 1|1 0|0 1|0 0
然后再把上面得到的每两个相邻分组相加,等到有多少个1。
0 1 + 1 0 = 11 0 1 + 00 = 01
tmp 0 0 1 1|0001
继续循环
0011+0001 = 0100
结果就是 4(0100)

编程之美上还有一个更快的,使用数学公式。不过比较难懂。

jernymy 2011-05-25
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 we_sky2008 的回复:]
用查表吧,最快的方法:

C/C++ code

#include<stdio.h>
#include<stdlib.h>


unsigned char numTable[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,……
[/Quote]

查表比较快
大熊猫侯佩 2011-05-25
  • 打赏
  • 举报
回复
一上来就将逻辑和界面很快搞混淆,是初学者的一大弊病
v风雪山神庙v 2011-05-25
  • 打赏
  • 举报
回复
位运算是最快的

/*
计算整数x的二进制中含有多少个1
*/

#include<stdio.h>
#include<stdlib.h>
#include <string.h>

int main()
{
int count = 0;
int x;

scanf("%d",&x);

while(x)
{
count++;
x = x&x-1;
}

printf("total: %d\n",count);

return 0;
}

qq120848369 2011-05-25
  • 打赏
  • 举报
回复
#include <iostream>
#include <bitset>
using namespace std;

int main()
{
int byte;

while( (byte=fgetc(stdin))!=EOF ) //假设就从终端输入字符串当做二进制得了,注意'0'对应的byte是48:
{
if(byte=='\n')
{
break;
}

//转化为unsigned char,然后隐式转化为unsigned long,防止有符号数扩宽时符号位填充1,这是你读二进制文件必须注意的
//但是,这里我限制bitset是8位,所以不注意也没关系。
bitset<8> cnt((unsigned char)byte);
cout<<cnt.count()<<" ";
}

cout<<endl;

return 0;
}
we_sky2008 2011-05-25
  • 打赏
  • 举报
回复
用查表吧,最快的方法:

#include<stdio.h>
#include<stdlib.h>


unsigned char numTable[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
};

int main()
{
FILE *pf;
int ch;
unsigned int total_num = 0;

if (NULL == (pf = fopen("in.bin", "rb")))
{
printf("%s\n", "Can not find the file!");
exit(1);
}

while ((ch = fgetc(pf)) != EOF)
{
total_num += numTable[ch];
}

printf("%d\n", total_num);

system("pause");
return 0;
}

weixiaoshashou 2011-05-25
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 hnuqinhuan 的回复:]
用位运算循环也可以啊
[/Quote]
用位循环?呵呵,不怎么清楚,可否细说一下。呵呵
無_1024 2011-05-25
  • 打赏
  • 举报
回复
用位运算循环也可以啊
luciferisnotsatan 2011-05-25
  • 打赏
  • 举报
回复
记得 编程珠玑 里有个单核并发求 1 位的。看过忘了。
不过就算自己写个遍历,也比先转成字符串,再转bitset,再count快。
vc里的count用的是一个查表,4位4位 计算
weixiaoshashou 2011-05-25
  • 打赏
  • 举报
回复

//这个按钮点击就会进行计算
void CMyDlg::OnBnClickedCalc()
{
// TODO: 在此添加控件通知处理程序代码
HANDLE hThread;
hThread = CreateThread(NULL,0,CountBit,NULL,0,NULL);//这里创建一个线程
CString str;
str.Format(L"比特数:%d,耗时:%ms,文件名:%d",CountBit(0),0,m_filename);//这里我用到 了CountBit函数我不知道这里对不对
CloseHandle(hThread);
}

luciferisnotsatan 2011-05-25
  • 打赏
  • 举报
回复
std::bitset<4096> f(s);这个s要是一个 10 字符串,你读进来就是10字符串?
可以用itoa转成 10 字符串。

不过这样做,不如你自己写个计算 1 的count来的快。
weixiaoshashou 2011-05-25
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 namelij 的回复:]
td::string s(str[0],4096);//这里有问题,暂时没有想好

这块确实有问题
你可以先把串搞成二进制的,然后传给你的bit set
[/Quote]
呵呵,能不能具体点,给几行代码也不错。呵呵
www_adintr_com 2011-05-25
  • 打赏
  • 举报
回复
CountBit 不是在 str.Format 这里直接调用了吗? 开线程是在做什么?
  • 打赏
  • 举报
回复
td::string s(str[0],4096);//这里有问题,暂时没有想好

这块确实有问题
你可以先把串搞成二进制的,然后传给你的bit set

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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