Hallo, ich habe da ein komisches Problem mit der Multiplikation mit -1. AVR Studio 7, Atmega32. FACTOR = 1000000UL; signed long result = 176000000L; signed int tmp = result/FACTOR; printf("Result: %d\n", tmp); if (IsNegative) result *= (-1); tmp = result/FACTOR; printf("Result: %d\n", tmp); Ich berechne da ein signed Long, das hat dann den Wert 176Mio. Wenn ich das herunter teile und über den COM Port ausgebe bekomme ich 176, passt. Wenn ich aber mit (-1) multipliziere weil mein Flag das sagt, dann bekomme ich 4118 ausgegeben, nicht -176. Anders gefragt: Wie mache ich aus einer positiven Long Zahl eine negative? So wie oben geht es nicht. Das Problem ist ganz eindeutig die Multiplikation, vorher passt es, nachher nicht. Besten Dank, Gruß Thomas
Thomas S. schrieb: > Das Problem ist ganz eindeutig die Multiplikation, vorher passt es, > nachher nicht. Zweierkomplement direkt rechnen, i.e. invertieren und +1
Thomas S. schrieb: > tmp = result/FACTOR; Das ist eine vorzeichenlose Division, da zwar der Zähler "signed long" ist, der Nenner aber "unsigned long".
:
Bearbeitet durch User
1 Million durch 176 Millionen ergibt niemals 167. Der Code passt nicht zu Deinem Text. Bitte überarbeite das nochmal. Und poste hier am besten kompilierbaren Code.
Wolfgang schrieb: > Zweierkomplement direkt rechnen, i.e. invertieren und +1 Wozu soll das denn gut sein? Allerdings könnte man auf die Idee kommen, einfach result = -result; hinzuschreiben.
Au weia. Ich habe mich verguckt. Die Division ist durchaus richtig. Sorry.
Beitrag #5556762 wurde vom Autor gelöscht.
Division c signed unsigned Ergibt bei Google z.b.: https://stackoverflow.com/questions/5328269/int-divided-by-unsigned-int-causing-rollover
Weiß jemand, warum C in so einem Fall zu unsigned konvertiert, also was ist die logische Begründung (Praxisbezug)? Auf den ersten Blick erscheint mir das unsinnig und irreführend.
Ingolf schrieb: > Weiß jemand, warum C in so einem Fall zu unsigned konvertiert, also was > ist die logische Begründung (Praxisbezug)? Auf den ersten Blick > erscheint mir das unsinnig und irreführend. Was wäre die Alternative und warum wäre sie sinniger? Tatsächlich steckt dieser Aspekt bereits von Anbeginn in C. Während die Situation bei int16 / uint8 erst mit ANSI-C entschieden wurde. Dennis Ritchie kannst du jedenfalls nicht mehr fragen.
Beitrag #5556850 wurde von einem Moderator gelöscht.
Beitrag #5556853 wurde von einem Moderator gelöscht.
Die Alternative wäre, dass eben signed quasi dominant ist, also nach signed promoted wird, wenn einer der Operanden signed ist. Weil das Vorzeichen eine Information ist (die offensichtlich wichtig ist, sonst wäre die Variable ja nicht signed). Diese Information geht ungefragt und per Default verloren. So, wie es jetzt ist, das ist für mich ähnlich logisch, als würde C von long nach int "promoten", wenn man z.B. long + int rechnet. Ein Designfehler. Kann natürlich sein, dass ich mich täusche und es eine logische Erklärung gibt. Aber auf solche Späße stößt man in C leider wirklich oft, was wirklich Schade ist. :(
Vorzeichenlose Rechnung ist in C als Modulo-Arithmetik definiert, während das Verhalten vorzeichenbehafteter Arithmetik bei Überlauf undefiniert ist. Die Dominanz des Vorzeichens würde damit etwas kollidieren. Man könnte Rechnungen verschiedener Typen auch ganz verbieten, mit Pflicht zu expliziter Konvertierung in homogene Typen. Das wäre eindeutig. Dann gäbe result / FACTOR eine Fehlermeldung, und nötig wäre sowas wie result / long(FACTOR) Aber das wäre dann nicht mehr C.
:
Bearbeitet durch User
Gibt es wenigstens Warnungen (-W???), welche man einschalten könnte und die auf solche Fälle hinweisen? Das wäre extrem hilfreich.
Hallo nochmal und vielen Dank für die zahlreichen Antworten. Die Division war der Knackpunkt, signed geteilt durch unsigned. Ich hab den FACTOR nun auch signed gemacht und siehe da es klappt! Case gelöst, schönes Wochenende an alle und vielen Dank! Gruß Thomas
A. K. schrieb im Beitrag #5556853: > Oder überhaupt nicht zulassen? Das wäre an sich gar nicht schlecht. Dann muss man sich vor so einer Operation nämlich immer selber Gedanken darüber machen, welcher Operand jetzt in den Typ des anderen konvertiert werden muss. Das Mischen von signed und unsigned bei Rechenoperationen ist sowieso selten eine gute Idee, wie man ja hier auch sieht. Ingolf schrieb: > Die Alternative wäre, dass eben signed quasi dominant ist, also nach > signed promoted wird, wenn einer der Operanden signed ist. Weil das > Vorzeichen eine Information ist (die offensichtlich wichtig ist, sonst > wäre die Variable ja nicht signed). Diese Information geht ungefragt und > per Default verloren. Und bei unsigned ist es eben die Information, dass der Wert in der oberen Hälfte des Wertebereichs liegt. Ist die denn vollkommen unwichtig und darf deshalb einfach verloren gehen? Beispiel: (für int = 16bit wie auf dem AVR) signed int i = 5; unsinged int j = 10000; long result = i * j; Was würdest du als Ergebnis erwarten? Nach den aktuellen Regeln steht in result nachher 50000 drin. Nach deinem Wunsch müsste die Rechnung vorzeichenbehaftet durchgeführt werden, wodurch das Ergebnis nicht mehr in den Wertebereich passt, was, wie schon erwähnt wurde, undefiniertes Verhalten bedeutet. Auf den meisten Systemen würde es vermutlich zu einem Wrap-Around kommen und das Ergebnis wäre -15536. > So, wie es jetzt ist, das ist für mich ähnlich logisch, als würde C von > long nach int "promoten", wenn man z.B. long + int rechnet. Das ist was anderes, da int je nach Plattform weniger Informationen enthalten kann als long. Bei signed- und unsigned-Variante des selben Typs ist das aber anders. Ingolf schrieb: > Gibt es wenigstens Warnungen (-W???), welche man einschalten könnte und > die auf solche Fälle hinweisen? Das wäre extrem hilfreich. Ja.
Ich habe es gerade mal mit Delphi ausprobiert: Entweder rechnet dieses immer in einem sehr breiten Datentyp oder es richtet sich nach dem Ergebnistyp. Im Endeffekt heißt das, dass die Vorzeicheninformation (selbst bei gemischten Typen) dort nicht verloren geht. Das Ergebnis deines Beispiels wäre dort korrekterweise 50000. Tausche ich 5 gegen -5, ist das Ergebnis weiterhin korrekt (-50000), vorausgesetzt, der Ergebnistyp ist signed und groß genug (den richtigen Typ für das Ergebnis muss der Programmierer natürlich schon selbst wählen). Ich finde das so jedenfalls logischer und nachvollziehbarer.
Ausserhalb von Insellösungen aus einer Quelle oder für genau einen Compiler ist die formelle Sprachdefinition wichtiger als das, was man als "logisch" empfindet. Der Ansatz "mal ausprobieren was dabei raus kommt" ist dann nicht sehr hilfreich. C hatte an ähnlicher Stelle einmal einen Bruch mit bestehendem Verhalten. Anfangs war in C offen, ob sich bei Operanden unterschiedlicher Grösse die Vorzeicheneigenschaft durchsetzt, oder der Wertebereich. Also ob bei beispielsweise int32 + ushort16 hinten int32 oder unsigned32 rauskommt. Bestehende Compiler waren uneinheitlich, mit Tendenz zur Vorzeicheneigenschaft. ANSI C definierte dann aber über den Wertebereich, also int32.
Rolf M. schrieb: > A. K. schrieb: >> Oder überhaupt nicht zulassen? > > Das wäre an sich gar nicht schlecht. Dann muss man sich vor so einer > Operation nämlich immer selber Gedanken darüber machen, welcher Operand > jetzt in den Typ des anderen konvertiert werden muss. Das Mischen von > signed und unsigned bei Rechenoperationen ist sowieso selten eine gute > Idee, wie man ja hier auch sieht. Der erste Schritt in die richtige Richtung ist -Wsign-conversion, damit der Compiler bei impliziten Vorzeichenkonvertierungen mit Informationsverlust (signed -> unsigned) warnt.
A. K. schrieb: > Vorzeichenlose Rechnung ist in C als Modulo-Arithmetik definiert, > während das Verhalten vorzeichenbehafteter Arithmetik bei Überlauf > undefiniert ist. Die Dominanz des Vorzeichens würde damit etwas > kollidieren. Naja, letztlich sind das auch wieder nur ein Haufen nutzloser Worte, die den Sachverhalt "C ist Scheisse" verschwurbelt umschreiben. Dein Ansatz ist: C definiert das halt so und deshalb muss es gut sein. Und ich sage: nein, das ist Scheisse, schon die Definition taugt nix. So sieht's aus. Und die Praxis gibt mir Recht. Wäre es anders, gäbe es nämlich z.B. diesen Thread erst garnicht. ;o)
Warum hat man damals eigentlich das Überlaufverhalten bei signed nicht definiert?
Hallo, c-hater schrieb: > Dein Ansatz ist: C definiert das halt so und deshalb muss es gut sein. Nein, das das sein Ansatz ist unterstellst du ihm, für mich ist sein Ansatz eher : "C definiert das halt so". > Und die Praxis gibt mir Recht. Finde ich nicht, denn selbst so ein "Bastelprogrammierer" wie ich hat sofort erkannt das das mit den unterschiedlich definierten Datentypen zu tun haben muss. Und vielleicht würde es manchen Fragestellern hier mal gut tun sich erstmal ein paar Gedanken über Probleme zu machen, bevor sie hier ihre Fragen stellen, dann > ... gäbe es nämlich z.B. diesen Thread erst garnicht. ;o) rhf
Ingolf schrieb: > Warum hat man damals eigentlich das Überlaufverhalten bei signed nicht > definiert? Weil eine sinnvolle Definition je nach Implementierung anders aussehen würde oder zusätzlichen Checker-code benötigt. und Definieren heißt konkret: festlegen, was bei 127+1 bei einem signed char (@8Bit) rauskommen soll.
Ingolf schrieb: > Warum hat man damals eigentlich das Überlaufverhalten bei signed nicht > definiert? Weil man auch nicht definiert hat, dass eine Rechnung mit Vorzeichen im Zweierkomplement durchzuführen ist. Mindestens bis in die 80er waren noch Maschinen im Einsatz, die im Einerkomplement rechneten. Daher auch der vom Standard geforderte Wertebereich von -32767..+32767 für int. Also ohne -32768. Exkurs in andere Gefilde: Die erste Implementierung von Pascal entstand auf einer Maschine, die im Einerkomplement rechnete. Die offiziell maximal darstellbare Integer war zwar 2**48-1, aber das war nur das Limit von Multiplikation und Division. Ansonsten wurden 60 Bits gerechnet und gespeichert. Weshalb if abs(i) > maxint then write (' too big'); auf dieser Maschine ganz offiziell Sinn ergab. Allein schon, weil die Ausgabe von Integers ausserhalb des 49-Bit Bereichs scheiterte. Zurück zu C: Versuch mal, da ein sinnvolles Überlaufverhalten zu definieren, ohne massiv an Effizienz zu verlieren. Da ist schon das definierte Verhalten vorzeichenloser Typen eine Herausfordeung.
:
Bearbeitet durch User
Roland F. schrieb: > c-hater schrieb: >> Dein Ansatz ist: C definiert das halt so und deshalb muss es gut sein. > > Nein, das das sein Ansatz ist unterstellst du ihm, für mich ist sein > Ansatz eher : "C definiert das halt so". Korrekt. Er mag C hassen. Ich jedoch kenne und verwende C, ohne es zu lieben oder auch nur wirklich gut zu finden. Ist mit Deutsch nicht viel anders.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.