Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Maßeinheiten als Typen (https://www.delphipraxis.net/198184-masseinheiten-als-typen.html)

Ghostwalker 12. Okt 2018 12:18

AW: Maßeinheiten als Typen
 
@Schokohase

Mein Post bezog sich insbesondere auf diese Aussage:
Zitat:

Zitat von TiGü (Beitrag 1415578)
Du musst nur verstehen das Kilogramm, Gramm, Mikrogramm, Nanogramm K E I N E verschiedenen Maßeinheiten sind.

und die ist schlicht [Zensiert]. :)

Klar sind 1000g = 1Kg [B]ABER] 1000g <> 1000Kg <> 1000m <> 1000V

TiGü 12. Okt 2018 12:24

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415622)
@Schokohase

Mein Post bezog sich insbesondere auf diese Aussage:
Zitat:

Zitat von TiGü (Beitrag 1415578)
Du musst nur verstehen das Kilogramm, Gramm, Mikrogramm, Nanogramm K E I N E verschiedenen Maßeinheiten sind.

und die ist schlicht [Zensiert]. :)

Klar sind 1000g = 1Kg [B]ABER] 1000g <> 1000Kg <> 1000m <> 1000V

Man könnte auch sagen [zensiert] = richtig! :roll:

Sowas wie 1000g <> 1000kg zog niemand in Zweifel, da 1000 g ungleich zu 1000000 g ist (bzw. 1 kg ungleich 1000 kg).
Du denkst - oder es kommt uns allen nur so vor - das die MaßEINHEIT Gramm und Kilogramm zwei verschiedene Paar Schuhe sind.
Das ist aber nicht so. Das eine Schuh-Paar ist nur "größer", aber sonst das selbe (!) Modell.

Einen gängigen Weg, wie man das mit Operatoren im Record erschlagen kann, hast du im Laufe der letzten Seiten vielfach aufgezeigt bekommen.

Ghostwalker 12. Okt 2018 13:08

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von TiGü (Beitrag 1415623)
Du denkst - oder es kommt uns allen nur so vor - das die MaßEINHEIT Gramm und Kilogramm zwei verschiedene Paar Schuhe sind.

Jain. Ich denke ich hab mich da ein wenig zu Umgangssprachlich ausgedrückt. :)

Die Maßeinheiten Gramm und Kilogramm bezeichnen letztlich ein Gewicht. Der Unterschied besteht hier nur in der Granulierung oder dem Faktor mit Bezug zu den anderen Einheiten bei Gewichten.

Und richtig, es wurde ein Beispiel für die Impelentierung mit einem Typen genannt.

Leider konnte mir bisher keiner Erläutern, wo der Vorteil liegt, wenn man das als ein Typ implementiert (gegenüber der Implementierung durch einzelne Typen; den seh ich nämlich irgendwie nicht wirklich).

TiGü 12. Okt 2018 13:37

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415626)
Leider konnte mir bisher keiner Erläutern, wo der Vorteil liegt, wenn man das als ein Typ implementiert (gegenüber der Implementierung durch einzelne Typen; den seh ich nämlich irgendwie nicht wirklich).

Wahrscheinlich weil du nur dein reales Problem siehst (was nichts mit Gewicht zu tun hat?) und eine schlechte Analogie verwendest und uns hier mit dem Gewicht-Beispiel mental verhungern lässt?!

Schokohase 12. Okt 2018 14:11

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415626)
Leider konnte mir bisher keiner Erläutern, wo der Vorteil liegt, wenn man das als ein Typ implementiert (gegenüber der Implementierung durch einzelne Typen; den seh ich nämlich irgendwie nicht wirklich).

Na dann erstelle doch einfach deine 21 Typen (Centigram, Decagram, Decigram, Gram, Hectogram, Kilogram, Kilopound, Kilotonne, LongHundredweight, LongTon, Megapound, Megatonne, Microgram, Milligram, Nanogram, Ounce, Pound, ShortHundredweight, ShortTon, Stone, Tonne) oder sogar mehr, wenn da noch Bedarf besteht.

Ich nehme da nur einen und bin schon fertig. Warum wohl? Eben, weil es schneller geht und ich keinen Vorteil bei der Aufsplitung sehe.

