When i try to write Heron algorithm to count sqrt from ECX register, it doesn't work. It looks like the problem is dividing floating numbers, because the result is integer.
My algorithm:
sqrtecx:
MOV EDX, 10 ; loop count
MOV EAX, 5 ; x_0 in heron algorythm
MOV DWORD[EBP-100], ECX ; save INPUT (ecx is input)
MOV DWORD[EBP-104], EDX ; save loop count
jmp loop
MOV ECX, EAX ; move OUTPUT to ECX
loop:
MOV DWORD[EBP-104], EDX ; save loop count
xor edx, edx
MOV ECX, EAX
MOV EAX, DWORD[EBP-100]
DIV ECX
ADD EAX, ECX
XOR EDX, EDX
mov ecx, 2
DIV ecx
MOV EDX, DWORD[EBP-104] ; load loop count
DEC EDX
JNZ loop
You need to use the Floating Point Instruction Set to achieve your goal. Some instructions you might find useful are:
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 st1 by st0, then pop from reg stack (again, push the result in st0)
Here's a short example snippet (VS2010 inline assembly):
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)
}
EDIT:
As harold pointed out, there's also an instruction which computes directly the square root, it is fsqrt
. Both the operand and the result are st0
.
EDIT #2:
I wasn't sure if you really could load into st0
an immediate value as my reference doesn't specify if clearly. Therefore I did a small snippet to check and the result is:
float res = 5.0 * 3 - 1;
000313BE D9 05 A8 57 03 00 fld dword ptr [__real@41600000 (357A8h)]
000313C4 D9 5D F8 fstp dword ptr [res]
These are the bytes at 357A8h
:
__real@41600000:
000357A8 00 00 add byte ptr [eax],al
000357AA 60 pushad
000357AB 41 inc ecx
So I have to conclude that, unfortunately, you have to store your numbers somewhere in the main memory both when loading and storing them. Of course using the stack as I suggested above isn't mandatory, in fact you could also have some variables defined in your data segment or somewhere else.
EDIT #3:
Don't worry, assembly is a strong beast to beat ;) Regarding your code:
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
You're missing the operands of fld
and fst
. Looking at your comments I suppose you wanted fld [esp]
and fst [esp]
, I don't get why you're talking about ebp
though. ebp
is supposed to hold the beginning of the stack frame (where there's a lot of stuff which we shouldn't mess up with) whereas esp
holds the end of it. We basically want to operate at the end of the stack frame because after it there's just junk no one cares about.
You should also add esp, 4
at the end, after you computed and saved the square root. This because push ecx
does also sub esp, 4
under the hood to make room for the value you push and you still need some room when saving the value back. It's just for this that you can also avoid sub esp, 100
and add esp, 100
, because the room is already made for you by push
.
One last "warning": integers and floating point values are represented in very different ways, so when you know you have to use both types be careful about the instructions you choose. The code you suggested uses fld
and fst
, which both operate on floating point values, so the result you get won't be what you expect it to be. An example? 00 00 00 A9 is the byte representation on 169, but it represents the floating point number +2.3681944047089408e-0043 (for the fussy people out there it is actually a long double).
So, the final code is:
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