Matematikk 1000 Øvingsoppgaver i numerikk leksjon 4 Intervallhalveringsmetoden med mer Løsningsforslag Oppgave 1 Fakultetfunksjonen a) I forrige leksjon så vi hvordan vi kan bruke for-løkker til å utføre gjentatte addisjoner. Vi kan bruke den samme tankegangen til å utføre gjentatte multiplikasjoner. Funksjonen kan implementeres slik: 1 function F=Fakultet(n) 2 3 % Funksjon som regner ut n!, n-fakultet, for det naturlige tallet n 4 % Funksjonen tar bare skalarer som input. 5 6 % Begynner med å sette F til en 7 F=1; 8 for i=1:n 9 F=F*i; % Mulitipliserer med i med i fra 1 til og med n 10 end Vi lagrer den som Faktultet.m og tester den i kommandovinduet: >> Fakultet(1) 1 >> Fakultet(4) 1
24 >> Fakultet(10) 3628800 >> Fakultet(20) 2.4329e+18 n! blir tydeligvis ganske stor ganske fort. Funksjonen slik vi har implementert den nå gir faktisk rett svar for n = 0 også. Men dette er ikke så opplagt. Vi kan bruke if-satser til å tvinge funksjonen til å gi rett svar for n = 0. Vi kan også bruke if-satser til å presisere at argumentet ikke kan være negativt: 1 function F=FakultetV2(n) 2 3 % Funksjon som regner ut n!, n-fakultet, for det naturlige tallet n 4 % Funksjonen tar bare skalarer som input. 5 6 if n<0 7 disp('n kan ikke være negativ') 8 return 9 elseif n==0 10 F=1; 11 else 12 F=1; % Setter F til én 13 for i=1:n 14 F=F*i; % Mulitipliserer med i med i fra 1 til og med n 15 end 16 end Vi tester versjon 2 også: >> FakultetV2(-5) n kan ikke være negativ >> FakultetV2(0) 1 2
Figur 1: Plott av γ(x + 1) og n!. >> FakultetV2(4) 24 Vi kunne også brukt en if-sats for å gi ei feilmelding dersom man satte inn et ikke-heltallig argument. b) Når vi nå lager et plott, er det mer praktisk å bruke MATLABs egen fakultets-funksjon siden denne tar vektor-argumenter: >> x=0:1e-2:5; >> y=gamma(x+1); >> n=0:5; >> y2=factorial(n); >> plot(x,y,'linewidth',2) >> hold on >> plot(n,y2,'ro','linewidth',2) >> hold off >> set(gca,'fontsize',15) >> legend('\gamma(x+1)','n!') Resultatet er vist i gur 1. c) Vi plotter e x /γ(x + 1) fra 0 til 20: 3
Figur 2: Plot av grafen til e x /γ(x + 1). I plottet til høgre har vi zoomet inn på maksimalverdien til funksjonen. >> x=0:1e-2:20; >> y=exp(x)./gamma(x+1); >> plot(x,y,'linewidth',2) >> set(gca,'fontsize',15) Resultatet er vist i gur 2. Mye tyder på at brøken går mot null når x blir stor altså at γ-funksjonen vokser raskere enn eksponentialfunksjonen. Vi ser også at brøken er maksimal for x 2.2. Oppgave 2 Intevallhalveringsmetoden cos x. a) Selv om likninga ser ganske enkel ut, har vi ingen teknikker for å løse denne med papir og blyant. b) Vi plotter: >> x=0:1e-2:3; >> y1=sqrt(x); >> y2=cos(x); >> plot(x,y1,'linewidth',2) >> hold on >> plot(x,y2,'r','linewidth',2) >> grid on >> hold off >> set(gca,'fontsize',15) >> legend('sqrt(x)','cos(x)') Resultatet ser vi i gur 3. Det kan se ut som at løsninga skal ligge i nærheten av 0.65. 4
Figur 3: Plot av grafen til x og til cos x. I plottet til høgre har vi zoomet inn skjæringspunktet. c) Vi kan skrive likninga som x cos 0, eller f(x) = 0 der f(x) = x cos x. Vi ser at f(0) = 0 cos 0 = 1 < 0 og ( π ) π f = 2 2 cos π π 2 = 2 > 0. Altså har f(x) ulike fortegn for 0 og π/2. Siden f er kontinuerlig, må den krysse x-aksen (y = 0) for (minst) en eller annen verdi mellom 0 og π/2 1. d) Vi setter i gang (kommentarene er der bare for å forklare hva vi gjør, vanligvis har det ikke så mye for seg å kommentere kommandoer utført i kommandovinduet): >> a=0; % Bestemmer a >> b=pi/2; % Bestemmer b >> Fa=sqrt(a)-cos(a); % Funksjonsverdiene >> Fb=sqrt(b)-cos(b); >> Fa*Fb % Kontrollerer at f(a) og f(b) har ulike fortegn -1.2533 >> c=(a+b)/2; % Midtpunktet >> Fc=sqrt(c)-cos(c); % Funksjonsverdien i midpunktet >> Fa*Fc % Ser om f(a) og f(b) har samme fortegn 1 Denne sammenhengen kalles skjæringssetninga. 5
-0.1791 >> b=c; % Siden de ikke har det, setter vi ny b til å være c >> c=(a+b)/2; % Nytt midtpunkt og funksjonsverdi >> Fc=sqrt(c)-cos(c); >> Fa*Fc % Sjekker fortegnene igjen 0.2972 >> a=c; % Siden f(a) og f(c) har samme forteng, lar vi ny a vere c >> c=(a+b)/2; >> Fc=sqrt(c)-cos(c); >> Fa*Fc 0.0640 >> a=c; >> c=(a+b)/2; >> Fc=sqrt(c)-cos(c); >> Fa*Fc -0.0560 >> b=c; >> c=(a+b)/2 % Nå har vi gjort dette nok; vi regner ut sluttsvaret c = 0.6381 Når vi gjør mange gjentakelser på denne måten, er det viktig å bruke piltastene for alt de er verd. Men selv om vi gjør dette, blir dette fort ganske kjedelig... Etter å ha gjentat prosedyren re ganger, har vi kommet fram til det tinærma svaret x 0.6381. e) Vi velger å gjøre 10 iterasjoner i stedet for 4. Da får vi et mer nøyaktig svar. Metoden kan implementeres slik: 1 % Implementering av intervallhalveringsmetoden for likninga 2 % sqrt(x)-cos(x)=0 med a=0 og b=pi/2 som start-grenser 3 4 % Grenser 6
5 a=0; 6 b=pi/2; 7 8 % Funksjonsverdier 9 Fa=sqrt(a)-cos(a); 10 Fb=sqrt(b)-cos(b); 11 12 % Starter for-løkke som kjøres 10 ganger 13 for i=1:10 14 c=(a+b)/2; % Midtpunktet 15 Fc=sqrt(c)-cos(c); % Funksjonsverdi i midtpunktet 16 if Fa*Fc<0 17 b=c; % Setter ny b til c 18 else 19 a=c; % Setter ny a til c 20 end 21 end 22 23 % Regner ut nytt midtpunkt og skriver svaret til skjerm 24 x=(a+b)/2 Vi har kalt det IntervallHalvering.m. I kommandovinduet gir det følgende svar: >> IntervallHalvering 0.6420 Du må ikke bli for frustret om dette ikke går på første forsøk. Det er veldig vanlig å gjøre små feil, enten det er feil i logikken eller trykkfeil, som gjør at ting ikke fungerer med en gang. Når dette skjer, les feilmeldinga du får i MATLAB og se om du kan rette den opp. Vi plotter f(x) sammen med nullpunkts-kandidaten vår: >> xvektor=0:1e-2:3; >> fvektor=sqrt(xvektor)-cos(xvektor); >> plot(xvektor,fvektor,'linewidth',2) >> grid on >> hold on >> plot(x,0,'ro','linewidth',2) >> hold off >> set(gca,'fontsize',15) Som vi ser, gur 4, ser dette ut til å stemme ganske bra med den nøyaktigheten vi har i plottet. 7
Figur 4: Plott som viser f(x) = x cos x sammen med nullpunktet vi fant i oppgave 2e). f) I vårt skript skal altså linje 13 erstattes med while abs(b-a)>1e-3. Vi gjør det, og kjører skriptet igjen: >> IntervallHalvering 0.6416 Vi kk et noe annet svar. Selv om vi ikke vet om dette svaret er mer eller mindre nøyaktig enn det svaret vi kk i e), har dette svaret en klar fordel: Vi vet at feilen ikke er større enn 0.001. Eller, siden vi har regna ut midtpunktet mellom a- og b-verdiene vi kk til slutt, vet vi at feilen er mindre enn 0.0005. while-løkka har nemlig kjørt helt til intervallet [a, b] har bredden 0.001. Selvsagt kan vi sette dette tallet enda lavere og få et mer nøyaktig svar. Om vi endrer linja til while abs(b-a)>1e-5, får vi dette svaret: >> format long >> IntervallHalvering 0.641716294950902 Her har vi skrevet ut svaret vårt med litt ere desimaler. Dette poenget står ganske sentralt i kurset: Selv om vi bare nner en tilnærma løsning, 8
kan vi få løsninga til å være så nøyaktig som vi selv måtte ønske. Og da er det kanskje ikke så farlig at den ikke er eksakt... g) 2x 4 Vår nye f(x) blir altså f(x) = 2x x 4. Siden f(0) = 4 og f(4) = 2, og f er kontinuerlig, må f ha minst ett nullpunkt på intervallet [0, 4]. Vi justerer a og b tilsvarende i linje 5 og 6, og oppdaterer f(x) i linje 9, 10 og 15. I while-linja beholder vi nøyaktigheten 10 5. Med disse endringene blir skriptet vårt seende slik ut: 1 % Implementering av intervallhalveringsmetoden for likninga 2 % 2x-sqrt(x)-4=0 med a=0 og b=4 som start-grenser 3 4 % Grenser 5 a=0; 6 b=4; 7 8 % Funksjonsverdier 9 Fa=2*a-sqrt(a)-4; 10 Fb=2*b-sqrt(b)-4; 11 12 % Starter for-løkke som kjøres 10 ganger 13 %for i=1:10 14 while abs(b-a)>1e-5 15 c=(a+b)/2; % Midtpunktet 16 Fc=2*c-sqrt(c)-4; % Funksjonsverdi i midtpunktet 17 if Fa*Fc<0 18 b=c; % Setter ny b til c 19 else 20 a=c; % Setter ny a til c 21 end 22 end 23 24 % Regner ut nytt midtpunkt og skriver svaret til skjerm 25 x=(a+b)/2 Vi kjører skriptet og får (med mange desimaler) >> IntervallHalvering 2.843067169189453 Likninga kan løses eksakt. Det er en andregradslikning ikke i x men i 9
x. Om vi lar u = x, slik at u 2, får vi 2u 2 u 4 = 0 u = ( 1) ± ( 1) 2 c 2 ( 4) 2 2 1 + 33 4 ( 1 + ) 2 ( ) 2 33 1 + 33 = 4 16 = 1 ± 33 4 Vi har her benyttet oss av at x ikke kan være negativ. Vi sammenligner løsninga vår med det eksakte svaret: >> Eksakt=(1+sqrt(33))^2/16; >> x-eksakt -3.1616e-06 Feilen er alstå 3.16 10 6. Det må vel kunne sies å være godkjent. h) Vi lager ei funksjonsl som implementerer f(x). Vi kan godt velge å bruke den siste funksjonen, 2x x 4: 1 function f=funktilinthalv(x) 2 3 % Funksjon som vi skal finne nullpunktet til 4 % Blir brukt av skriptet IntervallHalvering 5 6 %f=sqrt(x)-cos(x); 7 f=2*x-sqrt(x)-4; Her ser vi også at vi har gamle-funsjonen, f(x) = x cos(x) på lur; det er fort gjort å kommentere inn denne og ut den andre (Ta bort prosenttegnet i linje 6 og sett det inn i linje 7). Vi kan nå referere til denne funksjonen i intervallhalverings-skriptet vårt (linje 12, 13 og 19): 1 % Implementering av intervallhalveringsmetoden for likninga 2 % FunkTilIntHalv(x)=0, der funksjonen er gitt i ei eiga 3 % Funksjonfil. a og b er start-grensene for metoden. 4 5 % Grenser 6 a=0; 7 b=4; 8 9 % Presisjon 10 Pres=1e-5; 10
11 12 % Funksjonsverdier 13 Fa=FunkTilIntHalv(a); 14 Fb=FunkTilIntHalv(b); 15 16 % Starter for-løkke som kjøres 10 ganger 17 %for i=1:10 18 while abs(b-a)>pres 19 c=(a+b)/2; % Midtpunktet 20 Fc=FunkTilIntHalv(c); % Funksjonsverdi i midtpunktet 21 if Fa*Fc<0 22 b=c; % Setter ny b til c 23 else 24 a=c; % Setter ny a til c 25 end 26 end 27 28 % Regner ut nytt midtpunkt og skriver svaret til skjerm 29 x=(a+b)/2 På den måten er det enklare å oppdatere skriptet når vi skal løyse andre likninger senere. Her har vi også denert presisjonen, Pres, i ei eiga linje (linje 9). Variabelen Pres dukkar opp igjen i while-linja (linje 17). 11