Autor Beitrag
AXMD
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: So 20.04.08 17:28 
Hallo!

Ich arbeite momentan an einem Programm, das oft (mehrmals pro Sekunde) Zahlen formatieren muss, um genau zu sein soll eine Anzahl Bytes in einen String mit 3 Nachkommastellen konvertiert werden und die Präfixe K, M, G,... etc. angehängt werden. Folgenden Code habe ich bisher:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
        public static string FormatBytes(long Bytes)
        {
            //Remark: does not use float arithmetic and may be slightly inaccurate, but a lot faster
            if (Bytes < 0)
                return "?";
            char[] Prefixes = { 'K''M''G''T''P''E' }; //Zeta (Z, 70 bits) cannot be displayed with 64 bit
            int Prefix = -1;
            long TempBytes = Bytes;
            while ((TempBytes = (TempBytes >> 10)) != 0//One prefix for every 10 bits
                Prefix++;
            if (Prefix == -1//Just bytes
                return Bytes.ToString() + " Bytes";
            else
            {
                long Total = Bytes >> ((Prefix + 1) * 10); //10 bits for every prefix
                long Fractal = (Bytes >> (Prefix * 10)) & 0x3FF//Remove part before "decimal point" and keep last 10 bits (just sufficient for 3 decimal places)
                Fractal = (Fractal * 1000) >> 10//Convert fractal part from [0,1024] range to [0,1000] range
                return Total.ToString() + System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + Fractal.ToString("000") + " " + Prefixes[Prefix].ToString() + "B"
            }
        }


Er ist schon um einiges schneller als eine while-Schleife mit float-Operationen, aber da könnte man doch bestimmt noch mehr optimieren, oder ;) ? Vor allem die Zeile Fractal = (Fractal * 1000) >> 10//Convert fractal part from [0,1024] range to [0,1000] range könnte man doch vielleicht ohne Multiplikation hinbekommen. Die Frage ist nur wie - die Genauigkeit sollte nicht spürbar leiden. Welche Optimierungspotenziale gibt es hier noch?

AXMD
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 21.04.08 10:43 
Hi!

Anfangen würde ich damit, das Array nicht jedes Mal von Neuem zu definieren, sondern als readonly-Feld der Klasse zu machen. Auch könntest Du schauen, ob String.Format schneller ist, als eine String-"Addition".

Bist Du sicher, dass die Methode der Flaschenhals ist? Und macht das eigentlich Sinn, mehrmals die Sekunde einen Wert zu aktualisieren? :gruebel:

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 21.04.08 11:50 
Ferner gilt auch für emulierte Sprachen auf virtuellen Maschinen: Vergleiche mit 0 sind schneller.

Was Du also machen solltest, ist ne Index-Verschiebung einzubauen, so dass Index 0 nen Leerstring enthält (B hat ja keinen Präfix).

Ferner solltest Du schauen, dass Du Ki statt K schreibst (ist "konformer").

Insgesamt würde dass dann so aussehen:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
            readonly char[] Prefixes = { 'K''M''G''T''P''E' }; //Zeta (Z, 70 bits) cannot be displayed with 64 bit
            //Z: Will soon be necessary if current storage consumtion rates continue ;-)

        public static string FormatBytes(long Bytes)
        {
            //Remark: does not use float arithmetic and may be slightly inaccurate, but a lot faster
            if (Bytes < 0)
                return "?";
            int Prefix = 0;
            long TempBytes = Bytes;
            while ((TempBytes = (TempBytes >> 10)) != 0//One prefix for every 10 bits
                Prefix++;
            if (0 == Prefix) //Just bytes
                return Bytes.ToString() + " Bytes";
            else
            {
                long Total = Bytes >> ((Prefix) * 10); //10 bits for every prefix
                long Fractal = (Bytes >> ((Prefix - 1) * 10)) & 0x3FF//Remove part before "decimal point" and keep last 10 bits (just sufficient for 3 decimal places)
                Fractal = (Fractal * 1000) >> 10//Convert fractal part from [0,1024] range to [0,1000] range
                //Der Wert für System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator sollte gecacht werden ...
                return Total.ToString() + System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator + Fractal.ToString("000") + " " + Prefixes[Prefix].ToString() + "iB"
            }
        }


Ungetestet ...

HTH.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
AXMD Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 4006
Erhaltene Danke: 7

Windows 10 64 bit
C# (Visual Studio 2019 Express)
BeitragVerfasst: Mo 21.04.08 13:23 
user profile iconChristian S. hat folgendes geschrieben:
Bist Du sicher, dass die Methode der Flaschenhals ist? Und macht das eigentlich Sinn, mehrmals die Sekunde einen Wert zu aktualisieren? :gruebel:


Die Methode ist kein Flaschenhals in dem Sinn - sie benötigt nur im Vergleich zu den anderen Aktualisierungsoperationen die meiste Zeit, da sie öfters aufgerufen wird.

user profile iconBenBE hat folgendes geschrieben:
Ferner gilt auch für emulierte Sprachen auf virtuellen Maschinen: Vergleiche mit 0 sind schneller.

Was Du also machen solltest, ist ne Index-Verschiebung einzubauen, so dass Index 0 nen Leerstring enthält (B hat ja keinen Präfix).


Werd ich machen, das klingt sinnvoll. Allerdings hätt ich statt "B" gerne "Bytes" angezeigt - lässt sich das in diesem Konzept ohne viel Aufwand realisieren?

user profile iconBenBE hat folgendes geschrieben:
ausblenden C#-Quelltext
1:
//Z: Will soon be necessary if current storage consumtion rates continue ;-)					


Mit 64 Bit lassen sich trotzdem keine 70 Bit darstellen, und die FileStreams in .NET liefern alle maximal 64-Bit-Längen bzw. -Positionen ;)

Danke erstmal für die Tipps, werde das integrieren und mir ansehen, wie sich die Laufzeit verändert.

AXMD
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 21.04.08 13:34 
user profile iconAXMD hat folgendes geschrieben:
user profile iconBenBE hat folgendes geschrieben:
Ferner gilt auch für emulierte Sprachen auf virtuellen Maschinen: Vergleiche mit 0 sind schneller.

Was Du also machen solltest, ist ne Index-Verschiebung einzubauen, so dass Index 0 nen Leerstring enthält (B hat ja keinen Präfix).


Werd ich machen, das klingt sinnvoll. Allerdings hätt ich statt "B" gerne "Bytes" angezeigt - lässt sich das in diesem Konzept ohne viel Aufwand realisieren?

Siehe oben in meinem Beispiel, da hab ich das mal eben umgesetzt, hoffe, ich hab mich nicht vertan und soweit ale Vorkommen erwischt ...

Die Ausgabe Bytes statt B ist doch eigentlich nur hinten den String ändern, oder meinst Du Byte\Bytes je nach Präfix vorn?

Grob würd ich sagen:
ausblenden C#-Quelltext
1:
 /* ... */ + ( (0 == fractal) && (1 == total) ? "Byte" : "Bytes");					


user profile iconAXMD hat folgendes geschrieben:
user profile iconBenBE hat folgendes geschrieben:
ausblenden C#-Quelltext
1:
//Z: Will soon be necessary if current storage consumtion rates continue ;-)					


Mit 64 Bit lassen sich trotzdem keine 70 Bit darstellen, und die FileStreams in .NET liefern alle maximal 64-Bit-Längen bzw. -Positionen ;)

War ja auch erstmal rein hypothetisch ;-) Wollt's auch nur erwähnt haben :mrgreen:

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.