【问题标题】:Convert Hex to Decimal when no datatype can hold the full number当没有数据类型可以容纳完整数字时将十六进制转换为十进制
【发布时间】:2009-07-17 13:34:23
【问题描述】:

我正在使用 C 语言的 PIC 微处理器。它是 16F,因此它不能保存大于 32 位的整数(无符号 int32 是可用的最大数据大小)

从阅读器那里,我收到一个 5 字节的 ID 代码。要传输它,我必须逐位编码为 BCD。我无法将其冲刺成字符串,因为它大于数据大小,并且无法处理它。我不能分割它,因为它没有定义任何操作。

我想不出任何可能的解决方案,以前有没有人处理过这个问题?

编辑:

我收到 5 个字节的数字:

FF-FF-FF-FF-FF

我需要把它转换成十进制

0123456789012

(13 位,十进制长度为 256^5)通过 RS232 发送。第二个函数(获取 ASCII,然后发送)我已经让它工作了,但我需要完整数字的字符串表示,然后才能对它做任何事情。

【问题讨论】:

  • 请说得更具体些...你是如何收到这 5 个字节的?作为一个 unsigned char 数组?那么你需要传输的格式是什么?
  • 您的问题有点令人困惑:如果我理解正确,您会收到一个 5 字节长的数组,代表一个 ID。这个 ID 无论如何都没有被编码,只是一个 5*8 位长的整数,对吧?而您将其转换为该 ID 的十进制 ascii 表示,对吗?我问是因为您提到了BCD,我不明白它在哪里使用? ID 收到时是否以 BCD 编码?
  • 不,我必须以 BCD 输出,因此我需要十进制数的字符串表示形式(int 版本不够,因为我必须逐位发送)我需要转换 5 字节 Id 表示(5 个无符号 8 位)以发送整数。 (收件人可以将该数字转换为十六进制并获得原始的 5 个字节)
  • 好的,知道了。我可能有一个想法,我会尝试发布一些示例代码;)
  • 这是一个有趣的问题,但它并没有得到太多的 veiws,这是一个耻辱。很多人说“只使用一个库”,以至于他们从未考虑过如何实际做这样的事情。

标签: c algorithm bignum pic


【解决方案1】:

假设你有 32 位算术:2**24 = 16777216,所以取 x 作为最高有效 2 字节,y 作为最低有效 3:

  (16777216 * x + y) / 1000 
= (16777000 * x + 216 * x + y) / 1000
= 16777 * x + (216 * x + y) / 1000

第一项可以以 32 位计算而不会溢出(自 x < 2**16 起)。 第二项也可以不溢出计算(因为x < 2**16y < 2**24)。

这基本上是基数 2**24 的两位数的长除法,但预先计算的项知道除数是 1000。选择一千是因为它是大于 2**8 的 10 的最小幂。

所以,首先计算最低三位,使用(2**32) % 1000 == 296这一事实。所以这次我们将x作为最高字节,y作为低4字节

((2**32) * x + y) % 1000 = ((2**32) * x) % 1000 + y % 1000 (modulo 1000)
                         = (296 * x) % 1000 + y % 1000     (modulo 1000)
((2**32) * x + y) % 1000 = ((296 * x) % 1000 + y % 1000) % 1000

然后使用上面的公式将原始数字除以 1000。然后您就可以安全地进入 32 位领域,并且可以使用正常循环生成剩余的数字。

顺便说一句,如果我是你,我会检查结果:我还没有测试过这个,我可能在某个地方犯了错误。应该很容易与在 PC 上使用通常方法以 64 位整数完成的 bcd 转换结果进行比较。

【讨论】:

  • 好主意,我只需要思考如何使其适应 C。
  • 你的澄清,你是我的新数学英雄。
  • 我使用上面的公式得到了前 10 位数字,但我不知道如何修改它以获得它的模数。我在这里错过了什么?
  • 我已经进一步解释并整理了一下,希望对您有所帮助。
  • 我已经在 PC 中测试了这些公式,它们运行良好。恐怕有点玩弄对我来说仍然很神奇。谢谢!
