到目前为止,我想出的最好的公式是:
char c = 'd'; // or any other hex character
int value = (((c & 0x1F) + 9) % 25;
注意它不含分支,但确实包含昂贵的模型操作。
我可以做得更好吗?您可以在没有模块化和没有分支的情况下做到这一点,只有几个班次和减法。
int value = (c & 0x0F) + 9 - ((c&0x10)>>1) - ((c&0x10)>>4);
我只是从您的公式开始,并使用了一个事实,即
c&0x10
0
则是
0x10
。注意,正如评论中指出的那样,编译器将优化编译器将倍增和添加的mod提出,但这仍然应该更好,因为编译器没有前提条件:
0-9
是十六进制数字。如果您有一个快速乘以:
c
int value = (c & 0x0f) + 9 * (c >> 6)
非常直接的小提琴。 demo
(d & 0xf) + ((d & 0x40) >> 3) + ((d & 0x40) >> 6)
saves另一个位
几个版本
,得出的结论是,使用简单的查找表的速度是“花哨的数学功能”的两倍。从他的文章中进行复制:
and
where
uint32_t hex_to_u32_lookup(const uint8_t *src) {
uint32_t v1 = digittoval[src[0]];
uint32_t v2 = digittoval[src[1]];
uint32_t v3 = digittoval[src[2]];
uint32_t v4 = digittoval[src[3]];
return v1 << 12 | v2 << 8 | v3 << 4 | v4;
}
“是一个256个字节阵列,其中48(或'0')映射到0、65(或'a')被映射到10,依此类推”。
我甚至后来参加聚会,但我来找一个答案。 这里接受的答案使用了6种操作,对我来说似乎并不最佳,所以我进行了一些修补并提出了这些操作。 absumsuming您将其限制为ACII字符集,如果您在X64上,并且编译器很不错,那么这将优化一些比较,一个比较,两个添加和一个CMOV;因此,4个操作和一个CMOV
digittoval
u8 r = (u8)c & 0x1f;
r = (r <= 6) ? r += 9 : r -= 16;
这将优化到测试,一个CMOV,2位和一个变化。标志还作为即时值加载,因此处理器不必进入内存。 我尚未使用“查找表”方法测试这些方法,但是直觉表明,只要您可以保证它不会引起cache Miss。 *注意:“ U8”和“ U64”是我自己的无签名类型