Numerisk differentiation og integration med Python En uformel prototype til en tutorial, Karl Bjarnason, maj 2010 Vi vil gerne lave et program som numerisk integrerer og differentierer funktionen f(x)=x 2 fra x=a til x=b med en præcision som svarer til den traditionelle single præcision i programmeringssprog som Fortran, Basic, Pascal, C, C++, Java og Python, altså ca. syv betydende cifre. Vi bruger Python til programmeringen af en række prototyper til programmet og Maxima (Command line Maxima) til at kontrollere resultaterne fra vores prototyper. Indsætte illustration af diff og integration, blyantstegning, som forklarer principperne, ingen detaljer!!! Princippet Det princip som vi vil bruge ved udregning af både differentialkvotienten og integralet er at dele intervallet op i mange små intervaller [x i, x i+1 ] hvor i [0 ; N 1] og N er antallet af delintervaller og udregne funktionsværdierne i begge ender af dette lille delinterval. Disse funktionsværdier og x-værdierne som definerer start og slut på delintervallet, altså a og b, kan vi så bruge til at udregne en tilnærmet værdi for hældningskoefficienten i, lad os sige højre side af delintervallet, samt det bidrag som dette delinterval giver til integralet. Og så inkrementerer (forøger med 1) vi index variablen i og laver det samme nummer for næste delinterval, indtil i = N. Det er altså vores plan. Indsætte koden til prototype 1...og en funktionstabel inkl Python programmet Differentiering For hvert delinterval, altså i den løkke (loop) som vi forudser at vi skal bruge i vores program, kan vi bestemme en tilnærmet værdi for hældningskoefficienten, lad os kalde den k i som forskellen på funktionsværdierne divideret med forskellen på de to x- værdier i delintervallets endepunkter. k i = f x i 1 f x i x i 1 x i hvor i [0 ; N 1] og N er antallet af delintervaller Disse tilnærmede værdier bliver lige så mange som antallet af delintervaller, altså N, og vi kunne inkludere dem i en funktionstabel og senere afbilde dem i en graf sammen med selve funktionen f(x). Grafisk kan man forestille sig at den linje som går i gennem de to punkter på funktionens graf, som bestemmes af delintervallens endepunkter og de tilhørende funktionsværdier, mere og mere vil nærme sig at ligge helt oven i en linje som er tangent til grafen i den ene eller anden ende på delintervallet. Ind s æ tt e ind s k a n n et bille d s o m illu str er er prin cip p et for diff er e nti erin g m e d d et alj er, ind e x e r o s v.
Inden vi går i gang med at impl vores første prototype, så lad os lige vurdere hvor store vi forventer at værdierne bliver... Integration For hvert delinterval kan vi bestemme intervallets bidrag til integralet som arealet, A i, på den søjle som er defineret af intervallets endepunkter, x i og x i+1, og deres funktionsværdier. Her er der bare desværre to valgmuligheder, -vi kan bruge enten funktionsværdien for x i eller x i+1. Vi vælger at bruge f(x i+1 ) og bidraget til arealet bliver således. deltaa i = f x i 1 x i 1 x i hvor i [0 ; N 1] og N er antallet af delintervaller Bidragene A i til det samlede areal, A, under funktionens graf bliver lige så mange som antallet af delintervaller, altså N, og vi opsummerer dem ved hjælp af en tildelingssætning (assignment statement) inde i løkken. Vi kan også inkludere dem i funktionstabellen. Ind s æ tt e ind s k a n n et bill e d s o m illu str er er prin cip p et for int e g ration m e d d et alj er, ind e x er o s v. Inden vi går i gang med vores første prototype til programmet, så lad os først bruge Maxima til at integrere funktionen og bestemme værdien af den bestemte integral fra 0 til 1. Maxima giver os altså resultatet 1/3, og det er nok analytisk korrekt, men lad os nu se efter ved at tegne funktionens graf på ternet papir og lave lidt købmandsregning på antallet af de små kvadrater. Og det ser ud for at der godt kan være omkring ca. 33 små kvadrater under kurven.
Indexering nogle observationer Vi har planlagt at vores indexvariabel, i, skal starte med værdien 0 og slutte med værdien N hvor N er antallet af delintervaller. Vi bemærker at den måde vi brugte indexerne i vores definition af formlerne til udregning af k i og A i betyder at: 1. den første x-værdi og derfor også den tilhørende y-værdi får index 0 og den sidste får index N. 2. den første k-værdi får indexnummeret 1, og den sidste får indexnummeret N. 3. den første deltaa-værdi får indexnummeret 1, og den sidste bliver nummer N. Præcision Vi vil kunne styre antallet af delintervaller fordi vi har en begrundet mistanke om at fejlen på vores tilnærmede værdier for differentialkvotienten, ki, og bidraget til integralet, Ai, vil aftage når delintervallerne bliver mindre. Praktisk får det altså ingen betydning når delintervallet bliver tilstrækkelig lille, -men hvor lille er så tilstrækkelig lille? I praksis for en ingeniør vil det oftest være nok at vi ved eller er ret så sikre på at vi kender svaret med et bestemt antal betydende ciffre, f.eks. fire eller måske i værste tilfælde syv (1,234 eller 1,234567), men for en matematiker så vil et svar med syv cifre normalt være intet værd, han eller hun vil nok helt enkelt kræve at delintervallet skal være uendelig lille, fordi så vil der nemlig være uendelig lille forskel på vores linje mellem [x i, f(x i )] og [x ii, f(x ii )] og tangenterne til funktionens graf i x i og x ii, de vil nemlig ligge oven i hinanden. Dette er jo meget fint, men det er bare det lille problem at det vil kræve at vores program arbejder uendelig længe med udregningerne, -altså helt ubrugeligt for vores lille øvelse i at lave et program til numerisk udregning af differentialkvotient og integral. Implementering af Prototype 01 Vi laver nu en hurtig prototype hvor vi implementer disse ideer, vel vidende at der bliver flere muligheder til at forbedre prototypen, både med hensyn til effektiviteten, kodens opbygning og navngivning af variabler mm.
Vores program giver 0.506 for integralet fra 0 til 1 for funktionen f(x)=x 2 når vi bruger 10 delintervaller, og Maxima giver 1/3. Kan det passe? Regner vores program forkert eller rigtigt? Kan du forklare i detaljer ved hjælp af en skitse hvorfor vores program giver dette resultat? Det kan være vigtigt til at forstå hvilke forbedringer kan laves på algoritmen. Men lad os første prøve at køre programmet igen, og nu med et langt større antal delintervaller, for eksempel 100.
Nu giver vores program resultatet 0.33835, hvilket styrker os meget i troen at vi er på ret vej! Vi laver nu lidt om på programmet således at det kun skriver en linie ud efter afslutning af udregningerne, og så kører vi programmet et antal gange med stadig mindre delintervaller. Resultaterne følger her.
Ved nærmere undersøgelse ser det ud for at vi har nu 6 ciffre rigtige i svaret for arealet, men delintervallet er så blevet kun 0.000001, altså en milionte del af intervallet fra 0 til 1, og det kræver altså 1000000 gennemløb af løkken til at udregnen værdien af vores lille intergral. Detta kan forbedres, men hvordan? Fortsættelse følger... mvh Karl PS: Dette dokument er lavet med OpenOffice Writer, Python, IDLE, IrfanView og Maxima alle programmer som er open source og gratis.