Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - FloatToStrF und "geltende Ziffern"
Spaceguide - Di 25.07.06 12:59
Titel: FloatToStrF und "geltende Ziffern"
Wie krieg ich FloatToStrF dazu, sich wie folgend zu verhalten: Es sollen maximal vier geltende Ziffern angezeigt werden, keine Darstellung mit Exponent (also ffFixed) und unnötige Nullen hinten nicht angehängt werden. Beispiele:
Single => String
0.001234 => 0.001 (round)
0.0001234 => 0
1.0e-5 => 0
99.994 => 99.99
99.996 => 100
etc.
n-regen - Di 25.07.06 13:36
"Delphi für Kids" von Hans-Georg Schumann:
Zitat: |
FloatToStrF(Zahl, Format, Genauigkeit, Kommastellen)
[...]
FloatToStrF(Input, ffNumber, 8, 2)
|
Hilft dir das weiter?
Übrigens:
Genauigkeit bringt nicht wirklich was.
Spaceguide - Di 25.07.06 13:45
Nein, das hilft kein bisschen weiter.
digi_c - Di 25.07.06 14:35
Der gute alte Format('%f',[zahl]) Befehl hilft da bestimmt. Genaueres hab ich aber bei der Hitze auhc nciht mehr im Kopf...
Spaceguide - Di 25.07.06 14:47
Auch Format erlaubt mir nicht die gewünschte Ausgabe.
Lannes - Di 25.07.06 15:47
Hallo,
passt das ?
Delphi-Quelltext
1:
| Format('%.4g',[StrToFloat(Format('%.3f',[e]))]); |
Spaceguide - Di 25.07.06 15:51
Nein, 10000 wird zu 1E004
Lannes - Di 25.07.06 15:55
Spaceguide hat folgendes geschrieben: |
Nein, 10000 wird zu 1E004 |
und was soll bei 12345 herrauskommen?
Spaceguide - Di 25.07.06 15:57
Es soll etwas wie diese Funktion, die ich mir gestrickt habe, machen, nur ein bisschen eleganter.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| type float = single;
function MyFloatToStr(const aFloat : float; aDigits : byte = 7): string;
var dspos,left,right : integer; precision : integer; begin precision := Max(Trunc(Ceil(ln((Abs(aFloat)+1))/ln(10))),aDigits);
Result := FloatToStrF(aFloat,ffFixed,precision,10); dspos := Pos(DecimalSeparator,Result); if dspos>0 then begin left := Pos('-',Result)+1;
if dspos-left<aDigits then right := left+aDigits else right := dspos;
while Result[right]='0' do Dec(right); if Result[right]=DecimalSeparator then Dec(right); Result := Copy(Result,1,right); end; end; |
Spaceguide - Di 25.07.06 15:59
Lannes hat folgendes geschrieben: |
Spaceguide hat folgendes geschrieben: | Nein, 10000 wird zu 1E004 |
und was soll bei 12345 herrauskommen? |
Da soll dann natürlich 12345 rauskommen, genauso wie man es z.B. im Physikunterricht gemacht hat.
JayEff - Di 25.07.06 16:04
Kannst doch versuchen, hinterher das E mit *10^ zu ersetzen und das dann aus zu rechnen? also du suchst dir die stelle mit dem E und machst dann vielleicht
Delphi-Quelltext
1: 2: 3: 4:
| ZahlHinterE := StrToInt(copy(result,pos('E', result), length(result))); Result:=StringReplace(result, 'E'+IntToStr(ZahlHinterE), '', []); for i:=1 to zahlHinterE do result:=result+0; |
Kann aber sein, dass ich das problem nicht ganz verstanden hab ^^
Lannes - Di 25.07.06 23:23
Hallo,
12345 bei 4 signifikanten Stellen = 12345 :gruebel:
kannst ja mal das antesteten:
:!: unit math einbinden
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.Button3Click(Sender: TObject); var aDigits : byte; e : extended; begin aDigits := StrToInt(Edit2.Text); e := StrTofloat(Edit1.Text); if Round(Log10(ABS(e)))+1 > aDigits then Label1.Caption := IntToStr(round(e)) else Label1.Caption := Format('%.'+IntToStr(aDigits)+'g', [StrToFloat(Format('%.'+IntToStr(aDigits-1)+'f',[e]))] ); |
Spaceguide - Mi 26.07.06 08:08
Lannes hat folgendes geschrieben: |
12345 bei 4 signifikanten Stellen = 12345 :gruebel:
|
Nunja, wenn ich mich recht erinnere, war das im Physikunterricht so. Man sollte ja die Endergebnisse mit einer sinnvollen Stellenzahl angeben. Vor dem Komma wurde aber nix weggeschnippelt.
Sy- - Mi 26.07.06 09:55
Genügt nicht einfach folgendes:
Delphi-Quelltext
1: 2: 3:
| Zahl:=123456.78634; Fa:=100; result:=round(Zahl*Fa)/Fa; |
da wird auch nichts abgekürzt oä.
Hier mal als Function wie du es brauchst:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function myRound(Zahl:String; Stellen:integer=2):string; var fa,x:integer; gZahl:real; begin fa:=1; for x := 0 to fa do fa:=fa*10; try gZahl:=strtofloat(Zahl); result:=floattostr(round(gZahl*fa)/fa); except result:='0'; end; end; |
Gruß
Spaceguide - Mi 26.07.06 10:27
Testet doch einfach mal eure Funktionen gegen die oben genannten Anforderungen, bevor ihr sie postet.
digi_c - Mi 26.07.06 11:31
o.k. aber wie sind denn die genauen Bedingungen?
Zitat: |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function MyFloatToStr(const aFloat : float; aDigits : byte = 7): string; | |
Reicht mir nicht so richtig, wann muss Vorzeichen beachtet werden usw...
0.001234 => 0.001 (round) Also alle Nachkommas auf 3 Stellen?
0.0001234 => 0 Sobald 4 Stellen keine Kommas=0?
1.0e-5 => 0 Verdammt kleine Zahlen auf =0
99.994 => 99.99 Bei positiven Zahlen auch 2 Nachkommastellen?
99.996 => 100 Bei allen Zahlen aufrunden?
crowley - Mi 26.07.06 11:40
die funktion ist getestet und in mehreren anwendungen im einsatz... ich habe das mit deinen "testzahlen" von oben auch getestet... und es funktioniert...
ABER schau mal selbst bei dir oben: du hast in deinen Musterlösungen einen unterschiedliche Anzahl von erlaubten Nachkommastellen
hier: 0.001234 => 0.001 (round)
hier: 99.994 => 99.99
dementsprechend musst du das natürlich im Offset-Parameter anpassen.
Desweiteren wird hier richtig gerundet und nicht im Delphi- typischen
Banker's Rounding (bei einem exakten Nachkomma- Anteil von .5 wird immer zur "gerade" Zahl gerundet).
Um die Funktion nutzen zu können, musst du die Unit Math einbinden
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| function RoundEx(const X: Extended; const Offset: integer): Extended; begin if frac(X * Power(10, OffSet)) >= 0.5 then result := ceil(X * Power(10, OffSet)) / Power(10, OffSet) else result := floor(X * Power(10, OffSet)) / Power(10, OffSet); end; |
um das dann wie von dir gewünscht einsetzen zu können, kannst du dann bespielsweise
Delphi-Quelltext
1:
| Label1.Caption := FloatToStr(RoundEx(StrToFloat(edit1.Text), 3)); |
aufrufen.
C.
Anmerkung noch am Rande: Patzig den Leuten gegenüber sein, die dir helfen wollen, ist nicht die feine Art.
Sy- - Mi 26.07.06 11:49
Spaceguide, jetzt wird es zwar OT aber:
Arbeite mit den Scripten die du bekommst und verlang nicht auf dich exakt geschneiderte Scripte.
Wir sind hier um dir zu helfen, nicht um deine Arbeit zu erledigen.
Meins funktioniert nämlich auch und wie crowley schon sagte muss ein parameter mehr rein.
Fällt mir schwer zu glauben, dass du den anderen Script selber gecoded hast wenn du nichtmal unsere Scripte anwenden kannst.
Gruß
JayEff - Mi 26.07.06 16:07
Jaja.. Sy- wird wieder ausfallend, offensiv und spricht von oben herab, nur um zu verdecken, dass er das Problem nicht verstanden hat.
Hier gehts darum, eine Zahl nicht auf ihre Nachkommastellen, sondern auf ihre stellen Insgesammt zu runden, oder? Also während 1,12344 zu 1,234(4?) wird, wird 12,344 zu 12,34(4?), oder? Versuch doch noch ein paar mehr Beispiele zu geben, und wenn du im endeffekt nur 4 ziffern haben willst, was wird dann aus 12345? die zahl verändert sich ja maßgeblich, wenn du einfach eine stelle weglässt, weil du keine 5 sondern 4 ziffern haben willst.
jasocul - Mi 26.07.06 16:49
Probiere mal das:
Delphi-Quelltext
1: 2: 3: 4: 5:
| function GerundeteZahl(Zahl : Extended; Rundung : Integer) : Extended; begin while trunc(zahl) > power(10, rundung) do inc(rundung); result := RoundTo(zahl, Rundung); end; |
Du benötigst die Unit Math.
Ich habs nur mit zwei Werten getestet. Als Rundungswert musst du in deinen Beispielen -3 vorgeben.
Für weitere Infos kannst du auch in die Delphi-Hilfe schauen.
Sy- - Mi 26.07.06 16:50
Ich sehe schon ich bin dir Sympatisch JayEff :wink:
Aber du hast recht, etwas in der Richtung meint er wo ich drüber sah.
Vor dem Komma sollte scheinbar nichts weggetan werden.
Da frage ich mich aber wo der Sinn überhaupt sein soll in der Funktion :roll:
Spaceguide - Mi 26.07.06 20:37
Sy- hat folgendes geschrieben: |
Spaceguide, jetzt wird es zwar OT aber:
Arbeite mit den Scripten die du bekommst und verlang nicht auf dich exakt geschneiderte Scripte.
Wir sind hier um dir zu helfen, nicht um deine Arbeit zu erledigen.
|
Also wenn ich irgendwas haben will, dann kann ich auch gleich FloatToStrF nehmen, das funktioniert noch besser als das was du fabriziert hast. Wenn einer fragt, wie man zwei Zahlen addiert und du schreibst a-b und meckerst danach, dass er es sich gefälligst selbst anpassen soll, dann bist du überhaupt keine Hilfe.
Zitat: |
Meins funktioniert nämlich auch und wie crowley schon sagte muss ein parameter mehr rein.
|
myRound('1234.123123',4) = 1234.12 => FALSCH
Zitat: |
Fällt mir schwer zu glauben, dass du den anderen Script selber gecoded hast wenn du nichtmal unsere Scripte anwenden kannst.
|
Diplom-Informatiker, 10 Jahre Delphi-Erfahrung ... ich kann programmieren, glaub's mir.
JayEff - Do 27.07.06 00:15
[OT]
Sy- hat folgendes geschrieben: |
Ich sehe schon ich bin dir Sympatisch JayEff :wink: |
Woran liegt das nur, dass ich Sarkasmus erkenne... (ich verweise an dieser Stelle an den Zusatz meiner Signatur, nicht dass du mich schon wieder auf Rechtschreibfehler aufmerksam machst: 18 jähriger Gymnasiast, Mathe 15 Punkte, tut mir ja leid, dass ich in Deutsch weniger gut bin.)
Sy- hat folgendes geschrieben: |
Da frage ich mich aber wo der Sinn überhaupt sein soll in der Funktion :roll: |
Ich weis nicht, wie oft du dich mit den Gedanken anderer MEnschen auseinander gesetzt hast bzw deren Fragen zu Funktionen beantwortet hast: Die Frage stellt sich häufig. Ich habe allerdings in eigener Erfahrung bemerkt, dass Menschen IMMER einen Grund für ihr handeln haben und wenn wir nicht jede Zeile seines Programms kennen, was unwahrscheinlich ist, können wir nicht wissen, ob seine Funktion wirklich Sinn macht. Aus diesem Grund sollten wir so gut als möglich seine Frage beantworten und nicht seine Programmierkenntnisse auf überhebliche Art in Frage stellen. Versteh mich nicht falsch. Du hast dich schon 2 mal über andere Leute lustig gemacht, und ich glaube nicht, dass du selbst der Meinung bist, das würde in irgenteiner Art helfen... Also lass es doch bitte ;>
Zu deiner Signatur: Vollkommen richtig, gefällt mir :D , aber.. fällt das nicht unter den Kündigungsschutz? :motz: [/OT]
Zurück zum Thema.
jayeff hat folgendes geschrieben: |
Hier gehts darum, eine Zahl nicht auf ihre Nachkommastellen, sondern auf ihre Stellen insgesamt zu runden, oder? Also während 1,12344 zu 1,234(4?) wird, wird 12,344 zu 12,34(4?), oder? Versuch doch noch ein paar mehr Beispiele zu geben, und wenn du im endeffekt nur 4 ziffern haben willst, was wird dann aus 12345? |
Ähm ich muss gestehen, dass ich mir deinen QT nicht angeguckt hab...
digi_c - Do 27.07.06 08:48
Spaceguide also dein Ton ist wirklich ein bischen komisch wenn man bedenkt, dass wir hier zusammensitzen um dir bei deinem Problem zu helfen...
jasocul - Do 27.07.06 09:02
Leute, haltet doch mal den Ball flach. So führt das doch zu nichts.
Wenn einer mal einen Parameter vergessen hat, das kann mal passieren. Bei meinem Beispiel habe ich auch erst On-The-Fly programmiert und hinterher eine Funktion daraus gemacht. Dabei hatte ich auch was vergessen (ist übrigens korrigiert). Ja und? Ist doch menschlich. Da muss man niemanden einen Vorwurf machen und der Fehler-Produzent muss nicht sauer sein, wenn das bemerkt wird.
Sy- - Do 27.07.06 09:09
Spaceguide, wenn das mit FloatToStrF so ginge, dann würdest du es auch damit machen. Hast doch vorhin sogar selbst jede Variante verneint, weil da immer diese Abkürzungen kommen.
Das deine Reaktion unfreundlich war ist nicht zu bestreiten.
Du hast das Problem, dass du dich sehr schlecht ausdrückst. Obwohl ich jetzt schon gepostet habe, dass ich es nicht verstehe und JayEff eine Frage zusätzlich stellt ist es für mich fragwürdig wie man dir helfen soll.
Ich habe gemeint, dass ich es richtig verstanden habe und war deswegen etwas biestig. Das war darauf bezogen, dass die Variablen namen und die funktion gleich heißen sollte und das habe ich nicht eingesehen.
Nun ist klar, dass es anders sein soll.
Aber wie?
Die Frage ist ja nicht wie das Ergebnis auszusehen hat, sondern warum es so auzszusehen hat.
Du hättest nun ruhig sagen können:
myRound('1234.123123',4) = 1234.12 => FALSCH
myRound('1234.123123',4) = 1234 => RICHTIG
myRound('234.123123',4) = 234.1 => RICHTIG
Schon hätten wir dir helfen können, da es unsere Frage beantwortet :roll:
Aber nun für den Sinn. Also so sehe ich den Sinn, hat auch gewisse Vorteile.
Für meinen Geschmack aber fehlt dann für höhere Zahlen eine Abkürzung wie K (Tausend) und M usw. dass man kurze Zahlen hat und halt das relevanteste auch bei nicht so niedrigen. Vielleicht hat man auch ein Beschränktes Display.
und folgendes:
Zitat: |
Diplom-Informatiker, 10 Jahre Delphi-Erfahrung ... ich kann programmieren, glaub's mir.
|
Ich möchte ja niemanden lustig machen, auch wenn es sich manchmal so anhört, aber der Diplom und 10Jahre Erfahrung reichen dir nicht für eine saubere Lösung dieser Aufgabe? Ich würde das wie mit einer Kanone auf einen Spatz sehen aber dem ist nicht so.
Bevor wir hier aber noch länger Diskutieren, habe ich mir einfach dein Script angeschaut und hier ist meine saubere Lösung dazu:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| Function myRound(Zahl:real; Gen:integer):String; var i,c:integer; begin i:=ansipos(',',pchar(floattostr(zahl))); c:=gen-i+1; if(c<0)then c:=0; result:=floattostr(round(zahl*power(10,c))/power(10,c)); end; |
Grüße
Spaceguide - Do 27.07.06 09:40
Sy- hat folgendes geschrieben: |
Ich möchte ja niemanden lustig machen, auch wenn es sich manchmal so anhört, aber der Diplom und 10Jahre Erfahrung reichen dir nicht für eine saubere Lösung dieser Aufgabe? Ich würde das wie mit einer Kanone auf einen Spatz sehen aber dem ist nicht so.
|
Ich habe es ja gelöst gehabt, aber mir sah das zu pfuschig aus, weshalb ich mal nach zweiten Meinungen gefragt habe. Es ist besser eine Standardfunktion zu verwenden, als selbst etwas zu stricken.
Zitat: |
Bevor wir hier aber noch länger Diskutieren, habe ich mir einfach dein Script angeschaut und hier ist meine saubere Lösung dazu: |
myRound(0.00001,4) = 1E-5 => FALSCH (sollte 0 sein)
myRound(-100.123,4) = -100 => FALSCH (sollte -100.1 sein)
Komma ist hard-kodiert
Sy- - Do 27.07.06 10:21
Das mit dem Minus hab ich vergessen.
Wegen dem 1E-05 hab ich einfach mit dem Single gelöst, hat halt den Nachteil, dass er höhere Zahlen und ganz kleine Zahlen nicht mehr erfasst. Da es aber bei dir im Einsatz war, denke ich, dass es zu keinen Problemen führen sollte.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| Function myRound(Zahl:single; Gen:integer):String; var i,c,m:integer; begin if(zahl<0)then m:=-1 else m:=1; zahl:=zahl*m; i:=ansipos(',',pchar(floattostr(zahl))); c:=gen-i+1; if(c<0)then c:=0; result:=floattostr(round(zahl*power(10,c))/power(10,c)*m); end; |
jasocul - Do 27.07.06 11:05
Meine gestrige Variante war wohl ziemlich doof. Hier eine neue, die mit allen hier angegebenen Zahlen das richtige Ergebnis bringt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| function GerundeteZahl(Zahl : Extended; Rundung : Integer) : String; var i : Integer; begin if trunc(abs(zahl)) = 0 then dec(rundung); if trunc(abs(zahl)) >= power(10, rundung) then begin result := FloatToStr(trunc(zahl)); end else begin i := 0; while trunc(abs(zahl)) > 0 do begin inc (i); zahl := zahl / 10; end;
zahl := zahl * power(10, rundung); zahl := round(zahl); zahl := zahl / power(10, rundung-i); result := FloatToStr(zahl); end; end; |
Lannes - Do 27.07.06 17:14
Hallo,
@
Spaceguide, hast Du eigentlich meinen zuletzt geposteten Code getestet?
Zum Beitrag in diesem Thread [
http://www.delphi-forum.de/viewtopic.php?p=376356#376356]
Setzt man dort
round ein, IMHO entspricht das Ergebnis Deinem und dem zuletzt von
Sy- geposteten Code.
Mit
trunc entspricht er IMHO
jasoculs letztem Code.
Hab den Code mal in eine Funktion verpackt und übersichtlicher(besser?) gecodet:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function FloatToStrDigits(e: extended;aDigits: byte): String; begin if Round(Log10(ABS(e)))+1 > aDigits then Result := IntToStr(round(e)) else begin Result := Format('%.*f',[aDigits-1,e]); Result := Format('%.*g',[aDigits,StrToFloat(Result)]); end; end; |
Spaceguide - Do 27.07.06 17:29
@Lannes: Schmiert bei 0 ab.
JayEff - Do 27.07.06 17:31
Wenn sichs nur um 0 dreht, machste halt ein if e=0 then Result:='0' else begin end; rein ^^
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!