Effektiviteten hos en algoritm är en egenskap hos en algoritm som är relaterad till de beräkningsresurser som används av algoritmen. Algoritmen måste analyseras för att bestämma de resurser som behövs av algoritmen. Algoritmeffektivitet kan ses som analogt med produktionsprestanda för repetitiva eller kontinuerliga processer.
För att uppnå maximal effektivitet vill vi minska resursanvändningen. Olika resurser (som tid och minne) kan dock inte jämföras direkt, så vilken av de två algoritmerna som anses vara effektivare beror ofta på vilken faktor som är viktigast, såsom kravet på hög hastighet, minimal minnesanvändning eller annan åtgärd effektivitet.
Observera att den här artikeln INTE handlar om algoritmoptimering, vilket diskuteras i artiklarna programoptimering , optimering av kompilator , loopoptimering , objektkodsoptimerare och så vidare. Termen "optimering" i sig är missvisande, eftersom allt som kan göras faller under definitionen av "förbättring".Vikten av effektivitet med tonvikt på utförandetid betonades av Ada Lovelace 1843 om Charles Babbages Mechanical Analytical Engine :
”I nästan alla beräkningar är ett brett utbud av konfigurationer möjliga för att processen ska kunna slutföras framgångsrikt, och olika konventioner bör påverka valet för att utföra beräkningarna. Det väsentliga är valet av en konfiguration som kommer att leda till minimering av den tid som krävs för att utföra beräkningen” [1] .
Tidiga elektroniska datorer var mycket begränsade i både hastighet och minne. I vissa fall har man insett att det finns en avvägning mellan tidsminne , där en uppgift antingen måste använda en stor mängd minne för att uppnå hög hastighet, eller använda en långsammare algoritm som använder en liten mängd arbetsminne. I det här fallet användes den snabbaste algoritmen, för vilken det fanns tillräckligt med minne.
Moderna datorer är mycket snabbare än de tidiga datorerna och har mycket mer minne (gigabyte istället för kilobyte). Donald Knuth betonar dock att effektiviteten fortfarande är en viktig faktor:
"Inom etablerade ingenjörsdiscipliner är en förbättring på 12% lätt att uppnå, har aldrig ansetts upprörande, och jag tror att detsamma borde vara sant i programmering" [2]
En algoritm anses vara effektiv om resursen den förbrukar (eller kostnaden för resursen) är på eller under någon acceptabel nivå. Grovt sett betyder "acceptabelt" här "algoritmen kommer att köras under en rimlig tid på en tillgänglig dator". Eftersom det har skett en betydande ökning av datorkraft och tillgängligt minne för datorer sedan 1950-talet, var den befintliga "acceptabla nivån" inte acceptabel ens för 10 år sedan.
Datortillverkare släpper med jämna mellanrum nya modeller, ofta mer kraftfulla . Kostnaden för programvaran kan vara ganska hög, så i vissa fall är det lättare och billigare att få bättre prestanda genom att köpa en snabbare dator som är kompatibel med din befintliga dator.
Det finns många sätt att mäta resurserna som används av en algoritm. De två mest använda måtten är hastighet och använt minne. Andra mätningar kan inkludera överföringshastighet, tillfällig diskanvändning, långvarig diskanvändning, strömförbrukning, total ägandekostnad , svarstid på externa signaler och så vidare. Många av dessa mätningar beror på storleken på algoritmens indata (det vill säga de kvantiteter som behöver bearbetas). Mätningar kan också bero på hur data presenteras (till exempel fungerar vissa sorteringsalgoritmer inte bra på data som redan är sorterad eller när data sorteras i omvänd ordning).
I praktiken finns det andra faktorer som påverkar effektiviteten hos en algoritm, såsom den erforderliga noggrannheten och/eller robustheten. Som förklaras nedan kan sättet som en algoritm implementeras också ha en betydande effekt på den faktiska prestandan, även om många implementeringsaspekter är optimeringsfrågor.
I den teoretiska analysen av algoritmer är det vanligt att utvärdera komplexiteten hos en algoritm i dess asymptotiska beteende, det vill säga att återspegla komplexiteten hos en algoritm som en funktion av storleken på ingången n , den stora "O" -notationen används . Denna uppskattning är i allmänhet ganska korrekt för stort n , men kan leda till felaktiga slutsatser för små värden på n (till exempel kan bubbelsortering, som anses vara långsam, vara snabbare än "snabbsortering" om bara ett fåtal element behöver sorterad).
Några exempel på stor O- notation :
Beteckning | namn | Exempel |
---|---|---|
permanent | Avgöra om ett tal är jämnt eller udda. Använda en uppslagstabell av konstant storlek. Använd en lämplig hashfunktion för att välja ett element. | |
logaritmisk | Att hitta ett element i en sorterad array med binär sökning eller balanserat träd , precis som operationer på en binomial hög . | |
linjär | Att hitta ett element i en osorterad lista eller obalanserat träd (värsta fall). Tillägg av två n -bitars nummer med hjälp av carry through . | |
kvasilinjär , logaritmiskt linjär | Fast Fourier-transformationsberäkning , heapsort , quicksort ( bästa och genomsnittliga fall), mergesort | |
fyrkant | Multiplicera två n -siffriga tal med en enkel algoritm, bubbelsortering (sämsta fallet), skalsortering , snabbsortering (värsta fallet), urvalssortering , infogningssortering | |
exponentiell | Att hitta en (exakt) lösning på problemet med resande säljare med hjälp av dynamisk programmering . Avgöra om två booleska uttalanden är likvärdiga med hjälp av uttömmande sökning |
För nya versioner av programvara, eller för att ge jämförelser med konkurrerande system, används ibland riktmärken för att jämföra algoritmernas relativa prestanda. Om till exempel en ny sorteringsalgoritm släpps kan den jämföras med föregångare för att säkerställa att algoritmen är minst lika effektiv på känd data som de andra. Benchmarks kan användas av användare för att jämföra produkter från olika tillverkare för att utvärdera vilken produkt som bäst passar deras krav vad gäller funktionalitet och prestanda.
Vissa riktmärken ger ett sätt att jämföra olika kompilator- och tolkspråk, som Roy Longbottoms PC Benchmark Collection [3] och The Computer Language Benchmarks Game jämför prestandan för implementeringar av typiska uppgifter i vissa programmeringsspråk.
(Det är tillräckligt enkelt att skapa " hemgjorda " prestandatester för att få en uppfattning om den relativa prestandan för olika programmeringsspråk med hjälp av en uppsättning anpassade kriterier, som Christopher Covell-Shah gjorde i sin "Nine language Performance roundup") [ 4]
Implementeringsproblem kan också påverka faktiska prestanda. Detta inkluderar valet av programmeringsspråk och hur algoritmen faktiskt är kodad, valet av översättare för det valda språket eller kompilatoralternativ som används, och till och med vilket operativsystem som används. I vissa fall kan ett språk implementerat som tolk vara betydligt långsammare än ett språk implementerat som kompilator [5] .
Det finns andra faktorer som kan påverka tid eller minnesanvändning som är utom programmerarens kontroll. Detta inkluderar datajustering , granularitet sophämtning , parallellitet på instruktionsnivå och subrutinanrop .
Vissa processorer har förmågan att utföra vektoroperationer , vilket gör att en enda operation kan bearbeta flera operander. Det kan eller kanske inte är lätt att använda sådana funktioner på programmerings- eller kompileringsnivå. Algoritmer designade för seriell beräkning kan behöva göras om helt för att använda parallell beräkning .
Ett annat problem kan uppstå med kompatibiliteten hos processorer, där instruktioner kan implementeras annorlunda, så att instruktioner på vissa modeller kan vara relativt långsammare på andra modeller. Detta kan vara ett problem för en optimerande kompilator.
Måtten uttrycks vanligtvis som en funktion av ingångsstorleken n .
De två viktigaste måtten är:
För batteridrivna datorer (t.ex. bärbara datorer ) eller för mycket långa/stora beräkningar (t.ex. superdatorer ) är en annan typ av mätning av intresse:
I vissa fall behövs andra, mindre vanliga mätningar:
För algoritmanalys används vanligtvis algoritmtidskomplexitetsanalys för att uppskatta körtiden som en funktion av storleken på indata. Resultatet uttrycks vanligtvis i termer av "O" stort . Detta är användbart för att jämföra algoritmer, särskilt vid bearbetning av stora mängder data. Mer detaljerade uppskattningar behövs för att jämföra algoritmer när mängden data är liten (även om denna situation sannolikt inte kommer att orsaka problem). Algoritmer som involverar parallell beräkning kan vara svårare att analysera.
ÖvaJämförande tester av algoritmens gångtid används. Många programmeringsspråk innehåller funktioner som återspeglar CPU-användningstid. För långvariga algoritmer kan den förflutna tiden också vara av intresse. Resultaten i det allmänna fallet bör beräknas som ett medelvärde över en serie tester.
Denna typ av test kan vara mycket känslig för hårdvarukonfiguration och möjligheten för andra program att köras samtidigt i en multiprocessor- och multitasking- miljö.
Denna typ av tester beror också väsentligt på valet av programmeringsspråk, kompilator och dess alternativ, så att de jämförda algoritmerna måste implementeras under samma förutsättningar.
Detta avsnitt behandlar användningen av huvudminnet (ofta RAM) som krävs av algoritmen. Som med den temporala analysen ovan använder algoritmanalysen vanligtvis rymdkomplexitetsanalysen för algoritmen för att uppskatta det erforderliga körtidsminnet som en funktion av indatastorleken. Resultatet uttrycks vanligtvis i termer av "O" stort .
Det finns fyra aspekter av minnesanvändning:
Tidiga elektroniska datorer och hemdatorer hade relativt lite arbetsminne. Så 1949 hade EDSAC ett maximalt arbetsminne på 1024 17-bitars ord, och 1980 producerades Sinclair ZX80 med 1024 byte arbetsminne.
Moderna datorer kan ha en relativt stor mängd minne (kanske gigabyte), så att det krävs mindre för att komprimera minnet som används av en algoritm till en viss mängd minne än vad det brukade göra. Det är dock viktigt att det finns tre olika kategorier av minne:
En algoritm vars erforderliga minne passar in i datorns cache körs mycket snabbare än en algoritm som passar in i huvudminnet, vilket i sin tur kommer att vara mycket snabbare än en algoritm som använder virtuellt utrymme. Det komplicerade är det faktum att vissa system har upp till tre nivåer av cache. Olika system har olika mängder av dessa typer av minne, så effekten av minne på en algoritm kan variera avsevärt från ett system till ett annat.
I början av elektronisk datoranvändning, om en algoritm och dess data inte passade i huvudminnet, kunde den inte användas. Dessa dagar ger användningen av virtuellt minne enormt minne, men på bekostnad av prestanda. Om algoritmen och dess data passar i cachen kan mycket hög hastighet erhållas, så att minimera det nödvändiga minnet hjälper till att minimera tiden. En algoritm som inte passar helt i cachen, men säkerställer länklokalitet , kan köras relativt snabbt.
Program blir långsammare snabbare än datorer blir snabbare.
May säger:I utbredda system kan halvering av instruktionsexekveringen fördubbla batteritiden, och big data möjliggör bättre algoritmer: Att minska antalet operationer från N x N till N x log(N) har en stark effekt vid stort N... För N=30 miljarder, dessa förändringar liknar 50 år av tekniska förbättringar.
Följande tävlingar inbjuder dig att delta i utvecklingen av de bästa algoritmerna, vars kvalitetskriterier bestäms av domarna:
Programvara kvalitet | |||||
---|---|---|---|---|---|
Egenskaper |
| ||||
Standarder och rekommendationer |
| ||||
Processer och organisationer |
|