Springen naar inhoud

Inline assembler functie expx() (moet in assembler)


  • Log in om te kunnen reageren

#1

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 01 januari 2008 - 20:11

Hallo iedereen

Ik heb net een functie geschreven en dan voer in in een console scherm de waarde 10 in en wat blijkt deze geeft als resultaat -1.#IND geen idee wat hier fout in mijn code zit heb het volgens de wiskundige regels gedaan

Dat is mijn code die ik heb geschreven:

//================================================================
// Berekend ExpX(x)
// ExpX(x) = 2 ^ (x * Log(e)
// We gebruiken 3 vrije registers ST(0), ST(1), ST(2)
//================================================================
extern double ExpX(double x)
{
	double temp;
	short MaskedCW;
	short SaveCW;
	_asm
	{
		FST x
		FLDL2E
		FMUL
		FSTCW MaskedCW				;
		FSTCW SaveCW
		OR BYTE PTR MaskedCW + 1, 1100b;
		FLDCW MaskedCW
		FLD ST(0)
		FLD ST(0)						
		FRNDINT						; bereken gehele deel
		FXCH						; verwissel de int waarden
		FSUB ST(0), ST(1)			; bereken frac deel
		F2XM1						; bereken 2 ^ frac(x) - 1
		FLD1
		FADD						; bereken 2 ^ frac(x)
		FXCH						; Ophalen van het gehele deel
		FLD1						; bereken 1 * 2 ^ int(x)
		FSCALE
		FSTP ST(1)					; haal de waarde van de stack ST(1) op
		FMUL						; bereken 2 ^ int(x) * 2 ^ frac(x)
		FLDCW SaveCW				; herstel de afrondingsmode
		FST temp
		FNINIT
	}
	return(temp);
}

Heeft iemand enig idee wat hier fout gaat heb ik ergens iets overscrhreven?

Dit forum kan gratis blijven vanwege banners als deze. Door te registeren zal de onderstaande banner overigens verdwijnen.

#2

Rogier

    Rogier


  • >5k berichten
  • 5679 berichten
  • VIP

Geplaatst op 02 januari 2008 - 22:48

Die eerste FST x lijkt me fout. Je slaat daar st(0) op in x, terwijl je juist andersom wilt. Oftewel, veranderen in FLD x.

En er zit ook een FLD ST(0) te veel in, je kopieert de waarde daar twee keer, terwijl je maar 1 kopie nodig hebt.
In theory, there's no difference between theory and practice. In practice, there is.

#3

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 03 januari 2008 - 09:57

Heb deze functie nu kunnen volledig kunnen oplossen met die expX() en werkt nu volledig, nu nogeens verder moeten we samen bekijken waarom die ArcCos() het nooit wilt doen, is mijn code wil juist van deze functie?

