[OpenSource] SharpMath 1.14.7 - Mathematikbibliothek

    • Release
    • Open Source

    Es gibt 43 Antworten in diesem Thema. Der letzte Beitrag () ist von Trade.

      @ErfinderDesRades Es geht darum, dass structs in C# Wertetypen sind. Vektoren und Co. sind eigene Datentypen, die sich auch wie alle anderen Datentypen verhalten sollten, d.h. sie sollten byValue übergeben werden. Spart außerdem Speicher, in manchen Fällen.

      @AliveDevil Das Unreal-Engine Beispiel hinkt, ein struct in C++ ist mit einer Klasse nahezu identisch, nur alle Member sind per Default public ;)
      ich weiß, dass structs WerteTypen sind. Und class sind ReferenzTypen. Beides sind Datentypen.
      Und es ist eine architektonische Entscheidung, ob man einen Datentyp als Wert- oder als Ref-Typ anlegt.
      Für diese Entscheidung gibt es Kriterien. (Speicherplatz gehört übrigens nicht dazu).
      Im Falle Vectoren und Co sind die Kriterien erfüllt, dass diese Datentypen WertTypen sein sollten, also dem stimme ich zu.

      Aber im Falle Matrix sehe ich sie nicht als erfüllt an, es spricht sogar etwas dagegen: Nämlich eine struct, die Referenzen enthält, ermöglicht u.U. genau die Seiteneffekte, die bei struct (anders als bei class) nicht auftreten sollen.
      Array ist aber ein Ref-Typ.
      Daher frage ich nach dem Grund, warum nu auch Matrix als struct angelegt wird.
      Weils in Wpf, XNA, sonstwo auch so ist? (Zumindest in Winforms isses anders.)
      Weil AliveDevil das gesagt hat?
      @ErfinderDesRades
      AliveDevil ist nicht der einzige - ich (und wahrscheinlich auch andere) hatte(n) Trade schon davor darauf hingewiesen, außerdem ist es doch komplett logisch, dass eine Matrix eigentlich genauso ein Werttyp ist wie ein Vektor. Andererseits gebe ich dir Recht - Referenzen in einem Werttyp sind Unsinn, weshalb man dann halt die Verwendung eines Arrays zum Halten der Daten vermeiden muss.
      Referenzen dürfen dann natürlich nicht mehr benutzt werden, weshalb ich auf die entsprechenden Proeprties, wie M11, M12, ... etc. umsteigen werde. Natürlich alle readonly.
      @Higlav Okay. Aber was hat es mit Deinem 2. Punkt auf sich? Das sagt mir nichts. :D

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      nafets schrieb:

      ist es doch komplett logisch, dass eine Matrix eigentlich genauso ein Werttyp ist wie ein Vektor.
      Ist es nicht, zumindest nicht, bis mir mal jemand den Grund dafür nennt.
      Einen Gegen-Grund habich ja angeführt: Matrix beinhaltet höchstwahrscheinlich ein Array, und wenn das in einer struct nicht sehr umsichtig implementiert wird, kann das böse Überraschungen verursachen (für diesen Hinweis bitte ein Hilfreich ;) ).

      Nun bitte ich um den Für-Grund.
      Den muss es doch geben, wenn so viele dieser Meinung sind. Dass es "logisch" sei, ist kein Grund, das ist nur eine unbegründete Behauptung.
      Weil das Ganze Zeugs immutable sein soll. Sind sie zwar in MonoGame z. B. auch nicht, aber das ist eben eine Architektursache.
      Und wie gesagt, Referenzen gibt es dann nicht mehr, deswegen die M-Properties. Das ist mir schon klar, dass das zweidimensionale Array dann weg muss. Von daher lässt sich das relativ gut als Struktur realisieren.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      @ErfinderDesRades Ich zitiere mal die MSDN:

      ✓ CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.


      It logically represents a single value, similar to primitive types (int, double, etc.).


      msdn.microsoft.com/en-us/library/ms229017(v=vs.110).aspx
      Ui - gegen MSDN darf ich jetzt nix sagen.
      Also dem ersten Punkt widerspreche ich, aber der zweite ist der entscheidende.
      Immerhin - nu habt ihr das Kriterium gefunden :thumbsup: - dank meiner Penetranz :P
      Also das zweite - findet ihr das sehr überzeugend, es auf eine Matrix anzuwenden - also repräsentiert eine Matrix vonne Logik her wirklich einen einzelnen Wert, ähnlich int, double, etc.?



      @Trade: Hmm - ich trau mich kaum zu fragen, aber warum soll das immutable sein?
      Weil weder in Winforms, noch in Wpf, noch in MonoGame sind sie immutable - mehr Matrix-Klassen kenne ich nicht.

      Aber ich glaub ich geh dir nur auf die Nerven, indem ich dich fortgesetzt anrege, über deine Entscheidungsgründe zu nachzudenken.

      noch eine frage: Mit Matrix sind speziell Transformations-Matritzen für geometrische Transformationen gemeint, oder?
      Weil man kann Matrizenrechnung ja auch viel allgemeiner auffassen, oder?

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

      ErfinderDesRades schrieb:

      also repräsentiert eine Matrix vonne Logik her wirklich einen einzelnen Wert, ähnlich int, double, etc.?
      Ja klar, die Matrix repräsentiert bei mir nur double als Datentyp, nur, dass diese halt mehrfach in Form der Felder vorhanden sind. Also macht das schon imho Sinn.

      ErfinderDesRades schrieb:

      aber warum soll das immutable sein?
      stackoverflow.com/questions/37…c-sharp-structs-immutable

      ErfinderDesRades schrieb:

      Mit Matrix sind speziell Transformations-Matritzen für geometrische Transformationen gemeint, oder?
      Du kannst diese auf Vektoren anwenden. Generell werden aber natürlich auch Operationen mit Matrizen an sich unterstützt, aber klar, darauf läuft es im Endeffekt hinaus.

      Ich werde nun alles als unveränderbare Struktur implementieren. Das hat zwar den Nachteil, dass man keine allgemeinen, generischen Extensions sowie abstrahierende Interfaces benutzen kann und es sehr viel mehr Code wird, aber ist halt dann eben besser.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Trade schrieb:

      Ich werde nun alles als unveränderbare Struktur implementieren. Das hat zwar den Nachteil, dass man keine allgemeinen, generischen Extensions sowie abstrahierende Interfaces benutzen kann und es sehr viel mehr Code wird, aber ist halt dann eben besser.

      Wieso kannst du die nicht nutzen? Sowas hier geht doch trotzdem:

      C#-Quellcode

      1. public interface IMatrix
      2. {
      3. int Width { get; }
      4. int Height { get; }
      5. double this[int x, int y] { get; }
      6. }
      7. public struct Matrix2x2
      8. : IMatrix
      9. {
      10. public double this[int x, int y]
      11. {
      12. get
      13. {
      14. //Internal Access
      15. }
      16. }
      17. public int Width => 2;
      18. public int Height => 2;
      19. }

      Somit kannst du dann wiederum generische Methoden per Extension bereitstellen
      Das ist richtig, aber wie soll ich diese Extensions bauen, wenn ich Werte über den Indexer setzen muss? Und das wird wohl zwangsläufig so kommen, sobald ich einen neuen Vektor erstellen muss (wie z. B. bei Lerp etc.). Klar kann ich gewisse Methoden, die nur Skalare zurückgeben, dann direkt generisch implementieren, aber andere eben nicht. Das wäre dann halt so ein Gemisch und ob das so gut ist, weiß ich nicht.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      ErfinderDesRades schrieb:

      Ui - gegen MSDN darf ich jetzt nix sagen.

      Das Totschlagargument schlechthin :D

      Zum zweiten Punkt: In einem anderen Artikel ist die Rede davon, dass "kompakte Datentypen" als struct implementiert werden sollen. Als Beispiele werden da Point, Color und Rect genannt. Für mich ist eine Matrix bzw. deren spezifische 2x2, 3x3 und vielleicht 4x4 Form ein kompakter Datentyp.

      ErfinderDesRades schrieb:

      @Trade: Hmm - ich trau mich kaum zu fragen, aber warum soll das immutable sein?

      Also ich meine das sollte nicht heißen "Ich mache ein struct draus, weil es immutable sein soll" sondern "Ich mache es immutable, weil es ein struct sein soll". Um immutable zu sein muss die Matrix kein struct sein. Da aber structs by value übergeben werden, sollten sie immer immutable sein. Ansonsten könnte ein Programmierer fälschlicher Weise davon ausgehen eine Referenz zu einer Matrix zu bearbeiten, obwohl er eine Kopie bearbeitet.

      @Trade bitte nicht vergessen IEquatable<> zu implementieren ;) (vergiss das, hast du ja schon) Die Benennung "SquareMatrix" finde ich auch nicht wirklich gut, Matrix2x2 passt besser zu den anderen Matrizen.

      Solaris schrieb:

      @Trade bitte nicht vergessen IEquatable<> zu implementieren


      Alles gut. ;)
      Edit: Achso, Du meintest das bisherige. Naja, hatte/hätte ich so oder so. Und SquareMatrix war einfach eine Zwischenschicht, die fällt durch die Strukturen eh weg.

      Okay, meine Entscheidung steht jetzt fest. Ich werde eine Klasse VectorUtils belassen und dort generische Methoden definieren. Entsprechende Extensions kommen natürlich auch. Da fehlen dann zwar ein paar Sachen, die entsprechende T zurückgeben und Methoden, die auf diese intern zugreifen, aber wenigstens etwas Redundanz bleibt erspart. Dasselbe natürlich auch bei den Matrizen.
      Jetzt aber ran an's Werk.

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ () aus folgendem Grund: Siehe unten

      ErfinderDesRades schrieb:

      Zumindest point, rectangle, vector und zeugs sind alle mutable.

      Deswegen ja "sollten", dass sie es nicht sind ist schlecht und sollte hier nicht als Beispiel angeführt werden ;) Du beziehst dich damit auf die Game-Frameworks, richtig? Da wurde das sicherlich aus praktischen Gründen gemacht, ich finde es zum Beispiel schon praktisch, dass die Unity Engine ihre Vector-Typen mutable definiert hat. Das müsste man dann abwägen. Im Prinzip "Idiotensicherheit/Guidelineumsetzung gegen Usability".

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

      Trade schrieb:

      @Higlav Okay. Aber was hat es mit Deinem 2. Punkt auf sich? Das sagt mir nichts. :D

      Grüße

      Auch Grüsse von mir. :D
      Hier wird die Ausgleichsrechnung relativ anschaulich erklärt.
      But in the end it all boils down to: Beispielweise hat man
      $m$
      Messdaten und kennt ihren theoretischen Zusammenhang (Polynom mit dem Grad
      $s$
      ). Nun soll dieses Polynom aus den Messpunkten heraus errechnet werden. Und das Endresultat für Polynome(mit den Koeffizienten
      $\lambda_i$
      ) z.B. sieht so aus:
      $$A^TA=\sum_{i=1}^m\begin{pmatrix} x_i^{2s}&x_i^{2s-1}&\cdots&x_i^s\\ x_i^{2s-1}&x_i^{2s-2}&\cdots&x_i^{s-1}\\ \vdots&\vdots&\ddots&\vdots\\ x_i^{s}&x_i^{s-1}&\cdots&1 \end{pmatrix} \cdot\vec\lambda=\sum_{i=1}^m \begin{pmatrix} x_i^sy_i\\ x_i^{s-1}y_i\\ \vdots\\ y_i \end{pmatrix}=A^T\vec y$$

      Solaris schrieb:

      Im Prinzip "Idiotensicherheit/Guidelineumsetzung gegen Usability".
      Genau das ist die Sache. Ich habe SharpMath ursprünglich entwickelt, damit es vielfältig genutzt werden kann und wollte die Architektur möglichst abstrakt halten, daher auch die Klassen. Mittlerweile erscheint es mir aber auch logischer, dass Wertetypen viel mehr Sinn machen und entsprechend ist die Abstraktion natürlich mit den Strukturen jetzt etwas eingeschränkt, aber das geht. Hingegen die Frage, ob mutable oder immutable ist das größere Problem. Auf der einen Seite sind unveränderbare Strukturen zwar besser, aber auf der anderen bleibt die Flexibilität nicht erhalten, wenn man doch mal etwas verändern möchte.
      Daher werde ich jetzt wohl doch bei veränderbaren Strukturen bleiben, das ist einfach viel angenehmer, wenn ich mir das so überlege und alles lässt sich wunderbar implementieren. Die bisherige Diskussion hat deutlich gezeigt, wie schwer das zu entscheiden ist, aber ich denke, dass es okay sein wird. Zudem folge ich damit den existierenden Klassen von MS, sodass ich nicht der Einzige bin.
      Einen Nachteil hat das Zeugs mit den generischen Methoden natürlich: Beim Boxen von IVector z. B. wird Müll erzeugt.

      @Higlav Oh, danke. Ich schaue mir das mal an und versuche, das zu verstehen. :D

      Grüße
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      Update auf Version 1.11.4
      • Change all SharpMath.Geometry classes to structs and consequently, revise the whole architecture
      • Change Vector.ScalarProduct to VectorUtils.DotProduct<T>
      • Change Vector2.CrossProduct to Vector2.Perpendicular-property
      • Change Vector3.CrossProduct to Vector3.VectorProduct
      • Change Vector.IsParallelTo to VectorUtils.CheckForParallelism<T>
      • Change Vector.IsOrthogonalTo to VectorUtils.CheckForOrthogonality<T>
      • Change Vector.IsOrthonormalTo to VectorUtils.CheckForOrthonormality<T>
      • Add more extension methods for IMatrix in MatrixUtils
      • Add different structs implementing IMatrix and/or ISquareMatrix
      • Fix Polygon.ContainsPoint not working properly
      • Fix possible errors in comparison operators
      • Documentation improvements
      • ...
      Ich habe nun die Geometry-Klassen entsprechend zu Strukturen geändert. Diese implementierten ein jeweiliges Interface und in einer anderen Klasse sind für diese entsprechende Extensions definiert, die somit als solche oder statische Methoden genutzt werden können. Da eben beides möglich ist, habe ich ein paar Methoden umbenannt.
      Es fehlen immer noch UnitTests, neue Features, wie vorgeschlagen und ein paar Verbesserungen gibt es noch zu machen, aber die Architektur ist jetzt grundlegend mal umgeändert und man kann darauf aufbauen. Fehler wurden entsprechend behoben.

      Meldet weiterhin Probleme, Wünsche und Anregungen. Viel Spaß damit!
      #define for for(int z=0;z<2;++z)for // Have fun!
      Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

      Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
      "Vector.IsOrthonormalTo to VectorUtils.CheckForOrthonormality<T>" und die anderen beiden - weshalb? Ich hätte maximal das "To" entfernt, aber ansonsten war die ursprüngliche Variante doch keineswegs schlecht? Finde die neue eher unintuitiv.

      Grüße
      "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

      Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!