Die Gleitkommazahlen 99,15 und 28,85 und 78,30 haben keine exakten IEEE 754-Binärdarstellungen. Sie können dies mit einem C-Programm sehen, das dieselbe Berechnung durchführt:
#include <stdio.h>
int
main(int ac, char **av)
{
float a = 99.15;
float b = 20.85;
float c;
printf("a = %.7f\n", a);
printf("b = %.7f\n", b);
c = a - b;
printf("c = %.7f\n", c);
return 0;
}
Ich bekomme diese Antworten von einem x86- und einem x86_64-Computer, wahrscheinlich weil beide IEEE 754- Gleitkomma-Mathematik ausführen:
a = 99,1500015 b = 20,8500004 c = 78,3000031
Folgendes passiert: Gleitkommazahlen werden mit einem Vorzeichenbit (positiv oder negativ), einer Anzahl von Bits und einem Exponenten dargestellt. Nicht jede rationale Zahl (was in diesem Zusammenhang eine "Gleitkommazahl" ist) kann genau im IEEE 754-Format dargestellt werden. So kommt die Hardware so nah wie möglich. Leider erhält die Hardware in Ihrem Testfall keine exakte Darstellung eines der drei Werte. Es wird nicht einmal, wenn Sie double
statt verwenden float
, was awk
wahrscheinlich tut.
Hier ist eine weitere Erklärung des Abstands von Gleitkommazahlen mit exakten binären Darstellungen.
Sie können wahrscheinlich einige Werte finden, die Ihren Test bestehen, und andere, die dies nicht tun. Es gibt noch viel mehr, die das nicht tun.
Normalerweise lösen Menschen ein Gleitkommaproblem, indem sie Folgendes tun:
if (abs(c) <= epsilon) {
// We'll call it equal
} else {
// Not equal
}
Das ist viel schwieriger awk
. Wenn Sie Geld mit Geldeinheiten und zwei signifikanten Ziffern der Untereinheit (z. B. Dollar und Cent) verdienen, sollten Sie nur alle Berechnungen in den Untereinheiten (Cent in den USA) durchführen. Verwenden Sie keinen Gleitkommawert für monetäre Berechnungen. Sie werden diese Entscheidung nur bereuen.
awk 'BEGIN{a=99.15;b=20.85;c=78.30;printf("%22.20f %22.20f %22.20f",a,b,c)}' 99.15000000000000568434 20.85000000000000142109 78.29999999999999715783
Beachten Sie auch, dass die awk-Darstellung doppelt ist, Ihr c-Code einfach verwendet wird (daher der größere Fehler). Für doppelt mehr als 17 exakte Ziffern ist nicht sinnvoll.Sie werden von einem Gleitkomma-Rechenproblem gebissen.
http://floating-point-gui.de/ kann Ihnen möglicherweise dabei helfen, die Dinge für Sie zu klären. Es versucht zu erklären, was Gleitkomma ist und warum solche arithmetischen Fehler auftreten und wie Sie diese Art von Problemen in Ihrem System vermeiden können Programme.
quelle
Sie können solche Fehler vermeiden, indem Sie Zahlen bilden:
quelle
echo -e "0,99.16\n20.85,78.31\n78.31,0\n-99.15,99.15\n20.85,78.30" | awk -F, '{ if (NR != 1 && sprintf(CONVFMT,prior_tot-$1) != $2) {printf("Arithmetic fail...%s %30.30f",$0,prior_tot-$1)} else {print "OK"} prior_tot = $2}'