//========================================================================
// Berekend de boogcosinus van de ST(0) en plaatst het resultaat in de ST(0)
// Beschikbaar bereik is : -1 <= x <= +1
// ArcCos(x) = Atan(Sqrt(1 - x * x / ( x * x)))
//========================================================================
extern double ArcCos(double x)
{
	double temp = 0.0;
	double result = Deg2Rad(x);
	_asm
	{
		FLD result				; ST(0) := resukt
		FMUL					; ST(0) := result * result
		FLD ST(0)				; ST(0) := result ^ 2
		FLD1					; ST(0) := 1
		FSUBR					; ST(0) := 1 - (result ^ 2)
		FDIVR					; ST(0) := (1 - result ^ 2) / (result ^ 2)
		FSQRT					; ST(0) := SQRT((1 - result ^ 2) / (result ^ 2)
		FLD1					; ST(0) := 1
		FPATAN					; ST(0) := ArcTan
		FST temp				; temp := ST(0)
		FNINIT
	}
	return(temp);
}

Is ook men commentaar goed opgesteld dus verstaanbaar voor een andere programmeur?

#4

Rogier

    Rogier


  • >5k berichten
  • 5679 berichten
  • VIP

Geplaatst op 03 januari 2008 - 11:41

Bekijk dat andere topic nog eens, want de meeste fouten zijn daar ook al aan de orde gekomen:

1. FMUL fout in het begin (staat nog niets in ST(1), maak er FMUL ST(0),ST(0) van)

2. Deg2Rad in het begin is fout, x is geen graden of radialen (het is arccos, dus -1 :D x :D 1). De uitkomst is in radialen, dus je kunt desgewenst wel een Rad2Deg op het eind doen. In je commentaar bovenaan heb je het over "beschikbaar bereik", dat moet het domein zijn.

3. Wiskundig klopt het ook niet: LaTeX geldt alleen voor x>0. Voor x<0 is het antwoord fout, en voor x=0 krijg je zelfs een deling door nul (zie x^2 onder de streep) terwijl arccos(0) natuurlijk wel degelijk bestaat. Maar dat kun je gemakkelijk omzeilen, zie zometeen.

De enige juiste formule is LaTeX (wat gelijk is aan LaTeX ).
Nu krijg je hier een deling door nul als x=[plusmin]1, maar gelukkig zijn ze bij Intel zo vriendelijk geweest om de FPATAN instructie met een losse noemer en teller te laten werken. In plaats van zelf x door LaTeX te moeten delen, vervolgens 1 op de stack te zetten en daar dan de arctan van te nemen, kun je gewoon LaTeX en x apart houden (zonder te delen) en dan FPATAN doen.

Je commentaar lijkt me op zich ok, al blijft asm of FPU code altijd erg cryptisch. Bij FPU code vind ik het zelf wel handig om gewoon uit te schrijven wat er op de stack staat (niet alleen st(0)).
In theory, there's no difference between theory and practice. In practice, there is.

#5

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 03 januari 2008 - 22:43

waar zet ik die PI/2 in mijn code weet echt niet waar?

#6

Rogier

    Rogier


  • >5k berichten
  • 5679 berichten
  • VIP

Geplaatst op 04 januari 2008 - 11:27

waar zet ik die PI/2 in mijn code weet echt niet waar?

Maakt niet uit, als het resultaat maar pi/2-arctan is.
Je kunt in het begin PI/2 uitrekenen en op de stack laten staan, vervolgens de arctan uitrekenen en tenslotte verschil nemen met FSUB, of PI/2 aan het eind doen (terwijl arctan op de stack blijft) en dan FSUBR, resultaat is hetzelfde.
In theory, there's no difference between theory and practice. In practice, there is.

#7

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 06 januari 2008 - 14:11

Hallo Rogier

Kan jij eens bekijken als die functies wel juist zijn want ik krijg hier verkeerde resultaten van deze functies wiskundig zijn ze toch juist

//========================================================================
// Berekend de boogcotan van de ST(0) en plaatst het resultaat in de ST(0)
// x kan geen 0 worden
// ArcCot(x) = Atan(1/x)
//========================================================================
extern double ArcCot(double x)
{
	double temp = 0.0;
	_asm
	{
		FLD x					; ST(0) := result
		FLD1					; ST(0) := 1
		FXCH					; change ST(0) en ST(1)
		FSTP ST(0)				; pop 1 van de stack
		FPTAN					; ATan(ST(0) / ST(1)
		FST temp				; temp := ST(0)
		FNINIT
	}
	return(temp);
}

//========================================================================
// Berekend de boogCosSecant van de ST(0) en plaatst het resultaat in de ST(0)
// Absolute waarde van x abs(x) moet groter zijn dan 1
// ArcCsc(x) = ATan(sqrt(1 / (x * x - 1)))
//========================================================================
extern double ArcCsc(double x)
{
	double temp = 0.0;
	double result = Deg2Rad(x);
	_asm
	{
		FLD	result				; ST(0) := result
		FMUL					; ST(0) := result * result
		FLD1					; ST(0) := 1
		FSUB					; ST(0) := (result * result) - 1
		FLD1					; ST(0) := 1
		FDIVR					; ST(0) := 1 / (result * result) - 1
		FSQRT					; ST(0) := SQRT(1 / (result * result) - 1))
		FLD1					; ST(0) := 1
		FPATAN					; ST(0) := ATAN(SQRT(1 / (result * result) - 1))
		FST temp				; temp := ST(0)
		FNINIT
	}
	return(temp);
}

//========================================================================
// Berekend de boogSecan van de ST(0) en plaatst het resultaat in de ST(0)
// Absolute waarde van x abs(x) moet groter zijn dan 1
// ArcSec(x) = ATan(sqrt(x * x - 1))
//========================================================================
extern double ArcSec(double x)
{
	double temp = 0.0;
	double result = Deg2Rad(x);
	_asm
	{
		FLD	result				; ophalen van waarde x
		FMUL					; bereken x * x
		FLD1					; bereken (x * x) - 1
		FSUB					;
		FSQRT					; bereken sqrt((x * x) - 1))
		FLD1					;
		FPATAN					; bereken de arctan(sqrt(x * x) - 1)))
		FST temp				; opslaan in geheugenplaats
		FNINIT
	}
	return(temp);
}