【解决方案2】:

我要做的是实现编码为字符串的数字的加法和乘法(类似于 BigNum)。这样,您可以将 ID 的最高有效字节 sprintf 到字符串“A”,将它与字符串“4294967296”(256^4)相乘,得到字符串“B”,将 ID 的 4 个最低有效字节冲入另一个字符串“C”,最后加上“B”和“C”。

这不是很性感,尤其是在微控制器上,但它确实有效:)

【讨论】:

    【解决方案3】:

    PIC16F 没有硬件乘法或除法单元,因此除非您用 2 的幂进行乘法或除法运算,否则会对处理器造成负担。这是一个对 32 位数字执行 BCD 且不需要除法或乘法的例程。您可以通过分块将其调整为 5 字节数。

    void BCD32(int32u numIn) { int8u 数字 = 0;

    while (numIn >= 1000000000)
    {
        numIn -= 1000000000;
        digit++;
    }    
    debug[0] = digit + 48;   
    digit = 0;
    while (numIn >= 100000000)
    {
        numIn -= 100000000;
        digit++;
    }    
    debug[1] = digit + 48;            
    digit = 0;
    while (numIn >= 10000000)
    {
        numIn -= 10000000;
        digit++;
    }    
    debug[2] = digit + 48;            
    digit = 0;
    while (numIn >= 1000000)
    {
        numIn -= 1000000;
        digit++;
    }    
    debug[3] = digit + 48;            
    digit = 0;
    while (numIn >= 100000)
    {
        numIn -= 100000;
        digit++;
    }    
    debug[4] = digit + 48;            
    digit = 0;
    while (numIn >= 10000)
    {
        numIn -= 10000;
        digit++;
    }
    debug[5] = digit + 48;        
    digit = 0;
    while (numIn >= 1000)
    {
        numIn -= 1000;
        digit++;
    }
    debug[6] = digit + 48;    
    digit = 0;    
    while (numIn >= 100)
    {
        numIn -= 100;
        digit++;
    }
    debug[7] = digit + 48;
    
    digit = 0;
    while (numIn >= 10)
    {
        numIn -= 10;
        digit++;
    }
    debug[8] = digit + 48;
    
    digit = 0;
    while (numIn >= 1)
    {
        numIn -= 1;
        digit++;
    }
    debug[9] = digit + 48;    
    debug[10] = CARRIAGE_RETURN;
    debug[11] = NEW_LINE_FEED;
    SendUart(12);                           
    

    }

    【讨论】:

    • 如果我需要 BCD 例程的性能,我会考虑这一点。现在,我只是在 char 数组中执行 sprintf。但主要关注的是由onebyone进行的字节到字符串的转换。
    【解决方案4】:

    您始终可以自己手动将其“sprintf”转换为字符串。逐个字节地检查数据,并通过附加单个字符将其转换为数字字符串。

    【讨论】:

    • 嗯,没有。如果我这样做,我只会附加小数。我需要获取完整的十六进制数字(附加的 0-F 字符)并将整个内容转换为十进制。结果差异很大,因为每个数字是 16^n。
    【解决方案5】:

    我要说的这个问题的核心是转换为十进制的“长除法”之一。与您在小学学习的长除法并不完全不同,尽管使用二进制数,长除法要简单得多。但它仍然有很多工作。

    试试:
    http://mathforum.org/library/drmath/view/55951.html

    您必须实现自己的多字节减法和移位例程。

    【讨论】:

    • 实际上你可以只使用 shift 和 +3 操作来做到这一点。长除法是一种蛮力方法。
    猜你喜欢
    • 2014-04-16
    • 2010-10-16
    • 1970-01-01
    • 2015-11-29
    • 2017-08-12
    • 2015-01-26
    相关资源
    最近更新 更多