PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Punktrechnung vor Strichrechnung ???



Siro
15.12.2011, 20:43
Hallo zusammen,
ich bin mal wieder auf ein erstaunliches, bzw. ärgerliches Phänomen bei "C" gestoßen.

1 << 8 + 1 ergibt 512 ????????

in Pascal, Modula ergbit es 257

Mal zur Information:
Eine Verschiebung nach links entspricht einer Multiplikation mit n hoch x.
In der Schule wurde mir beigebracht, daß Punktrechnung vor Strichrechnung geht.
Wie kommt es, daß "C" anderer Meinung ist.
Hier wird erst die Addition durchgeführt dann die Verschiebung.

Keiner Sorge, ich hab mir das schon durchgelesen.
Präzendenz.... in "C" hat eine "eigene Tabelle"
Ich bin eigentlich nur enttäuscht.
Siro

Felix G
15.12.2011, 21:11
Naja, ein Linksshift ist eben per Definition keine Multiplikation (obwohl er gerne dafür eingesetzt wird)

verwendet man den "normalen" *-Operator, stimmt auch die Rechnung wieder


edit:
auch interessant ist, was der C-Standard zu dem Thema zu sagen hat:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2^E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2^E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.Man muss also bei diesem Operator schon aufpassen in welchen Fällen man ihn einsetzt, denn nicht immer ist das Ergebnis definiert (beim Rechtsshift als Division ist es noch schlimmer)

SprinterSB
15.12.2011, 22:19
> Hallo zusammen, ich bin mal wieder auf ein erstaunliches, bzw.
> ärgerliches Phänomen bei "Spache" gestoßen.

*Das wird dir mit *jeder* Programmier-, Skript-, Satz-, Markup-Sprache passieren: Tryial by Error ist *immer* ineffektiver als phänomenale Dokumentation lesen!

Siro
16.12.2011, 08:25
Eigentlich wollte ich dem Compiler etwas Arbeit abnehmen mit dem Shift,
es gibt ja Controller die nicht multiplizieren können und da bin ich es halt gewohnt zu schieben.
Hätt ich den normalen Multiplikator verwendet geht es richtig, da stimme ich Felix G völlig zu.
Ich bin auch erstaunt was der C-Standard dazu sagt.
"behavior is undefined" "Das Verhalten ist undefiniert"
Das ist ja wie bei einem FlipFlop: beim Einschalten, "undefinert" man braucht halt einen Vorzugskondensator,
hier halt die Klammern oder das "*".

Dokumentation lesen ist sicher nicht verkehrt, da bin ich ganz deiner Meinung.
Aber wie sagt man so schön: Aus Fehlern lernt man. Und ich glaube auch, daß man durch Analysieren der Fehler oder "Programmierfallen"
wesentlich mehr lernt als nur vom Lesen.
Man muss einfach mal loslegen und viel Zeit investieren und auch viel Programmieren und auch "probieren"
Nach einigen Jahren kommt man dann meist recht gut zurecht.
Wenn ich dann Bücher sehe wie : Java in 14 Tagen lernen, kann ich nur lachen.
Programmieren ist ein Prozess in dem man ständig dazulernt und dieser endet nie, auch nicht nach 30 Jahren.
Und jede Programmiersprache hat seine Eigenheiten, die man dann irgendwann auch kennt.
Man (ich) ärgert sich dann nur, wenn man bestimmte Dinge in einer anderen Programmiersprache anders gelernt hat als es in der Sprache Y funktioniert
Macht zieht dann automatisch seine Vergleiche und diese fallen im Moment bei C eher negativ aus.

Zitat von Sprint SB:
Computer sind Maschinen, mit denen man Probleme lösen kann, die es ohne sie nicht gäbe.

ich würd es im Moment so beschreiben, bitte nicht negativ auffassen:
Mit C kann man Probleme lösen, die man in X garnicht hatte :-)

Einen schönes Wochenende Euch allen.
Siro

lokirobotics
16.12.2011, 10:15
Programmieren und Java sind ja auch zwei völlig verschiedene Sachen.
Java ist "nur" eine Sprache, die kann man locker in 14 Tagen lernen. Kommt man von C#
braucht's nur einen Tag.

Programmiererisches Können ist unabhängig von der Sprache. Sich in den Wust der
Laufzeitbibliotheken einzuarbeiten kann dagegen schon ein wenig Zeit in Anspruch nehmen, vorausgesetzt, man will sofort alles wissen.
Sonst guckt man einfach in die Dokumentation, dann braucht man nicht einige Jahre um leidlich zurecht zu kommen. ;)

Calis007
16.12.2011, 10:37
Also ich hab mir einfach angewoehnt, alles zu klammern sobald auch nur der geringste Zweifel besteht.
Und ich hab fast alles durch, von APL bis Z80-Assembler :p

Mit Punktrechnung vor Strichrechnung kommst nicht weit, APL ist gleich das erste Beispiel (Auswertung strikt von rechts(!) nach links), Forth ein weiteres ...

radbruch
16.12.2011, 16:09
Hallo

Addition vor Shift:
http://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit% C3%A4t

Das Stichwort lautet "Bindung der Operatoren (http://www.google.de/search?q=c+Operatoren+bindung)"

"...alles zu klammern sobald auch nur der geringste Zweifel besteht." praktiziere ich auch.

Gruß

mic

Felix G
17.12.2011, 00:47
Klammern ist immer gut, dadurch werden solche Ausdrücke auch besser lesbar :-)
(wenn man trotzdem das Gefühl hat ein Ausdruck wäre mit Klammern schlechter lesbar, dann ist der Ausdruck zu lang und sollte ohnehin in mehrere leichter verdauliche Häppchen zerlegt werden)


Vielleicht noch eine Kleinigkeit zur Verwendung von Shifts als Ersatz für Multiplikation oder Division:
Normalerweise tut man das aus Performancegründen, aber nicht immer ist diese Variante auch tatsächlich schneller. Ein ATmega z.B. hat üblicherweise einen eingebauten Multiplizierer, der für eine 8x8 Bit Multiplikation genau 2 Takte benötigt. Ein Linksshift hingegen benötigt nur einen Takt, also müssten Multiplikationen damit ja doppelt so schnell laufen, korrekt?

Falsch!
Denn was viele übersehen ist, daß ein ATmega keinen Barrel-Shifter hat, d.h. er kann mit einem Shift-Befehl auch nur um ein Bit shiften. Es bleibt also nur ein einziger Fall übrig bei dem der Shift tatsächlich schneller ist, und das ist die Multiplikation mit 2.

Programmiert man in Assembler fällt das sofort auf, da die Shift Befehle jeweils nur einen Operanden haben (nämlich das zu shiftende Register). In C hingegen merkt man das überhaupt nicht (wer käme schon auf die Idee, daß "<< 7" mehr Befehle braucht als "<< 2").

Dazu kommen natürlich noch die schon erwähnten Sonderfälle die man beachten muss, wenn die Ergebnisse auch korrekt sein sollen.


Das nur mal als kleiner Hinweis am Rande, daß vermeintliche Optimierungen manchmal genau das Gegenteil von dem bewirken, was man eigentlich wollte.