Inline assembler functie expx() (moet in assembler)

Moderators: jkien, Xilvo

Reageer
Berichten: 609

Inline assembler functie expx() (moet in assembler)

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:

Code: Selecteer alles

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

// 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?

Gebruikersavatar
Berichten: 5.679

Re: Inline assembler functie expx() (moet in assembler)

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.

Berichten: 609

Re: Inline assembler functie expx() (moet in assembler)

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?

Code: Selecteer alles

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

// 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?

Gebruikersavatar
Berichten: 5.679

Re: Inline assembler functie expx() (moet in assembler)

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:
\(\arccos(x)=\arctan\left(\sqrt{\frac{1-x^2}{x^2}}\right)\)
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
\(\arccos(x)=\frac{\pi}{2}-\arctan\left(\frac{x}{\sqrt{1-x^2}}\right)\)
(wat gelijk is aan
\(\frac{\pi}{2}-\arcsin(x)\)
).

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
\(\sqrt{1-x^2}\)
te moeten delen, vervolgens 1 op de stack te zetten en daar dan de arctan van te nemen, kun je gewoon
\(\sqrt{1-x^2}\)
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.

Berichten: 609

Re: Inline assembler functie expx() (moet in assembler)

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

Gebruikersavatar
Berichten: 5.679

Re: Inline assembler functie expx() (moet in assembler)

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.

Berichten: 609

Re: Inline assembler functie expx() (moet in assembler)

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

Code: Selecteer alles

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

// 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);

}

Gebruikersavatar
Berichten: 5.679

Re: Inline assembler functie expx() (moet in assembler)

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)

Code: Selecteer alles

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.
In theory, there's no difference between theory and practice. In practice, there is.

Berichten: 609

Re: Inline assembler functie expx() (moet in assembler)

Rogier schreef: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

Code: Selecteer alles

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);

}

Gebruikersavatar
Berichten: 5.679

Re: Inline assembler functie expx() (moet in assembler)

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

Voorbeeld:

Code: Selecteer alles

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.

Berichten: 609

Re: Inline assembler functie expx() (moet in assembler)

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:

Code: Selecteer alles

 

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);

}

Code: Selecteer alles

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

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

// 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]

Reageer