JasonDX 12. Okt 2018 14:21

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415626)
Leider konnte mir bisher keiner Erläutern, wo der Vorteil liegt, wenn man das als ein Typ implementiert (gegenüber der Implementierung durch einzelne Typen; den seh ich nämlich irgendwie nicht wirklich).

Weil durch einzelne Typen jede Methode, die bspw. einen Gewichtsparameter hat, für jeden Typen für Gewicht überladen werden muss.
Einfaches Beispiel:
Delphi-Quellcode:
procedure doSomething(weight: TTon);
procedure doSomething(weight: TTonne);
procedure doSomething(weight: TKilogram);
procedure doSomething(weight: TGram);
procedure doSomething(weight: TMilligram);
procedure doSomething(weight: TMicrogram);
procedure doSomething(weight: TPound);
procedure doSomething(weight: TStone);
procedure doSomething(weight: TSlug);

// Aufruf:
doSomething(100 as TStone);
Im Gegensatz zu
Delphi-Quellcode:
procedure doSomething(weight: TWeight);

// Aufruf:
doSomething(TWeight.getStones(100));
Und das ganze wird schlimmer, wenn du Parameter kombinieren willst:

Delphi-Quellcode:
function computeSpeed(distance: TYards; time: TSeconds): TMeterPerSecond
function computeSpeed(distance: TMeters; time: TSeconds): TMeterPerSecond
function computeSpeed(distance: TMillimeters; time: TSeconds): TMeterPerSecond
function computeSpeed(distance: TKilometers; time: TSeconds): TMeterPerSecond
function computeSpeed(distance: TInches; time: TSeconds): TMeterPerSecond
function computeSpeed(distance: TMiles; time: TSeconds): TMeterPerSecond

function computeSpeed(distance: TYards; time: TMinutes): TMeterPerSecond
function computeSpeed(distance: TMeters; time: TMinutes): TMeterPerSecond
function computeSpeed(distance: TMillimeters; time: TMinutes): TMeterPerSecond
function computeSpeed(distance: TKilometers; time: TMinutes): TMeterPerSecond
function computeSpeed(distance: TInches; time: TMinutes): TMeterPerSecond
function computeSpeed(distance: TMiles; time: TMinutes): TMeterPerSecond

function computeSpeed(distance: TYards; time: THours): TMeterPerSecond
function computeSpeed(distance: TMeters; time: THours): TMeterPerSecond
function computeSpeed(distance: TMillimeters; time: THours): TMeterPerSecond
function computeSpeed(distance: TKilometers; time: THours): TMeterPerSecond
function computeSpeed(distance: TInches; time: THours): TMeterPerSecond
function computeSpeed(distance: TMiles; time: THours): TMeterPerSecond

Mikkey 12. Okt 2018 21:18

AW: Maßeinheiten als Typen
 
Eine Anregung von jenseits des Delphi-Tellerrands:
Es gibt für C++ eine Bibliothek, die Deine Aufgabenstellung (m.E. perfekt) aufgreift:

https://www.boost.org/doc/libs/1_37_...ost_units.html

Ich habe die selbst schon verwendet und finde den Ansatz sehr gut.

Vielleicht kannst Du daraus ein paar Anregungen mitnehmen und Dir etwas erstellen, was (natürlich) nicht so komplett ist, aber den Bedarf erfüllt.

TigerLilly 15. Okt 2018 07:39

AW: Maßeinheiten als Typen
 
Hmm. Zurück auf den Boden. Ich kenn das, was der TE will, zB aus dem Bereich von Rezepturen. Da hast du Zutaten, mache in GRAMM, manche in KILOGRAMM, vielleicht sogar manche in LITER.
Wenn man das Gesamtgewicht der Rezeptur wissen will, muss man addieren + da wäre es natürlich ganz cool wenn schon der Compiler dafür sorgt, dass GRAMM und KILOGRAMM von der richtigen Methode addiert würden.

