簡體   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