简体   繁体   English

8位BCD检查

[英]8-digit BCD check

I've a 8-digit BCD number and need to check it out to see if it is a valid BCD number. 我有一个8位数的BCD号码,需要查看它是否是有效的BCD号码。 How can I programmatically (C/C++) make this? 我怎样才能以编程方式(C / C ++)制作这个?

Ex: 0x12345678 is valid, but 0x00f00abc isn't. 例如:0x12345678有效,但0x00f00abc不是。

Thanks in advance! 提前致谢!

You need to check each 4-bit quantity to make sure it's less than 10. For efficiency you want to work on as many bits as you can at a single time. 您需要检查每个4位数量以确保它小于10.为了提高效率,您希望一次处理尽可能多的位。

Here I break the digits apart to leave a zero between each one, then add 6 to each and check for overflow. 在这里,我将数字分开以在每个数字之间留下零,然后为每个数字加6并检查溢出。

uint32_t highs = (value & 0xf0f0f0f0) >> 4;
uint32_t lows = value & 0x0f0f0f0f;
bool invalid = (((highs + 0x06060606) | (lows + 0x06060606)) & 0xf0f0f0f0) != 0;

Edit: actually we can do slightly better. 编辑:实际上我们可以做得更好。 It doesn't take 4 bits to detect overflow, only 1. If we divide all the digits by 2, it frees a bit and we can check all the digits at once. 它不需要4位来检测溢出,只有1.如果我们将所有数字除以2,它会释放一些,我们可以立即检查所有数字。

uint32_t halfdigits = (value >> 1) & 0x77777777;
bool invalid = ((halfdigits + 0x33333333) & 0x88888888) != 0;

The obvious way to do this is: 显而易见的方法是:

/* returns 1 if x is valid BCD */
int
isvalidbcd (uint32_t x)
{
    for (; x; x = x>>4)
    {
        if ((x & 0xf) >= 0xa)
            return 0;
    }
    return 1;
}

This link tells you all about BCD, and recommends something like this asa more optimised solution (reworking to check all the digits, and hence using a 64 bit data type, and untested): 此链接告诉您有关BCD的所有信息,并建议使用此类更优化的解决方案(重新检查所有数字,因此使用64位数据类型,并且未经测试):

/* returns 1 if x is valid BCD */
int
isvalidbcd (uint32_t x)
{
   return !!(((uint64_t)x + 0x66666666ULL) ^ (uint64_t)x) & 0x111111110ULL;
}

For a digit to be invalid, it needs to be 10-15. 要使数字无效,则需要为10-15。 That in turn means 8 + 4 or 8+2 - the low bit doesn't matter at all. 这反过来意味着8 + 4或8 + 2 - 低位根本不重要。

So: 所以:

long mask8 = value & 0x88888888;
long mask4 = value & 0x44444444;
long mask2 = value & 0x22222222;
return ((mask8 >> 2) & ((mask4 >>1) | mask2) == 0;

Slightly less obvious: 略显不明显:

long mask8 = (value>>2);
long mask42 = (value | (value>>1);
return (mask8 & mask42 & 0x22222222) == 0;

By shifting before masking, we don't need 3 different masks. 通过在掩蔽之前移位,我们不需要3个不同的掩模。

Inspired by @Mark Ransom 灵感来自@Mark Ransom

 bool invalid = (0x88888888 & (((value & 0xEEEEEEEE) >> 1) + (0x66666666 >> 1))) != 0;
 // or
 bool valid = !((((value & 0xEEEEEEEEu) >> 1) + 0x33333333) & 0x88888888);

Mask off each BCD digit's 1's place, shift right, then add 6 and check for BCD digit overflow. 屏蔽每个BCD数字1的位置,向右移动,然后加6并检查BCD数字溢出。


How this works: 这是如何工作的:
By adding +6 to each digit, we look for an overflow * of the 4-digit sum. 通过向每个数字添加+6,我们寻找4位数总和的溢出*

 abcd
+ 110
-----
*efgd

But the bit value of d does not contribute to the sum, so first mask off that bit and shift right. 但是d的位值对总和没有贡献,所以首先屏蔽该位并向右移位。 Now the overflow bit is in the 8's place. 现在溢出位在8's位。 This all is done in parallel and we mask these carry bits with 0x88888888 and test if any are set. 这一切都是并行完成的,我们用0x88888888屏蔽这些进位,并测试是否有任何设置。

 0abc
+  11
-----
 *efg

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM