繁体   English   中英

C ++:二进制到十进制转换

[英]C++: Binary to Decimal Conversion

我试图通过以下方式将二进制数组转换为十进制:

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位二进制数组转换为十进制数,我必须做几百万次。

任何人都可以帮助我,有没有更快的方法来做到这一点? 或者上面的那个好吗?

你的方法是足够的,称之为我不会混合按位运算和“数学”转换为十进制的方式,即使用

    decimal = decimal << 1 | array[i];

要么

    decimal = decimal * 2 + array[i];

在尝试任何优化之前,重要的是分析代码。 计算时间,查看生成的代码,并在您了解正在进行的操作时进行优化。

正如已经指出的那样,最好的优化是不做某事,而是做出更高级别的改变以消除需求。

然而...

您可能想要在这里轻易做出的大多数更改很可能是编译器已经完成的事情(移位与编译器的乘法相同)。 有些实际上可能会阻止编译器进行优化(更改addor将限制编译器 - 有更多方法可以添加数字,只有您知道在这种情况下结果将是相同的)。

指针算法可能更好,但编译器并不愚蠢 - 它应该已经生成了用于解除引用数组的合适代码,所以你需要通过引入一个额外的变量来检查你实际上是否使事情变得更糟。

在这种情况下,循环计数定义明确且有限,因此展开可能是有意义的。

更进一步,它取决于您希望结果在目标体系结构上的依赖程度。 如果您想要可移植性,那么优化就很难了。

例如,以下代码产生更好的代码:

unsigned int x0 = *(unsigned int *)array;
unsigned int x1 = *(unsigned int *)(array+4);

int decimal = ((x0 * 0x8040201) >> 20) + ((x1 * 0x8040201) >> 24);

我可能还会推出一个64位版本,一次只能做8位而不是4位。

但它绝对不是可移植的代码。 如果我知道我在运行什么,我可能会在本地使用它,我只想快速处理数字。 但我可能不会把它放在生产代码中。 当然不是没有记录它做了什么,并且没有附带的单元测试来检查它实际上是否有效。

你可以使用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。

二进制“压缩”可以概括为加权和的问题 - 并且有一些有趣的技术。

  • X mod(255)表示所有独立8位数的基本求和。
  • 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&~256)%254 +((a >> 9)&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));

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)&255]; 因为与这个给定的256个不同阵列的小子​​集没有冲突。 然而,为了应用这一点,人们已经选择了更便携的道路,并且最终可能最终使用SSE内在函数。

试试这个,我转换了一个高达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;
}

从理论上讲,这种方法适用于无限长度的二进制数字

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM