sudhanshu bahuguna
sudhanshu bahuguna

Reputation: 45

Most efficient way to convert ASCII to Binary in x86 Assembly

I have a number stored in memory as ASCII and want to convert it to its binary value (multiplied by 100).

so 1.23 may be stored in memory in ASCII as 0x312E3233 and this should be converted to the binary value 123.

I currently have the following but is there a more efficient way?

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:

The ascii source is referenced by esi.

At the point of the label "skip", edx has the binary value.

Upvotes: 2

Views: 1781

Answers (2)

Sep Roland
Sep Roland

Reputation: 39166

It's best to not include those conditional jumps if the routine can work with zero values. BSWAP should be faster than 2 times shifting by 8. IMUL could be changed into 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:

EDIT

The original question never stated that the input range would be [0.00,1.00]. In fact the example given (1.23) lies outside this range and so I understood the full range was implied. That's the main reason that I no longer included those conditional jumps.

Testing everyone's codes on a Pentium 133 in real address mode revealed these execution times.

              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  

After several tests I found that replacing imul ecx,10 with the well-known LEA/ADD combo was very profitable. Replacing imul eax,100 on the other hand made things worse (by approximately the same amount). I realised that given a limited input range the last jz skip is crucial. So I introduced all these findings in both answers and got these execution times.

              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  

Still not overwhelmed by these results I conjured up a much faster solution that always executes in 9.580 sec.

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]

Upvotes: 2

Rudy Velthuis
Rudy Velthuis

Reputation: 28806

A few simple things could improve this a little. Get rid of the comparatively slow imul and use lea and add:

    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:

On modern processors, it probably doesn't make a huge difference, but it should still be noticeable.

Upvotes: 0

Related Questions