Aber wie ich auch schon gesagt habe, scheint mir das zu umständlich und auch knapp daneben gezielt. Denn ich habe ja immer eine Kombination aus Wert+Einheit + so würde ich das auch meinen Methoden übergeben:
Addiere(120, 'KG', 12, 'GRAMM');
AddiereKGzuGRAMM(120,12); // da kann ich sogar Typsicherheit haben! type TKG = type Float;
ToGramm(TKG):TGRAMM; // wieder: Typsicher
ToGramm(TMG):TGRAMM; // wieder: Typsicher + overloaded

Schokohase 15. Okt 2018 08:21

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von TigerLilly (Beitrag 1415759)
Denn ich habe ja immer eine Kombination aus Wert+Einheit

Genau, es ist eine Kombination, die man z.B. auch so abbilden kann
Delphi-Quellcode:
TMassUnit = (Undefined, Gram, Kilogram, Milligram, Tonne);

TMass = record
private
  FValue: Extended; // Wert
  FUnit: TMassUnit; // Einheit
public
  constructor Create(AValue: Extended; AUnit: TMassUnit);
  property Value: Extended read FValue;
  property &Unit: TMassUnit read FUnit;
private
  function AsBaseUnit(): Extended;
  function AsBaseNumericType(AUnit: TMassUnit);
public
  property Grams: Extended index TMassUnit.Gram read AsBaseNumericType;
  property Kilograms: Extended index TMassUnit.Kilogram read AsBaseNumericType;
  property Milligrams: Extended index TMassUnit.Milligram read AsBaseNumericType;
  property Tonnes: Extended index TMassUnit.Tonne read AsBaseNumericType;
end;

function TMass.AsBaseUnit(): Extended;
var
  x:Extended;
begin
  x := Value;
  case FUnit of
    TMass.Gram: Result := x / 1e3;
    TMass.Kilogram: Result := x;
    TMass.Milligram: Result := x / 1e6;
    TMass.Tonne: Result := x * 1e3;
  else
    raise ENotImplementedException.Create('Fehler');
  end;
end;

function TMass.AsBaseNumericType(AUnit: TMassUnit): Extended;
var
  x: Extended;
begin
  if (AUnit = FUnit)
    Exit(FValue);

  x := AsBaseUnit();

  case AUnit of
    TMass.Gram: Result := x * 1e3;
    TMass.Kilogram: Result := x;
    TMass.Milligram: Result := x * 1e6;
    TMass.Tonne: Result := x / 1e3;
  else
    raise ENotImplementedException.Create('Fehler');
  end;
end;
In diesem Record kann man jetzt problemlos die Rechenoperationen und Umrechnungen implementieren und man hat einen Typen für das Gewicht.

KodeZwerg 15. Okt 2018 08:24

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Schokohase (Beitrag 1415761)
In diesem Record kann man jetzt problemlos die Rechenoperationen und Umrechnungen implementieren und man hat einen Typen für das Gewicht.

roter text, du hast mir meinen gedanken geklaut, wollte fast das gleich schreiben da der komplette thread letztendlich auf sowas hinaus läuft, bin ich jedenfalls auch der meinung.

Schokohase 15. Okt 2018 08:33

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1415762)
Zitat:

Zitat von Schokohase (Beitrag 1415761)
In diesem Record kann man jetzt problemlos die Rechenoperationen und Umrechnungen implementieren und man hat einen Typen für das Gewicht.

roter text, du hast mir meinen gedanken geklaut, wollte fast das gleich schreiben da der komplette thread letztendlich auf sowas hinaus läuft, bin ich jedenfalls auch der meinung.

Also von dir habe ich das ganz bestimmt nicht, sondern von hier (und den Link zu dem Projekt hatte ich auch schon gepostet)

KodeZwerg 15. Okt 2018 08:51

AW: Maßeinheiten als Typen
 
Du hast mich missverstanden, macht ja nichts, ich wollte nicht sagen das Du etwas von mir hast, ich wollte fast das selbe schreiben, sagte ich ja.
Gute Hilfe, weiter so.

dummzeuch 15. Okt 2018 13:08

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Schokohase (Beitrag 1415761)
Zitat:

Zitat von TigerLilly (Beitrag 1415759)
Denn ich habe ja immer eine Kombination aus Wert+Einheit

