Skrivet av Alling:
Snyggt! Det förvånar mig inte att detta C-program är snabbare än den helt naiva Haskell-koden ovan, som är skriven helt utan prestanda i åtanke. Jag inkluderade prestandasiffran endast för att ge ett hum om hur stora filer det går att använda programmet på.
Några frågor som uppstår:
Hur lätt är respektive program att skriva, förstå och modifiera?
Hur lätt är det att försäkra sig om att respektive program gör precis det man vill?
Hur lätt är det att plocka ut delar ur respektive program och återanvända dem?
Hur viktig är exekveringstiden för det aktuella användningsområdet?
Svaren varierar förstås beroende på vem man frågar.
Hur lätt är respektive program att skriva, förstå och modifiera?
Här man skilja på "lätt" och "enkelt". För mig är det ju betydligt lättare att både skriva, förstå och modifiera C-programmet då jag inte programmerat Haswell på rätt många år och har aldrig varit bra på det. I fallet C (och C++) är det språk jag jobbat med i >20 år, inklusive jobbat med utveckling av deras standardbibliotek.
För just det här exemplet ser jag inte att något av språket ger ett enklare program.
Hur lätt är det att försäkra sig om att respektive program gör precis det man vill?
Även här finns två svar då det beror väldigt mycket på vad man menar.
C (och kanske än mer C++) ger dig som programmerar superkrafter utan att ge speciellt mycket i form av skyddsutrustning
Innan man lärt sig tygla dessa krafter, vilket man som människa i praktiken aldrig kommer lyckas med till 100 % då människor tappar fokus ibland och gör misstag, kommer saker gå fel, rejält fel!
Fast ändå lär du aldrig hittat något annat än program skrivna i just C (och inget annat än C, möjligen någon rad assembler!) i den typ av applikationer som under inga omständigheter får göra fel då fel i dessa miljöer ofta betyder stor ekonomisk skada eller stor skada/dödsfall av människa.
Enda sättet att med önskvärd nivå säkerställa att programmet är korrekt räcker det inte med att verifiera att programmet i sig är rätt, man måste verifiera att även kompilatorer, operativsystem etc är korrekt. I C finns här en väldigt stor fördel i att inget är implicit, finns massor med saker som är implicita i C++, Java, Haskell, JS vilket i normalfallet är väldigt trevligt då det underlättar men det skulle rejält öka kostnaden för att certifiera resultatet för korrekthet.
Det skrivet: ser noll anledning att skriva något utanför OS-kärnor och programvara avsedd för "safety critical" i C 2019. Framförallt givet hur hopplöst det är att hitta folk under 40-50 år som kan C
Hur lätt är det att plocka ut delar ur respektive program och återanvända dem?
Detta har rätt lite med val av programspråk att göra. Går att skapa big-ball-of-mud i alla språk och går att göra väldigt återanvändbara delar i ren assembler.
I "modern" C++ (C++11 och senare) finns stora skäl att hålla så stor andel som möjligt av sina funktioner "pure" då det ger kompilatorn långt fler möjligheter till riktigt coola optimeringar, bl.a. kommer dagens C++ kompilatorer evaluera de delar av ditt program där indata är känt vid kompilering och funktionen är "pure" direkt när man kompilerar. I ett större program betyder det att inte ens den bästa assembler guru matchar prestanda då inget är snabbare än kod som aldrig behöver köras (eller som i C++ fallet, redan körts).
Hur viktig är exekveringstiden för det aktuella användningsområdet?
Är en direkt funktion av:
hur många gånger kommer jag behöva köra programmet
med vilken frekvens kommer jag behöva köra programmet
hur stor är förväntat genomsnittlig indata
Är svaret "ofta+frekvent+väldigt stor" kommer prestanda vara den mest kritiska egenskapen. Men i många fall är det bättre att göra det som går fortast att skriva.
Målet är ju typiskt att minimera TOC.
Skrivet av Dalton Sleeper:
@Yoshman: Jag har för vana att skriva ++i i for-loopen, har dock inte koll på hur kompilatorn uppfattar detta jämfört med det "vanliga" viset nuförtin'. Skulle det kunna ge en fördel i detta program?
Med optimeringar påslagna så kvittar det helt om man kör ++i eller i++, blir samma resultat.
Du kan testa detta
int pre_inc(int i) {
++i;
return i;
}
int post_inc(int i) {
i++;
return i;
}
i compiler-explorer. På x86 blir det samma resultat vare sig man har optimeringar på eller ej
Att skriva ++it är typisk C++-ism (och det var en relevant optimering på 90-talet!). Men faktum är att moderna C++ kompilatorer fattar att optimera även det fallet när de ser att returvärdet inte används, detta blir också samma sak med optimeringar på
#include <vector>
void pre_inc(std::vector<int>::iterator &it) { ++it; }
void post_inc(std::vector<int>::iterator &it) { it++; }