Delphi-PRAXiS
Seite 1 von 3  1 23      

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() );


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:27 Uhr.
Seite 1 von 3  1 23      

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