Shell-Skript und Hinzufügen großer Werte in einem durch Trennzeichen getrennten Dateiproblem

Shell-Skript und Hinzufügen großer Werte in einem durch Trennzeichen getrennten Dateiproblem

Ich habe ein Skript, das eine durch Trennzeichen getrennte Datei liest und für jeden Datensatz das 3. Element in der Datei addiert. Bei den meisten Datendateien funktioniert das einwandfrei, bis auf eine. Ich habe eine Datendatei mit 193 Datensätzen. Ich erwarte, dass das Skript 2028219,43 zurückgibt. Stattdessen erhalte ich eine Exponentialzahl, die aufgerundet zu sein scheint. Zuerst dachte ich, dass ich die Zahl durch die Verwendung von printf erhalten würde, aber wenn die Zahl bereits gerundet wurde, bekomme ich nicht das zurück, was ich erwarte.

Dies ist der Code, den ich zum Lesen der durch Trennzeichen getrennten Datendatei verwende. Die Daten in jedem Datensatz sind durch ein *. getrennt:

export clm_total=$( awk -F* '{f1+=$3} END {print f1}' datafile.dat)
export new_clm_total=$(printf "%.2f" $clm_total)

Folgendes wird im Protokoll angezeigt, wenn ich das Skript ausführe:

+ export clm_total=2.02822e+06
+ printf %.2f 2.02822e+06
+ export new_clm_total=2028220.00
+ echo 2028220.00

Dies ist ein Beispiel der Datendatei. Es gibt noch mehr Datensätze, ich hielt es nicht für notwendig, alle 193 Datensätze anzuzeigen:

CLM*123456789*4820.9***13:A:1**A*Y*Y
CLM*123698547*3642.05***13:A:7**A*Y*Y
CLM*147852369*579.25***13:A:1**A*Y*Y
CLM*789654123*929.8***13:A:1**A*Y*Y

Was ich zurückerwarte ist 2028219.43 Was ich zurückbekomme ist 2.02822e+06 Was dann als 2028220.00 formatiert wird

Antwort1

Awk führt Arithmetik mit Gleitkommazahlen doppelter Genauigkeit durch. Ich weiß nicht genau, bis zu welcher Grenze Sie genaue Ergebnisse für Zahlen mit zwei Dezimalstellen erhalten, aber Sie liegen im Bereich. Dieskönnte ein Problem sein, wenn die Zahlen größer werden. Wenn Sie sicher sein müssen, genaue Ergebnisse zu erhalten, bleiben Sie entweder bei ganzen Zahlen und achten Sie auf Überläufe, oder verwenden Sie , bcwodurch Arithmetik mit beliebiger Genauigkeit durchgeführt wird.

Das Problem besteht darin, dass awk das richtige Ergebnis berechnet, das Standarddruckformat jedoch ungefähr ist. Verwenden Sie beim Ausdrucken des Ergebnisses ein explizites Format.

export clm_total=$( awk -F'*' '{f1+=$3} END {printf "%.2f\n", f1}' datafile.dat)

Alternativ können Sie bei bleiben, printvorausgesetzt, Sie ändern das Druckformat für die Konvertierung von Zahlen in Zeichenfolgen. Die Standardeinstellung ist , %.6gwas zu der angezeigten Annäherung führt.

export clm_total=$( awk -F'*' -v CONVFMT='%.2f' '{f1+=$3} END {print f1}' datafile.dat)

Antwort2

Wenn Sie sich in der Informatik mit Gleitkommamathematik befassen (speziell awkin Ihrem Fall), müssen Sie auf die zugrunde liegenden Mechanismen achten, die zur Darstellung Ihrer Daten im System verwendet werden.

Ich glaube, das ist das Problem, mit dem Sie in Ihrem speziellen Fall konfrontiert sind. Lesen Sie diesen Artikel:D.3 Einschränkungen bei Gleitkommazahlen, für weitere Informationen zu diesem Thema. Dieser Artikel war ebenfalls hilfreich, um Licht in das Problem zu bringen:15.2 Fließkomma-Programmierung verstehen.

Soweit ich es beurteilen kann, stehen beim Umgang mit Gleitkommazahlen anscheinend awknur wenige Ziffern für den Mantissenanteil der Zahl zur Verfügung. Beim weiteren Ansammeln von Zahlen gelangen Sie also an den Punkt, an dem Rundungs- und Abschneidefehler auftreten und die Genauigkeit verloren geht.

Beispiel

Sie können hier sehen, wann wir den Schwellenwert überschreiten und beginnen, die wissenschaftliche Notation zu verwenden, um die tatsächliche Zahl zu verfolgen.

$ seq -f "%f" 1413 | awk '{f1+=$1+0.4} END {print f1}'
999556
$ seq -f "%f" 1414 | awk '{f1+=$1+0.4} END {print f1}'
1.00097e+06

verwandte Informationen