1 van 2

Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 10:26
door Stef31
Hallo iedereen

We hebben een opdracht gehad om functies te schrijven in assembler, bepaalde functies werken al maar deze functies werken echt niet heb echt verkeerde resultaten en heb al erg weinig kennis van die assembler want was ook veel zelfstudie met die FPU 8087 processorset.

Op deze functies namelijk ArcSin(), ArcCos(), TanX(), SH(x), CH(x) en de functies voor Exp2(x) geven zelfs verkeerde resultaten, en heb al een 4 tal uur zitten zoeken op die fout maar kan ze helaas niet vinden, we moeten wel dit project ingeven en we mogen van internet en forums gebruikmaken. Heeft hier iemand assembler kennis en mij kan helpen wat hier fout gaat in die stukjes code?

Hier zijn de codes die helemaal niet werken:

Code: Selecteer alles

extern double Exp2(double x)

{

double temp = 0.0;

short MaskedCW;

short SaveCW;

_asm

{

FLD x

; waarde van x ophalen

FSTCW MaskedCW

; 

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

}

// Werkt niet rond de waarde af

extern double TanX(double x)

{

double temp = 0.0;

double result = Deg2Rad(x);

_asm

{

FLD result	; sla de terugkeerwaarde op op de TOS

FPTAN		; bereken de Tan(x)

FST temp	; sla de terugkeerwaarde op op de TOS

FNINIT

}

return(temp);

}

extern double ArcSin(double x)

{

double temp = 0.0;

// double result = Deg2Rad(x);

_asm

{

FINIT

FLD x

FST ST(1)

FMUL

FST ST(1)

FLD1

FSUBR

FSQRT

FDIVR x

FST ST(1)

FLD1

; bereken de ArcTan

FPATAN

FST temp

; opslaan in de temp

}

return(temp);

}

extern double ArcCos(double x)

{

double temp = 0.0;

double result = Deg2Rad(x);

_asm

{

FLD result

FMUL

; berekend x * x

FLD ST(0)

; x * x op de TOS

FLD1

; bereken 1 - x^2

FSUBR

FDIVR

; bereken (1 - x^2) / (x^2)

FSQRT

; bereken sqrt(1 - x^2) / (x^2)

FLD1

; bereken de ArcTan

FPATAN

FST temp

; opslaan in de temp

FNINIT

}

return(temp);

}
Is niet de bedoeling mijn huiswerk te maken want heb dit wel zelf allemaal geschreven en gehaald uit de wiskunde maar het gaat mis als ik dat uitvoer met de computer waarom daar stel ik wel de vraag om

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:10
door Rogier
Let goed op wat die FPU instructies doen, sommige zijn niet helemaal intuïtief. Zo berekent FPTAN bijvoorbeeld niet alleen tan(st(0)) maar pusht vervolgens ook nog eens 1 op de stack (het achterliggende idee daarvan is dat een tan een verhoudingen tussen twee coordinaten 1:t representeert).

Dus hij rondt de waarde niet af, volgens mij krijg je altijd 1.0 terug uit jouw TanX functie. Zo moet ie wel werken: (let op de extra FSTP st(0) na de FPTAN)

Code: Selecteer alles

extern double TanX(double x)

{

  double temp = 0.0;

  double result = Deg2Rad(x);

  _asm

  {

FLD result ; sla de terugkeerwaarde op op de TOS

FPTAN	  ; bereken de Tan(x) en pusht 1

FSTP st(0) ; pop 1 van de stack (staat daar door fptan)

FST temp   ; sla de terugkeerwaarde op op de TOS

FNINIT

  }

  return(temp);

}
In jouw Exp2 functie vergeet je de oorspronkelijke status in SaveCW op te slaan, terwijl je hem daar op het eind wel weer uit restored. Zet voor of na FSTCW MaskedCW ook even FSTCW SaveCW, voor de rest moet die functie wel werken.

Die ArcSin functie van je is volgens mij in orde. Maar vergeet je niet dat je daar radialen in moet stoppen, omdat de Deg2Rad gecomment staat? (ik zou sowieso altijd overal met radialen werken, voorkomt verwarring en wiskundig gezien slaat 360 graden in een cirkel nergens op).

Je ArcCos functie lijkt te zijn gebaseerd op
\(\arccos(x) = \arctan(\frac{x^2}{\sqrt{1-x^2}})\)
maar die gelijkheid klopt niet. Moet zijn:
\(\arccos(x) = \frac{1}{2}\pi-\arctan(\frac{x}{\sqrt{1-x^2}})\)
. Tevens vergeet je in het begin om st(0) te kopiëren (op het moment dat je FMUL doet om x*x te berekenen staat er nog niets in st(1), vergelijk met ArcSin) dus waarschijnlijk geeft die functie nu een exception.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:24
door Stef31
Ik heb eerst in ArcSin toch die functie gebruikt om graden om te zetten in radialen maar krijg toch een foutief resultaat hoor en wat moet ik aanpassen in de code voor mijn ArcCos() ?

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:42
door Rogier
Ik heb eerst in ArcSin toch die functie gebruikt om graden om te zetten in radialen maar krijg toch een foutief resultaat hoor
Je gebruikt twee keer x in die functie. Als je toch graden i.p.v. radialen wilt gebriuken moet je die functie ont-commenten en op beide plekken x vervangen door result.
en wat moet ik aanpassen in de code voor mijn ArcCos() ?
Nou,
\(\arccos(x) = \frac{1}{2}\pi-\arctan(\frac{x}{\sqrt{1-x^2}}) = \frac{1}{2}\pi-\arcsin(x)\)
Dus je kunt het makkelijkste gewoon de code van ArcSin kopiëren en daar die
\(\frac{1}{2}\pi-\)
bij proppen.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:44
door Stef31
Ik heb mijn code aangepast :

Code: Selecteer alles

extern double ArcSin(double x)

{

double temp = 0.0;

double result = Deg2Rad(x);

_asm

{

FLD result

FMUL

; berekend x * x

FLD ST(0)

; x * x op de TOS

FLD1

; bereken 1 - x^2

FSUBR

FDIV

; bereken x^2 / (1 - x^2)

FSQRT

; bereken sqrt(x^2) / (1 - x^2)

FLD1

; bereken de ArcTan

FPATAN

FST temp

; opslaan in de temp

FNINIT

}

return(temp);

}

Geen idee waar ik dat moet bij proppen

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:52
door Rogier
Ik heb mijn code aangepast :
Bijna goed nu, je maakt alleen nog die fmul fout in het begin. Oftewel een FST ST(1) voor de FMUL, ofwel er FMUL st(0),st(0) van maken.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 12:55
door Stef31
Waarom moet dat er zo staan "FST ST(1)" wat is de functie daarvan als je dat in commentaar schrijft?

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 13:01
door Rogier
Waarom moet dat er zo staan "FST ST(1)" wat is de functie daarvan als je dat in commentaar schrijft?
st(0) kopiëren naar st(1), dat deed je zelf toch ook al in je oorspronkelijke ArcSin functie? Of weet je zelf niet meer wat je daar hebt uitgespookt :D

Maar FMUL st(0),st(0) is misschien duidelijker.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 13:24
door Stef31
Ja inderdaad weet wat het doet je je vermenigvuldigd de inhoud die op de stack op index 0 staat met zichzelf en plaatst het terug in de stack met index 0

Dan nog een vraagje:

Hoe los je dit op ik wil van de ene assembler routine een functie aanroepen naar een andere maar met een call gaat dit verkeerd hoe kan je oplossen?

Voorbeeld:

=======

Code: Selecteer alles

extern double Exp2(double x)

{

double temp = 0.0;

short MaskedCW;

short SaveCW;

_asm

{

FLD x

; waarde van x ophalen

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

extern double Exp10(double x)

{

double temp;

short MaskedCW;

short SaveCW;

_asm

{

FLD x

; waarde van x ophalen

FLDL2T

; zet de Log(10) op de stack

FMUL

; berekend x * Log(10)

; CALL Exp2

; berekend 2 ^ x * Log(10)

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

// Aanroep van de functie Exp2

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

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

}
Hallo Rogier of andere programmeurs

Mijn ArcCos() heeft nog steeds verkeerde resultaten en vind die fout nergens heb het nu zo aangepast:

Code: Selecteer alles

extern double ArcCos(double x)

{

double temp = 0.0;

double result = Deg2Rad(x);

_asm

{

FLD result

FMUL

; berekend x * x

FLD ST(0)

; x * x op de TOS

FLD1

; bereken 1 - x^2

FSUBR

FDIVR

; bereken (1 - x^2) / (x^2)

FSQRT

; bereken sqrt(1 - x^2) / (x^2)

FLD1

; bereken de ArcTan

FPATAN

FST temp

; opslaan in de temp

FNINIT

}

return(temp);

}

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 14:14
door Rogier
Hoe los je dit op ik wil van de ene assembler routine een functie aanroepen naar een andere maar met een call gaat dit verkeerd hoe kan je oplossen?
Hangt van je compiler af, en met name de calling conventies die die compiler gebruikt. Die bepalen o.a. hoe en in welke volgorde de argumenten worden meegegeven, zou bijvoorbeeld kunnen dat je compiler om te optimizen float of double argumenten meteen in de FPU meegeeft. Om functies vanuit asm aan te roepen moet je denk ik iets van __declspec(naked) gebruiken, zie ook.
Mijn ArcCos() heeft nog steeds verkeerde resultaten en vind die fout nergens heb het nu zo aangepast:
Je doet nu nog hetzelfde als bij ArcSin hierboven (inclusief weer die FMUL fout), alleen met FDIVR in plaats van FDIV. Da's niet correct, je moet het FPATAN resultaat van \(\frac{1}{2}\pi\) aftrekken om het gewenste resultaat (arccos) te krijgen.

Wat betreft de wiskunde die ermee gemoeid is:
\(\arctan(\frac{x}{\sqrt{1-x^2}})\)
is niet hetzelfde als
\(\arctan(\sqrt{\frac{x^2}{1-x^2}})\)
(let op negatieve x) en
\(\arctan(\frac{\sqrt{1-x^2}{x}})\)
is ook niet hetzelfde als
\(\frac{1}{2}\pi-\arctan(\frac{x}{\sqrt{1-x^2}})\)
(let wederom op negatieve x). Voor positieve x zouden die twee wel kloppen, maar ik neem aan dat het voor iedere x moet werken.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: wo 26 dec 2007, 14:32
door Rogier
Sorry, foutje in latex en mag nu m'n bericht niet meer wijzigen... onderste zin moest zijn:

Wat betreft de wiskunde die ermee gemoeid is:
\(\arctan\left(\frac{x}{\sqrt{1-x^2}}\right)\)
is niet hetzelfde als
\(\arctan\left(\sqrt{\frac{x^2}{1-x^2}}\right)\)
(let op negatieve x), en
\(\arctan\left(\frac{\sqrt{1-x^2}}{x}\right)\)
is ook niet hetzelfde als
\(\frac{1}{2}\pi-\arctan\left(\frac{x}{\sqrt{1-x^2}}\right)\)
(let wederom op negatieve x). Voor positieve x zouden die twee wel kloppen, maar ik neem aan dat het voor iedere x moet werken.

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: di 01 jan 2008, 17:35
door Stef31
Hallo iedereen

Kan mij eens iemand vertellen wat er juist gebeurt of hoe kan je dat best voorstellen visueel want we moeten onze code ook gaan uitleggen?

Code: Selecteer alles

FLD result

; ST := result

FPTAN

; ST := Tan(x)

FSTP ST(0)

; pop 1 van de stack

FST temp

; sla de terugkeerwaarde op op de TOS

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: di 01 jan 2008, 18:23
door Stef31
Hallo iedereen

Bij de functie ArcSin voer ik 60 in en deze geeft een raar resultaat en op de rekenmachine is het wel juist hoe kan ik dat oplossen?

Code: Selecteer alles

extern double ArcSin(double x)

{

double temp = 0.0;

double result = Deg2Rad(x);

_asm

{

FLD result

FST ST(1)

FMUL

; berekend x * x

FLD ST(0)

; x * x op de TOS

FLD1

; bereken 1 - x^2

FSUBR

FDIV

; bereken x^2 / (1 - x^2)

FSQRT

; bereken sqrt(x^2) / (1 - x^2)

FLD1

; bereken de ArcTan

FPATAN

FST temp

; opslaan in de temp

FNINIT

}

return(temp);

}
Voor de rest werkt mijn code maar bij 60° gaat het goed mis geen idee wat het is

Kan iemand mij dat eens zeggen en oplossen wat er mis gaat

Ik heb zelfde probleem met TanH(x) deze geeft ook een verkeerd resultaat af

hier is mijn code

Code: Selecteer alles

extern double TanH(double x)

{

double MCX = 0.0;

double MSX = 0.0;

double temp = 0.0;

// double result = Deg2Rad(x);

MCX = CosH(x);

MSX = SinH(x);

_asm

{

FLD MCX

; load MCX := CosH(x) => ST(0)

FLD MSX

; load MSX := SinH(x) => ST(1)

FDIVR

; ST(0) := SinH(x) / CosH(x)

FST temp

; mem[temp] := SinH(x) / CosH(x)

FNINIT

; init FPU registers

}

return(temp);

}

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: di 01 jan 2008, 18:51
door Safe
Je werkt toch in radialen!

Re: Opdracht digitale technieken schrijven assembler functies samen met c++ code

Geplaatst: di 01 jan 2008, 19:57
door Stef31
Neen de gebruiker kan graden invoeren en wordt intern omgezet naar radialen