Genau, es ist eine Kombination, die man z.B. auch so abbilden kann
Delphi-Quellcode:
TMassUnit = (Undefined, Gram, Kilogram, Milligram, Tonne);

TMass = record
private
  FValue: Extended; // Wert
  FUnit: TMassUnit; // Einheit
public
  constructor Create(AValue: Extended; AUnit: TMassUnit);
  property Value: Extended read FValue;
  property &Unit: TMassUnit read FUnit;
private
  function AsBaseUnit(): Extended;
  function AsBaseNumericType(AUnit: TMassUnit);
public
  property Grams: Extended index TMassUnit.Gram read AsBaseNumericType;
  property Kilograms: Extended index TMassUnit.Kilogram read AsBaseNumericType;
  property Milligrams: Extended index TMassUnit.Milligram read AsBaseNumericType;
  property Tonnes: Extended index TMassUnit.Tonne read AsBaseNumericType;
end;
In diesem Record kann man jetzt problemlos die Rechenoperationen und Umrechnungen implementieren und man hat einen Typen für das Gewicht.

Aber es ist immernoch zu kompliziert. Wieso nicht den Wert immer in der Basiseinheit speichern und beim Zuweisen bzw. Auslesen aus diesem umrechnen? Die von Dir gewählte Implementation hat höchstens den Vorteil, dass, wenn man in derselben Einheit schreibt und dann ausliest, keine Umrechnungstattfindet, also auch keine Rechenungenauigkeiten auftreten.

Letzteres ist ein nicht zu unterschätzendes Problem, wenn es auf Genauigkeit ankommt. Da wäre es evtl. sinnvoll, zum Speichern des Wertes statt eines Fließkommatyps einen Integer in einer Einheit zu verwenden, die klein genug ist, um alles notwendige abzubilden, z.B. 1 mg oder auch 1 ug (vorausgesetzt kleinere Massen interessieren nicht). Oder man kombiniert einen Integer mit einem dezimalen Exponenten. d.h. Bei Zuweisung von 1 mg speichert man 1 als Wert und -1000000 als Exponent. Liest man dann den Wert in g aus, erhält man 0.001.

twm

freimatz 15. Okt 2018 13:31

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von dummzeuch (Beitrag 1415774)
Letzteres ist ein nicht zu unterschätzendes Problem, wenn es auf Genauigkeit ankommt. Da wäre es evtl. sinnvoll, zum Speichern des Wertes statt eines Fließkommatyps einen Integer in einer Einheit zu verwenden, die klein genug ist, um alles notwendige abzubilden, z.B. 1 mg oder auch 1 ug (vorausgesetzt kleinere Massen interessieren nicht).

Versteh ich nicht. Ein Fließkommatyp ist doch genauer als ein Integer? (Zumindest wenn man Double nimmt.)

Schokohase 15. Okt 2018 14:01

AW: Maßeinheiten als Typen
 
@dummzeuch

Es ist zu kompliziert, dass der Typ exakt das speichert was man dem zugewiesen hat? Das ist nicht höchtens sondern genau der Vorteil dieser Implementierung. So gut wie keine Veränderung der zugewiesenen Daten (bis auf die allgemeine Problem mit den Fließkommazahlen).

Es geht hier auch nicht darum ein höchst exakt rechnendes System vorzustellen, sondern nur einen Typen, der so genau ist wie Delphi selber rechnet aber mit Dimensionen/Einheiten umgehen kann.

Aber man kann es ja auch wie folgt deklarieren:
Delphi-Quellcode:
TValueType = Extended;

TMassUnit = (Undefined, Gram, Kilogram, Milligram, Tonne);

TMass = record
private
  FValue: TValueType; // Wert
  FUnit: TMassUnit; // Einheit
public
  constructor Create(AValue: TValueType; AUnit: TMassUnit);
  property Value: TValueType read FValue;
  property &Unit: TMassUnit read FUnit;
private
  function AsBaseUnit(): TValueType;
  function AsBaseNumericType(AUnit: TMassUnit);
