[英]8-digit BCD check
我有一個8位數的BCD號碼,需要查看它是否是有效的BCD號碼。 我怎樣才能以編程方式(C / C ++)制作這個?
例如:0x12345678有效,但0x00f00abc不是。
提前致謝!
您需要檢查每個4位數量以確保它小於10.為了提高效率,您希望一次處理盡可能多的位。
在這里,我將數字分開以在每個數字之間留下零,然后為每個數字加6並檢查溢出。
uint32_t highs = (value & 0xf0f0f0f0) >> 4;
uint32_t lows = value & 0x0f0f0f0f;
bool invalid = (((highs + 0x06060606) | (lows + 0x06060606)) & 0xf0f0f0f0) != 0;
編輯:實際上我們可以做得更好。 它不需要4位來檢測溢出,只有1.如果我們將所有數字除以2,它會釋放一些,我們可以立即檢查所有數字。
uint32_t halfdigits = (value >> 1) & 0x77777777;
bool invalid = ((halfdigits + 0x33333333) & 0x88888888) != 0;
顯而易見的方法是:
/* 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;
}
此鏈接告訴您有關BCD的所有信息,並建議使用此類更優化的解決方案(重新檢查所有數字,因此使用64位數據類型,並且未經測試):
/* returns 1 if x is valid BCD */
int
isvalidbcd (uint32_t x)
{
return !!(((uint64_t)x + 0x66666666ULL) ^ (uint64_t)x) & 0x111111110ULL;
}
要使數字無效,則需要為10-15。 這反過來意味着8 + 4或8 + 2 - 低位根本不重要。
所以:
long mask8 = value & 0x88888888;
long mask4 = value & 0x44444444;
long mask2 = value & 0x22222222;
return ((mask8 >> 2) & ((mask4 >>1) | mask2) == 0;
略顯不明顯:
long mask8 = (value>>2);
long mask42 = (value | (value>>1);
return (mask8 & mask42 & 0x22222222) == 0;
通過在掩蔽之前移位,我們不需要3個不同的掩模。
靈感來自@Mark Ransom
bool invalid = (0x88888888 & (((value & 0xEEEEEEEE) >> 1) + (0x66666666 >> 1))) != 0;
// or
bool valid = !((((value & 0xEEEEEEEEu) >> 1) + 0x33333333) & 0x88888888);
屏蔽每個BCD數字1的位置,向右移動,然后加6並檢查BCD數字溢出。
這是如何工作的:
通過向每個數字添加+6,我們尋找4位數總和的溢出*
。
abcd
+ 110
-----
*efgd
但是d
的位值對總和沒有貢獻,所以首先屏蔽該位並向右移位。 現在溢出位在8's
位。 這一切都是並行完成的,我們用0x88888888
屏蔽這些進位,並測試是否有任何設置。
0abc
+ 11
-----
*efg
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.