Wil*_*ill -2 c windows 64-bit assembly
我正在编写一个程序,将二进制值的十六进制表示转换为常规字符串.因此十六进制表示中的每个字符都将转换为字符串中的两个十六进制字符.这意味着结果将是两倍大小; 1字节的十六进制表示将需要字符串中的两个字节.
十六进制字符
0123456789 ;0x30 - 0x39
ABCDEF ;0x41 - 0x46
Run Code Online (Sandbox Code Playgroud)
例
0xF05C1E3A ;hex
4032568890 ;dec
Run Code Online (Sandbox Code Playgroud)
会成为
0x4630354331453341 ;hex
5057600944242766657 ;dec
Run Code Online (Sandbox Code Playgroud)
题?
是否有任何优雅/替代(/有趣)方法在这些状态之间进行转换,而不是查找表,(按位运算,移位,模数等)? 我不是在寻找库中的函数,而是如何实现/应该如何实现.有任何想法吗?
将半字节扩展到字节很容易pdep:
spread = _pdep_u64(raw, 0x0F0F0F0F0F0F0F0F);
Run Code Online (Sandbox Code Playgroud)
现在我们必须将 0x30 添加到 0-9 范围内的字节,并将 0x41 添加到更高的字节。这可以通过 SWAR 从每个字节中减去 10 然后使用符号来选择要添加的数字来完成,例如(未测试)
H = 0x8080808080808080;
ten = 0x0A0A0A0A0A0A0A0A
cmp = ((spread | H) - (ten &~H)) ^ ((spread ^~ten) & H); // SWAR subtract
masks = ((cmp & H) >> 7) * 255;
// if x-10 is negative, take 0x30, else 0x41
add = (masks & 0x3030303030303030) | (~masks & 0x3737373737373737);
asString = spread + add;
Run Code Online (Sandbox Code Playgroud)
SWAR 比较可能可以优化,因为您不需要完全减法来实现它。
这里有一些不同的建议,包括 SIMD: http: //0x80.pl/articles/convert-to-hex.html
这是一个只有移位,和/或加/减的解决方案.也没有循环.
uint64_t x, m;
x = 0xF05C1E3A;
x = ((x & 0x00000000ffff0000LL) << 16) | (x & 0x000000000000ffffLL);
x = ((x & 0x0000ff000000ff00LL) << 8) | (x & 0x000000ff000000ffLL);
x = ((x & 0x00f000f000f000f0LL) << 4) | (x & 0x000f000f000f000fLL);
x += 0x0606060606060606LL;
m = ((x & 0x1010101010101010LL) >> 4) + 0x7f7f7f7f7f7f7f7fLL;
x += (m & 0x2a2a2a2a2a2a2a2aLL) | (~m & 0x3131313131313131LL);
Run Code Online (Sandbox Code Playgroud)
以上是经过一段时间反思后我想出的简化版本.以下是原始答案.
uint64_t x, m;
x = 0xF05C1E3A;
x = ((x & 0x00000000ffff0000LL) << 16) | (x & 0x000000000000ffffLL);
x = ((x & 0x0000ff000000ff00LL) << 8) | (x & 0x000000ff000000ffLL);
x = ((x & 0x00f000f000f000f0LL) << 4) | (x & 0x000f000f000f000fLL);
x += 0x3636363636363636LL;
m = (x & 0x4040404040404040LL) >> 6;
x += m;
m = m ^ 0x0101010101010101LL;
x -= (m << 2) | (m << 1);
Run Code Online (Sandbox Code Playgroud)
请参阅实际操作:http://ideone.com/nMhJ2q