Punktrechnung geht vor Strichrechnung?
Mit anderen Worten: die verwendeten Unären Operatoren haben eine
unterschiedliche Priorisierung in der Ausführung. Siehe auch Operator
Precedence
Bei a wird erst der Term auf der rechten Seite aufgelöst (2) und dann a
durch die 2 geteilt.
Bei b wird erstmal die Punktrechnung durchgeführt, also b/2*5 bzw. b/10
und danach die 8 abgezogen und das dann zugewiesen.
Der Codeschnipsel oben gibt mir das (erwartete) Ergebnis:
1
0
2
-8
Getestet mit GCC 3.4.4 (cygwin).
Edit:
1
a/=2*5-8;
ist wie prx schon geschrieben hat, gleichbedeutend wie a=a/(2*5-8). Der
/= Operator nimmt alles was auf der rechten Seite steht als Divisor.
Deshalb ist das Ergebnis 0.
1
b=b/2*5-8;
Hier kommt die normale Punk-vor-Strich-Regel zur Anwendung:
b=((b/2)*5)-8.
> Vom Ergebnis ist a/=2 und a=a/2 für mich und für MSVC++9 total das> selbe.
also bei mir nicht
C:\>cl test2.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test2.c
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test2.exe
test2.obj
C:\>test2.exe
0
-8
casud schrieb:
> Ok, dann erklär's mir.> Vom Ergebnis ist a/=2 und a=a/2 für mich und für MSVC++9 total das> selbe.
Thomas Pircher hat doch schon geschrieben was der Grund ist...und
natürlich hat das bei einem simplen /2 keine Auswirkung...
casud schrieb:
> Ok, dann erklär's mir.> Vom Ergebnis ist a/=2 und a=a/2 für mich und für MSVC++9 total das> selbe.
Nur in der Fragestellung steht keine "2" sondern "2*5-8"
und a /= 2 wird zu a = 0/2
bzw a = a/2*5-8 wird zu a = ((0/2) * 5) - 8
Siehe http://www.difranco.net/cop2220/op-prec.htm
Student schrieb:
> Leider ist aber>> (a/=2*5-8;) != (a=a/(2*5-8);)>> wers nicht klaubt kann ja selber mal den Schnipsel durch einen Kompiler> jagen...
Nö, der Compiler ist mit mir der Meinung, beides ist identisch:
casud schrieb:
> Was bitte ist der Unterschied zwischen a/(2*5-8) und a/2?
Das Ergebnis beispielsweise.
> Jeder schlaue Compiler wird die ->Klammer<- auflösen.
Er wird erst den Inhalt der Klammer rechnen und dann dividieren. Bei
a/2*5-8 wird er erst dividieren und dann weiterrechnen.
Der Thread ist köstlich. Falls es noch keinem aufgefallen ist: Hier
schwirren gerade drei fast identische Codeteile herum. Und von jedem
wird was anderes behauptet.
Die Verwirrung ist echt komplett!
Es sollte aber, denke ich, klar geworden sein, dass
a/=2*5-8;
nicht das Gleiche ist, wie
b=b/2*5-8;
Das liegt aber nicht am Compiler, sondern an den vorherrschenden
Mathematikregeln :P
Simon K. schrieb:
> Das liegt aber nicht am Compiler, sondern an den vorherrschenden> Mathematikregeln :P
Zwischen denen ursächlicher Zusammenhang besteht ;-). Es gibt aber
Sprachen die von die Mathematikregeln gänzlich anderere Ansichten haben,
bei denen beispielsweise bei a/(2*5-8) und bei a/2*5-8 stets exakt das
gleiche Ergebnis rauskommt.
Simon K. schrieb:
> Der Thread ist köstlich. Falls es noch keinem aufgefallen ist: Hier> schwirren gerade drei fast identische Codeteile herum. Und von jedem> wird was anderes behauptet.>> Die Verwirrung ist echt komplett!>> Es sollte aber, denke ich, klar geworden sein, dass> a/=2*5-8;> nicht das Gleiche ist, wie> b=b/2*5-8;>> Das liegt aber nicht am Compiler, sondern an den vorherrschenden> Mathematikregeln :P
und daran, daß a etwas anderes ist als b :-)
A. K. schrieb:
> Es gibt aber Sprachen die von die Mathematikregeln gänzlich anderere> Ansichten haben, bei denen beispielsweise bei a/(2*5-8) und bei> a/2*5-8 stets exakt das gleiche Ergebnis rauskommt.
Igittigitt! Was sind denn das für welche? Eine davon heißt ganz sicher
Obfusca ;-)
yalu schrieb:
> Igittigitt! Was sind denn das für welche? Eine davon heißt ganz sicher> Obfusca ;-)
Ich habe dabei mal grosszügig / als Division und * als Multiplikation
verstanden, wenngleich das zumindest in der Originalversion der Sprache
etwas anders aussieht. Aber es gibt auch Abirrungen die mit ASCII
arbeiten.
Und die Logik der Rechenweise von APL ist doch wirklich ganz einfach und
übersichtlich: unter Missachtung aller althergebrachter Vorrangregeln
strikt von rechts nach links.
Aber klassische APL-Programme haben schon was Obfusca-mässiges. Ein paar
Zeilen Sonderzeichengewirr, das aussieht wie ein Binärfile im
Texteditor, an Stelle von etlichen Seiten C.
>> Was bitte ist der Unterschied zwischen a/(2*5-8) und a/2?>Das Ergebnis beispielsweise.
Ahja. Also kommt bei a/(2*5-8) und a/2 etwas unterschiedliches raus
interessant. Halt ich zwar immernoch für ein Gerücht aber wer's mag.
Ich bezog mich nie auf "a/2*5-8" sondern auf "a/(2*5-8)" und jemand in
diesem Thread meint das: a=a/(2*5-8) != a /= 2*5-8. Aber ich bin mir
hundertprozentig sicher das der Compiler hier sogar den selben Code
generieren wird. Siehe Auszug von peda.
casud schrieb:
>>> Was bitte ist der Unterschied zwischen a/(2*5-8) und a/2?>>Das Ergebnis beispielsweise.>> Ahja. Also kommt bei a/(2*5-8) und a/2 etwas unterschiedliches raus> interessant. Halt ich zwar immernoch für ein Gerücht aber wer's mag.
Hier betreibst du jetzt Haarspalterei.
Es geht nicht darum, dass 2*5-8 zufällig auch 2 ergibt. Und wenns den
anderen so ergeht wie mir, dann haben sie das auch bis vor 20 Sekunden
noch nicht gemerkt.
Es geht darum, dass
a/2*5-8 und a/(2*5-8)
unterschiedliche Auswertungen liefern.
Mit demselben recht könnte ich ja auch sagen, dass
x * x == x + x
denn für
2 * 2 == 2 + 2
stimmts ja.
> Siehe Auszug von peda.
Der beweist aber eigentlich damit etwas völlig anderes.
Jetzt betreibe ich auch mal Haarspalterei
> Was bitte ist der Unterschied zwischen a/(2*5-8) und a/2?> Jeder schlaue Compiler wird die ->Klammer<- auflösen.
Jeder schlaue Compiler wird die Klammer eben nicht auflösen, sondern er
wird ein Constant Folding betreiben und den Ausdruck in der Klammer zur
Compilezeit evaluieren (=berechnen)
Unter Klammer auflösen versteht man etwas anderes :-)
a*( 3 + 5 ) ==> a*3 + a*5
und genau das wird der Compiler sicher nicht tun.
Simon K. schrieb:
> Die Verwirrung ist echt komplett!
Das ist das schöne an solchen Threads. Hat was von Monty Python. Muss ja
nicht immer bierernst sein.
Leute bleibt doch mal auf dem Boden.
Zum ersten: Punkt geht vor Strichrechnung:
Das bedeutet daß a/(b-c) etwas anderes ist als a/b-c.
Das zweite hier viel wichtigere ist die Priorität der Operatoren der
Programmiersprache. Das hängt von der Programmiersprache ab und ggf. hat
da ein Compiler auch mal ein Fehler.
der Operator y /=x bedeutet y = y/x
Die Frage ist wie setzt der Compiler das um wenn x = b-c ist:
entweder y = y/(b-c) oder y = y/b-c
Das hängt von der Priorität der Operatoren '/=' und '-' ab und sollte in
der Sprach und/oder Compilerdoku zu finden sein.
Logisch wäre hier die Priorisierung '/=' ganz zuletzt also y = y/(b-c)
Gruß, Udo
Udo R. S. schrieb:
> Programmiersprache. Das hängt von der Programmiersprache ab und ggf. hat> da ein Compiler auch mal ein Fehler.
Möglich wenn auch unwahrscheinlich.
> der Operator y /=x bedeutet y = y/x
definiere das doch gleich richtig
y /= x <==> y = y / (x)
und damit erübrigt sich dann auch die Betrachtung der Operator
Precendence, die sowieso nicht zutrifft, denn im Resultat deiner
Umformung kommt /= gar nicht mehr vor.
Die Operator Precedence regelt Dinge wie das hier
a = y /= 5 * 2;
welches als
a = ( y /= 5 * 2 );
angesehen werden muss und nicht als
a = ( y /= 5 ) * 2;
(Nicht das ich jemandem explizit empfehlen würde sowas zu schreiben.
Aber der C-Standard muss so etwas regeln)
Noch was
@Simon K: a ist zwar nicht immer b aber in dem Beispiel war a = b und
nur deshalb in zwei Variablen gepackt um es für den Verfasser
übersichtlicher zu gestalten.
Aber wichtiger: Ihr rechnet hier mit Integer Variablen. Das heisst es
wird Ganzzahlarithmetik ohne Rundung betrieben.
8/5 ist da 1 (zumindest in C) und 8*2/5 was anderes als 8/5*2
nämlich:
8*2 = 16 16/5 = 3 (rest 1 fliegt einfach weg)
8/5 = 1 (Rest 3 fliegt weg) 1*2 = 2
Mein Tip programmiert Microcontroller immer in Assembler, da wisst ihr
wenigstens was passiert :-)
Gruß, Udo
Udo R. S. schrieb:
> Mein Tip programmiert Microcontroller immer in Assembler, da wisst ihr> wenigstens was passiert :-)
Oder lernt die C-Regeln.
So schwer sind die nicht und der Komfort dass sich der Compiler um das
Auswerten von komplexeren Ausdrücken kümmert ist nicht von der Hand zu
weisen.
@Karl Heinz Buchegger
Da könnte man jetzt drüber streiten :-)
Du definierst in Deinem Posting implizit daß '/=' eine niedrigere
Operator Precendence hat als alle Operatoren, die danach benutzt werden.
Ich habe gerade mal nachgesehen, bei Java ist das auch so und ich nehme
stark an daß das in C auch so ist.
ich wollte hier nur darauf hinweisen, daß es so etwas wie eine Priorität
der Operatoren gibt und daß man da ein Auge darauf haben sollte wenn man
in Hochsprachen programmiert.
Und dass an solchen Ecken alle Compiler feherfrei sind würde ich nicht
ungesehen unterschreiben.
Gruß, Udo
Man kann auch einfach Klammern. Das ist natuerlich nicht elitaer, aber
ich habe einfach schon zu oft Code gesehen, bei dem der Autor meinte
er wuesste jede Praezedenzregel auswendig.
Udo R. S. schrieb:
> Du definierst in Deinem Posting implizit daß '/=' eine niedrigere> Operator Precendence hat als alle Operatoren, die danach benutzt werden.
Nicht ich definiere das, sondern der C-Standard.
Und die Prioritäten sind so gewählt, dass sich automatisch die Punkt vor
Strich Rechnung ergibt. Alle anderen Operatoren sind in diese Tabelle
auch eingefügt, wobei es bei manchen eine Überraschung gibt.
> ich wollte hier nur darauf hinweisen, daß es so etwas wie eine Priorität> der Operatoren gibt und daß man da ein Auge darauf haben sollte wenn man> in Hochsprachen programmiert.
Das unterchreibe ich vorbehaltlos.
> Und dass an solchen Ecken alle Compiler feherfrei sind würde ich nicht> ungesehen unterschreiben.
Och. Du unterschätzt die Compilerbauer.
Die Tabelle der Precedence ist vorgegeben und bevor ein Compiler auf den
Markt geschmissen wird, durchläuft er erst mal eine Testsuite die ihn
auf ein paar hundert Testprogramme loslässt die unter anderem auch das
korrekte Auswerten von Ausdrücken umfassen.
Wenn es hier einen Fehler gibt, fällt das sehr schnell auf noch ehe der
Compiler auf den Markt kommt.
(Ein beliebter Test ist zb. dass sich ein Compiler selbst übersetzen
muss. Mit dem erhaltenen EXE wird dann der Compiler noch einmal selbst
übersetzt.
Die Ergebnisse aus dem Zwischendruchgang und dem Endergebnis müssen Byte
für Byte übereinstimmen(*). Und da ein Compiler ein nichttriviales
Programm darstellt hat man dadurch schon einen guten Teil der
Funktionalitäten getestet. Das ist aber eher sowas wie ein Quick&Dirty
Rundumschlagtest. Das Durchlaufen der Testsuiten erfolgt natürlich immer
noch)
(*) Da habe ich jetzt eine Stufe vergessen. Der ganze Prozess ist 4
stufig. Der A Compiler erzeugt den Compiler B.
Wenn sich B den Source vornimmt und Compiler C erzeugt UND C aus
demselben Source einen Compiler D erzeugt, dann müssen C und D Byte für
Byte identisch sein.
Die Compilerversion B ist ja mit einem 'alten Compiler A' entstanden und
kann daher abweichen.
A. K. schrieb:
> Und die Logik der Rechenweise von APL ist doch wirklich ganz einfach und> übersichtlich: unter Missachtung aller althergebrachter Vorrangregeln> strikt von rechts nach links.
Stimmt, das ist ja ganz einfach. Ich hatte etwas in diese Richtung
geahnt, hatte aber erst nicht berücksichtigt, dass die rechtsassoziative
Auswertung natürlich auch innerhalb des Klammerausdrucks in a÷(2×5−8)
Anwendung findet. Beachtet man dies, liefert der Ausdruck tatsächlich
das gleiche Ergebnis wie a÷2×5−8, nämlich a÷¯6.
Ich glaube, APL ist die Superangebersprache, deswegen muss ich sie mir
irgendwann mal reinziehen. Die lustigen Symbole, die ungewohnte Auswer-
tungsreihenfolge, die nahezu redundanzfreie Syntax ... da stimmt einfach
alles ;-)
yalu schrieb:
> A. K. schrieb:>> Und die Logik der Rechenweise von APL ist doch wirklich ganz einfach und>> übersichtlich: unter Missachtung aller althergebrachter Vorrangregeln>> strikt von rechts nach links.>> Stimmt, das ist ja ganz einfach. Ich hatte etwas in diese Richtung> geahnt, hatte aber erst nicht berücksichtigt, dass die rechtsassoziative> Auswertung natürlich auch innerhalb des Klammerausdrucks in a÷(2×5−8)> Anwendung findet. Beachtet man dies, liefert der Ausdruck tatsächlich> das gleiche Ergebnis wie a÷2×5−8, nämlich a÷¯6.>> Ich glaube, APL ist die Superangebersprache, deswegen muss ich sie mir> irgendwann mal reinziehen. Die lustigen Symbole, die ungewohnte Auswer-> tungsreihenfolge, die nahezu redundanzfreie Syntax ... da stimmt einfach> alles ;-)
Nicht zu vergessen:
Das komplette Referenzmanual passt auf eine beidseitig bedruckte Karte
von der Größe einer Scheckkarte :-)
(Wenn ich meine noch mal finde, scanne ich sie)
yalu schrieb:
> Ich glaube, APL ist die Superangebersprache,
Ja, in solchem Kontext wie hier ist das tatsächlich ein bischen so als
ob jemand sagt, er könne koreanisch lesen. Allerdings hatte ich mir die
nicht ausgesucht. Das war schlicht die einzige Sprache, die damals in
der Schule zur Verfügung stand.