Math.Round - Wieso geht das nicht ...

  • VB.NET

Es gibt 28 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Nicht, dass ich es jetzt nochmal versuchen möchte, da ich so schön ignoriert werde, aber wie schön einfach es wäre, *100 \(1024 * 1024) und Mod 100 für die Nachkommastelle zu verwenden? Lass einfach den Double weg...

    VB.NET-Quellcode

    1. Dim bytes As Long
    2. Dim output As String
    3. bytes = 100 * bytes \ 1024 * 1024
    4. output = (bytes\ 100).ToString() & Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator & (bytes Mod 100).ToString()

    und warum sollte man bei Gigabyte- oder Kilobyte-großen Dateien MBs anzeigen.
    Übrigens kannst du auch noch (bytes \ 1024) * 100 \ 1024 verwenden, dann beugst du einem (für realistische Dateien unmöglichen) Überlauf vor.

    Gruß
    ~blaze~
    Damit scheint es jetzt zu funktioniert:

    VB.NET-Quellcode

    1. Me.Label2.Text = Math.Round(e.BytesReceived / 1024 / 1024, 2) & " MB / " & Math.Round(e.TotalBytesToReceive / 1024 / 1024, 2) & " MB bereits runtergeladen"


    @~blaze~
    Ich weiß nicht so Recht wie ich das in meinen Code umsetzen kann, kannst du das mit dem Code (Seite 1) verknüpft nochmal zeigen? :)
    "Denken ist die schwerste Arbeit, die es gibt. Das ist wahrscheinlich auch der Grund, warum sich so wenig Leute damit beschäftigen." - Henry Ford
    Dann sag's doch einfach ;). Das ist besser, als es einfach stehen zu lassen, ohne alles.
    Wenn man meinem Code noch die Double.ToString-Methode gibt, sieht's wohl so aus:

    VB.NET-Quellcode

    1. Public Shared Function ByteAmountToString(ByVal numberBytes As Double, ByVal digits As Integer) As String
    2. Dim value As Double = Math.Log(numberBytes, 1024.0#)
    3. Dim units() As String
    4. Dim index As Integer
    5. If value < 0.0# Then
    6. units = New String() {"B", "mB", "µB", "nB", "pB", "fB", "aB", "zB", "yB"}
    7. Else
    8. units = New String() {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
    9. End If
    10. index = Math.Min(units.Length, CInt(Math.Floor(value)))
    11. Return (numberBytes / 1024.0# ^ index).ToString("0." & new String("0"c, digits)) & units(Math.Abs(index))
    12. End Function

    Es sind übrigens eigentlich KiB, MiB, etc. und gebrochene Bytes gibt's nicht, das war nur zur Veranschaulichung. Was der Code macht ist, er ermittelt erst mal, die Einheit, die verwendet wird (über den Logarithmus zur Basis 1024) und dividiert dann eben durch ihn, um die Darstellung in der Einheit zu ermöglichen. Es gibt übrigens noch eine elegante Umformung direkt auf Integern, da 1024 = 2^10 und somit 1024^x = 1<< (10* x), ist aber egal jetzt.
    Ansonsten rufst du einfach nur ByteAmountToString(empfangeneBytes, 2) auf.

    Gruß
    ~blaze~
    Deswegen war das mit den gebrochenen Bytes nur zur Veranschaulichung, wie's bei anderen Einheiten funktionieren würde. ;) Klar, in dem Kontext macht's definitiv keinen Sinn, aber halt für Meter, etc. Hatte glaub' ich damals eine allgemein gültige Funktion geschrieben für beliebige Einheiten.

    Gruß
    ~blaze~
    Hab' mal noch eine rein auf Integer basierte Version geschrieben:

    VB.NET-Quellcode

    1. Private Shared ReadOnly _units As String() = New String() {" B", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB", " ZiB", " YiB"}
    2. Public Shared Function FormatSize(ByVal size As Long) As String
    3. If size < 0 Then Throw New ArgumentOutOfRangeException("value", "Positive value or zero expected.")
    4. If size = 0 Then Return "0"c & _units(0)
    5. Dim index As Integer = Math.Min(FloorLog2(size) \ 10, _units.Length) 'Logarithmus zur Basis 1024, da log_1024 x = (log_2 x) / (log_2 1024) = (log_2 x)/10 und Abgleich mit den moeglichen Einheiten
    6. size = ((size * 100) >> (10 * index)) 'auf n Stellen genau runden ==> size * 10^n und um 1024^index nach rechts schieben
    7. If size Mod 100 = 0 Then 'gerade Werte ohne Komma darstellen (man koennte auch zwei 0-en anhaengen, also das auskommentieren)
    8. Return (size \ 100).ToString() & _units(index)
    9. Else 'sonst mit Komma darstellen
    10. Return (size \ 100).ToString() & System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator & (size Mod 100).ToString("00") & _units(index)
    11. End If
    12. End Function
    13. Public Shared Function FloorLog2(ByVal value As Long) As Integer
    14. If value <= 0 Then Throw New ArgumentOutOfRangeException("value", "Positive value expected.")
    15. Dim lower = 0, upper = 64
    16. Dim log As Integer
    17. Do
    18. log = (lower + upper) >> 1 'Mittelwert von lower und upper ermitteln
    19. Dim cv As Long = value >> log 'value um den angenommenen Logarithmus shiften
    20. If cv = 0 Then 'wenn value >> log = 0, gilt, dass log > floor(log_2 value)
    21. upper = log 'daher den oberen Wert auf log setzen
    22. ElseIf cv > 1 Then 'wenn es groesser als 1 ist, gilt, dass log < floor(log_2 value)
    23. lower = log 'daher eben den unteren Wert auf log setzen
    24. Else
    25. Exit Do 'bei = 1 ist floor(log_2 value)) berechnet worden
    26. End If
    27. Loop
    28. Return log
    29. End Function

    Ist halt nochmal 'n Stück komplizierter, als die Double-Version. FloorLog2 sollte in O(log n) den Logarithmus einer Long-Zahl abgerundet berechnen.

    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()