public
  property Grams: TValueType index TMassUnit.Gram read AsBaseNumericType;
  property Kilograms: TValueType index TMassUnit.Kilogram read AsBaseNumericType;
  property Milligrams: TValueType index TMassUnit.Milligram read AsBaseNumericType;
  property Tonnes: TValueType index TMassUnit.Tonne read AsBaseNumericType;
end;
dann implementierst du einen gaaaaaanz genauen Float-Type und tauscht den dort gegen Extended aus.

PS

Achja, ich vergaß noch einen (in meinen Augen) Vorteil:

Wenn man sich beim debuggen die lokalen Variablen anschaut, dann erscheint dort z.B.:
Code:
(15,Gram)
Finde ich persönlich eingängiger, als wenn dort lediglich
Code:
(0.015)
steht (die basiseinheit ist ja Kilogramm)

Und wenn man dann noch
Delphi-Quellcode:
ToString()
implementiert, dann ist es doch auch schön wenn dort 15g ausgegeben wird und eben nicht 0,015kg, eben immer so wie man es der Variablen auch zugewiesen hat.

p80286 15. Okt 2018 16:20

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von freimatz (Beitrag 1415775)
Zitat:

Zitat von dummzeuch (Beitrag 1415774)
Letzteres ist ein nicht zu unterschätzendes Problem, wenn es auf Genauigkeit ankommt. Da wäre es evtl. sinnvoll, zum Speichern des Wertes statt eines Fließkommatyps einen Integer in einer Einheit zu verwenden, die klein genug ist, um alles notwendige abzubilden, z.B. 1 mg oder auch 1 ug (vorausgesetzt kleinere Massen interessieren nicht).

Versteh ich nicht. Ein Fließkommatyp ist doch genauer als ein Integer? (Zumindest wenn man Double nimmt.)

Nö, ein Fießkommatyp ist immer eine Näherung, meist eine sehr genaue, aber eben eine Näherung.
vgl hierzu Currency!

Gruß
K-H

freimatz 15. Okt 2018 17:05

AW: Maßeinheiten als Typen
 
Sorry versteh ich immer noch nicht. Nach http://docwiki.embarcadero.com/RADSt...e_Typenhttp:// hat ein Integer 32-Bit. Ein Double benötigt 64-Bit, davon hat die Mantisse 52 Bit. Das ist immer noch weit mehr als die 32 bei Integer. Ich kann jeden beliebigen Wert eines Integers in einem Double speichern und wieder herausholen ohne Verlust. Anders sieht es bei einem Int64 aus, der hat dann mehr als der Double.

Wir verwenden fast grundsätzlich Double, welche als Länge in Millimeter oder als Bogenmass definiert sind. Umgerechnet werden die nur bei der Ein- und Ausgabe.

Ghostwalker 15. Okt 2018 17:21

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von freimatz (Beitrag 1415802)
Sorry versteh ich immer noch nicht. Nach http://docwiki.embarcadero.com/RADSt...e_Typenhttp:// hat ein Integer 32-Bit. Ein Double benötigt 64-Bit, davon hat die Mantisse 52 Bit. Das ist immer noch weit mehr als die 32 bei Integer. Ich kann jeden beliebigen Wert eines Integers in einem Double speichern und wieder herausholen ohne Verlust. Anders sieht es bei einem Int64 aus, der hat dann mehr als der Double.

Wir verwenden fast grundsätzlich Double, welche als Länge in Millimeter oder als Bogenmass definiert sind. Umgerechnet werden die nur bei der Ein- und Ausgabe.

Jain.

Int64 hat, wie double auch, 64-Bit. Sein Ganzzahliger Wertebereich ist aber größer als der von Double. Dafür kann ich den kleineren Wertebereich von Double genauer auflösen. Alternativ kann man auch Extended verwenden, der dann 80 Bit(32-Bit win) hat und noch genauer auflöst.

Ob man nun Fließkomma oder Ganzzahlige Werte benutzt, kommt auf den Context an. u.U. ist auch eine Festkomma Aritmethik eine Option.

Ghostwalker 16. Okt 2018 06:03

AW: Maßeinheiten als Typen
 
Ich hab den Vorschlag von Uwe Raabe mal aufgegriffen und das ganze testhalber mal wie folgt
aufgebaut:

