Normalisieren von Gleitpunktzahlen (Stilfrage)
Michael Schröpl
- perl
Hallo Leute,
ich möchte gerne in Perl Gleitpunktzahlen normalisieren:
a) rechtsstehende Nullen aus dem Nachkomma-Anzeil abtrennen und
b) einen danach überflüssigen Dezimalpunkt ebenfalls entfernen.
Mein Lösungsversuch
# Gleitpunkt-Darstellung normalisieren
# (rechtsstehende Nachkomma-Nullen entfernen)
if ($zahl =~ /^(\d+).(\d*?)0+$/)
{
my ($vorkomma, $nachkomma) = ($1, $2);
if ($nachkomma) { $vorkomma .= '.'; }
$zahl = $vorkomma . $nachkomma;
}
scheint zwar zu funktionieren, kommt mir aber nicht arg 'perlish' vor.
Geht das nicht irgendwie noch deutlich eleganter?
Ach ja, das Ganze läuft als eine von vielen Teilfunktionen über eine
Datei mit 757 MB, und das Ganze ist Bestandteil eines täglich laufenden
Produktionsjobs - eine performante Lösung wäre mir also nicht unlieb. ;-)
Viele Grüße
Michael
Hallo,
ich möchte gerne in Perl Gleitpunktzahlen normalisieren:
a) rechtsstehende Nullen aus dem Nachkomma-Anzeil abtrennen und
b) einen danach überflüssigen Dezimalpunkt ebenfalls entfernen.
Ich gehe mal davon aus, das Du eine Bruchdarstellung von Integern wieder in "richtige" Integer umwandeln möchtest, ja?
Hörte sich zumindest so an.
Also z.B.:
123.00 zu 123
567567.0000000 zu 567567
?
Mein Lösungsversuch
# Gleitpunkt-Darstellung normalisieren
# (rechtsstehende Nachkomma-Nullen entfernen)
if ($zahl =~ /^(\d+).(\d*?)0+$/)
{
my ($vorkomma, $nachkomma) = ($1, $2);
if ($nachkomma) { $vorkomma .= '.'; }
$zahl = $vorkomma . $nachkomma;
}
scheint zwar zu funktionieren, kommt mir aber nicht arg 'perlish' vor.
Das ist mit Sicherheit nicht "perlish", denn es ist gut lesbar, verständlich und ist nicht in einer Zeile.
SCNR >;->
Aber ich habe Dich wohl mißverstanden, denn der RegEx sagt mir sowas wie:
123.1230000 zu 123123
Geht das nicht irgendwie noch deutlich eleganter?
Wenn es nur Nullen sind:
$zahl = 123.000 # eine Zahl.
if ($zahl =~ /^(\d+).0+$/)
{
$zahl = sprintf "$lu",$zahl;
}
(Aber sprintf ist erstens teuer, sagt perldoc und zweitens war das ja sowieso nicht gefragt ;-)
$zahl = 123.123000;
if ($zahl =~ /^(\d+).(\d*?)(0*)$/)
{
$zahl = $1 . $2;
}
print $zahl; # ergibt 123123,
# Test:
# mit $zahl = $1 . $2 . $3 ergibt es 123123000
Wenn Du den Test nicht brauchst (also genau weißt, das es sich um eine Zahl handelt) reicht auch:
$zahl =~ s/^(\d+).(\d*?)(0*)$/$1$2/;
Das sieht dann wenigstens schon ansatzweise "perlish" aus. ;-)
(Hoffentlich stimmt das auch alles, habe nur die Funktion geprüft, nicht auf Fehler oder gar irgendwelche Seiteneffekte)
Ach ja, das Ganze läuft als eine von vielen Teilfunktionen über eine
Datei mit 757 MB, und das Ganze ist Bestandteil eines täglich laufenden
Produktionsjobs - eine performante Lösung wäre mir also nicht unlieb. ;-)
Tja, das wäre dann noch zu testen. Zumindest wären zwei Variablen gespart und eine Prüfung, im zweitem Fall sogar noch eine Prüfung.
Aber ich bin nicht der Perlspezialist und eigentlich bin ich ja auch nur aufgestanden, weil die Blase voll war ;-)
Da sind doch mit Sicherheit ein paar mathematische Funktionen in Perl, oder? Wenn es ein Float ist, also eine reguläre Zahl, sollte ein wenig Exponentialrechnung eigentlich besser behilflich sein. Wenn Modulo Floats unterstützt wäre es auch einfacher.
so short
Christoph Zurnieden
Hallo Christoph,
Ich gehe mal davon aus, das Du eine Bruchdarstellung von Integern
wieder in "richtige" Integer umwandeln möchtest, ja?
nein - es sind keine Integers (jedenfalls nicht immer).
if ($nachkomma) { $vorkomma .= '.'; }
Deshalb hängt ich an $vorkomma ja auch den '.' an, falls in
$nachkomma noch etwas Signifikantes übrig geblieben ist (und nur dann).
123.1230000 zu 123123
Nicht ganz. ;-)
Den Dezimalpunkt brauche ich durchaus noch - jedenfalls manchmal.
Geht das nicht irgendwie noch deutlich eleganter?
(Aber sprintf ist erstens teuer, sagt perldoc und zweitens war das
ja sowieso nicht gefragt ;-)
"sprintf" habe ich durchaus auch probiert, aber ohne Erfolg.
(Das ist mir zu "C-ish", um zu begreifen, wie ich das nutzen kann ...)
Viele Grüße
Michael
Hallo,
Ich gehe mal davon aus, das Du eine Bruchdarstellung von Integern
wieder in "richtige" Integer umwandeln möchtest, ja?
nein - es sind keine Integers (jedenfalls nicht immer).
if ($nachkomma) { $vorkomma .= '.'; }
Deshalb hängt ich an $vorkomma ja auch den '.' an, falls in
$nachkomma noch etwas Signifikantes übrig geblieben ist (und nur dann).
123.1230000 zu 123123
Nicht ganz. ;-)
Den Dezimalpunkt brauche ich durchaus noch - jedenfalls manchmal.
Kein Problem, dann so:
$zahl =~ s/^(\d+)(.)(\d*?)(0*)$/$1$2$3/;
Kurzer Moment der Andacht, dann den hier:
$zahl1 =~ s/^(\d+.\d*?)(0*)$/$1/;
Geht das nicht irgendwie noch deutlich eleganter?
(Aber sprintf ist erstens teuer, sagt perldoc und zweitens war das
ja sowieso nicht gefragt ;-)
"sprintf" habe ich durchaus auch probiert, aber ohne Erfolg.
(Das ist mir zu "C-ish", um zu begreifen, wie ich das nutzen kann ...)
Aber nicht "C-ish" genug, das ich da auf Anhieb mit klar kam ;-)
so short
Christoph Zurnieden
Hallo Leute,
ich möchte gerne in Perl Gleitpunktzahlen normalisieren:
a) rechtsstehende Nullen aus dem Nachkomma-Anzeil abtrennen und
b) einen danach überflüssigen Dezimalpunkt ebenfalls entfernen.
hm, hab Perl leider sehr wenig ahnung, aber ich kann sagen wie ich es in PHP machen würde (müsste übertragbar sein).
Also, wenn ich dich richtig verstehe soll
1982.2900 zu 1982.29
7733.0000 zu 7733 werden
mein Vorschlag in PHP
$Zahl = strrev(strrev($Zahl));
die Variable einfach 2x umdrehen hat genau den gewünschten effekt. kann zwar nicht wirklich sagen wie performant das ist, dürfte aber schneller als ein regex sein.
gruss
Thorsten S.
Hallo,
Also, wenn ich dich richtig verstehe soll
1982.2900 zu 1982.29
7733.0000 zu 7733 werden
Also, so hab ich's auch verstanden.
mein Vorschlag in PHP
$Zahl = strrev(strrev($Zahl));
In Perl geht das noch einfacher:
$zahl = $zahl + 0;
Beispiel:
$zahl = '12.3400';
$zahl = $zahl + 0;
print $zahl;
Ergebnis: 12.34
Wäre $zahl = "12.000", würde "12" ausgegeben werden.
Aber die Lösung erscheint mir so trivial, daß bestimmt was an der
Fragestellung falsch verstanden wurde, oder?
Gruß
Slyh
Hallo nochmal,
Aber die Lösung erscheint mir so trivial, daß bestimmt was an der
Fragestellung falsch verstanden wurde, oder?
Nachdem ich darauf aufmerksam gemacht wurde, daß dieser Satz ausgesprochen
unglücklich formuliert ist, möchte ich kurz darauf hinweisen, daß dieser
Satz in keiner Weise abwertend gemeint ist/war. Er soll tatsächlich nur das
ausdrücken, was dort wörtlich steht: Nämlich die Vermutung, daß ich die
Fragestellung möglichweise falsch verstanden habe.
Ich kenne Michael Schröpl durch stets hochkompetente Postings. Schon alleine
deshalb würde mir eine solche niederschmetternde Wertung, die man zugegebener-
maßen in den zitierten Satz hineininterpretieren könnte, nicht im Traum
einfallen.
Gruß
Slyh
Hallo Slyh,
Ich kenne Michael Schröpl durch stets hochkompetente Postings.
;-)
Aber Perl kann ich halt nicht annähernd richtig ... nochmal: Danke!
Viele Grüße
Michael
Hallo Slyh,
In Perl geht das noch einfacher:
$zahl = $zahl + 0;
ach je - Perl, die Sprache ohne Datentypen ...
Warum komme ich eigentlich nicht auf das Naheliegende?
(Wahrscheinlich, weil der Feldwert, den ich eigentlich zu analysieren
habe, zusätzlich auch noch die Zeichen ' :dn' enthält, die ich per
vorherigem regexp allerdings bereits entfernt hatte ...)
Mit dem Brett vor meinem Kopf werde ich mir heute abend ein gemütliches
Kaminfeuer machen. :-)
Danke schön!
Viele Grüße
Michael