Optimeringar är en utmanande fråga. I detta exempel matas mm:ss in i ett fält och skall omvandlas till 100-delar i sekunder för att mottagande system behöver detta format. Frågan är - hur skulle ni skriva denna kod så optimerat som möjligt? Indata är mm:ss, utdata är m,ss. Jag vet inte om den är optimerad, men lite snabare kanske den är: Ska den göra rätt också? Ja, den skall göra rätt också :) . 2 decimaler max. Hur kommer indatan se ut. "mm:ss" betyder för mig att det alltid kommer vara två siffror som beskriver både minuter och sekunder. tex 05:08. I så fall behövs inte LastIndexOf(':') utan man kan alltid sätta positionen till 2. Andreas (och min innan jag såg hans) som använder heltal räknar fel på en del tider också. Tex 02:34 "avrundas" felaktigt till 2,56 som bör vara 2,57. Om man profilerar dom olika förslagen, så är Pelles förslag sämst, sen följer Daniels variation av Andreas förslag, och snabbast hittills verkar den här varianten vara: Här har du en riktigt långsam, men med mindre kod: Jonas är den ända som ger rätt resultat på tider som ska avrundas uppåt. <b>Jonas är den ända som ger rätt resultat på tider som ska avrundas uppåt. </b> Ok, den här borde väl ge korrekt resultat (och är fortfarande snabbast enligt mina test..) Jag har jämfört mot Simons funktion som helt klart var snabb. Jag har ett nytt alternativ vilket förutsätter korrekt input M:SS där SS är tvåsiffrig och inte överstiger 59: Edit: jahapp...Andreas var på samma spår och var visst några minuter före :) Jävlar, min kod har nog samma "fel" som Jonas. Nu har jag testat lite med Environment.TickCount som Erik nämner. Min var visst ordentligt långsam :) Ställer mig lite vid sidan av tråden och skäms... Jahapp där ser man. Daniels är marginellt snabbare än min, däremot är din Andreas dubbelt och inte långt ifrån tredubbelt snabbare, så ja, Parse/ToString är inge vidare, Split inte heller (Substring inte lika farligt btw) Ännu snabbare är att förbereda alla 3600 kombinationer av värden som strängar från Låter troligt att det är snabbare, men som sagt, hur mycket är det värt att optimera? Först måste jag säga att givetvis var inte min kod snabbast - då hade ni ju inte kunnat briljera som ni gjort här med undersökningar, tester och energi. Bra jobbat! Jag tror att många kan vara intresserade av såna här typer av frågeställningar. Just i mitt fall så behövs ingen optimerad rutin, men betänk att det hade lika gärna kunnat vara en omräkning på 1 miljon poster och då hade varenda millisekund räknats som dyrbar. <b>Har någon tid så kan ni ju även omsätta en sån här tråd till en artikel vilket är både nyttigt och lärorikt.</b> > Men som sagt.. tänker/vill nån annan göra det, så säg bara till... En fråga bara: misstänker att det där är för liten snutt för att unmanaged/assembler ska ha nån större betydelse... ok.. har börjat lite smått, men "don't hold your breath" :-) Var några veckor sen, har du kommit någonstans? <b>Var några veckor sen, har du kommit någonstans?</b>Konvertera ett värde till timmar, minuter och sekunder
Exempel:
string varde = ConvertMinSekToHundreds("2:36")
varde = "2,60"
Och funktionen:
public string ConvertMinSekToHundreds(string thetime) {
char[] sep = {':'};
Array tmp = thetime.Split(sep);
string min = "";
decimal s = 0;
decimal sec = 0;
if (tmp.Length >0) {
min = tmp.GetValue(0).ToString() ;
s = Convert.ToDecimal(tmp.GetValue(1).ToString());
sec = (s * 100)/60; //sec = (s /60d) * 100d;
} else {
return "0,0";
}
return min + ',' + sec.ToString();
}
Sv: Optimerad funktion - någon som kan bättre?
public string ConvertMinSekToHundreds(string thetime)
{
int pos = thetime.LastIndexOf(':');
if (pos != -1)
{
int s = int.Parse(thetime.Substring(pos+1));
int sec = (s * 100) / 60; //sec = (s /60d) * 100d;
return thetime.Substring(0, pos) + ',' + sec.ToString();
}
else
{
return "0,0";
}
}
Jag antar att LastIndexOf är snabbare en split, då en splitt inte vet hur många värden som finns. Borde ge den lite over head.
Jag antar oxå att Substring() är relativt snabb. Alokera minne för strängen, kopiera över text.
Heltal borde vara snabbare än decimal.
Att anropa toString() på en sträng är ju helt onödigt.
Om ett kollon(:) saknas behöver ju inga variabler deklareras eller tilldelas.
Tilldelar inga defaultvärden då det är onödigtm men detta borde kanske kompilatorn optimera bort.
Sv: Optimerad funktion - någon som kan bättre?
Om man skickar in 2:01 får man inget roligt resultat:
2,1,6666666666666666666666666667
/johan/Sv:Optimerad funktion - någon som kan bättre?
Sv: Optimerad funktion - någon som kan bättre?
Min lösning blev ganska precis som Andreas därför postar jag inte den. Men man behöver inte två int för sekunderna.
int s = int.Parse(thetime.Substring(pos+1));
int sec = (s * 100) / 60;
---------
int s = int.Parse(thetime.Substring(pos+1));
s = (s * 100) / 60;
Sv: Optimerad funktion - någon som kan bättre?
EDIT: metoden skall naturligtvis vara statisk...
public static string ConvertMinSekToHundreds(string thetime)
{
int pos = thetime.LastIndexOf(':');
if (pos != -1)
{
int s = int.Parse(thetime.Substring(pos + 1));
s = (s * 100) / 60;
return thetime.Substring(0, pos) + "," + s.ToString();
}
else
{
return "0,0";
}
}
Sv: Optimerad funktion - någon som kan bättre?
<code>
public static string ConvertMinSekToHundreds(string t)
{
DateTime d = DateTime.Parse((t.ToString().Contains(":") ? "00:" : "00:00:") + t);
return string.Format("{0:00},{1:00}", d.Minute, d.Second * 1.67);
}
</code>Sv:Optimerad funktion - någon som kan bättre?
Har ni något som kan mäta tiden som en metod kör eller är det gissningar och antagande ni gjort tidigare tråden?Sv: Optimerad funktion - någon som kan bättre?
Jasså, care to give an example..?
<b>Har ni något som kan mäta tiden som en metod kör eller är det gissningar och antagande ni gjort tidigare tråden?</b>
Jag har åtminstone använt profilern som finns i VS (>= team edition developer)Sv: Optimerad funktion - någon som kan bättre?
public static string ConvertMinSekToHundreds(string thetime)
{
int pos = thetime.LastIndexOf(':');
if (pos != -1)
{
int s = int.Parse(thetime.Substring(pos + 1));
s = (s * 100 + 30) / 60;
return thetime.Substring(0, pos) + "," + s.ToString();
}
else
{
return "0,0";
}
}
Här är lite rådata, 99999 anrop, enhet ms
<code>
Function Incl children
Pelle 255.6 1032.4
Jonas 188.7 1291.5
Simon 123.4 372.1
</code>
Sv: Optimerad funktion - någon som kan bättre?
Testning gjordes med GetTickCount() i C och Environment.TickCount i C#. TickCount sparades före och efter funktionens start resp slut. Differensen mellan StartCount och EndCount är de värden jag redovisar.
En miljon iterationer av koden tog ca 750ms på min dator. Bara för att testa skrev jag samma sak i C, och med string.h var C-versionen endast några få millisekunder snabbare. Troligtvis skulle detta gå att förbättra en hel del med intelligentare minneshantering, precis som C# gör.
Efter lite optimering fick jag dock ner C-versionen på ca 250ms, vilket är 3 ggr så snabbt som i C#.
Jag kan lova att den optimerade versionen inte hade direkt hög läsbarhet, men den var snabb iallafall.
Om du hör till de människor som översätter mellan olika tidsformat miljarder gånger per dag kan sån här optimering vara intressant. I övrigt känns det som det är bättre att satsa på läsbar kod samt att lära sig en profiler för att identifiera hotspots som faktiskt lämpar sig för optimering.Sv: Optimerad funktion - någon som kan bättre?
private static char[] minutesAsDecimal = new char[] {
'0', '0', // 0
'0', '1', // 1
'0', '3', // 2
'0', '5', // 3
'0', '6', // 4
'0', '8', // 5
'1', '0', // 6
'1', '1', // 7
'1', '3', // 8
'1', '5', // 9
'1', '6', //10
'1', '8', //11
'2', '0', //12
'2', '1', //13
'2', '3', //14
'2', '5', //15
'2', '6', //16
'2', '8', //17
'3', '0', //18
'3', '1', //19
'3', '3', //20
'3', '5', //21
'3', '6', //22
'3', '8', //23
'4', '0', //24
'4', '1', //25
'4', '3', //26
'4', '5', //27
'4', '6', //28
'4', '8', //29
'5', '0', //30
'5', '1', //31
'5', '3', //32
'5', '5', //33
'5', '6', //34
'5', '8', //35
'6', '0', //36
'6', '1', //37
'6', '3', //38
'6', '5', //39
'6', '6', //40
'6', '8', //41
'7', '0', //42
'7', '1', //43
'7', '3', //44
'7', '5', //45
'7', '6', //46
'7', '8', //47
'8', '0', //48
'8', '1', //49
'8', '3', //50
'8', '5', //51
'8', '6', //52
'8', '8', //53
'9', '0', //54
'9', '1', //55
'9', '3', //56
'9', '5', //57
'9', '6', //58
'9', '8', //59
};
static public string ConvertMinSekToHundreds(string thetime)
{
char[] data = thetime.ToCharArray();
int length = data.Length;
int s = (data[length-2]*10) + data[length-1] - 528;
s *= 2;
data[length - 1] = minutesAsDecimal[s + 1];
data[length - 2] = minutesAsDecimal[s];
data[length - 3] = ',';
return new string(data);
}
Vet inte om den är snabbare. Men jag tror den borde vara det.
Vill man avrunda upåt så är det bara att uppdatera arrayen. Vill bara visa principen.
Finns risk att den är lite långsamare än något man kan göra i C. Just för att man arbetar med objekt.
Sv: Optimerad funktion - någon som kan bättre?
Nu har jag fått till en ny version som är lite olik de andra.
Den är optimerad med tanka på tid och inte minne och bör vara aningen snabbare än Simons.
private static int[] lut = {0, 2, 3, 5, 7, 8, 10,
12, 13, 15, 17, 18, 20,
22, 23, 25, 27, 28, 30,
32, 33, 35, 37, 38, 40,
42, 43, 45, 47, 48, 50,
52, 53, 55, 57, 58, 60,
62, 63, 65, 67, 68, 70,
72, 73, 75, 77, 78, 80,
82, 83, 85, 87, 88, 90,
92, 93, 95, 97, 98};
public static string ConvertMinSekToHundreds(string thetime)
{
int pos = thetime.LastIndexOf(':');
if (pos == -1)
return "0,00";
return thetime.Substring(0, pos) + ',' + lut[int.Parse(thetime.Substring(pos + 1))];
}
Hittade även en bugg i Jonas version också. Den ger fel värden på sekunderna om de skrivs med en nolla först. 15:05 ger 15,08 vilket borde vara 15,8.
Sv:Optimerad funktion - någon som kan bättre?
Men jag kan inte förstå hur fem minuter bör vara 0,8.
5 minuter (0,08) är ju mindre än 48 minuter (0,8).
Frågan är om man tjänar något på att optimera bort split() och int.Parse() och toString().Sv: Optimerad funktion - någon som kan bättre?
Andreas och Jonas: glöm det jag skrev om felet i Jonas funktion. Jag vet inte hur jag tänkte och jag tror det betyder att min räknar fel nu. Sv: Optimerad funktion - någon som kan bättre?
(Sen är det ju en annan femma hur mycket det är värt att optimera..)
Andreas
System.String..ctor(char[]) 99999 37.102189 37.102189 37.102189 37.102189
System.String.ToCharArray() 99999 14.424489 14.424489 14.424489 14.424489
Daniel
System.String.Concat(object,object,object) 99999 103.406767 103.406767 103.406767 103.406767
System.Int32.Parse(string) 99999 41.113222 41.113222 41.113222 41.113222
System.String.LastIndexOf(char) 99999 19.465046 19.465046 19.465046 19.465046
System.String.Substring(int32) 99999 15.921165 15.921165 15.921165 15.921165
System.String.Substring(int32,int32) 99999 15.425451 15.425451 15.425451 15.425451
Simon
System.String.Substring(int32) 99999 63.405950 63.405950 63.405950 63.405950
System.Int32.Parse(string) 99999 43.684979 43.684979 43.684979 43.684979
System.Int32.ToString() 99999 40.745828 40.745828 40.745828 40.745828
System.String.Substring(int32,int32) 99999 35.071989 35.071989 35.071989 35.071989
System.String.Concat(string,string,string) 99999 32.616640 32.616640 32.616640 32.616640
System.String.LastIndexOf(char) 99999 12.709621 12.709621 12.709621 12.709621
Daniel 2 (se nedan)
System.String.Substring(int32,int32) 99999 39.863986 39.863986 39.863986 39.863986
System.Int32.Parse(string) 99999 37.033350 37.033350 37.033350 37.033350
System.String.Concat(string,string,string) 99999 22.287204 22.287204 22.287204 22.287204
System.String.Substring(int32) 99999 18.941672 18.941672 18.941672 18.941672
System.String.LastIndexOf(char) 99999 14.520839 14.520839 14.520839 14.520839
Baserat på profileringen av Daniels kod testade jag med följande: (som Daniel2 ovan)
private static string[] lut2 = {"0", "2", "3", "5", "7", "8", "10",
"12", "13", "15", "17", "18", "20",
"22", "23", "25", "27", "28", "30",
"32", "33", "35", "37", "38", "40",
"42", "43", "45", "47", "48", "50",
"52", "53", "55", "57", "58", "60",
"62", "63", "65", "67", "68", "70",
"72", "73", "75", "77", "78", "80",
"82", "83", "85", "87", "88", "90",
"92", "93", "95", "97", "98"};
public static string Daniel2ConvertMinSekToHundreds(string thetime)
{
int pos = thetime.LastIndexOf(':');
if (pos == -1)
return "0,00";
return thetime.Substring(0, pos) + "," + lut2[int.Parse(thetime.Substring(pos + 1))];
}
Sv: Optimerad funktion - någon som kan bättre?
"00:00" till "59:59" i en Hashtable och sedan slå upp i den.
Jag får ca 125 ms på en miljon iterationer.Sv:Optimerad funktion - någon som kan bättre?
Den koden är något tråkig att skriva och sedan felsöka om man töntat till det hela..Sv: Optimerad funktion - någon som kan bättre?
Bra utredning och bra jobbat. Skicka gärna in flera liknande diskussioner så kanske vi kan ha ett forum som heter nåt i stil med just kodoptimering eller liknande där vi kan påvisa dessa stora differanser.
Har någon tid så kan ni ju även omsätta en sån här tråd till en artikel vilket är både nyttigt och lärorikt.
//PelleSv:Optimerad funktion - någon som kan bättre?
Jag kan nog göra det, dock skulle det vara bättre att i så fall använda sej av nån fri/gratis profiler (om nån sån finns), iom att "kundkretsen" är något liten om det krävs >= Team Edition Developer av Visual Studio, dessutom har antagligen denna lilla kundkrets redan koll på detta område?
Men som sagt.. tänker/vill nån annan göra det, så säg bara till...Sv: Optimerad funktion - någon som kan bättre?
Oavsett vem som skriver så vill jag läsa :PSv: Optimerad funktion - någon som kan bättre?
Är det nån som har nån uppfattning vilken prestandaförbättring man skulle
kunna uppnå om man använder sig av ( unmanaged code / assembler ) i
detta fall?Sv:Optimerad funktion - någon som kan bättre?
Sv: Optimerad funktion - någon som kan bättre?
Sv:Optimerad funktion - någon som kan bättre?
Jag skrev en annan nu som verkar fungera ganska bra.
static void Main(string[] args)
{
int x = 510;
string y = ConvertToTime(x);
Console.WriteLine("x är {0} och konverterat är värdet {1}", x, y);
}
static string ConvertToTime(int TotalSeconds)
{
int Hours, Seconds, Minutes;
Hours = TotalSeconds / 3600;
TotalSeconds -= Hours * 3600;
Minutes = (TotalSeconds / 60);
Seconds = TotalSeconds - Minutes * 60;
return Minutes.ToString().PadLeft(2, '0') + ":" + Seconds.ToString().PadLeft(2, '0');
}
Sv: Optimerad funktion - någon som kan bättre?
Angående artikeln menar du?
Jo har nog kommit en bra bit, men har ett par grejer jag vill ha med ännu. Tyvärr har jag inte hunnit/orkat skriva den klar, men förhoppningsvis "den som väntar på något gott..." :-D