Delphi-Quellcode:
TYPE
  TGramm = -9223372036854775807..9223372036854775807;
  TKilo = -9223372036854775..9223372036854775;
  TTonne = -9223372036854..9223372036854;
  TMegat = -9223372036..9223372036;

  TGewicht = Record
    private
      fvalue : int64;

    strict private
      Class constructor Create; //<-- Hier werden die Classvars entsprechend belegt

    private class var
        GrammPerKilo : int64;
        GrammPerTonne: int64;
        GrammPerMegat: int64;

    public

       Class Operator Implicit(const value:int64):TGewicht;
       Class Operator Implicit(const value:TGewicht):int64;

       Class Operator Implicit(const value:TGramm):TGewicht;
       Class Operator Implicit(const value:TKilo):TGewicht;
       Class Operator Implicit(const value:TTonne):TGewicht;
       Class Operator Implicit(const value:TMegat):TGewicht;

       Class Operator Add(const left,right:TGewicht):TGewicht;
       Class Operator Subtract(const left,right:TGewicht):TGewicht;
  End;
Damit hätte ich die meisten Anforderungen eigentlich abgedeckt. Was meint ihr ?

freimatz 16. Okt 2018 06:57

AW: Maßeinheiten als Typen
 
Welche Anforderungen? Die des Ausgangspostings? Dann meine ich Ja.
Bei den Anforderungen die ich an sowas hätte Nein. Wenn ich 1437 Gramm hätte und das als Kilogramm wollte, dann würde ich schon 1.437 Kilogramm wollen.

Die private class var verstehe ich nicht so recht. Reichen da nicht Konstanten?

Uwe Raabe 16. Okt 2018 07:50

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von freimatz (Beitrag 1415827)
Wenn ich 1437 Gramm hätte und das als Kilogramm wollte, dann würde ich schon 1.437 Kilogramm wollen.

Ich kann zwar die Implementierung hier nicht sehen, aber nach meinem Vorschlag sollte jedenfalls genau das dabei herauskommen. Zumindest ist das in meinem Beispiel von #14 so.

KodeZwerg 16. Okt 2018 08:08

AW: Maßeinheiten als Typen
 
Wir sind doch erst auf Seite 7, da kommt noch mehr :-]

Uwe Raabe 16. Okt 2018 08:19

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von freimatz (Beitrag 1415827)
Wenn ich 1437 Gramm hätte und das als Kilogramm wollte, dann würde ich schon 1.437 Kilogramm wollen.

Ich sehe gerade, daß dort mit Int64 statt einem Float-Typ gearbeitet wird. Dann kann das natürlich wirklich nicht funktionieren.

Sherlock 16. Okt 2018 09:29

AW: Maßeinheiten als Typen
 
Verstehe ich das richtig, daß hier die eierlegende Wollmilchsau gesucht wird? Das ist sowas von nicht KISS, jeder Vorschlag dafür würde bei uns im Keim erstickt werden. Aber für akademische Diskussionen sicherlich schön.

Sherlock

TiGü 16. Okt 2018 09:56

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415825)
Delphi-Quellcode:
TYPE
  TGramm = -9223372036854775807..9223372036854775807;
  TKilo = -9223372036854775..9223372036854775;
  TTonne = -9223372036854..9223372036854;
  TMegat = -9223372036..9223372036;
Damit hätte ich die meisten Anforderungen eigentlich abgedeckt. Was meint ihr ?

Wirklich? Ein ganzzahliger negativer Wertebereich? Für Gewicht? :roll:

"Ich hätte gerne minus 3 kg Gehacktes!"

Hoffentlich sieht kein Kollege von dir diesen Thread.

freimatz 16. Okt 2018 10:25

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von TiGü (Beitrag 1415847)
Wirklich? Ein ganzzahliger negativer Wertebereich? Für Gewicht? :roll:
"Ich hätte gerne minus 3 kg Gehacktes!"

Das bedeutet dann "Ich würde gerne 3 kg Gehacktes zurückgeben." :lol:
Wirft zwar eine ENotHygienicException, aber was solls ;-)

Ghostwalker 16. Okt 2018 13:05

AW: Maßeinheiten als Typen
 
