![](/img/trans.png)
[英]How To Convert QBytearray BCD to Decimal QString Representation?
[英]How best to implement BCD as an exercise?
我是学习C ++的初学者(自学)程序员,最近我决定实现一个二进制编码的十进制(BCD)类作为练习,因此我可以在Euler项目上处理非常大的数字。 我想从头开始正确地尽可能地做到这一点。
我开始使用一个整数数组,其中输入数字的每个数字都保存为一个单独的整数。 我知道每个BCD数字只能用4位编码,因此我认为为此使用一个完整的int有点过分。 我现在正在使用bitset <4>的数组。
编辑:这样做的主要原因是作为练习-我不想使用GMP之类的库,因为整个观点都是我自己写的。 有没有一种方法可以确保每个十进制数字仅使用4位?
请注意,使用bitset<4>
数组将需要与long数组相同的空间。 通常通过将字大小的整数数组作为位的后备存储来实现位集,以便按位操作可以使用按位字操作,而不是字节操作,因此一次可以完成更多操作。
另外,我质疑你的动机。 在系统之间发送BCD时,通常将BCD用作数字字符串的打包表示。 通常,算术实际上没有任何关系。 您真正想要的是一个任意大小的整数算术库,例如GMP 。
是否也在使用类似此类的库类?
我将它与一系列整数进行基准比较,以查看哪种表现更好。 如果bitset <4>的数组更快,那么不算过分。 一点点帮助解决一些体育问题
您会认为它作弊吗?
一点都不。
有一个更好的方法吗?
就像格雷格·罗杰斯(Greg Rogers)所建议的那样,任意精度库可能是一个更好的选择,除非您只是想从自己的基础上学习。 从这两种方法中都有一些要学习的东西(使用库还是编写库)。 我很懒,所以我通常使用Python。
就像格雷格·罗杰斯(Greg Rogers)所说的那样,使用位集可能不会比int节省任何空间,并且实际上不会提供任何其他好处。 我可能会改用向量。 它的大小是所需大小的两倍,但是您可以为每个数字建立更简单,更快速的索引。
如果要使用打包的BCD,则可以编写自定义索引功能,并在每个字节中存储两位数字。
- 是否也在使用类似此类的库类?
- 您会认为它作弊吗?
- 有一个更好的方法吗?
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;
}
在第一次迭代中,它应该像这样:
在第二次迭代中:
因此,最后结果为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.