Wstawka asm w C++, program wyznaczający wartości funkcji danej funkcji dla przedziału od x = –4 do x = 15 z krokiem 0.1

0

Panowie, napotkałem na dość duży problem z programem asm zaimplementowanym do C++. Mianowicie, dostałem do napisania program wyznaczający wartości funkcji y= ax^3 – bx +sin(c*x) dla przedziału od x = –4 do x = 15 z krokiem 0.1; A wyniki zapisać do dwóch tablic (jedna tablica kod asm, druga kod w C++) na koniec wyświetlić i porównać wyniki. Program w C++ liczy i wyświetla a z asm nie mogę dojść do ładu, na tą chwilę wali błędami "Error 3 error C2415: improper operand type" dla linii mov esi, offset wynik2;. Bardzo was proszę o jakieś podpowiedzi.

Poniżej kod:

#include "stdafx.h"
#include <iostream>
#include <math.h>
using namespace std;

#define zakres (15-(-4))*10+1	//zakres [-4 do 15] z krokiem 0.1



int main()
{
	float x = 3;
	float a = 2;
	float b = 5;
	float c = 7;
	float wynik[zakres];
	float wynik2[zakres];
	int j = 0;
	float start = -4;
	float step = 0.1;


	for (int i = 0; i < zakres; i++)
	{
		x = -4 + i*0.1;
		wynik[i] = a*pow(x, 3) - b*x + sin(c*x);
	}

	__asm
	{
		mov esi, offset wynik2;	//adres tablicy do zmiennej tab
	petla:

		fld start;
		fild j;
		fld step;

		fmulp st(1), st(0);			//mnozymy st(1) razy st(0) wynik laduje do st(1) 
		faddp st(1), st(0);			//dodaj st(1) + st(0) wynik laduje do st(1) 
		fstp x;						//do x wynik
		fld a;						//na stos koprocesora 
		fld x;
		fld x;
		fld x;
		fmulp st(1), st(0);			//st(1) razy st(0) wynik laduje do st(1) 
		fmulp st(1), st(0);			//st(1) razy st(0) wynik laduje do st(1) 
		fmulp st(1), st(0);			//st(1) razy st(0) wynik laduje do st(1) 
		fld b;
		fld x;
		fmulp st(1), st(0);			//st(1) razy st(0) wynik laduje do st(1) 
		fsubp st(1), st(0);			//st(1) - st(0) wynik laduje do st(1) 	
		fld c;						//na stos koprocesora
		fld x;
		fmulp st(1), st(0);			//st(1) razy st(0) wynik laduje do st(1) 
		fsin;						//oblicz sinusa st(0) = sin(st(0))
		faddp st(1), st(0);			//dodaj st(1) + st(0) wynik do st(1) 
		fstp esi; 					//zapis wyniku do tablicy
		add esi, 4;					//zwiekszanie adresu o 4 przesuwajac sie na kolejna pole w tablicy
		inc j;						//zwikaszmay o 1 j
		cmp j, zakres;				//porownanie j z zakres
		jge koniec;					//gdy j >= zakres	to skacz do koniec
		jmp petla;					//skacz do petli w przeciwnym razie
	koniec:

	}
	cout << "WYNIK1      WYNIK2" << endl;
	for (int i = 0; i < zakres; i++)
	{
		cout << wynik[i] << "  " << wynik2[i] << endl;
	}
	system("Pause");
	return 0;
}


0

W 32-bitach kompilujesz?

0

Tak w 32 bitach

0

Daj tak:

lea esi, wynik2;
0

Racja, moja nie uwaga :) Dzięki. Pojawił mi się kolejny problem, którego nie mogłem dzisiaj zwalczyć.
Error 3 error C2415: improper operand type w linii fstp esi; zapisując wynik do tablicy.

1

Dawno nie pisałem w assemblerze, ale z tego co pamiętam, nie można ściągać wartości ze stosu FPU bezpośrednio do rejestrów CPU. Użyj zmiennej pomocniczej.

Chyba że chodzi Ci o coś takiego:

fstp dword ptr [esi]   ;lub qword jeśli double
0

Kolejna moja nieuwaga i prosty błąd, wystarczyło dodać nawias fstp [esi]; lub tak jak mówisz jakąś zmienną pomocniczą. Właśnie do tego doszedłem. Dzięki za pomoc.

1

Pouczające może być sprawdzenie, jaki kod generuje kompilator dla wersji w C++, np. Visual C++ 2015:

