Generische Struct/Klasse und Operatoren

  • C#
  • .NET 7–8

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Generische Struct/Klasse und Operatoren

    Ich habe versucht, eine generische Struct zu erstellen, die Operatoren benötigt

    C#-Quellcode

    1. public struct Struktur<T> where T: struct
    2. {
    3. ...
    4. }


    Folgendes Konstrukt geht nicht

    C#-Quellcode

    1. public bool Gleich( T x, T y)
    2. {
    3. return x==y;
    4. }


    weil der Compiler nicht weiß, ob der Operator== überhaupt zur Laufzeit existiert. Nun gut!

    Kann ich dem Compiler irgendwie begreiflich machen, dass bei den structs, die hier als T zum Einsatz kommen, die benötigten Operatoren vorhanden sind?

    Zunächst dachte ich, ich beschränkte die Struktur nicht auf (alle) struct sondern auf ein Interface mit den entsprechenden Operatoren. Nun musste ich aber lernen, dass Operatoren nicht in Interfaces angegeben werden können.

    Ich probier schon Ewigkeiten da rum, mir fällt aber nichts dazu ein.

    So eine Frage hatte ich vor knapp zwei Jahren schon mal. Vielleicht weiß jetzt einer, wie man sich das hinbiegen kann.

    Gruß

    Joachim
    Da T ein Structure sein soll, sollte doch Equals funktionieren wie =
    Und da Equals für Objects definiert ist, kann er da auch nicht meckern.

    Kannst du erklären, was du damit machst? Würde mich interessieren.

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

    MasterQ schrieb:

    Nun musste ich aber lernen, dass Operatoren nicht in Interfaces angegeben werden können.
    Was? Du hast oben .NET 7-8 angegeben, da geht das schon. Genau dafür wurden diese in Interfaces gepackt. Der == Operator steckt im IEqualityOperators<TSelf, TOther, TResult>

    C#-Quellcode

    1. public struct Struktur<T> where T : IEqualityOperators<T, T, bool> {
    2. public bool Gleich(T x, T y) {
    3. return x == y;
    4. }
    5. }

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

    Ich benötige aktuell

    operator+
    operator-

    operator==
    operator!=

    == geht mit Equals, das stimmt. Ich bin mir aber nicht sicher, ob es später eine Variante mit class geben muss, von daher versuche ich allgemein zu bleiben. Und Equals ist ein Kapitel für sich.

    Vielleicht kommen noch andere Operatoren dazu, das kann ich ebenfalls noch nicht abschätzen, je nachdem wohin mich die Reise trägt.


    Zum Hintergrund:
    Ich versuche, ein numerisches Problem zu lösen. Die Informationen stecken in 2^33 Bits. Doof, gerade eins zuviel für int. Nehme ich long, mülle ich mir den Speicher mit 31 ungenutzen Bits zu. Ich bastele daher mit verschiedenen eigenen Datenstrukturen und hätte dafür gerne die genannten Operatoren verwendet. Da ich gleichzeitig mit einigen Milliarden an Datensätzen im Speicher hantieren muss, versuche ich effizient zu sein. Meine 64GB an Ram reichen gerade so aus.

    Nun habe ich festgestellt, dass eine Variante mit long und eine mit einem Bitfeld (1xint + 1xbyte) ab einem gewissen Punkt unterschiedliche Ergebnisse liefern. Und jetzt muss ich auf die Suche gehen, woran das liegt. Daher kam der Gedanke auf eine generische class oder struct, um dann leichter zwischen den Varianten umschalten zu können, ohne groß was an der Numerik ändern zu müssen.

    MasterQ schrieb:

    mülle ich mir den Speicher mit 31 ungenutzen Bits zu
    Wie viele solcher Strukturen liegen gleichzeitig im Speicher?
    Wie groß ist die Wahrscheinlichkeit, dass weitere Bits dazu kommen?
    Wenn ich den Aufwand betrachte, nähme ich long und feddich.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    MasterQ schrieb:

    Ich benötige aktuell

    operator+
    operator-

    operator==
    operator!=


    C#-Quellcode

    1. ​public struct Struktur<T> where T : IEqualityOperators<T, T, bool>, IAdditionOperators<T, T, T>, ISubtractionOperators<T, T, T> {
    2. public bool Gleich(T x, T y) {
    3. return x == y;
    4. }
    5. public bool Ungleich(T x, T y) {
    6. return x != y;
    7. }
    8. public T Plus(T x, T y) {
    9. return x + y;
    10. }
    11. public T Minus(T x, T y) {
    12. return x - y;
    13. }
    14. }


    Die meisten stecken in Interfaces. Schau einfach wie weit du kommst.
    Vollzitat eines Vorposts an dieser Stelle entfernt ~VaporiZed

    es liegen knappe 240Mio (nicht Mrd!) im Speicher gleichzeitig. Wenn ich wirklich alles im Speicher behalte ohne Zwischenspeichern, sind's 830Mio (max RAM Gebrauch ca. 61GB)
    Es kommen definitiv keine weiteren Bits dazu

    Die Daten müssen aber noch gespeichert werden, dann folgt ein Postprocessing. Das geht dann in den Bereich von vielen Stunden die das benötigt. Mit long läuft's ja schon. Ich versuche aktuell das Postprocessing zu beschleunigen. Keine Ahnung, ob mir das gelingen wird.

    Das generische Zeugs hier versuche ich, weil mir aufgefallen ist, dass es Diskrepanzen zwischen den Ergebnissen mit long und der int-byte Kombi gibt. Da ich nicht weiß, was das richtige Ergebnis liefert, muss ich jetzt erst mal aufpassen und die Unterschiede klären.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „VaporiZed“ ()

    MasterQ schrieb:

    Es kommen definitiv keine weiteren Bits dazu
    Dann mach Dir eine Struktur aus einem UInt und einem Boolean.
    Das Boolean als Vorzeichen des UInt-Wertes.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Haudruferzappeltnoch schrieb:

    Meinst du denn der Aufwand selbst eine Struktur zu entwickeln die kleiner ist als Long und größer als Integer ist es wert?
    Ich kann mir nicht vorstellen, dass ein Long soviel schlechter performt als irgendwas selbstgebasteltes.

    So wie ich das verstanden habe geht es ja um den Speicherplatz, weil es so viele Werte sind. Und long mit 61GB im Gegensatz zu z.B. int+byte wären dann 39GB. Das ja schon ein großer unterschied.
    Vollzitat eines Vorposts an dieser Stelle entfernt ~VaporiZed

    Boolean wird intern als int verwaltet, bietet somit keinen Mehrwert an Speicherplatz. Boolean + int ist somit das gleiche wie long.Die kleinste Einheit, die intern verwaltet werden kann ist ein Byte. Damit kann Boolean nicht als einzelnes Bit gespeichert werden, sondern bestenfalls als Byte. C# macht aber ein int32 draus.


    Die meiste CPU-Zeit geht beim Lesen und Schreiben auf die SSD drauf. Von daher erhoffe ich mir schon einen Gewinn an Geschwindigkeit wenn ich nicht verwendete Bit versuche zu umgehen.

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

    Nu, wenn ich 10^9 Booleans lade, dann verbraucht das 1.7GB
    Bei 10^9 Integers sind es 6.7GB
    Faktor 4 sieht also eher nach einem Byte aus, was auch irgendwie Sinn macht.

    Also ganz so geht die Rechnung nicht auf, aber ich hab die auch einfach der Reihe nach in eine Liste geschmissen. Ich denke wir hatten irgendwo schonmal geklärt, dass die Datentypen im Array kompakter liegen als wenn man alle einzeln vorliegen hat.

    MasterQ schrieb:

    Boolean wird intern als int verwaltet
    Bist Du da sicher?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    ja, ich hab das auch iwo auf msdn so nachgelesen: bool verbraucht 32 bit.
    Nenenen Moment. In C war das so. Da gab es kein bool und da wurde dann einfach BOOL defined mit 0 als false und 1 als true. Aber schon C++ nimmt für bool nur 1 byte und c# (.NET) auch. Bool ist ein byte und nur wenn das per DLLImport gemarschallt wird, für die klassische C-API, wird das zu einem int. Weil wie schon gesagt, es in C so war.

    Edit: Da kommt es manchmal zur Verwirrung, weil einfach nur gelesen wird Marshal.SizeOf<bool>() == 4, aber das ist die Umwandlung/Kompatibilität zur alten C-API. Intern ist wie RodFromGermany richtig geschrieben hat sizeof(bool) == 1.
    Dann müssen wir eben (native) Strukturen oder Arrays aufbauen, die so beschaffen sind, dass ein bool oder ein byte nur ein Byte Ram benutzt:

    C#-Quellcode

    1. [StructLayout(LayoutKind.Sequential, Pack = 1)]

    Wenn 8 BPP Kamera-Bilder mit 1 Byte pro Pixel in einem Byte-Array abgelegt werden, solte es doch auch möglich sein, das genannte Problem zu lösen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!