#8

Rogier

    Rogier


  • >5k berichten
  • 5679 berichten
  • VIP

Geplaatst op 06 januari 2008 - 15:17

Stef31, begrijp je wel wat die instructies doen?

In die eerste functie stop je eerst twee getallen (x en 1) op de stack, vervolgens verwissel je ze (kon je ze net zo goed in omgekeerde volgorde erop zetten), vervolgens pop je x weer een van de stack af (waarom dan in de eerste plaats erop zetten), daarna doe je FPTAN maar je commentaar heb je het over atan (en het moet ook atan zijn lijkt me).

Probeer het eens zo: (x mag hier ook 0 zijn trouwens)
extern double ArcCot(double x)
{
  double result;
  _asm
  {
	FLD1	   ; 1
	FLD x	  ; x , 1
	FPATAN	 ; arctan(1/x)
	FSTP result; store result
  }
  return result;
}
Voor andere functies, zie eerdere opmerkingen.

Veranderd door Rogier, 06 januari 2008 - 15:19

In theory, there's no difference between theory and practice. In practice, there is.

#9

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 06 januari 2008 - 16:08

Maakt niet uit, als het resultaat maar pi/2-arctan is.
Je kunt in het begin PI/2 uitrekenen en op de stack laten staan, vervolgens de arctan uitrekenen en tenslotte verschil nemen met FSUB, of PI/2 aan het eind doen (terwijl arctan op de stack blijft) en dan FSUBR, resultaat is hetzelfde.


Kan jij eens zeggen waar ik dat in mijn code moet zetten lukt hier wel niet

