목표를 달성하려면 부동 소수점 명령어 세트를 사용해야합니다. 당신이 유용 할 수있는 몇 가지 방법은 다음과 같습니다 여기
fild <int> - loads and integer into st0 (not an immediate
faddp - adds st0 to st1, and pop from reg stack (i.e. result in st0)
fdivp - divides st0 by st1, then pop from reg stack (again, result in st0)
짧은 예를 조각 (VS2010 인라인 어셈블리)입니다 :
int main(void)
{
float res;
__asm {
push dword ptr 5; // fild needs a memory location, the trick is
fild [esp]; // to use the stack as a temp. storage
fild [esp]; // now st0 and st1 both contain (float) 5
add esp, 4; // better not screw up the stack
fadd st(0), st(0); // st0 = st0 + st0 = 10
fdivp st(1), st(0); // st0 = st1/st0 = 5/10 = 0.5
sub esp, 4; // again, let's make some room on the stack
fstp [esp]; // store the content of st0 into [esp]
pop eax; // get 0.5 off the stack
mov res, eax; // move it into res (main's local var)
add esp, 4; // preserve the stack
}
printf("res is %f", res); // write the result (0.5)
}
편집 :
해롤드가 지적한 바와 같이, 계산 명령도있다 직접 평방근은 fsqrt
입니다. 피연산자와 결과는 모두 st0
입니다.
편집 # 2 : 당신이 정말 명확 경우 reference 지정하지 않는 내로 st0
즉시 값으로로드 할 수있는 경우
나는 확실하지 않았다. 그러므로 나는 확인하기 위해 작은 조각을했고, 그 결과는 다음과 같습니다
[email protected]:
000357A8 00 00 add byte ptr [eax],al
000357AA 60 pushad
000357AB 41 inc ecx
그래서 내가 불행하게도, 당신이 어딘가에 당신의 번호를 저장해야, 그 결론을 내릴 필요가 :
float res = 5.0 * 3 - 1;
000313BE D9 05 A8 57 03 00 fld dword ptr [[email protected] (357A8h)]
000313C4 D9 5D F8 fstp dword ptr [res]
이들은 357A8h
의 바이트는 주 메모리에서로드 및 저장하는 경우. 물론 위에서 제안한대로 스택을 사용하는 것은 필수 사항은 아니며 사실 데이터 세그먼트 또는 다른 곳에 정의 된 변수가있을 수도 있습니다.
수정 # 3 :
어셈블리가 이길 수있는 강한 짐승, 걱정하지 마십시오) 코드에 대해서는 :
mov ecx, 169 ; the number with i wanna to root
sub esp, 100 ; i move esp for free space
push ecx ; i save value of ecx
add esp,4 ; push was move my ebp,then i must come back
fld ; i load from esp, then i should load ecx
fsqrt ; i sqrt it
fst ; i save it on ebp+100
add esp,100 ; back esp to ebp
당신은 fld
및 fst
의 피연산자를 놓치고있어. 귀하의 의견을 보면 내가 fld [esp]
과 fst [esp]
을 원한다고 생각하지만, 왜 당신이 ebp
에 대해 이야기하는지 알 수 없습니다. ebp
은 스택 프레임의 시작 부분을 잡아 두어야합니다 (많은 부분이 엉망이되어서는 안되는 반면). esp
은 그 끝을 가지고 있습니다. 우리는 기본적으로 스택 프레임의 끝에서 작동하기를 원합니다. 그 이후에는 그냥 아무 쓸모가 없기 때문입니다.
제곱근을 계산하고 저장 한 후에는 끝에 add esp, 4
도 입력해야합니다. 이는 push ecx
도 sub esp, 4
을 푸시 값으로 사용할 수있는 공간으로 만들기 때문에 값을 다시 저장할 때 여전히 약간의 공간이 필요합니다. 객실이 이미 push
으로 만들어져 있기 때문에 sub esp, 100
과 add esp, 100
을 피할 수 있습니다.
하나의 마지막 "경고": 정수와 부동 소수점 값은 매우 다른 방식으로 표현되므로 두 가지 유형을 사용해야하는 경우 선택할 지침에주의하십시오. 제안한 코드는 모두 부동 소수점 값에서 작동하는 fld
및 fst
을 사용하므로 결과가 예상 한 값과 다를 수 있습니다. 예를 들면? 00 00 00 A9는 169의 바이트 표현이지만 부동 소수점 수 + 2.3681944047089408e-0043을 나타냅니다 (까다로운 사람들에게는 실제로는 긴 이중입니다).
그래서 최종 코드는 다음과 같습니다 지금 당신이 정수의 부동 소수점 제곱근을 할 것으로 가정합니다 있도록
mov ecx, 169; // the number which we wanna root
push ecx; // save it on the stack
fild [esp]; // load into st0
fsqrt; // find the square root
fistp [esp]; // save it back on stack (as an integer)
// or fst [esp] for saving it as a float
pop ecx; // get it back in ecx
FPU 코드와 SSE 코드 모두 제곱근에 대한 지침이 있습니다. 그래서 당신은 정말로 이것을 필요로하지 않습니다 .. – harold
@harold, nasm assembly에서 제곱근에 대한 지시가 있습니까? CodeTable에이 코드가 없습니다. 그걸 말해 줄 수 있니? –
FPE 코드의 경우 FSQRT (D9 FA), SSE의 경우 SQRTSS (F3 0F 51/r) 및 SSE2의 경우 SQRTSD (F2 0F 51/r)입니다 (4 개의 부동 소수점 또는 2 개의 압축 복식을 사용하는 버전도 있음). 여기에 더 완전한 레퍼런스입니다 : http://siyobik.info/main/reference/ – harold