2012-01-10 6 views
3

私はECXレジスタからsqrtを数えるためにHeronアルゴリズムを書こうとすると動作しません。結果は整数なので、問題は浮動小数点数を分割するようです。x86アセンブリで浮動小数点数を分割する方法は?

マイアルゴリズム:

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 
+0

ところで、FPUコードとSSEコードの両方に平方根の命令があります。だからあなたは本当にこれを必要としません.. – harold

+0

@harold、nasmアセンブリの平方根のための指示がありますか? CodeTableにはありません。あなたはそれを教えてくれますか? FSEコードの場合は –

+1

SSE2の場合はFSQRT(D9 FA)、SSE2の場合はSQRTSS(F3 0F 51/r)、SSE2の場合はSQRTSD(F2 0F 51/r)(4パック浮動小数点または2パック2倍パックもあります)。ここでは、より完全なリファレンスです:http://siyobik.info/main/reference/ – harold

答えて

5

DIVは、整数の除算のためである - あなたは浮動小数点(またはこの特定のケースではFIDIV可能性が高いためFDIVを必要とする、あなたは整数値で開始しているように見えるので、 )。

+0

私はDIV、FiDIV、またはFDIVに編集するときは動作しません。おそらく私はsth間違っています。確かに、それは裸で働くのですか? FFTCount32.S:188:エラー:オペコードとオペランドの組み合わせが無効 FFTCount32.S:192:エラー:オペコードとオペランドの組み合わせが無効 –

8

目的を達成するには、浮動小数点命令セットを使用する必要があります。あなたが役立つかもしれないいくつかの手順は以下のとおりです。

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:
ハロルドが指摘したように、計算命令もあります

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のインラインアセンブリ)です直接的に平方根、それはfsqrtです。オペランドと結果はともにst0です。

EDIT#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のバイトがありますメインメモリにロードして格納するときに使用します。もちろん、私が上で示唆したようにスタックを使用することは必須ではなく、実際にはあなたのデータセグメントや他の場所に定義された変数を持つこともできます。

EDIT#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 

あなたがfldfstのオペランドを逃しています。あなたのコメントを見て、あなたがfld [esp]fst [esp]を望んだとしたら、どうしてあなたはebpについて話しているのですか? ebpは、スタックフレームの先頭を保持することになっています(ここでは、多くのものが混乱してはいけません)一方、espは、その終わりを保持しています。基本的にスタックフレームの最後で動作したいのは、スタックフレームの後にはジャンクがないからです。誰も気にしません。
平方根を計算して保存した後は、最後にadd esp, 4にする必要があります。これは、push ecxsub esp, 4をフードの下に置いて、値を押し込むためのスペースを確保しています。値を保存するときにはまだ部屋が必要です。部屋が既にpushで作られているので、sub esp, 100add esp, 100を避けることもできます。
最後の1つの警告:整数と浮動小数点値は非常に異なる方法で表現されるため、両方の型を使用する必要がある場合は、選択した命令に注意してください。あなたが提案したコードは両方とも浮動小数点値で動作するfldfstを使用しているので、結果は期待どおりになりません。例? 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 
+0

整数のためのアノードレジスタと浮動小数点数があります。しかし、もし私がECXで整数値を持っていて、スタックを使わずにst0のECXから平方根を求めたいのであれば、どうしたらいいですか?スタックを使わなくても可能ですか? 私はこのようなSTHを試してみました: 'ECX \t FSQRT、MOV \t ECX、144 \t MOV \t ST0' しかし、それは:( –

+0

@MieszkoMikulski仕事doesntの:私の編集を参照してください:) – BlackBear

+0

はあなたの次の答えをいただき、ありがとうございます。私は初め、私の理解レベルは低いです。あなたの答えを読んだ後、私はこのようなコードを書く 'mov \t ecx、169;私は根元にある数字を \tサブ\t esp、100;私は自由空間のためにespを動かす。 \tプッシュ\t ecx;私はecxの値を保存する \tを加えて\t esp、4;プッシュは私のebpを移動し、その後私は戻ってくる必要があります \t fld \t;私はespからロードし、次にecxをロードする必要があります \t fsqrt \t; i sqrt it \t fst;私はebp + 100に保存します。 \t \t esp、100;私の意見では、私の意見では( ';'の後に)コメントに投稿するのと同じように動作するはずですが、それはありません。 –

4

今の私はあなたが整数の浮動小数点の平方根を取るようにしたいと仮定しますので、私は、あなたが実際に何をしたいのか全くわからないんだけど。

mov dword ptr[esp],ecx ; can't load a GRP onto the FPU stack, so go through mem 
fild dword ptr[esp]  ; read it back (as integer, converted to float) 
fsqrt     ; take the square root 

最初のdword ptrは、アセンブラによってはオプションです。

このコードの後、結果はFPUスタックST(0)の先頭にあります。私はあなたがint型にそれを丸めるとECXに戻ってそれを置きたい場合、私はこのことをお勧めします..あなたが後でそれをどうしたいのか分からない:

fistp dword ptr[esp]  ; again it can't go directly, it has to go through mem 
mov ecx,dword ptr[esp] 

私はSSE2にスローされます良い方法のための道:

cvtsi2sd xmm0,ecx ; convert int to double 
sqrtsd xmm0,xmm0 ; take the square root 
cvtsd2si ecx,xmm0 ; round back to int (cvttsd2si for truncate instead of round) 

これはちょっと簡単です。

関連する問題