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

C++ C++;:二进制到十进制的转换,c++,C++,我正在尝试以下方式将二进制数组转换为十进制: 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] ; uint8_t数组[8]={1,1,1,0,1,1,1}; 整数小数=0; 对于(int i=0;i>9)和2) 获取权重的另一种机制是将每个二进制数字预乘255,并

我正在尝试以下方式将二进制数组转换为十进制:

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] ;
uint8_t数组[8]={1,1,1,0,1,1,1};
整数小数=0;
对于(int i=0;i<8;i++)

decimal=(decimal您的方法已经足够了,称之为nice,我不会将按位运算和转换为十进制的“数学”方式混合使用,即使用

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

在尝试任何优化之前,对代码进行分析是很重要的。对代码进行计时,查看生成的代码,只有当您了解发生了什么时才进行优化

正如已经指出的,最好的优化不是做什么,而是进行更高级别的更改,从而消除需求

然而

您可能希望在此处进行的大多数更改可能是编译器已经完成的事情(移位与对编译器的乘法相同)。有些更改实际上可能会阻止编译器进行优化(将
添加
更改为
将限制编译器-有更多的方法添加数字,只有您知道在这种情况下结果是相同的)

指针算法可能更好,但编译器并不愚蠢——它应该已经生成了用于解引用数组的适当代码,因此您需要检查是否通过引入额外的变量使情况变得更糟

在这种情况下,循环计数定义良好且有限,因此展开可能有意义

此外,它还取决于您希望结果对目标体系结构的依赖程度。如果您希望可移植性,则很难(呃)进行优化

例如,以下内容在此处生成更好的代码:

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

int decimal = ((x0 * 0x8040201) >> 20) + ((x1 * 0x8040201) >> 24);
我可能还可以推出一个64位版本,一次8位,而不是4位


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

您可以使用
累加
,使用加倍和添加二进制操作:

int doubleSumAndAdd(const int& sum, const int& next) {
    return (sum * 2) + next;
}

int decimal = accumulate(array, array+ARRAY_SIZE,
                         doubleSumAndAdd);

这会产生大端整数,而操作码会产生小端整数。

二进制“压缩”可以概括为一个加权和问题——为此有一些有趣的技术

  • X mod(255)表示所有独立8位数字的总和
  • X mod 254意味着用加倍的权重对每个数字求和,因为1 mod 254=1、256 mod 254=2、256*256 mod 254=2*2=4等

    如果编码是big-endian,则*(unsigned long-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进行更正):

对于持怀疑态度的人来说:我确实对模数版本进行了分析,认为它(稍微)比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));

ret=((a[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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
长二进制\十进制(字符串num)/*函数,用于将二进制转换为十进制*/
{
长dec=0,n=1,exp=0;
字符串bin=num;
如果(bin.length()>1020){

CUT不管它是在一个数组中还是作为一个字符串都不重要,无论如何你必须循环这些比特。可能有更多的C++特定的方法来完成它,但最终会有一个循环在位上。可能帮助你通常可以获得大的优化效益,而不是从小的函数中获得,而是寻找更高的层次。为什么数字是ST?以这种方式进行or?您可以使用循环展开和/或指针算法而不是数组访问。这将加快速度,但仍保持相同的算法复杂性。但是请注意,任何合适的编译器都会以相同的方式处理移位和乘法,而使用“or”而不是“add”将限制其优化的能力。实际上,MSVC在这里为第一个示例生成的代码较差,但第二个示例生成的代码与原始示例相同。您确实知道
long
是32(或64)位,而你实际上无法将1020位放入其中?是的..你可能误读了它。它的工作原理是这样的:bin:101 dec:5我读取一个最多1020位的字符串,每次我达到1,我就加上2*pow。尝试用一个超过31或63位的字符串测试你的代码。你不可能在32或64位有符号整数中表示1020位的值呃。结果溢出并环绕..当我给它32位或更多位时,结果是-1。应该很明显,
1020
位不能用
32
位变量表示。我正在设计一个虚拟机,它工作得很好,我解码了一个1020位二进制文件,并将结果存储在一个双精度文件中。这个代码不使用或返回
d双精度
。即使您将其更改为使用
双精度
,您也应该意识到IEEE 754双精度浮点的有效位为53位(约16位十进制数字)。您无法在
双精度
中实际存储1020位有效位,这将是一个近似值。唯一有效的方法是使用一些大整数库。
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;
#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;
}