ik heb weer een vraag over programmeren, ditmaal is het onderwerp: 'nulpuntsbepaling'
Hier de opdracht
zo komt het eruit te zien als je waarden hebt ingevuld (in mijn uitwerking zijn een aantal formules anders.):Programma-opzet
Schrijf een programma dat een nulpunt van een functie benadert.
De gebruiker geeft de functie op door er één te kiezen uit een lijstje dat het programma geeft, en gebruiker geeft twee getallen a en b die voldoen aan de volgende voorwaarden:
• a<b
• de functie moet continu zijn op het interval [a,b]?? Hoe kun je dit invullen?
• ( f(a)<0 en f(b)>0) of (f(a)>0 en f(b)<0), kort gezegd: f(a) en f(b) zijn verschillend van teken.
De gebruiker kiest ook een maximale afwijking ε, in principe een getal dicht bij 0; ε spreek je uit als ‘epsilon’, de Griekse letter e, waarmee wordt genoteerd welke fout je ergens in maakt.
Het programma benadert het nulpunt x0, of één van de nulpunten als er meerdere tussen a en b liggen. De benadering is zodanig nauwkeurig dat . Het getal ε geeft aan hoeveel f(x0) naar boven of naar beneden van 0 mag afwijken. De gebruiker moet een ε >0 opgeven, want anders kan de computer geen x0 vinden die voldoet aan .
Als niet aan alle voorwaarden is voldaan, dan geeft de computer een melding aan de gebruiker.
Als wel aan de voorwaarden is voldaan, ligt er een nulpunt tussen a en b, en gaat de computer een nulpunt ertussen zoeken met het volgende algoritme.
Het bisectie-algoritme
Er zijn vele algoritmes voor een nulpuntsbenadering. Eén daarvan is de bisectie-methode, ofwel halveringsmethode. Het is de eenvoudigste methode voor nulpuntbenadering, al is het niet de meest efficiënte (dat betekent: andere methoden kunnen dezelfde nauwkeurigheid in minder rekentijd bereiken). De halveringsmethode bestaat uit stappen, waarbij in elke stap het interval [a,b] waarin het gezochte nulpunt kan liggen gehalveerd wordt. Dat gaat als volgt:
Het gemiddelde van a en b noemen we m, dus . Als , dan hebben we een goede benadering (namelijk m) van het nulpunt gevonden. Zo niet, dan kijk je of het nulpunt tussen a en m ligt, of tussen m en b. Daartoe pas je één van de intervalgrenzen a en b aan, zodat je verder gaat zoeken tussen a en m, of tussen m en b, afhankelijk van waar het nulpunt moet liggen. Je hebt het zoekinterval nu gehalveerd (vandaar de naam ‘halveringsmethode’). Herhaal de halvering van het interval totdat (ofwel zo lang als ). Na afloop is m de benadering van het nulpunt.
Voorbeeld.
Gegeven is de functie . De gebruiker geeft op: a=1 en b=2.
Dat voldoet aan de voorwaarden: f is een continue functie, f(1) = -1 en f(2) = 2, en zijn dus verschillend van teken. Er ligt dus een nulpunt in het interval [1,2]; je kunt eenvoudig narekenen dat dit nulpunt is, want , maar we kijken nu hoe je dit nulpunt met het bisectie-algoritme zou benaderen.
Stap 1 De computer berekent , en vervolgens f(1,5) = 0,25.
Omdat f(1) en f(1,5) een verschillend teken hebben, ligt er een nulpunt tussen 1 en 1,5.
Het nieuwe zoekinterval wordt [1; 1,5].
Stap 2 De computer berekent en f(1,25) = -0,4375.
Omdat f(1,25) en f(1,5) een verschillend teken hebben, ligt er een nulpunt tussen 1,25 en 1,5, dus het nieuwe zoekinterval wordt [1,25; 1,5].
Enzovoort, totdat de waarde van f(m) klein genoeg is. Zie onderstaande voorbeelduitvoer.
en dit is een voorbeeld hoe je het programma kan gaan uitwerken
Eerste fase
Gebruik in deze fase steeds dezelfde functie f, bijvoorbeeld uit het voorbeeld; zet de hele berekening in de event-handler Button1Click.
Declareer f als functie in je programma, dus met als kopregel:
function f (x: real): real;
begin { hier komt de berekening van f}
end;
Bij de berekeningen in het bisectie-algoritme roep je dus de functie f aan met f(a), f(m), etc.
Tip: het bisectie-algoritme bevat een herhaling, waarin tenminste één stap moet worden uitgevoerd, want je moet minstens één keer m en f(m) berekenen, voordat de conclusie kan zijn dat het nulpunt gevonden is. Bij een dergelijk soort herhaling past heel goed het ‘repeat…until’ statement.
Neem een Memoveld op waarin je de tussenstappen laat zetten, zoals in het voorbeeld.
Je krijgt mooie uitvoer als je aan het begin de kopregel in het Memo laat zetten met:
Memo1.Clear;
Memo1.Lines.Add (' a ' +
' m ' +
' b ')
De waarden van a, b, etc, krijg je mooi op het scherm met:
Memo1.Lines.Add ( Format('%10.6f',[a]) + ' '
+ Format('%10.6f',[m]) + ' '
+ Format('%10.6f',));
Zelf even aanvullen met de functiewaarden.
Als je programma niet goed werkt, dan kun je met de uitvoer van deze waarden nagaan wat er mis gaat.
Tweede fase
Als het bisectie-algoritme goed werkt, dan breid je het programma uit en verander je het, zodat de gebruiker een functie kan kiezen uit een stuk of tien. Bedenk zelf een aantal geschikte van zo veel mogelijk verschillende soort.
De gebruiker selecteert de functie uit een listbox waarin de functievoorschriften met strings staan. In de functie f bereken je het functieresultaat, waarbij afhankelijk van de waarde van Listbox1.Itemindex het juiste voorschrift wordt gebruikt om het functieresultaat te berekenen. In de functie f hangt het gebruikte functievoorschrift dus af van de waarde van Listbox1.Itemindex. Hiervoor heb je een keuzestatement nodig, en omdat er uit een tiental varianten gekozen moet worden, is een case-statement erg geschikt.
Verwijs binnen de declaratie van f naar Itemindex met Form1.Listbox1.Itemindex, want zonder Form1 ervoor is Listbox1 een onbekende component.
Ik heb hier de hele opdracht neergezet, zodat jullie begrijpen waar het over gaat. Mijn vraag gaat maar over een deel van de opdracht.
ik zal gelijk even laten zien wat mijn uitwerking hiervan is
Code: Selecteer alles
Function f (x:real):real;
begin
case form1.ListBox1.itemindex of
0: {formule (x^2)-2}
begin
result:=(power(x,2)-2 );
end;
1: {formule (3*x)-1}
begin
result:= ((3*x)-1);
end;
2: {formule x^3+x^2+x+1}
begin
result:= (power(x,3)+ power(x,2)+x+1);
end;
3: {formule x^2-4x+7}
begin
result:= (power(x,2)-(4*x)+7);
end;
end;
End;
procedure TForm1.BerekenClick(Sender: TObject);
var a,b,m,ya,yb,ym,nulpunt,e: real;
begin
e:= StrToFloat(edit3.text); {maximale afwijking}
a:= StrToFloat(edit1.text);
b:= StrToFloat(edit2.Text);
m:= ((a+b)/2);
ya:= f(a); {aanroepen van de functie}
yb:= f(b);
ym:= f(m);
{berekening nulpunt}
repeat
m:= ((a+b)/2);
ym:= f(m);
if ym>0 then
b:=m
else a:=m;
until (ym<e);
nulpunt:= m;
{uitvoer}
{tussenstappen toevoegen in de memo}
Memo1.Clear;
Memo1.Lines.Add (' a ' + ' m '
+ ' b ' + ' f(a) '
+ ' f(m) ' + ' f(b) ');
Memo1.Lines.Add ( Format('%7.6f',[a]) + ' '
+ Format('%7.6f',[m]) + ' '
+ Format('%7.6f',[b]) + ' '
+ Format('%7.6f',[f(a)]) + ' '
+ Format('%7.6f',[f(m)]) + ' '
+ Format('%7.6f',[f(b)]));
if (a<b) then
edit4.text:= FloatToStr(nulpunt)
else
Showmessage ('vul juiste waarden a en b in');
end;
end.
Omdat je steeds weer verschillende waardes van a en b krijgt (de ene stap voor b en de andere stap weer voor a), omdat het interval verandert. Maar ik weet niet zo goed hoe je dat invult, zodat je in de memo, alle tussenstappen krijgt te zien.
Nu ik dit zo heb ingevuld, krijg ik ook maar één tussenstap te zien en een verkeerd nulpunt.
Wat doe ik verkeerd??