Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Extended To String mit dekadischen Einheiten (https://www.delphipraxis.net/136103-extended-string-mit-dekadischen-einheiten.html)

markus5766h 23. Jun 2009 15:53


Extended To String mit dekadischen Einheiten
 
Hallo,
da ich bei der Suche nach einer Umwandlungsfunktion, die mir einen Extended-Wert in einen String wandelt,
und dabei auch die dekadischen (Tausender-) Einheiten angibt, nichts passendes gefunden habe, hier
meine Funktion :

Delphi-Quellcode:
 // uses MATH                  
function ConvertValueToString(Value : Extended; Short, Eleminate : Boolean; OutString : String; accuracy : Integer): String;
Const
 ExportString : array[Boolean, 1..17] of String =
        (('Yokto', 'Zepto', 'Atto', 'Femto', 'Piko', 'Nano', 'Micro', 'Milli',
         '', 'Kilo', 'Mega', 'Giga', 'Terra', 'Peta', 'Exa', 'Zetta', 'Yotta'),
         ('y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm',
         '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'));
var
 Exp    : Integer;
 Range  : Integer;
 ExpStep : Extended;
begin
 ExpStep := 1 / 1000;
 if (accuracy < 0) or (accuracy > 18) then accuracy := 3; // set accuracy := 3 at wrong Input
 if Value = 0 then                                        // Value = 0
  begin
   Result := '0.000 '+OutString;
   Exit;
  end;

 if Value < 0 then Range := -1 else Range := 1;
 Exp := Trunc(ln(Value * Range) / ln(2) / 10+ ExpStep);

 if (Value >= 1E25) or ((1/Value) >= 1E25)
  then Result := Format('%.*f %s', [0, Value, OutString])
   else
    if Eleminate and (Value > -1) and (Value < 1) and (Exp > -8)
     then Result := Format('%.*f %s%s', [accuracy, Value*1000 / Power(10, Exp * 3),
                            ExportString[Short, Exp+8], OutString])
      else Result := Format('%.*f %s%s', [accuracy, Value / Power(10, Exp * 3),
                             ExportString[Short, Exp+9], OutString]);

end;

// konvertiert einen Extended-Wert in einen String
// Value : Wert [Extended]
// Short : True = kurze Exponententialwerte : 'K für Kilo' .... , False = Exponentialwerte ausgeschrieben
// OutString : Einheit zum Anhängen an die Ausgabe
// ausserhalb der Definitionen wird die Standard-Schreibweise zurückgegeben (Bereich: <1E-25 und >1E25)
// accuracy : 0.. 18 NachkommaStellen
// 0 wird als 0.000 und ggf. + OutString zurückgegeben
// Eliminate : True = Eliminierung der führenden Null bei -1 < Wert < 1 , aus 0,123Milli... wird 123Mikro...

shmia 23. Jun 2009 16:03

Re: Extended To String mit dekadischen Einheiten
 
Ich würde den "OutString" einfach weglassen.
Der Benutzer der Funktion kann ja jederzeit selbst eine Einheit (oder sonstigen String) hinten anhängen.
Statt 'not defined' würde ich in diesem Problemfall einfach die wissenschaftliche E-Schreibweise (z.B. 2,789E67) zurückliefern.

himitsu 23. Jun 2009 16:06

Re: Extended To String mit dekadischen Einheiten
 
Zitat:

Delphi-Quellcode:
Result := '0.000 '+OutString;

und was ist, wenn bei ich bei accuracy was anderes wollte, und nicht .000 ?

Zitat:

Delphi-Quellcode:
frmt := '%.'+IntToStr(accuracy)+'f %s';
Format(frmt, [Value, S])

da gibt es so ein knuffiges *
Delphi-Quellcode:
Format('%.*f %s', [accuracy, Value, S])

Zitat:

Delphi-Quellcode:
if (Value * Range) < 1 then Index := 9 + Exp else Index := Exp + 9;

9 + Exp oder Exp + 9 kommt bei mir aber auf's Gleiche raus :gruebel:

Delphi-Quellcode:
Const
ExpString : array[Boolean, 1..17] of String
  = (('Yokto', 'Zepto', 'Atto', 'Femto', 'Piko', 'Nano', 'Micro', 'Milli',
      '', 'Kilo', 'Mega', 'Giga', 'Terra', 'Peta', 'Exa', 'Zetta', 'Yotta'),
     ('y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm',
      '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'));

Result := Format('%.*f %s %s', [accuracy, Value / Power(10, Exp * 3),
  ExpString[Short, Index], OutString]);

// oder doch besser array[Boolean] of array[1..17] of String *grübel*

markus5766h 23. Jun 2009 16:31

Re: Extended To String mit dekadischen Einheiten
 
Hallo,
die überflüssige Zeile mit mit Index ... ist entfernt
und die Rückgabe von 0 kann ja jeder gestalten, wie er möchte,
zumal es wenig Sinn macht, 0 durch diese Funktion zu jagen.

@himitsu : danke, an ein zweidimensionales array hab' ich nun gar nicht gedacht.
... warum einfach, wenn's auch schwer geht ...... :wall:

markus5766h 20. Mär 2016 19:54

AW: Extended To String mit dekadischen Einheiten
 
Moin.

eine etwas überarbeitete Version :

Delphi-Quellcode:

// Value : Wert [Extended]
// Short : True = kurze Exponententialwerte : 'K für Kilo' .... , False = Exponentialwerte ausgeschrieben
// OutString : Einheit zum Anhängen an die Ausgabe
// Accuracy : Genauigkeit
// Digits : NachkommaStellen
// Eliminate : True = Eliminierung der führenden Null bei -1 < Wert < 1 , aus 0,123Milli... wird 123Mikro..

function FloatToStrS(Value : Extended; Short, Eliminate : Boolean; OutString : String; accuracy, digits : Integer): String;
const
  ExportString : array[Boolean, 1..17] of String =
                       ((' Yokto', ' Zepto', ' Atto', ' Femto', ' Piko', ' Nano', ' Micro', ' Milli',
                       ' ', ' Kilo', ' Mega', ' Giga', ' Tera', ' Peta', ' Exa', ' Zetta', ' Yotta'),
                       (' y', ' z', ' a', ' f', ' p', ' n', ' µ', ' m',
                       ' ', ' K', ' M', ' G', ' T', ' P', ' E', ' Z', ' Y'));
var
  Exp : Integer;
  Range : Integer;
  ExpStep : Extended;
begin
  ExpStep := 1 / 1000;
  if (accuracy < 0) or (accuracy > 18) then accuracy := 3;
  if Value = 0 then
    begin
      Result := '0 '+OutString;
      Exit;
    end;

  if Value < 0 then Range := -1 else Range := 1;
  if ((Value > -1) and (Value < 1))
    then Exp := Trunc(ln(Value * Range) / ln(2) / 10 + ExpStep)
      else Exp := Trunc(ln((Value*10) * Range) / ln(2) / 10 + ExpStep)+1;

  if (Value >= 1E25) or ((1/Value) >= 1E25)
    then Result := 'out of Range'
      else
        if ((Eliminate) and (Value > -1) and (Value < 1) and (Exp > -8))
          then Result := FloatToStrF(Value*1000 / Power(10, Exp * 3), ffNumber, accuracy, digits) + ExportString[Short, Exp+8] + OutString
            else if not Eliminate then Result := FloatToStrF(Value / Power(10, Exp * 3), ffNumber, accuracy, digits) + ExportString[Short, Exp+9] + OutString
              else if Eliminate then Result := FloatToStrF(Value / Power(10, (Exp-1) * 3), ffNumber, accuracy, digits) + ExportString[Short, Exp+8] + OutString;
end;

Amateurprofi 21. Mär 2016 03:12

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von markus5766h (Beitrag 1333407)
Moin.

eine etwas überarbeitete Version :

Delphi-Quellcode:

// Value : Wert [Extended]
// Short : True = kurze Exponententialwerte : 'K für Kilo' .... , False = Exponentialwerte ausgeschrieben
// OutString : Einheit zum Anhängen an die Ausgabe
// Accuracy : Genauigkeit
// Digits : NachkommaStellen
// Eliminate : True = Eliminierung der führenden Null bei -1 < Wert < 1 , aus 0,123Milli... wird 123Mikro..

function FloatToStrS(Value : Extended; Short, Eleminate : Boolean; OutString : String; Accuracy, Digits : Integer): String;
const
  ExportString : array[Boolean, 1..17] of String =
        (('Yokto', 'Zepto', 'Atto', 'Femto', 'Piko', 'Nano', 'Micro', 'Milli',
         '', 'Kilo', 'Mega', 'Giga', 'Terra', 'Peta', 'Exa', 'Zetta', 'Yotta'),
         ('y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm',
         '', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'));
var
  Exp : Integer;
  ExpStep : Extended;
begin
  Result := '0' + ' ' + OutString;
  ExpStep := 1/1000;
  Exp := 0;
  if Value <> 0 then
    begin
      Exp := Trunc(ln(Value) / ln(2) / 10 + ExpStep);
      if ((Eleminate) and (Value > -1) and (Value < 1)) then Dec(Exp, 1);
      Value := Value / Power(10, Exp * 3);
    end
      else Value := 0;
  Result := FloatToStrF(Value, ffNumber, accuracy, digits) + ' ' + ExportString[Short, Exp+9] + OutString;
end;

Was fehlt, ist die Prüfung, ob Value innerhalb des verarbeitbaren Bereiches liegt.
Zum Beispiel bei S:=FloatToStrS(1e50,False,False,'',10,5);
gibt deine Funktion 100.000000 m zurück.
Und: "Terra" sollte "Tera" heißen, und die korrekte Kurzform für "Kilo" ist "k", nicht "K"

himitsu 21. Mär 2016 07:44

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von Amateurprofi (Beitrag 1333416)
Und: "Terra" sollte "Tera" heißen, und die korrekte Kurzform für "Kilo" ist "k", nicht "K"

Stimmt, auch wenn es etwas wiedersprüchlich ist, wo doch alle anderen "großen" Einheiten groß und die kleinen Einheiten klein geschrieben sind. :gruebel:


Das erste
Delphi-Quellcode:
Result := '0' + ' ' + OutString;
kann weg, denn der Code kommt immer beim letzten
Delphi-Quellcode:
Result := ...
vorbei. (nur die Nicht-verwendet-Prüfung funktioniert bei gemanageden Typen nicht so richtig)
Delphi-Quellcode:
else Value := 0;
könnte auch weg, denn es ist ja schon 0, aber ich würde die Prüfung eher mit IsZero, IsSameValue oder CompareValue und einem passenden Epsilon aufbauen, falls der Fließkommawert eben mal nicht "ganz" genau 0 ist. :angle:

markus5766h 21. Mär 2016 09:12

AW: Extended To String mit dekadischen Einheiten
 
Moin,

danke für die Anregungen,

"Tera" ist geändert.
Das "K" für KILO ist bewusst groß geschrieben, da sich mittlerweile dies im Allgemeinen als
Schreibweise durchgesetzt hat, wer mag, kann dies ja ändern.

... über eine sinnvolle Prüfung / Behandlung von Werten außerhalb des Arbeitsbereiches werd' ich heute Abend mal nachgrübeln :gruebel:

markus5766h 21. Mär 2016 09:19

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von himitsu (Beitrag 1333422)
...aber ich würde die Prüfung eher mit IsZero, IsSameValue oder CompareValue und einem passenden Expsilon aufbauen, falls der Fließkommawert eben mal nicht "ganz" genau 0 ist. :angle:

Stimmt, aber dann hätte ich diese Prüfung mit passendem Epsilon in der Funktion, wo ich sie eigentlich nicht haben möchte - diese
Funktion benutze ich in Programmen (z.B. beim Vergleich von errechneten Widerstandswerten mit der E-96- bzw. E192-Reihe), wo ich dann
auch einen entsprechenden Epsilon-Wert definiere, verschieden für z.B. die E-96-Reihe und E-192-Reihe.

Sir Rufo 21. Mär 2016 09:30

AW: Extended To String mit dekadischen Einheiten
 
Teilweise weichen die Bezeichner etwas ab.

z.B. km und KB

Aus diesem Grund würde ich für jeden Kontext einen Record verwenden, der den Wert selber speichert und mit einer
Delphi-Quellcode:
ToString
Methode diesen Friendly-String ausgibt. Dann hat man exakt das, was man haben will und genau da wo man es braucht.

Der Quellcode liest sich dann auch viel einfacher:
Delphi-Quellcode:
function CalculateResistance( const U: TVoltage; const I: TCurrent ): TResistance;
begin
  Result := I.Value / U.Value;
end;

WriteLn( CalculateResistance( 24, 4 ).ToString() );

himitsu 21. Mär 2016 10:05

AW: Extended To String mit dekadischen Einheiten
 
Ersmal: Nicht Extended verwenden, sondern Double.
Im Grunde was Extended nicht für die Verwendung vorgesehen, sondern "nur" für die internen Berechnungen der FPU.
In 64 Bit gibt es Extended daher auch nicht mehr. (der Delphi-Compiler verwendet an der Stelle "heimlich" Double)

Extended kann bis zu 4951 Nachkommastellen haben und Double auch immernoch 324.
Wenn es nicht genau 0 wird, dann die kann Schleife viel öfters durchlaufen, als gewollt.

markus5766h 21. Mär 2016 11:34

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von himitsu (Beitrag 1333435)
Ersmal: Nicht Extended verwenden, sondern Double.
Im Grunde was Extended nicht für die Verwendung vorgesehen, sondern "nur" für die internen Berechnungen der FPU.
In 64 Bit gibt es Extended daher auch nicht mehr. (der Delphi-Compiler verwendet an der Stelle "heimlich" Double)

Extended kann bis zu 4951 Nachkommastellen haben und Double auch immernoch 324.
Wenn es nicht genau 0 wird, dann die kann Schleife viel öfters durchlaufen, als gewollt.

o.k., danke --> dann spar' ich mir ja noch zwei Byte :-D

. . . überarbeitet

Luckie 21. Mär 2016 19:32

AW: Extended To String mit dekadischen Einheiten
 
Und bitte übernimm nicht den Tippfehler von himitsu. Es heißt Epsilon und nicht Expsilon. :roll:

markus5766h 21. Mär 2016 20:51

AW: Extended To String mit dekadischen Einheiten
 
ups :shock:

himitsu 22. Mär 2016 10:01

AW: Extended To String mit dekadischen Einheiten
 
Neee, das ist doch kein Fehler ... war nur von Expstep geguttenbergt. :oops:

CodeX 12. Nov 2016 02:12

AW: Extended To String mit dekadischen Einheiten
 
Zunächst: Danke für die Funktion! Habe gerade genau nach so etwas gesucht.

Ist die aktuellste Version im Beitrag #5?
Wenn ja, dann ist dort Tera immer noch falsch geschrieben.
Zudem sollte es vermutlich Eliminate statt Eleminate heißen (wenn damit "eliminieren" gemeint ist).

Meine eigentliche Frage bezieht sich jedoch auf die Anzahl der Vorkommastellen. Ist hierfür Accuracy vorgesehen? Wie kann ich denn festlegen, dass ab 4 Vorkommastellen in die nächste Einheit gewechselt werden soll?
Delphi-Quellcode:
FloatToStrS(1000000000, True, True, '', 3, 0)
liefert "1E3 M"
Delphi-Quellcode:
FloatToStrS(1000000000, True, True, '', 4, 0)
liefert "1.000 M"
Wie komme ich denn zu "1 G"?

t.roller 12. Nov 2016 08:30

AW: Extended To String mit dekadischen Einheiten
 
Vorsätze für Maßeinheiten

CodeX 12. Nov 2016 10:13

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von t.roller (Beitrag 1353424)

Was willst du mir damit sagen? :?

markus5766h 12. Nov 2016 18:35

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von CodeX (Beitrag 1353422)
Zunächst: Danke für die Funktion! Habe gerade genau nach so etwas gesucht.

Ist die aktuellste Version im Beitrag #5?
Wenn ja, dann ist dort Tera immer noch falsch geschrieben.
Zudem sollte es vermutlich Eliminate statt Eleminate heißen (wenn damit "eliminieren" gemeint ist).

Meine eigentliche Frage bezieht sich jedoch auf die Anzahl der Vorkommastellen. Ist hierfür Accuracy vorgesehen? Wie kann ich denn festlegen, dass ab 4 Vorkommastellen in die nächste Einheit gewechselt werden soll?
Delphi-Quellcode:
FloatToStrS(1000000000, True, True, '', 3, 0)
liefert "1E3 M"
Delphi-Quellcode:
FloatToStrS(1000000000, True, True, '', 4, 0)
liefert "1.000 M"
Wie komme ich denn zu "1 G"?

Hab' den Post # 5 noch mal geändert :
FloatToStrS(1000000000, False, False, 6, 0) sollte 1 G ergeben.

CodeX 12. Nov 2016 19:43

AW: Extended To String mit dekadischen Einheiten
 
Sorry, aber irgendwie passt das nicht. Ist jetzt noch falscher als vorher.

Zum Testen:
Delphi-Quellcode:
  for i := 0 to 9 do
  begin
    Number := Power(10, i);
    s := s + FloatToStrS(Number, False, False, '', 3, 0) + #13#10;
  end;
  ShowMessage(s);
Erwartete Ausgabe:
Code:
1
10 
100 
1 Kilo
10 Kilo
100 Kilo
1 Mega
10 Mega
100 Mega
1 Giga
Alte Version:
Code:

10 
100 
1E3 
10 Kilo
100 Kilo
1E3 Kilo
10 Mega
100 Mega
1E3 Mega
Neue Version:
Code:
0 Kilo
0 Kilo
0 Kilo
1 Kilo
0 Mega
0 Mega
1 Mega
0 Giga
0 Giga
1 Giga

markus5766h 12. Nov 2016 19:56

AW: Extended To String mit dekadischen Einheiten
 
Liste der Anhänge anzeigen (Anzahl: 2)
@ CodeX

Du musst die Anzahl der Digits schon hoch setzen, sonst erwischt Du nur die 1000er !
siehe Screenshot
... oder Eliminate verwenden - siehe Screenshot 2

CodeX 12. Nov 2016 20:30

AW: Extended To String mit dekadischen Einheiten
 
Naja, Sinn ist es doch, dass ich einfach eine Zahl übergebe und diese mit einer optimalen Formatierung erhalte, ohne mir Gedanken zu machen, wie viele Stellen die Zahl hat bzw. ohne weitere Parameter anzupassen.
Dein zweiter Screenshot zeigt das Problem doch auch: Warum sind es 1.000 Mega und nicht 1 Giga? Sobald die nächst größere Einheit mit Zahl vor dem Komma erreicht ist, sollte doch auch in diese gewechselt werden.

Das wäre wie gesagt die gewünschte Ausgabe:
Code:

1
10 
100 
1 Kilo    !
10 Kilo
100 Kilo
1 Mega    !
10 Mega
100 Mega
1 Giga    !

markus5766h 12. Nov 2016 20:45

AW: Extended To String mit dekadischen Einheiten
 
was soll den die optimale Formatierung sein ?
Diese ist in jedem Fall erst mal von der Verwendung abhängig,
z.B. beim Messen elektrischer Größen benötige ich bei einer
Bauteilangebe von : Toleranz = ±0,02 % mind. 4 Nachkommastellen,
um dieses Bauteil beurteilen zu können.
Woher soll die Funktion wissen, wie viele Nachkomastellen -
oder Vorkommastellen ich haben möchte ?

o.k. an dem Wechsel zu den 1000er-Stellen muss ich noch mal nachschauen,
die Anzahl der Vor- oder Nachkommastellen soll jedenfalls weiterhin mit
übergeben werden.

CodeX 12. Nov 2016 20:54

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von markus5766h (Beitrag 1353479)
die Anzahl der Vor- oder Nachkommastellen soll jedenfalls weiterhin mit übergeben werden.

Nichts anderes versuche ich zu erfragen bzw. zu empfehlen. So wie ich die Funktion verstanden habe, sollte per
Delphi-Quellcode:
FloatToStrS(Zahl, True, True, '', 3, 0)
eine Formatierung herauskommen, die ab 4 Vorkommastellen in die nächste Einheit wechselt und keine Nachkommastellen hat. Stattdessen kommt sowas wie "1E3 Mega" raus. Das halte ich für falsch. Da sollte in dem Fall "1 Giga" stehen.

Nochmal: Statt "1E3 Mega" oder "1000 Mega" sollte "1 Giga" herauskommen. Gleiches natürlich für die anderen Einheiten.

markus5766h 12. Nov 2016 21:14

AW: Extended To String mit dekadischen Einheiten
 
Liste der Anhänge anzeigen (Anzahl: 1)
@ CodeX

... so sollte es gehen, ist bestimmt noch verbesserbar, liefert aber erstmal das gewünschte Ergebnis.

Post # 5 aktualisiert

CodeX 12. Nov 2016 23:13

AW: Extended To String mit dekadischen Einheiten
 
Jetzt passt es, danke! :thumb:

CodeX 8. Jun 2017 11:06

AW: Extended To String mit dekadischen Einheiten
 
Ich möchte ja nicht wieder "meckern", aber es funktioniert wohl doch noch nicht richtig. Bei runden Zahlen klappt das (wie in Deinem Screenshot zu sehen), aber ab 102 kommt nur Quatsch:
Delphi-Quellcode:
  for i := 0 to 2000 do
    Memo1.Lines.Add(IntToStr(i) +': '+ FloatToStrS(i, True, True, '', 3, 0));
Code:
99: 99
100: 100
101: 101
102: 0 K
103: 0 K
...
498: 0 K
499: 0 K
500: 1 K
501: 1 K
...
1498: 1 K
1499: 1 K
1500: 2 K
1501: 2 K

CodeX 17. Jun 2017 12:47

AW: Extended To String mit dekadischen Einheiten
 
Keine Idee?

markus5766h 19. Jun 2017 17:54

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von CodeX (Beitrag 1374754)
Keine Idee?

doch . . . setz mal die Digit's auf 3,
dann bekommst Du bei einem Ausgangswert von 498 ----> 0,498 K.
Wenn dagegen die Anzahl der Nachkommastellen auf 0 steht, kann da nichts Vernünftiges bei 'raus kommen.

CodeX 19. Jun 2017 20:47

AW: Extended To String mit dekadischen Einheiten
 
Zitat:

Zitat von markus5766h (Beitrag 1374911)
Wenn dagegen die Anzahl der Nachkommastellen auf 0 steht, kann da nichts Vernünftiges bei 'raus kommen.

Warum denn nicht? Das ist doch genau meine Absicht, damit nur Ganzzahlen zu erhalten. Ich möchte ja eben keine Nachkommastellen haben.
Du willst doch nicht sagen, dass es so gewollt ist:
101 -> 101
102 -> 0 K

Was macht es für einen Sinn, dass 102-499 in 0 K umgewandelt werden, und 500-999 in 1 K? Es sind nur 3 Stellen, daher brauchen sie ja nicht in die nächsthöhere Einheit umgewandelt werden. Erst bei 1000 - 1999 müsste es 1 K sein (bei 0 Nachkommastellen).


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:50 Uhr.

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