Dramatische Zeitunterschiede bei ULong und Long

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von picoflop.

    Dramatische Zeitunterschiede bei ULong und Long

    Hallo, ich habe ein Programm entwickelt, welches Primzahllücken findet, z.B zwischen 2.000.000.000 und 2.002.000.000. Deklariere ich die Variablen mit Dim As ULong braucht mein Programm für das genannte Beispiel 8:28 min, bei Dim As Long nur 11 s (bei Integer übrigens nur 5,5 s). Wie erklärt sich dieser Unterschied, da doch beide Datentypen die gleiche Bitgröße belegen, nämlich 64 bit. Wichtiger noch, wie kann ich die Typdeklaration den Eingabezahlen anpassen, ohne (!) das Programm zu verändern? Wenn ich die Variablen explizit konvertiere wenn die größere Zahl < Integer.MaxValue, etwa mit Convert oder CInt, dann bleibt die Rechendauer hoch. Gibt es eine Lösung?

    Mit freundlichen Grüßen von Werner

    VB.NET-Quellcode

    1. Private Sub foo()
    2. Dim i As System.UInt64 = 1UL
    3. i += 1
    4. End Sub
    5. Private Sub bar()
    6. Dim i As System.Int64 = 1L
    7. i += 1
    8. End Sub


    IL-Code für foo (ULong):

    Quellcode

    1. .method private instance void foo() cil managed
    2. {
    3. // Code size 29 (0x1d)
    4. .maxstack 2
    5. .locals init ([0] uint64 i)
    6. IL_0000: nop
    7. IL_0001: ldc.i4.1
    8. IL_0002: conv.i8
    9. IL_0003: stloc.0
    10. IL_0004: ldloc.0
    11. IL_0005: newobj instance void [mscorlib]System.Decimal::.ctor(uint64)
    12. IL_000a: nop
    13. IL_000b: ldsfld valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::One
    14. IL_0010: call valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::Add(valuetype [mscorlib]System.Decimal,
    15. valuetype [mscorlib]System.Decimal)
    16. IL_0015: call uint64 [mscorlib]System.Convert::ToUInt64(valuetype [mscorlib]System.Decimal)
    17. IL_001a: stloc.0
    18. IL_001b: nop
    19. IL_001c: ret
    20. } // end of method Form1::foo


    Dagegen bar (Long)

    Quellcode

    1. .method private instance void bar() cil managed
    2. {
    3. // Code size 11 (0xb)
    4. .maxstack 2
    5. .locals init ([0] int64 i)
    6. IL_0000: nop
    7. IL_0001: ldc.i4.1
    8. IL_0002: conv.i8
    9. IL_0003: stloc.0
    10. IL_0004: ldloc.0
    11. IL_0005: ldc.i4.1
    12. IL_0006: conv.i8
    13. IL_0007: add.ovf
    14. IL_0008: stloc.0
    15. IL_0009: nop
    16. IL_000a: ret
    17. } // end of method Form1::bar


    Wie man sieht, wird bei UL mit objekten rumgepuscht, während bei L nur elementare Operationen nötig sind.

    Welch ein Datentyp ist ULong?

    Vielen Dank für die Antwort. Ich verstehe zwar den Zwischencode nicht, aber ich kann erkennen, dass er für ULong viel umständlicher ist als für Long. Ist ULong nun ein Werttyp oder Verweistyp (Referenztyp)? In den mit zugänglichen Büchern habe ich keinen Hinweis gefunden, dass ULong so erheblich langsamer ist als Long. Und mir ist auch unklar, was die Entwickler von VB damit bezwecken.

    Da die Übersetzung des Quellcodes nun einmal so ist wie sie ist, bleibt für mich die Frage, kann ich im Programm eine zahlenangepasste Deklarierung erreichen? Ein Programm, welches Zahlen auf ihre Primeigenschaft untersucht oder die Faktoren einer Zahl errechnet, soll ja für unterschiedliche Zahlengrößen gelten. Wenn ich z.B. die Zahl 1.111.111.111.111.111.111 (19 mal die 1) untersuche (sie ist prim), macht es schon einen Zeitunterschied ob sie als Long oder ULong deklariert wird.

    Viele Grüße Werner
    Der Grund, warum ULong so langsam ist, ist, dass die Zahl vor der Rechenoperation in eine Decimal-Zahl umgewandelt wird.
    msdn.microsoft.com/en-us/libra…m.decimal%28VS.71%29.aspx

    The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335.

    Dieser Datentyp muss mit extrem großen Zahlen umgehen und dabei noch extrem genau sein (Gleitkommazahl). Dadurch erhöht sich der Speicherverbrauch und der Prozessor braucht einige Zyklen, un Decimal-Zahlen zu berechnen. Dazu kommt noch die ständige Konvertierung von ULong zu Decimal und wieder zurück.

    Zu deiner Frage: das ist nicht möglich. Du kannst aber ein Object deklarieren, dann per Long.MaxValue / ULong.MaxValue / Decimal.MaxValue usw. herausfinden wo die Zahl noch "rein passt". Dann weist du dem Object diese Zahl zu und das Object hat dann den richtigen Typ. Nach der Zuweisung ruft du deine überladene (für jeden in Frage kommenden Datentyp) Funktion auf und übergibst als Parameter CType(<Object-Variable>,Datentyp). So würde ich das machen.

    lg SeriTools
    | Keine Fragen per PN oder Skype.
    Es sieht so aus als ob ULong die Addition der Decimalstruktur überlässt, also erst mal ein Objekt von Decimal erstellt (warum eigentlich, Decimal ist doch ein Werttyp?), dann Decimal.One, aslo 1 lädt, dann Decimal.Add aufruft und dann das ganze wieder in ULong zurückkonvertiert. Umständlich was? Aber anscheinend ist Decimal der einzige Typ, der mit Zahlen größer als Int64.MaxValue umgehen kann.
    ich glaube ab .Net 4 gibt es einen BigInteger, ebenso sollte zu BigInteger einiges zu finden sein, z.B. zum rechnen mit Strings(natürlich nicht "1" + "2"^^) ;)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---