@TiGü

Wie ich bereits, gefühlte 1000 mal geschrieben hab, ist das ein Beispiel. Ob du nun Gewichte, Zeit, Längen oder Engström nutzt ist fürs prinzipielle Vorgehen relativ wurscht.

@freimatz

Nein, da es kein "class const" gibt. Um die umrechnerei in den Class Operatoren unter zu kriegen, muss man den Umweg über "class var" in Verbindung mit dem Class Constructor gehen. Emba hats in TTimespan z.B. auch so gemacht.

Uwe Raabe 16. Okt 2018 13:13

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415864)
Nein, da es kein "class const" gibt.

Was würde denn dann eine
Delphi-Quellcode:
class const
Konstante von einer gemeinen
Delphi-Quellcode:
const
Konstante unterscheiden? :gruebel:

Delphi-Quellcode:
  TGewicht = Record
  private const
    GrammPerKilo = 1000;
    GrammPerTonne = 1000+GrammPerKilo;
    GrammPerMegat = 1000*1000*GrammPerTonne;
  End;

Raible 16. Okt 2018 13:55

AW: Maßeinheiten als Typen
 
Hallo zusammen,

ich habe mal einen record für Werte mit SI-Einheit umgesetzt.

Code:
 
TSIValue = record
  Value   : double;
  UnitExpr : TSIUnitExpression;
  ...

TSIUnitExpression = record
private
  FUnitArray :TSIUnitArray;
  ...

TSIUnitArray = TArray<TSIUnit>;

TSIUnit = record
  Praefix  :TSIPraefix;
  UnitTyp  :TSIUnitTyp;
  Power    :shortint;
  ...

  {$SCOPEDENUMS ON}
  TSIPraefix = (
    Yotta,
    Zetta,
    Exa,
    Peta,
    Tera,
    Giga,
    Mega,
    Kilo,
    Hekto,
    Deka,
    None,
    Dezi,
    Zenti,
    Milli,
    Mikro,
    Nano,
    Piko,
    Femto,
    Atto,
    Zepto,
    Yokto);

  TSIUnitTyp = (
    None,

    //SI Basiseinheiten
    Metre,
    Gramm,
    Second,
    Ampere,
    Kelvin,
    Mole,
    Candela,

    //nicht SI Basiseinheiten
    Euro,

    //Abgeleitete SI-Einheiten
    Newton,
    Joule,
    Watt,
    Coulomb,
    Volt,
    Ohm,
    Farad,
    &Pascal,
    Bar
   );
  {$SCOPEDENUMS OFF}
die Einheit TSIUnit setzt sich dabei aus einem Einheitentyp (m, sec, g, ...), einem Faktor (TSIPraefix G, M, k, ...) und einer Potenz zusammen. Die Potenz ist wichtig für zB. m² oder für Einheiten im Nenner.

TSIUnitExpression definiert eine Liste von TSIUnit die miteinander Multipliziert die eigentliche Einheit darstellt.
Hier kann dann z.B N = kg*m/sec² realisiert werden.

Möchte man zwei TSIValue miteinander verrechnen müssen auch die TSIUnitExpression mathematisch korrekt verrechnet werden.

Beispiel:
Code:
var
  Masse:TSIValue;
  Laenge:TSIValue;
  Zeit:TSIValue;
  Kraft:TSIValue;
  Text:string;

begin
  Masse := '5 kg'
  Laenge:= '123 cm';
  Zeit := '10 s';
  Kraft := Masse * Laenge / (Zeit * Zeit);
  Text := Kraft; // Text='0.06 m*kg/s²'

Bei Interesse könnte ich den Code
auch zur Verfügung stellen.
Allerdings benötige ich dann etwas
Hilfe bei Lizenzierungsfragen.

Ghostwalker 17. Okt 2018 05:14

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1415867)
Zitat:

Zitat von Ghostwalker (Beitrag 1415864)
Nein, da es kein "class const" gibt.

Was würde denn dann eine
Delphi-Quellcode:
class const
Konstante von einer gemeinen
Delphi-Quellcode:
const
Konstante unterscheiden? :gruebel:

