2017-06-24 13 views
4

Ich habe eine Textdatei namens "test.txt" mit mehreren Zeilen mit den Feldern durch ein Semikolon getrennt. Ich versuche, den Wert von field3 zu nehmen> strip out alles außer den Zahlen in dem Feld> vergleichen Sie es mit dem Wert von Feld 3 in der vorherigen Zeile> wenn der Wert eindeutig ist, umleiten Sie den Feld 3 Wert und die Differenz zwischen ihm und der letzte Wert einer Datei namens "differences.txt".Unerwarteter Wert zählt mit awk

so weit, ich habe den folgenden Code:

awk -F';' ' 
BEGIN{d=0} {gsub(/^.*=/,"",$3); 
if(d>0 && $3-d>0){print $3,$3-d} d=$3} 
' test.txt > differences.txt 

Dies funktioniert absolut in Ordnung, wenn ich versuche im Folgenden ausgeführt:

field1=xxx;field2=xxx;field3=111222222;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222222;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222333;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222444;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222555;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222555;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222777;field4=xxx;field5=xxx 
field1=xxx;field2=xxx;field3=111222888;field4=xxx;field5=xxx 

Ausgang, wie erwartet:

111222333 111 
111222444 111 
111222555 111 
111222777 222 
111222888 111 

jedoch, wenn ich versuche und den folgenden Text ausführen, bekomme ich völlig andere, unerwartete Zahlen - ich bin nicht sicher, wenn es wegen der erhöhten Länge des Feldes oder etwas ist?

Test:

test=none;test=20170606;test=1111111111111111111; 
test=none;test=20170606;test=2222222222222222222; 
test=none;test=20170606;test=3333333333333333333; 
test=none;test=20170606;test=4444444444444444444; 
test=none;test=20170606;test=5555555555555555555; 
test=none;test=20170606;test=5555555555555555555; 
test=none;test=20170606;test=6666666666666666666; 
test=none;test=20170606;test=7777777777777777777; 
test=none;test=20170606;test=8888888888888888888; 
test=none;test=20170606;test=9999999999999999999; 
test=none;test=20170606;test=100000000000000000000; 
test=none;test=20170606;test=11111111111111111111; 

Ausgang, mit unerwarteten Werten:

2222222222222222222 1111111111111111168 
3333333333333333333 1111111111111111168 
4444444444444444444 1111111111111111168 
5555555555555555555 1111111111111110656 
6666666666666666666 1111111111111111680 
7777777777777777777 1111111111111110656 
8888888888888888888 1111111111111111680 
9999999999999999999 1111111111111110656 
100000000000000000000 90000000000000000000 

Kann jemand sehen, wo ich falsch gehe, da ich offensichtlich etwas fehlt bin ... und es ist mir fahren geistig !!

Vielen Dank! :)

Antwort

3

Die Zahlen im zweiten Beispiel sind zu groß. Obwohl die Logik des Programms korrekt ist, gibt es einen Verlust der Genauigkeit, wenn Berechnungen mit sehr großen Ganzzahlen wie 2222222222222222222 - 11111111111111111111111111111111111168 anstelle der erwarteten statt.

Hier finden Sie eine ausführliche Erklärung in The GNU Awk User’s Guide:

Wie bereits erwähnt, awk verwendet Hardware mit doppelter Genauigkeit mit 64-Bit-IEEE binären Gleitkommazahlen Darstellung für Zahlen auf den meisten Systemen. Eine große ganze Zahl wie 9,007,199,254,740,997 hat eine binäre Darstellung, die, obwohl endlich, mehr als 53 Bits lang ist; es muss auch auf 53 Bits gerundet werden. Die größte Ganzzahl, die in einem C-Double gespeichert werden kann, entspricht normalerweise dem größtmöglichen Wert eines Double. Wenn Ihr System doppelt IEEE 64-Bit Double ist, ist dieser größtmögliche Wert eine ganze Zahl und kann genau dargestellt werden. Was sollte man mehr über Integer wissen?

Wenn Sie wissen möchten, was die größte Ganzzahl ist, so dass sie und alle kleineren Ganzzahlen in 64-Bit-Doppel gespeichert werden können, ohne Genauigkeit zu verlieren, lautet die Antwort 2^53. Die nächste darstellbare Zahl ist die gerade Zahl 2^53 + 2, was bedeutet, dass es unwahrscheinlich ist, dass Sie gawk print 2^53 + 1 im Ganzzahlformat machen können. Der Bereich von Ganzzahlen, der durch ein 64-Bit-Double genau dargestellt werden kann, ist [-2^53, 2^53]. Wenn Sie in awk eine Ganzzahl außerhalb dieses Bereichs mit 64-Bit-Doubles sehen, haben Sie Grund, der Genauigkeit der Ausgabe sehr verdächtig zu sein.

Wie @EdMorton wies in einem Kommentar aus, Sie beliebiger Genauigkeit arithmetische wenn Ihr Awk mit MPFR Unterstützung kompiliert wurde und Sie geben die -M Flagge haben. Weitere Einzelheiten finden Sie unter 15.3 Arbitrary-Precision Arithmetic Features.

Verwandte Themen