008D1009  fld         dword ptr [__real@3dcccccd (08D3148h)]  
008D100F  xor         eax,eax  
008D1011  fld         dword ptr [__real@40800000 (08D314Ch)]  
008D1017  fld         dword ptr [__real@40e00000 (08D3154h)]  
008D101D  fld         dword ptr [__real@40a00000 (08D3150h)]  
008D1023  mov         dword ptr [ebp-4],eax  
008D1026  fild        dword ptr [i]  
008D1029  fmul        st,st(4)  
008D102B  fsub        st,st(3)  
008D102D  fld         st(0)  
008D102F  fmul        st,st(3)  
008D1031  fsin  
008D1033  fld         st(1)  
008D1035  fadd        st,st(2)  
008D1037  fmul        st,st(2)  
008D1039  fmul        st,st(2)  
008D103B  fxch        st(2)  
008D103D  fmul        st,st(3)  
008D103F  fsubp       st(2),st  
008D1041  faddp       st(1),st  
008D1043  fstp        dword ptr wynik[eax*4]  
008D104A  inc         eax  
008D104B  mov         dword ptr [i],eax  
008D104E  cmp         eax,0BFh  
008D1053  jl          main+26h (08D1026h)

EDIT: zmieniłem pow(x,3) na x*x*x dla uniknięcia calla do funkcji bibliotecznej.

I dla porównania ten sam kod w wersji SSE2:

0138101D  xor         esi,esi  
0138101F  nop  
01381020  movd        xmm0,esi  
01381024  pshufd      xmm0,xmm0,0  
01381029  paddd       xmm0,xmmword ptr [__xmm@00000003000000020000000100000000 (01383160h)]  
01381031  cvtdq2ps    xmm2,xmm0  
01381034  mulps       xmm2,xmmword ptr [__xmm@3dcccccd3dcccccd3dcccccd3dcccccd (01383170h)]  
0138103B  subps       xmm2,xmmword ptr [__xmm@40800000408000004080000040800000 (01383190h)]  
01381042  movaps      xmm0,xmm2  
01381045  movaps      xmm1,xmm2  
01381048  mulps       xmm0,xmmword ptr [__xmm@40000000400000004000000040000000 (01383180h)]  
0138104F  mulps       xmm1,xmmword ptr [__xmm@40a0000040a0000040a0000040a00000 (013831A0h)]  
01381056  mulps       xmm0,xmm2  
01381059  mulps       xmm0,xmm2  
0138105C  mulps       xmm2,xmmword ptr [__xmm@40e0000040e0000040e0000040e00000 (013831B0h)]  
01381063  subps       xmm0,xmm1  
01381066  movaps      xmmword ptr [ebp-20h],xmm0  
0138106A  movaps      xmm0,xmm2  
0138106D  call        ___vdecl_sinf4 (01382060h)  
01381072  movaps      xmm1,xmmword ptr [ebp-20h]  
01381076  addps       xmm1,xmm0  
01381079  movups      xmmword ptr wynik[esi*4],xmm1  
01381081  add         esi,4  
01381084  cmp         esi,0BCh  
0138108A  jl          main+20h (01381020h)  
0138108C  cmp         esi,0BFh  
01381092  jge         main+0FFh (013810FFh)  
01381094  nop         dword ptr [eax]  
01381098  nop         dword ptr [eax+eax]  
013810A0  movd        xmm0,esi  
013810A4  cvtdq2ps    xmm0,xmm0  
013810A7  mulss       xmm0,dword ptr [__real@3dcccccd (01383148h)]  
013810AF  subss       xmm0,dword ptr [__real@40800000 (0138314Ch)]  
013810B7  movss       dword ptr [x],xmm0  
013810BC  mulss       xmm0,dword ptr [__real@40e00000 (01383154h)]  
013810C4  call        ___libm_sse2_sinf (01382B86h)  
013810C9  movss       xmm2,dword ptr [x]  
013810CE  movaps      xmm1,xmm2  
013810D1  addss       xmm1,xmm2  
013810D5  mulss       xmm1,xmm2  
013810D9  mulss       xmm1,xmm2  
013810DD  mulss       xmm2,dword ptr [__real@40a00000 (01383150h)]  
013810E5  subss       xmm1,xmm2  
013810E9  addss       xmm0,xmm1  
013810ED  movss       dword ptr wynik[esi*4],xmm0  
013810F6  inc         esi  
013810F7  cmp         esi,0BFh  
013810FD  jl          main+0A0h (013810A0h)
```
niestety, SSE2 chyba nie ma instrukcji do liczenia sinusa.

1 użytkowników online, w tym zalogowanych: 0, gości: 1