Delphi-Quellcode:
  TGewicht = Record
  private const
    GrammPerKilo = 1000;
    GrammPerTonne = 1000+GrammPerKilo;
    GrammPerMegat = 1000*1000*GrammPerTonne;
  End;

Ganz einfach.

Bei "private const" stehen die Konstanten nur in einer konkreten Instanz (sprich Variable) zur Verfügung.
Folglich (und das hat mir der Delphi-Compiler recht deutlich mitgeteilt) kann man sie so nicht in den
Operatoren verwenden.

Also hab ich mir ein Beispiel an Emba genommen und das ganze wie oben umgesetzt. Damit kann ich die Konstanten auch in den Operatoren verwenden.

Uwe Raabe 17. Okt 2018 07:20

AW: Maßeinheiten als Typen
 
Zitat:

Zitat von Ghostwalker (Beitrag 1415920)
Bei "private const" stehen die Konstanten nur in einer konkreten Instanz (sprich Variable) zur Verfügung.
Folglich (und das hat mir der Delphi-Compiler recht deutlich mitgeteilt) kann man sie so nicht in den
Operatoren verwenden.

Also mein Compiler (10.2.3) findet das hier vollkommen OK:
Delphi-Quellcode:
  TGewicht = record
  private
    FValue : Extended;
  private const
    GrammPerKilo = 1000.0;
    GrammPerTonne = 1000.0*GrammPerKilo;
    GrammPerMegat = 1000.0*1000.0*GrammPerTonne;
  public
     Class Operator Implicit(const Value:TTonne):TGewicht;
  end;

class operator TGewicht.Implicit(const Value: TTonne): TGewicht;
begin
  Result.FValue := Value*GrammPerTonne;
end;

Ghostwalker 17. Okt 2018 08:49

AW: Maßeinheiten als Typen
 
:gruebel:Öhmm.....jup.....nochmal getestet...nu tuts.....komisch.

Am Rande

Delphi-Quellcode:
Type
  TGramm = -xxxxxx .. xxxxxx
  usw.

  TGewicht = record
    //wie gehabt
    Class Oporator Implicit(const value:int64):TGewicht;
    Class Operator Implicit(const value:TGewicht):Int64;

    Class Operator Implicit(const value:TGramm):TGewicht;
    Class Operator Implicit(const value:TKilo):TGewicht;
    Class Operator Implicit(const value:TTonne):TGewicht;


IMPLEMENTATION

Class Opertator TGewicht.Implicit(const value:int64):TGewicht;
begin
  result.fvalue := value;
end;

Class Opertator TGewicht.Implicit(const value:TGewicht):Int64;
begin
  result := value.fvalue;
end;

Class Opertator TGewicht.Implicit(const value:TGramm):TGewicht;
begin
  result.fvalue := value;
end;

Class Opertator TGewicht.Implicit(const value:TKilo):TGewicht;
begin
  result.fvalue := value*GrammPerKilo;
end;

Class Opertator TGewicht.Implicit(const value:TTonne):TGewicht;
begin
  result.fvalue := value*GrammPerTonne;
end;
In die IDE zeigt mir hier einen Fehler im Implementation Abschnitt an, das der Bezeichner redifiniert wird. Allerdings erst bei Implicit(const value:TKilo). Der Compiler läuft ohne Probleme durch, und lt. meinen
Unittests wird das ganze auch korrekt gehandhabt.

KodeZwerg 17. Okt 2018 09:04

AW: Maßeinheiten als Typen
 
Delphi-Quellcode:
Class Oporator Implicit(const value:int64):TGewicht;
// <-- classname korrekt?
Delphi-Quellcode:
Class Opertator
// <-- classname korrekt?

Ghostwalker 18. Okt 2018 09:31

AW: Maßeinheiten als Typen
 
@Kodezwerg

Nope, da sind nur zwei Tippfehler hier im Forum drinn, im Quelltext is alles richtig geschrieben.
Außerdem würde da der Compiler auch Meckern. :)


Die Fehlermeldung ist:

"Bezeichner neu deklariert TGewicht.Implicit !"

Auch ein overload bei der Deklaration hilft leider nicht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:52 Uhr.
Seite 2 von 2     12   

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