我试图通过以下方式将二进制数组转换为十进制:
uint8_t array[8] = {1,1,1,1,0,1,1,1} ;
int decimal = 0 ;
for(int i = 0 ; i < 8 ; i++)
decimal = (decimal << 1) + array[i] ;
实际上我必须将64位二进制数组转换为十进制数,而且我必须进行数百万次。
任何人都可以帮助我,有没有更快的方法来做到这一点?或者上面的那个好吗?
答案 0 :(得分:5)
你的方法已经足够了,称之为很好我不会将按位操作和“数学”方式转换为十进制,即使用
decimal = decimal << 1 | array[i];
或
decimal = decimal * 2 + array[i];
答案 1 :(得分:2)
在尝试任何优化之前,重要的是对代码进行概要分析。计算时间,查看生成的代码,并在您了解正在进行的操作时进行优化。
正如已经指出的那样,最好的优化是不做某事,而是做出更高级别的改变以消除需求。
...然而
您可能想要在这里轻易做出的大多数更改很可能是编译器已经完成的事情(转换与编译器的乘法相同)。有些人可能阻止编译器进行优化(将add
更改为or
会限制编译器 - 有更多方法可以添加数字,只有你知道在这种情况下,结果将是相同的。)
指针算法可能更好,但编译器并不愚蠢 - 它应该已经生成了用于解除引用数组的合适代码,所以你需要通过引入一个额外的变量来检查你实际上是否使事情变得更糟。 / p>
在这种情况下,循环计数定义明确且有限,因此展开可能是有意义的。
此外,它还取决于您希望结果在目标体系结构上的依赖程度。如果您想要可移植性,那么优化很难(呃)。
例如,以下代码产生更好的代码:
unsigned int x0 = *(unsigned int *)array;
unsigned int x1 = *(unsigned int *)(array+4);
int decimal = ((x0 * 0x8040201) >> 20) + ((x1 * 0x8040201) >> 24);
我可能还会推出一个64位版本,一次只能执行8位而不是4位。
但它绝对不是可移植的代码。如果我知道我在运行什么,我可能会在本地使用它,我只想快速处理数字。但我可能不会把它放在生产代码中。当然不是没有记录它做了什么,也没有附带的单元测试来检查它确实有效。
答案 2 :(得分:0)
你可以使用accumulate
,加倍并添加二进制操作:
int doubleSumAndAdd(const int& sum, const int& next) {
return (sum * 2) + next;
}
int decimal = accumulate(array, array+ARRAY_SIZE,
doubleSumAndAdd);
这会生成big-endian整数,而OP代码会生成little-endian。
答案 3 :(得分:0)
二进制“压缩”可以概括为加权和的问题 - 并且有一些有趣的技术。
X mod 254表示将每个数字加倍加权,因为1 mod 254 = 1,256 mod 254 = 2,256 * 256 mod 254 = 2 * 2 = 4等。
如果编码是大端,则*(无符号长long)数组%254将产生加权和(截断范围为0..253)。然后使用权重2删除值并手动添加它将产生正确的结果:
uint64_t a = *(uint64_t *)数组; 返回(a&amp; ~256)%254 +((a&gt;&gt; 9)&amp; 2);
获得权重的其他机制是将每个二进制数字预乘255并屏蔽正确的位:
uint64_t a = (*(uint64_t *)array * 255) & 0x0102040810204080ULL; // little endian
uint64_t a = (*(uint64_t *)array * 255) & 0x8040201008040201ULL; // big endian
在这两种情况下,都可以取255的余数(现在用重量1来纠正):
return (a & 0x00ffffffffffffff) % 255 + (a>>56); // little endian, or
return (a & ~1) % 255 + (a&1);
对于持怀疑态度的思想:我实际上对模数版本进行了分析,比x64上的迭代更快(稍微)。
为了继续JasonD的回答,可以迭代地使用并行比特选择。 但首先以完整形式表达方程式将有助于编译器使用累积来消除迭代方法创建的人为依赖:
ret = ((a[0]<<7) | (a[1]<<6) | (a[2]<<5) | (a[3]<<4) |
(a[4]<<3) | (a[5]<<2) | (a[6]<<1) | (a[7]<<0));
VS。
HI=*(uint32_t)array, LO=*(uint32_t)&array[4];
LO |= (HI<<4); // The HI dword has a weight 16 relative to Lo bytes
LO |= (LO>>14); // High word has 4x weight compared to low word
LO |= (LO>>9); // high byte has 2x weight compared to lower byte
return LO & 255;
另一个有趣的技术是利用crc32作为压缩函数;那么结果就是LookUpTable [crc32(array)&amp; 255];因为与这个给定的256个不同阵列的小子集没有冲突。然而,为了应用这一点,人们已经选择了更便携的道路,最终可能会使用SSE内在函数。
答案 4 :(得分:0)
试试这个,我转换了一个最多1020位的二进制数字
#include <sstream>
#include <string>
#include <math.h>
#include <iostream>
using namespace std;
long binary_decimal(string num) /* Function to convert binary to dec */
{
long dec = 0, n = 1, exp = 0;
string bin = num;
if(bin.length() > 1020){
cout << "Binary Digit too large" << endl;
}
else {
for(int i = bin.length() - 1; i > -1; i--)
{
n = pow(2,exp++);
if(bin.at(i) == '1')
dec += n;
}
}
return dec;
}
理论上,此方法适用于无限长度的二进制数字