在 x86 汇编中将 ASCII 转换为二进制的最有效方法

Most efficient way to convert ASCII to Binary in x86 Assembly

我有一个数字作为 ASCII 存储在内存中,想将其转换为二进制值(乘以 100)。

所以 1.23 可能会以 ASCII 形式存储在内存中作为 0x312E3233,这应该转换为二进制值 123。

我目前有以下方法,但有没有更有效的方法?

mov eax,[esi]
xor eax, 0x302E3030
mov edx, eax
and edx, 0x000000FF
shr eax,8
jz skip
mov ecx,eax
and ecx, 0x000000FF
imul ecx, 10
add edx, ecx
shr eax,8
jz skip
shr eax,8
imul eax,100
add edx, eax
skip:

ascii 源被 esi 引用。

在标签 "skip" 处,edx 具有二进制值。

一些简单的事情可以稍微改善这一点。摆脱相对较慢的 imul 并使用 leaadd:

    mov eax,[esi]
    xor eax,0x302E3030
    mov edx,eax
    jz skip
    and edx,0x000000FF
    shr eax,8
    jz skip
    mov ecx,eax
    and ecx,0x000000FF
    lea ecx,[ecx+4*ecx]
    add ecx,ecx
    add edx,ecx
    shr eax,8
    jz skip
    shr eax,8
    lea eax,[eax+4*eax]
    lea eax,[eax+4*eax]
    add eax,eax
    add eax,eax 
    add edx,eax
skip:

在现代处理器上,它可能不会产生太大的差异,但它应该仍然很明显。

如果例程可以使用零值,最好不要包含那些条件跳转。 BSWAP 应该快于 2 次移位 8。IMUL 可以更改为 LEA/ADD combo。

mov eax,[esi]
mov edx,eax
and edx,0x0000000F
mov ecx,eax
shr ecx,8
and ecx,0x0000000F
;;;imul ecx,10
lea ecx,[ecx+ecx*4]
add ecx,ecx
add edx,ecx
bswap eax
and eax,0x0000000F
;;;imul eax,100
lea eax,[eax+eax*4]
add eax,eax
lea eax,[eax+eax*4]
add eax,eax
add edx,eax
skip:

编辑

原题没有说输入范围是[0.00,1.00]。 事实上,给出的示例 (1.23) 位于此范围之外,因此我理解隐含了整个范围。这是我不再包含那些条件跳转的主要原因。

在 Pentium 133 上以实地址模式测试每个人的代码揭示了这些执行时间。

              sudhanshu bahuguna    Rudy Velthuis         user3144770
[0.00,9.99]   19.640 sec            18.921 sec            19.161 sec  
[0.00,1.00]   13.244 sec            11.460 sec            19.161 sec  

经过多次测试,我发现用众所周知的 LEA/ADD 组合替换 imul ecx,10 是非常有利可图的。另一方面,替换 imul eax,100 使事情变得更糟(大约相同的数量)。我意识到在有限的输入范围内,最后一个 jz skip 是至关重要的。所以我在两个答案中介绍了所有这些发现并得到了这些执行时间。

              sudhanshu bahuguna    Rudy Velthuis (2)     user3144770 (2)
[0.00,9.99]   19.640 sec            17.843 sec            17.364 sec  
[0.00,1.00]   13.244 sec            11.448 sec            12.035 sec  

仍然没有被这些结果所淹没,我想到了一个总是在 9.580 秒内执行的更快的解决方案。

movzx   eax, byte [esi+3]
add     eax,eax
lea     eax,[eax+eax*4-480]
add     al,[esi+1]
add     eax,eax
lea     eax,[eax+eax*4-480]
movzx   edx, byte [esi]
lea     edx,[eax+edx-48]