Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   [.NET] Generics und Operatorüberladung (https://www.delphipraxis.net/136943-%5B-net%5D-generics-und-operatorueberladung.html)

Phoenix 11. Jul 2009 14:26

Re: [.NET] Generics und Operatorüberladung
 
Erm.. Dax... musstest Du ihn jetzt so schocken? :mrgreen:
Gleich mit Anonymen Methoden so um Dich zu hauen ist ned nett auf einen Samstagnachmittag ;-)

Medium 11. Jul 2009 14:56

Re: [.NET] Generics und Operatorüberladung
 
Um ehrlich zu sein, gefällt mir das sogar garnicht schlecht! Und ich erwäge ernsthaft meine jetzt bereits bestehende 2-Klassen Lösung dafür zu opfern. Ich muss nur noch austüfteln wie ich da nun die Multiplikation mit umsetze, wobei ich, glaube ich, schon eine grobe Vorstellung hab. Phoenix' Bedenken waren nicht ungerechtfertigt - aber ich schein grad ne helle Minute zu haben :) Goßen Dank!

Phoenix 11. Jul 2009 15:59

Re: [.NET] Generics und Operatorüberladung
 
Zusätzlich zum Combiner<T> kannst Du ja noch einen Multiplier<T> mit übergeben. Der sieht dann im Prinzip genauso aus, multipliziert halt anstelle von Addition.

Dax 11. Jul 2009 17:18

Re: [.NET] Generics und Operatorüberladung
 
Zitat:

Zitat von Phoenix
Zusätzlich zum Combiner<T> kannst Du ja noch einen Multiplier<T> mit übergeben. Der sieht dann im Prinzip genauso aus, multipliziert halt anstelle von Addition.

Mein Gedanke war eigentlich, den Combiner alles tun zu lassen, aber so geht es natürlich auch ;)

Medium 11. Jul 2009 17:25

Re: [.NET] Generics und Operatorüberladung
 
Sooo, ich bin auf dem Wege, stoße aber gerade an.

Ich hab den Combiner um die Multiplikation erweitert:
Code:
   public class Combiner<T>
   { 
      public Func<T, T, T> Add { 
         get;
         private set;
      }
      
      public Func<T, T, T> Mul {
         get;
         private set;
      }
   
      public Combiner(Func<T, T, T> _add, Func<T, T, T> _mul)
      { 
         Add = _add;
         Mul = _mul;
      } 
   }
Dann in der Matrix<T> Klasse folgenden Operator hinzugefügt:
Code:
      public static Matrix<T> operator *(Matrix<T> left, Matrix<T> right)
      {
         if (left.dimX != right.dimY) throw new ArrayTypeMismatchException("Operation * on mismatching matrices");
         else{
            Matrix<T> result = new Matrix<T>(right.ops, right.dimX, left.dimY);
            result.values = new T[right.dimX*left.dimY];
            for (int x = 0; x < result.dimX; x++) {
               for (int y = 0; y < result.dimX; y++) {
                  for (int k=0; k<left.dimX; k++) {
                     result[x, y] = left.ops.Add(result[x, y], left.ops.Mul(left[k, y], right[x, k]));
                  }
               }
            }
            return result;
         }
      }
Ich erzeuge 2 MatrixFactories:
Code:
   MatrixFactory<double> mfd = new MatrixFactory<double>(new Combiner<double>((a, b) => a + b, (a, b) => a * b));
   MatrixFactory<Matrix<double>> mfm = new MatrixFactory<Matrix<double>>(new Combiner<Matrix<double>>((a, b) => a + b, (a, b) => a * b));
Und dann 2 Matrizen daraus:
Code:
   C = mfd.New(4, 4);

   Q = mfm.New(4, 4);
   for (int x=0; x<4; x++)
      for (int y=0; y<4; y++)
         Q[x, y] = mfd.New(2, 1);
Dann versuche ich sie zu multiplizieren:
Code:
   Matrix<Matrix<double>> tmp;
   tmp = Q*C;
Und der Compiler quittiert mit:
"Operator '*' cannot be applied to operands of type 'Matrix<double>' and 'Matrix<Matrix<double>>' (CS0019)

:gruebel: Was hab ich falsch gemacht?

Phoenix 11. Jul 2009 17:32

Re: [.NET] Generics und Operatorüberladung
 
Code:
public static Matrix<T> operator *(Matrix<T> left, Matrix<T> right);
Matrix<Matrix<double>> tmp = Q*C;
Der * Operator auf einer Matrix<T> liefert laut Definition eine Matrix<T>, also eine Matrix, die T aufnimmt, zurück.
Du definierst aber für tmp eine Matrix<Matrix<T>> als Rückgabetyp.
Also eine Matrix, die Matrizen von T aufnimmt, und nicht eine Matrix, die T aufnimmt.

Eine Matrix die T aufnimmt kann aber nicht automatisch in eine Matrix, die Matrizen von T aufnimmt, konvertiert werden.

Dax 11. Jul 2009 17:45

Re: [.NET] Generics und Operatorüberladung
 
Dein Operator in Q*C hat den Typ (T, Matrix<T>) => Matrix<T>, den hast du aber nicht implementiert. Das ist aber kein Problem, weil die Multiplikation Skalar * Matrix ja echt simpel ist.

Medium 11. Jul 2009 17:59

Re: [.NET] Generics und Operatorüberladung
 
Zitat:

Zitat von Phoenix
Der * Operator auf einer Matrix<T> liefert laut Definition eine Matrix<T>, also eine Matrix, die T aufnimmt, zurück.

Ich multipliziere jedoch eine Matrix<T> mit einer Matrix<Matrix<T>>, was wiederum eine Matrix<Matrix<T>> zurück liefern sollte. Glaub ich =)

Aber was Dax sagte kam mir vor 1min auch in den Sinn. Ich hab zwar die Matrizen mit welchem Inhalt auch immer abgedeckt, jeoch nicht den Fall Inhalt*Matrix bzw. umgekehrt, was ja am Ende dieser Kette ansteht. Das dürfte es gewesen sein, mal testen. Merci euch beiden mal wieder :)

Medium 11. Jul 2009 18:41

Re: [.NET] Generics und Operatorüberladung
 
Fies.

Folgende Konstruktion:
Code:
Matrix<double> k1;
Matrix<Matrix<double>> Q, k2;
k2 = k1 * Q;
Hier ergibt sich eine nicht eindeutige Situation:
Ist k1 nun ein T oder ein Matrix<T>?

Der compiler wählt jedenfalls die falsche Überladung:
Code:
// sollte es sein
public static Matrix<T> operator *(Matrix<T> left, Matrix<T> right)
// wird statt dessen genommen
public static Matrix<T> operator *(T left, Matrix<T> right)
Hintergrund ist der dass k1 eine 1x4 Matrix ist, Q aber eine 4x4|1x2. Somit trifft nachher 1x4 auf 1x2, obwohl ich nicht k1 mit den Komponenten von Q sondern mit Q selbst multiplizieren will, was 1x4*4x4 und damit gültig wäre. Das ist arg unschön :(

Apollonius 11. Jul 2009 18:48

Re: [.NET] Generics und Operatorüberladung
 
Was du vor hast, scheitert nicht an der Überladungsauflösung des Compilers. Vielmehr liegt es daran, dass du dich auf zwei Matrizen mit dem gleichen Elementtyp beschränkst. Denn du willst eben T = double für den linken Operanden und T = Matrix<double> für den rechten. Dafür brauchst du zwei generische Parameter.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:58 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz