簡體   English   中英

如何最好地實施BCD作為練習?

[英]How best to implement BCD as an exercise?

我是學習C ++的初學者(自學)程序員,最近我決定實現一個二進制編碼的十進制(BCD)類作為練習,因此我可以在Euler項目上處理非常大的數字。 我想從頭開始正確地盡可能地做到這一點。

我開始使用一個整數數組,其中輸入數字的每個數字都保存為一個單獨的整數。 我知道每個BCD數字只能用4位編碼,因此我認為為此使用一個完整的int有點過分。 我現在正在使用bitset <4>的數組。

  1. 是否也在使用類似此類的庫類?
  2. 您會認為它作弊嗎?
  3. 有一個更好的方法嗎?

編輯:這樣做的主要原因是作為練習-我不想使用GMP之類的庫,因為整個觀點都是我自己寫的。 有沒有一種方法可以確保每個十進制數字僅使用4位?

請注意,使用bitset<4>數組將需要與long數組相同的空間。 通常通過將字大小的整數數組作為位的后備存儲來實現位集,以便按位操作可以使用按位字操作,而不是字節操作,因此一次可以完成更多操作。

另外,我質疑你的動機。 在系統之間發送BCD時,通常將BCD用作數字字符串的打包表示。 通常,算術實際上沒有任何關系。 您真正想要的是一個任意大小的整數算術庫,例如GMP

是否也在使用類似此類的庫類?

我將它與一系列整數進行基准比較,以查看哪種表現更好。 如果bitset <4>的數組更快,那么不算過分。 一點點幫助解決一些體育問題

您會認為它作弊嗎?

一點都不。

有一個更好的方法嗎?

就像格雷格·羅傑斯(Greg Rogers)所建議的那樣,任意精度庫可能是一個更好的選擇,除非您只是想從自己的基礎上學習。 從這兩種方法中都有一些要學習的東西(使用庫還是編寫庫)。 我很懶,所以我通常使用Python。

就像格雷格·羅傑斯(Greg Rogers)所說的那樣,使用位集可能不會比int節省任何空間,並且實際上不會提供任何其他好處。 我可能會改用向量。 它的大小是所需大小的兩倍,但是您可以為每個數字建立更簡單,更快速的索引。

如果要使用打包的BCD,則可以編寫自定義索引功能,並在每個字節中存儲兩位數字。

  1. 是否也在使用類似此類的庫類?
  2. 您會認為它作弊嗎?
  3. 有一個更好的方法嗎?

1&2:不是真的

3:每個字節有8位,您可以在每個未簽名的char中存儲2個BCD。

通常,位操作是在整數的上下文中應用的,因此從性能方面來看,沒有真正的理由去使用位。

如果您想通過一點方法來獲得經驗,那么這可能會有所幫助

#include <stdio.h>
int main
(
    void
)
{
    typedef struct
    {
        unsigned int value:4;

    } Nibble;

    Nibble nibble;

    for (nibble.value = 0; nibble.value < 20; nibble.value++)
    {
        printf("nibble.value is %d\n", nibble.value);
    }

    return 0;
}

要點是在struct內部,您正在創建一個短整數,一個4位寬的整數。 實際情況下,它實際上仍然是整數,但是對於您的預期用途,它看起來像是4位整數。

for循環清楚地表明了這一點,它實際上是一個無限循環 當半字節值達到16時,該值實際上為零,因為只有4位可以使用。 結果, nibble.value <20永遠不會為真。

如果您查看《 K&R白皮書》,其中一項便箋是這樣的位操作不可移植的事實,因此,如果您想將程序移植到另一個平台上,可能會或可能不會。

玩得開心。

您正在嘗試獲取以10為基的表示形式(即數組的每個單元格中的十進制數字)。 這樣就浪費了空間(每個數字一個整數)或時間(每個dgit 4位,但打包/拆包的開銷)。

例如,為什么不嘗試使用base-256並使用字節數組呢? 甚至是基數為2 ^ 32的整數數組? 這些操作的實現方式與10級基礎相同。 唯一不同的是將數字轉換為人類可讀的字符串。

它可能是這樣工作的:假設以256為基,每個“數字”都有256個可能的值,因此數字0-255都是單數字值。 大於256的字符寫為1:0(我將使用冒號分隔“數字”,我們不能使用像base-16那樣的字母),base-10的類比是9之后的數字,等於10。1030類似。 -10)= 4 * 256 + 6 = 4:6(以256為基)。 1020(base-10)= 3 * 256 + 252 = 3:252(base-256)是base-256中的兩位數。

現在假設我們將數字放在字節數組中,最低有效數字在前:

unsigned short digits1[] = { 212, 121 }; // 121 * 256 + 212 = 31188
int len1 = 2;
unsigned short digits2[] = { 202, 20  }; // 20 * 256 + 202 = 5322
int len2 = 2;

然后添加將如下所示(警告:前面的記事本代碼可能已損壞):

unsigned short resultdigits[enough length] = { 0 };
int len = len1 > len2 ? len1 : len2; // max of the lengths
int carry = 0;
int i;
for (i = 0; i < len; i++) {
    int leftdigit = i < len1 ? digits1[i] : 0;
    int rightdigit = i < len2 ? digits2[i] : 0;
    int sum = leftdigit + rightdigit + carry;
    if (sum > 255) {
        carry = 1;
        sum -= 256;
    } else {
        carry = 0;
    }
    resultdigits[i] = sum;
}
if (carry > 0) {
    resultdigits[i] = carry;
}

在第一次迭代中,它應該像這樣:

  1. 總和= 212 + 202 + 0 = 414
  2. 414> 256,所以進位= 1且總和= 414-256 = 158
  3. resultdigits [0] = 158

在第二次迭代中:

  1. 總和= 121 + 20 + 1 = 142
  2. 142 <256,所以進位= 0
  3. resultdigits [1] = 142

因此,最后結果為digits [] = {158,142},即142:158(base-256)= 142 * 256 + 158 = 36510(base-10),正好是31188 + 5322

請注意,將這個數字轉換為人類可讀的格式絕非易事-它需要乘以10或256的乘法和除法,如果沒有適當的研究,我將無法作為示例提供代碼。 這樣做的好處是可以真正有效地執行“加”,“減”和“乘”運算,並且在計算的開始和結束之后僅進行一次與以10為底的大量轉換。

說了這么多,就我個人而言,我將使用以10為基數的字節數組,而不關心內存丟失。 這將需要將常數255和256分別調整為9和10。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM