2015-01-27 2 views
2

숫자를 ASCII로 메모리에 저장하고 이진 값 (100을 곱한 값)으로 변환하려고합니다.ASCII를 ASCII에서 이진으로 변환하는 가장 효율적인 방법

그래서 1.23는 0x312E3233으로 ASCII에 메모리에 저장 될 수 있으며 이것은 내가 현재 다음했지만 더 효율적인 방법이 이진 값 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는 이진 값을 갖습니다.

+0

SSE2가 옵션이면 모든 숫자를 병렬로 곱셈 해 볼 수 있고 두 개의 수평 덧셈을 사용하여 모든 것을 합산 할 수 있다고 가정하십시오. 그게 더 효율적인지는 모르겠지만. 당신은 그것을 시도하고 약간의 측정을 할 수 있습니다. – Michael

+0

'실행 시간, 코드 크기, 우아함 측면에서 '더 효율적입니까? (단 하나의 선택 만 가능) –

+0

보다 효율적인 = 최소 실행 시간. –

답변

2

루틴이 0 값으로 작동 할 수있는 조건부 점프를 포함하지 않는 것이 가장 좋습니다. BSWAP는 2 배 이상 8 시프트해야합니다. IMUL을 LEA/ADD 콤보로 변경할 수 있습니다.

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)는이 범위를 벗어나므로 전체 범위가 암시되었음을 이해했습니다. 이것이 제가 조건부 점프를 더 이상 포함하지 않는 주된 이유입니다.

실제 주소 모드의 펜티엄 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와 imul ecx,10 교체/콤보를 ADD하는 것은 매우 수익성있는 것을 발견했다. 반면에 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 초안에 실행되는 훨씬 빠른 해결책을 고안했습니다.

+0

이 솔루션과 @Rudy Velthuis의 다른 제안을 벤치마킹했습니다. 8 천만 회 이상의 전환을 시도했습니다. 내 모든 코드뿐만 아니라 내 원래 코드도 서로 2 % 이내로 실행됩니다. 그리고 여러 번 달리자 수상자가 바뀌었다. 그래서 나는 모든 솔루션이 대체로 비슷하다고 생각합니다. 나는 내가 테스트 한 Core i5가 IMUL을 매우 빠르게 처리한다고 생각한다. IMUL 대 LEA 해킹은 아마 구형 x86 프로세서에서 작동합니다. 어쨌든 제안에 감사드립니다. –

+0

이론적으로 @ user3144770의 해결책은 더 빨리 실행되어야한다고 생각합니다. 그러나 입력이 0.00에서 1.00이고 상대 무작위이므로 값 1.00은 101 번에 한 번 이상 나타납니다. 위의 솔루션은 십진수 앞의 숫자를 무조건 처리하기 때문에 평균적으로 손실됩니다. –

+0

현재 제한된 입력 범위를 기반으로 내 대답을 편집했습니다! –

0

몇 가지 간단한 것들이 조금 향상시킬 수 있습니다. 비교적 느린 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: 

를, 아마 큰 차이를 만들하지 않지만, 여전히 눈에 띄는해야한다.

+0

첫 번째 * jz 건너 뛰기 *는 OP에 명시된대로 EDX를 제공하지 않습니다. (** "건너 뛰기"레이블의 지점에서 edx는 이진 값을가집니다 **) –

+0

Darn! 네가 옳아. 그 줄을 건너 뜁니다. 방금 ​​이동했는데 이제 제대로 작동합니다. –

+1

나는 그걸 들여다 보지 않았지만 어떻게 든 10 배의 첫 번째 곱셈이 ecx 대신에 eax를 곱하기 위해 사용될 수 있다는 ISTM 때문에 두 번째 곱셈은 다시 10에 불과합니다. –

관련 문제