AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Maßeinheiten als Typen

Ein Thema von Ghostwalker · begonnen am 11. Okt 2018 · letzter Beitrag vom 18. Okt 2018
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von JasonDX
JasonDX
(CodeLib-Manager)

Registriert seit: 5. Aug 2004
Ort: München
1.062 Beiträge
 
#1

AW: Maßeinheiten als Typen

  Alt 12. Okt 2018, 14:21
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
Mike
Passion is no replacement for reason
  Mit Zitat antworten Zitat
Mikkey

Registriert seit: 5. Aug 2013
265 Beiträge
 
#2

AW: Maßeinheiten als Typen

  Alt 12. Okt 2018, 21:18
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.
  Mit Zitat antworten Zitat
Benutzerbild von TigerLilly
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
1.251 Beiträge
 
Delphi 12 Athens
 
#3

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 07:39
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
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#4

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 08:21
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.

Geändert von Schokohase (15. Okt 2018 um 08:35 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 08:24
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.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#6

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 08:33
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)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 08:51
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.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.735 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 13:08
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
Thomas Mueller
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.520 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 13:31
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.)
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#10

AW: Maßeinheiten als Typen

  Alt 15. Okt 2018, 14:01
@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 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.

Geändert von Schokohase (15. Okt 2018 um 14:10 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:10 Uhr.
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