extern double ArcCos(double x)
{
	double temp = 0.0;
	_asm
	{
		FLD x					; ST(0) := resukt
		FMUL					; ST(0) := result * result
		FLD ST(0)				; ST(0) := result ^ 2
		FLD1					; ST(0) := 1
		FSUBR					; ST(0) := 1 - (result ^ 2)
		FDIVR					; ST(0) := (1 - result ^ 2) / (result ^ 2)
		FSQRT					; ST(0) := SQRT((1 - result ^ 2) / (result ^ 2)
		FLD1					; ST(0) := 1
		FPATAN					; ST(0) := ArcTan
		FST temp				; temp := ST(0)
		FNINIT
	}
	return(temp);
}

#10

Rogier

    Rogier


  • >5k berichten
  • 5679 berichten
  • VIP

Geplaatst op 06 januari 2008 - 16:37

Zoals ik al zei, dat maakt dus niet uit, het kan helemaal in het begin, of op het eind na de FPATAN.

Voorbeeld:
extern double ArcCos(double x)
{
  double result;
  _asm
  {
	FLD x			; x
	FLD st(0)		; x , x
	FMUL st(0),st(0) ; x^2 , x (geen gewone FMUL want die tweede x moet daar blijven staan)
	FLD1			 ; 1 , x^2 , x
	FSUBR			; 1-x^2 , x
	FSQRT			; sqrt(1-x^2) , x
	FPATAN		   ; arctan( x / sqrt(1-x^2) )
	FLDPI			; pi , arctan
	FLD1			 ; 1 , pi , arctan
	FADD st(0),st(0) ; 2 , pi , arctan
	FDIV			 ; pi/2 , arctan
	FSUBR			; pi/2 - arctan
	FSTP result	  ; store result
  }  
  return(result); // eventueel: return Rad2Deg(result);
}
In theory, there's no difference between theory and practice. In practice, there is.

#11

Stef31

    Stef31


  • >250 berichten
  • 609 berichten
  • Ervaren gebruiker

Geplaatst op 06 januari 2008 - 16:37

Zijn die laatste twee functies hier juist want krijg steeds de verkeerde resultaten en met die ArcCos() loopt het nog steeds vast heb volgende gedaan:


extern double ArcCos(double x)
{
	double temp = 0.0;
	_asm
	{
		FLD x					; ST(0) := resukt
							   ; Ik doe dit
								FLDPI
							   ; maar waar / 2 ????
		FMUL					; ST(0) := result * result
		FLD ST(0)				; ST(0) := result ^ 2
		FLD1					; ST(0) := 1
		FSUBR					; ST(0) := 1 - (result ^ 2)
		FDIVR					; ST(0) := (1 - result ^ 2) / (result ^ 2)
		FSQRT					; ST(0) := SQRT((1 - result ^ 2) / (result ^ 2)
		FLD1					; ST(0) := 1
		FPATAN					; ST(0) := ArcTan
		FST temp				; temp := ST(0)
		FNINIT
	}
	return(temp);
}

//========================================================================

//========================================================================
// Berekend de boogCosSecant van de ST(0) en plaatst het resultaat in de ST(0)
// Absolute waarde van x abs(x) moet groter zijn dan 1
// ArcCsc(x) = ATan(sqrt(1 / (x * x - 1)))
//========================================================================
extern double ArcCsc(double x)
{
	double temp = 0.0;
	double result = Deg2Rad(x);
	_asm
	{
		FLD	result			; ST(0) := result
		FMUL				; ST(0) := result * result
		FLD1				; ST(0) := 1
		FSUB				; ST(0) := (result * result) - 1
		FLD1				; ST(0) := 1
		FDIVR				; ST(0) := 1 / (result * result) - 1
		FSQRT				; ST(0) := SQRT(1 / (result * result) - 1))
		FLD1				; ST(0) := 1
		FPATAN				; ST(0) := ATAN(SQRT(1 / (result * result) - 1))
		FST temp			; temp := ST(0)
		FNINIT
	}
	return(temp);
}

//========================================================================
// Berekend de boogSecan van de ST(0) en plaatst het resultaat in de ST(0)
// Absolute waarde van x abs(x) moet groter zijn dan 1
// ArcSec(x) = ATan(sqrt(x * x - 1))
//========================================================================
extern double ArcSec(double x)
{
	double temp = 0.0;
	double result = Deg2Rad(x);
	_asm
	{
		FLD	result			; ophalen van waarde x
		FMUL				; bereken x * x
		FLD1				; bereken (x * x) - 1
		FSUB				;
		FSQRT				; bereken sqrt((x * x) - 1))
		FLD1				;
		FPATAN				; bereken de arctan(sqrt(x * x) - 1)))
		FST temp			; opslaan in geheugenplaats
		FNINIT
	}
	return(temp);
}
[/quote]





0 gebruiker(s) lezen dit onderwerp

0 leden, 0 bezoekers, 0 anonieme gebruikers

Ook adverteren op onze website? Lees hier meer!

Gesponsorde vacatures

Vacatures