繁体   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