Och Leute - seid ihr alle durch JavaScript und PHP soweit vom Blech abgehoben, dass ihr die Grundlagen nicht mehr kennt?
Einfache Genauigkeit
Fließkomma in C
Mit Kommutativität / Assoziativität hat das wenig zu tun. Sicher, in C ist die Reihenfolge der Operandenauswertung undefiniert, aber die Reihenfolge, in der die OPERATOREN angewendet werden, ist durch die Assoziativität bestimmt und deswegen erfolgt die Addition in Zeile 21 von links nach rechts.
Das Problem ist ein anderes: Die Genauigkeit von float ist winzig, es sind 23 Bit und damit ist $$2^{24}-1$$ der größte darstellbare Mantissewert. Also ca 16 Millionen, demzufolge 7-8 signifikante Stellen. Die Addition
10000
0,000111
============
10000,000111
braucht 9 signifikante Ziffern, damit der kleine Summand nicht untergeht. Deswegen sind die Summanden x2 und x4 nach der Zuweisung an die Akkumulatorvariable float y
verschwunden.
Wenn man y als double deklariert, ist das Problem weg. Vermutlich aus dem gleichen Grund, aus dem das bei dem langen Term anders ist; und ich würde es schon fast als Compiler-Bug ansehen. Es sei denn, K&R haben dem Compiler hier wieder mal die Freiheit der Interpretation gelassen, und eine Auswertung von float-Expressions mit double-Genauigkeit ist legitim. Fließkommaarithmerik macht ein Prozessor von heute jedenfalls mit der FPU und die arbeiten heute alle mit 64 oder 80 Bit, also double oder long double. Doppelte Genauigkeit hat 53 signifikante Bits oder 16 signifikante Dezimalstellen, und deswegen bleiben die Summanden dann erhalten.
Durch die interne genauere Rechnung haben sich am Ende die großen Werte gegenseitig ausgelöscht und man hat ein Ergebnis nahe 0. DAS kann dann wieder als float gespeichert werden.
In einem Uralt-C-Compiler, der noch Code für CPUs ohne FPU erzeugen kann, könnte man einmal einstellen, dass er eine 32-bit Float-Emulation nutzen soll (Fastmath oder sowas). Und dann dürfte auch die einzeilige Rechnung die kleinen Werte verlieren.
Rolf