最近,我开始编写一个比较DNA序列的程序。由于字母表只包含四个字母(ATCG),将每个字符压缩为2位似乎可以提供更快的比较(两个字符相同或不同)。然而,当我运行测试时,char比较比位比较快得多(约30%)。在两个程序中进行压缩作为对照。我在这里错过了什么?是否有更有效的方法来比较位? 附:我也尝试过矢量,但它比bitset慢一点。
// File: bittest.cc
// Test use of bitset container
#include <ctime>
#include <iostream>
#include <bitset>
#include <vector>
#include <string>
using namespace std;
void compress(string&, bitset<74>&);
void compare(bitset<74>&, bitset<74>&);
int main()
{
// Start timer
std::clock_t start;
double difference;
start = std::clock();
for(int i=0; i<10000000; ++i){
string frag1="ATCGACTGACTGACTGACTGACTGACTGACTGACTGA";
string frag2="AACGAACGAACGAACGAACGAACGAACGAACGAACGA";
int a=37;
bitset<74> bits1;
bitset<74> bits2;
compress(frag1, bits1);
compress(frag2, bits2);
compare(bits1, bits2);
}
difference = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
int minutes = difference/60;
int seconds = difference - minutes * 60;
if (seconds < 10){
cout << "\nRunning time: " << minutes << ":0" << seconds << endl << endl;
}else{
cout << "\nRunning time: " << minutes << ":" << seconds << endl << endl;
}
return 0;
}
void compress(string& in, bitset<74>& out){
char c;
int b=0;
for(int i=0; i<in.length(); ++i){
c=in[i];
b=2*i;
switch(c){
case 'A':
break;
case 'C':
out.set(b+1);
break;
case 'G':
out.set(b);
break;
case 'T':
out.set(b);
out.set(b+1);
break;
default:
cout << "Invalid character in fragment.\n";
}
}
}
void compare(bitset<74>& a, bitset<74>& b){
for(int i=0; i<74; ++i){
if(a[i] != b[i]){
}
}
}
字符串线束......
// File: bittest.cc
#include <ctime>
#include <iostream>
#include <bitset>
#include <vector>
#include <string>
using namespace std;
void compress(string&, bitset<74>&);
void compare(string&, string&);
int main()
{
// Start timer
std::clock_t start;
double difference;
start = std::clock();
for(int i=0; i<10000000; ++i){
string frag1="ATCGACTGACTGACTGACTGACTGACTGACTGACTGA";
string frag2="AACGAACGAACGAACGAACGAACGAACGAACGAACGA";
int a=37;
bitset<74> bits1;
bitset<74> bits2;
compress(frag1, bits1);
compress(frag2, bits2);
compare(frag1, frag2);
}
difference = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
int minutes = difference/60;
int seconds = difference - minutes * 60;
if (seconds < 10){
cout << "\nRunning time: " << minutes << ":0" << seconds << endl << endl;
}else{
cout << "\nRunning time: " << minutes << ":" << seconds << endl << endl;
}
return 0;
}
void compress(string& in, bitset<74>& out){
char c;
int b=0;
for(int i=0; i<in.length(); ++i){
c=in[i];
b=2*i;
switch(c){
case 'A':
break;
case 'C':
out.set(b+1);
break;
case 'G':
out.set(b);
break;
case 'T':
out.set(b);
out.set(b+1);
break;
default:
cout << "Invalid character in frag.\n";
}
}
}
void compare(string& a, string& b){
for(int i=0; i<37; ++i){
if(a[i] != b[i]){
}
}
}
答案 0 :(得分:4)
考虑两个比较例程:
void compare(bitset<74>& a, bitset<74>& b){
for(int i=0; i<74; ++i){
if(a[i] != b[i]){
}
}
}
和
void compare(string& a, string& b){
for(int i=0; i<37; ++i){
if(a[i] != b[i]){
}
}
}
你可以看到一个正在执行循环74
次,另一个正在执行循环37
次。因此,bitset方法已经开始处于弱势地位。
现在考虑被访问的数据类型;访问单个字节的速度相当快;从任何数据结构访问各个位可能会在整个字节中存储单个位,甚至可能存储更大的字大小。如果它将位存储在各个位中,则必须引入一些位掩码操作,并且这些操作也都具有处理能力。如果这些位以字节存储,那么您实际上只比较每个位上每个字符的 half 。如果这些位以字或更大的形式存储,则会增加CPU数据高速缓存的大小 - 可能会将一些可能完全适合一条高速缓存行的内容转移到多个高速缓存行。这可能会导致巨大的速度惩罚,虽然这些输入很小,但它可能并不太可怕。
如果您将bitset
替换为足以容纳所有数据的char[]
,请在压缩例程中手动设置这些位,然后比较{{1} }一次一个字节或更大的数组,你可以大大提高比较例程的速度。加速是否足以克服压缩程序的成本?这很难说,部分取决于你可以对每种压缩形式进行多少次比较。
如果您可以使用char[]
或更大的数据类型执行比较,那么您可能会更快地进行比较,因为现代CPU通常在访问4字节或8字节时比1字节更快。一时间大多数int
或strcmp(3)
例程都经过优化,可以执行巨大的,对齐的读取。如果您使用memcmp(3)
进行比较,那么您将获得最高速度的最佳机会 - 这适用于压缩和未压缩版本。
答案 1 :(得分:2)
CPU不会加载小于一个字节的任何内容,即8位。因此,当程序处理一对位时,CPU实际加载8位,然后屏蔽未使用的6位。屏蔽操作需要处理器时间。
您必须将内存使用效率与执行时间进行交换。您更喜欢哪种选择。