2015-02-07 53 views
1

我想保存8布尔值为一个字节,然后将其保存到一个文件(这项工作必须完成一个非常大的数据),我已经使用了下面的代码,但我不知道它是最好的一个(在速度和空间方面):将8布尔转换为一个字节的最佳方法?

int bits[]={1,0,0,0,0,1,1,1}; 
char a='\0'; 
for (int i=0;i<8;i++){ 
    a=a<<1; 
    a+=bits[i] 
} 
//and then save "a" 

任何人都可以给我一个更好的代码(更快的速度)?

+0

这是一样好。 – 2015-02-07 13:33:19

+0

你确定这有效吗?在写第一个字节之前,你先进行移位。 – Blob 2015-02-07 13:34:33

+2

你没有做的一件事就是在开始之前清除'a'。 – 2015-02-07 13:35:31

回答

3

如果你不介意使用SSE内在函数,那么_mm_movemask_epi8是非常适合的。它使用16个字节,但您可以将其他设置为零。

例如(未测试)

__m128i values = _mm_loadl_epi64((__m128i*)array); 
__m128i order = _mm_set_epi8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
          0, 1, 2, 3, 4, 5, 6, 7); 
values = _mm_shuffle_epi8(values, order); 
int result = _mm_movemask_epi8(_mm_slli_epi32(values, 7)); 

这假定阵列是字符数组。如果你无法做到这一点,它需要更多的负载和包装,它变得有点烦人。

+0

我测试了这个命令,它似乎有更好的性能,但它返回错误的结果。当我给它11001000位的字符数组时,它会返回我19,这是不正确的。 – abdolahS 2015-03-02 13:04:03

+0

@abdolahS对我来说看起来很对,或者你想让它颠倒吗? – harold 2015-03-02 14:28:07

+0

是的,我想要以相反的顺序!我该怎么做。感谢您的回答。 – abdolahS 2015-03-02 14:35:30

-1

+=运营商更换为|=,这是按位操作(实际上您希望在此执行的操作)。 如果可能,请使用unsigned char作为您的真值。我想,除非你想手动展开你的循环和/或使用SIMD内在函数,否则这将是编译器最优化的解决方案。

还有另一招:struct s可以有位偏移量,你可以使用union来滥用它们作为整数。

顺便说一句:你的代码是越野车。你先转,然后写;你使用加法,但一个signed char,这肯定会出错的第7和第8位(鉴于你错误地转换得太早,如果你做得很好,只有第8位会引起危险)。

+2

由于他只添加单个0/1值,并且该位已知为从零开始(如果在启动之前清零累加器),添加和ORing之间没有有效的区别。 – 2015-02-07 13:37:22

+0

@HotLicks:是的 - 他使用signed int,所以将1移到最高位将会颠倒他的值的符号;那么,+1不一定等于| 1。 – 2015-02-07 14:06:57

+0

那么??会有什么不同? – 2015-02-07 14:11:49

2

关于

谁能给我一个更好的代码(更快的速度)

你应该措施。序列化文件速度的大部分影响是I/O速度。你对这些位做什么可能会产生不可估量的影响,但如果它有任何影响,那么这可能主要受到你对布尔序列的原始表示的影响。


现在对于给定的代码

int bits[]={1,0,0,0,0,1,1,1}; 
char a='\0'; 
for (int i=0;i<8;i++){ 
a=a<<1; 
a+=bits[i] 
} 
//and then save "a" 
  • 使用unsigned char为字节型,只是在原则。
  • 使用位级OR,|运算符,再次只是原则上。
  • 使用前缀++,是的,也只是原则上。

针对第一点原则”的“是因为在实践中你的代码不会在任何机器上使用标志和幅度或符号整数,其中char签订的一个补码表示形式运行。但我认为在代码中表达一个人的意图通常是一个好主意,而不是将其重写为稍微不同的东西。这里的意图是处理位,一个无符号的字节。

“原则”对于位级OR是因为在这种特殊情况下,位级OR和加法之间没有实际的区别。但总的来说,用代码编写表达意思是个好主意。然后写一个位级别或者是一个额外的东西并不是好事:它甚至可能会让你感到痛苦,在某种情况下咬你一个**。

上原理” “的用于前缀++是因为在实践中,编译器将优化前缀和后缀++为基本型,当表达结果不被使用时,以非常相同的机器代码。但是,再次写出想要表达的内容通常会更好。要求原始值(后缀++)只是误导了代码的读者,当您没有使用原始值–,并且与表示为加法的位级OR一样,表示为后缀++的纯增量可能会使您绊倒,在一些其他情况下,例如,在a **中咬你与迭代器。


的明确编码升档和或门,在我看来是很好的,因为std::bitset不从布尔(文本字符串只在初始化)序列支持初始化的一般方法,所以它不会救你任何工作。但通常检查标准库是个好主意,它是否支持任何人想做的事情。甚至可能发生其他人在这里用一些我没有想到的基于标准库的方法在这里发出的声音! ;-)

+0

为什么不是无符号整数“原则”? – 2015-02-07 14:27:41

+0

@NeilKirk:如果你的意思是,为什么'unsigned int'不是字节类型,在大多数机器上,'unsigned'不止一个字节。它*可以*是一个字节,取决于平台。但通常情况更多。考虑到OP的任务是将字节值存储在一个文件中,如果他希望高效地执行该操作,那么一个好方法是一次输出一大块字节,一个字节序列。然后序列项需要一个确切的字节类型。 – 2015-02-07 14:29:13

+0

对不起,我指的是“位”类型,但我现在看到您指的是“a”类型。 – 2015-02-07 18:51:41