Habe zu folgendem Code eine Frage: TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms Ziel ist es den Wert auf 8Bit zu bekommen, da das Registern eben so groß ist. Mir ist unklar warum ein "-" vor der äußersten Klammerauddruck steht? Wie castet man 16Bit in 8Bit um? Dachte das geht nicht. (uint8_t)(int16_t) oder passiert hier etwas anderes? Bitte keine Verweise auf Lehrbücher, da wurde ich nicht fündig. Danke vorab. MfG Elias
Elias H. schrieb: > Bitte keine Verweise auf Lehrbücher, da wurde ich nicht fündig. Dann hast du die falschen Bücher. Ja, da wird von 16 signed auf 8 Bit unsigned gecastet, und ja, das geht. Schreib dir die Bitmuster der Werte auf, und schau dir an, was da passiert. Oliver
Beitrag #6152825 wurde vom Autor gelöscht.
CPU schrieb: > welchen Zahlenwert hat F_CPU? Ist für diesen Cast völlig irrelevant und beantwortet die Frage nach dem Minus nicht. Die Funktion des Minuszeichens erschließt sich mir auch nicht und ich konnte dazu auch nichts finden, weder in den bei mir vorhandenen C Büchern noch im Netz. Also was bewirkt das Minus? Ich habe bisher so ein Konstrukt noch nicht gesehen.
Hallo das hier um Timer 0 geht und der im overflow modus betrieben wird, wird immer von dem Startwert aufwärts gezählt. Beim überlsuf von 0xff zu 0x00 erfolgt ein Interrupt Request. Steht aber alles im Datenblatt und man muss sich nicht dumm stellen. Tipp schreibe 0-(<expression>), dann wird es klarer!
F_CPU = 1000000, gut, mal rechnen: 1000000 / 1024 = 976,56... * 10e-3 = 9,7656... + 0.5 = 10,2656... -(..) = -10,2656... (int16_t) = 0xFFF6 (uint8_t) = 0xF6 // preload for 10ms Der Blick in die Glaskugel...du hast ein Register TCNT0 welches vorwärtszählt und bis zum Überlauf 10ms brauchen soll.
Elias H. schrieb: > Mir ist unklar warum ein "-" vor der äußersten Klammerauddruck steht? Ich würde annehmen, schlicht aus demselben Grund aus dem üblicherweise das unäre Minus verwendet wird: weil man von etwas den negativen Wert haben möchte.
Zeno schrieb: > Ist für diesen Cast völlig irrelevant und beantwortet die Frage nach dem > Minus nicht. Es ermöglicht Dir, das Beispiel Nachzuvollziehen. Ein aus der Luft gegriffener wert könnte mit falschem Überlauf verwirren.
as schrieb: > Es ermöglicht Dir, das Beispiel Nachzuvollziehen. Ein aus der Luft > gegriffener wert könnte mit falschem Überlauf verwirren. Karl hat es verständlich erklärt, auch ohne einen konkreten Wert.
Elias H. schrieb: > TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); // preload for > 10ms Gibt es hier etwa jemanden, der einen solchen Quellcode für gut und ordentlich erachtet? Wenn schon, dann sollte man sowas in einer oder mehreren #define(s) separat erledigen und eben nicht so eine Verrenkung fabrizieren. W.S.
W.S. schrieb: > Gibt es hier etwa jemanden, der einen solchen Quellcode für gut und > ordentlich erachtet? Sprach der Magic Number Priester?
Elias H. schrieb: > TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); Wow, auf die Idee muss man erst einmal kommen: einen Integer mit Fließkomma zu verwursten, negativ machen, dann auf 16bit casten, dann nochmal auf 8bit ohne Vorzeichen casten. Was hat der Autor geraucht? Das Zeug will ich auch haben. Dann ergeben vielleicht auch andere seltsame Dinge in meinem Leben Sinn. Zum Beispiel Pferde im Flur oder Häuser auf der Autobahn. Oder das Gerede mancher Frauen. Das ist meiner Meinung nach für Menschen unlesbarer Code. Wer so etwas schreibt, hat den Sinn der Programmiersprache verfehlt. Da kann man gleich Maschinencode schreiben.
Stefan ⛄ F. schrieb: > Was hat der Autor geraucht? Das Zeug will ich auch haben. Das sind ganz normale Standardtechniken. Ein erfahrener Programmierer schreibt keine magischen Nummern hin, sondern den Rechenweg. Das erlaubt es z.B. eine andere F_CPU zu verwenden, ohne den Ausdruck korrigieren zun müssen. Die Berechnung in float vermeidet Rundungsfehler und Überläufe. Der cast zu int hindert den Compiler daran, die float-Lib zur Laufzeit einzubinden. Der cast zum Zieltyp vermeidet dann eine Compilerwarnung.
Der Term besteht sowieso nur aus Konstanten, den kann der Präprozessor schon wegräumen.
Peter D. schrieb: > Die Berechnung in float vermeidet Rundungsfehler Das habe ich anders im Kopf. Float ist dafür bekannt (besonders bei sehr großen und sehr kleinen Zahlen) auffällig ungenau zu sein. > Der cast zu int hindert den Compiler daran, die float-Lib > zur Laufzeit einzubinden. > Der cast zum Zieltyp vermeidet dann eine Compilerwarnung. Interessant, da habe ich mal wieder was gelernt. Dankeschön.
Karl M. schrieb: > Tipp schreibe 0-(<expression>), dann wird es klarer! Man könnte sogar 256-(<expression>) schreiben. CPU schrieb: > F_CPU = 1000000, gut, mal rechnen: > > 1000000 / 1024 = 976,56... Nicht ganz. Das Ergebnis ist 976, da in Integer gerechnet wird. Erst die Rechnungen danach sind dann in double. Zeno schrieb: > as schrieb: >> Es ermöglicht Dir, das Beispiel Nachzuvollziehen. Ein aus der Luft >> gegriffener wert könnte mit falschem Überlauf verwirren. > > Karl hat es verständlich erklärt, auch ohne einen konkreten Wert. Mit wird es klarer. So etwas nennt man "Beispiel". Stefan ⛄ F. schrieb: > Was hat der Autor geraucht? Kritisieren, ohne eine bessere Alternative zu zeigen, ist einfach. Johannes S. schrieb: > Der Term besteht sowieso nur aus Konstanten, den kann der Präprozessor > schon wegräumen. Dem Präprozessor ist das ziemlich egal. Der macht nur die Ersetzung von F_CPU und TCNT0, sonst nichts. Stefan ⛄ F. schrieb: > Peter D. schrieb: >> Die Berechnung in float vermeidet Rundungsfehler > > Das habe ich anders im Kopf. Float ist dafür bekannt (besonders bei sehr > großen und sehr kleinen Zahlen) auffällig ungenau zu sein. Hier kommen aber keine sehr großen oder sehr kleinen Zahlen vor, sondern nur welche in einem Bereich, in dem es genauer als int ist. Außerdem wird hier nicht in float, sondern in double gerechnet - was aber hier vermutlich keinen Unterschied macht, da es sich um Code für AVR-GCC zu handeln scheint.
Hallo Vielleicht wäre es etwas verständlicher, wenn der Code mit einer weiteren Klammer geschrieben wäre: TCNT0 = (uint8_t)(int16_t)(0-(F_CPU / 1024 * 10e-3 + 0.5));
Rolf M. schrieb: >> 1000000 / 1024 = 976,56... > > Nicht ganz. Das Ergebnis ist 976, da in Integer gerechnet wird. Erst die > Rechnungen danach sind dann in double. Bewirkt das +0.5 nicht, dass hier für den ganzen Ausdruck Double genutzt wird? Andernfalls wäre es ja sinnlos, weil 0.5 in Integer gecastet 0 ergibt, meine ich. Ergänzungsfrage: Stünde 0.5 außerhalb der Klammer, würde dann der Ausdruck in der Klammer als Integer berechnet und anschließend mit 0.5 als Double multipliziert, Ergebnis wäre dann wieder Double? Also so: TCNT0 = (uint8_t)(int16_t)-((F_CPU / 1024 * 10e-3) + 0.5); Ach ja, warum eigentlich Double und nicht Float?
Interessierter schrieb: > Rolf M. schrieb: >>> 1000000 / 1024 = 976,56... >> >> Nicht ganz. Das Ergebnis ist 976, da in Integer gerechnet wird. Erst die >> Rechnungen danach sind dann in double. > > Bewirkt das +0.5 nicht, dass hier für den ganzen Ausdruck Double genutzt > wird? Nicht der ganze Ausdruck. Jeder Teilausdruck wird für sich behandelt. Das erste, was ausgerechnet wird, ist F_CPU / 1024. Da F_CPU vermutlich vom Typ unsigned long ist und 1024 vom Typ int, wird die Berechnung in unsigned long durchgeführt. Danach kommt die Multiplikation mit 10e-3, was ein double ist. Das heißt, das Ergebnis aus der ersten Berechnung wird nach double konviertiert, und dann geht's mit dem Typ weiter. Auch das +0.5 wird dann in double gerechnet. > Ergänzungsfrage: Stünde 0.5 außerhalb der Klammer, würde dann der > Ausdruck in der Klammer als Integer berechnet und anschließend mit 0.5 > als Double multipliziert, Ergebnis wäre dann wieder Double? > Also so: TCNT0 = (uint8_t)(int16_t)-((F_CPU / 1024 * 10e-3) + 0.5); Nein, da 10e-3 auch ein double ist. > Ach ja, warum eigentlich Double und nicht Float? Weil das der Default für floating point literals ist. Wenn man float will, muss man das explizit angeben. 0.5 ist double, float wäre 0.5f.
Ich mag Züge, C und Peter Danneggers Code. Hier leider nur als Fragment wiedergegeben, so dass man nur schwer das Ziel dieses Ausdrucks nachvollziehen kann. Seine Programme, die ich bisher gefunden und gelesen haben, zeugen von sehr vier Erfahrung und einem eigenen Stil. Da wird nichts umsonst oder aufwändig in C formuliert, Zielsetzung in meinen Augen ist effizienter C zu Assembler Code. Z.B. seine Matrix-Tastaturabfrage, mit Entprellung und KeyPressed und KeyReleased usw. Funktionen. Also Lieber Peter, wenn Du wieder etwas neues hast, dann lass mich bitte daran teilhaben.
CPU schrieb: > F_CPU = 1000000, gut, mal rechnen: > > 1000000 / 1024 = 976,56... > * 10e-3 = 9,7656... > + 0.5 = 10,2656... > -(..) = -10,2656... > (int16_t) = 0xFFF6 > (uint8_t) = 0xF6 // preload for 10ms > > Der Blick in die Glaskugel...du hast ein Register TCNT0 welches > vorwärtszählt und bis zum Überlauf 10ms brauchen soll. Ich habe das jetzt mal nachgerechnet wie oft der Timercounter zählen muss wenn der Prozessor mit 1Mhz arbeitet und der Prescaler des Timercounter mit 1024 den Takt teilt. Das bedeutet zunächst alle 0,000 102 4 Takte pro Sekunde (Tps) wird der Timercounter um 1 erhöht. 10 ms entsprechen 0,010 Tps Teilt man also 0,010 / 0,000 102 4 = 97,65, aufgerundet ergibt das einen Wert von 98. Bedudeutet also der Timercounter muss 98Mal zählen, dann darf er einen Interrupt auslösen, dies ergibt ein Interval von 10ms oder 0,010Tps Eine unit8_t kann also eine Zahl die maximal 512 (Dez.) annehmen. Das Timercounter Daten Register schafft allerdings nur 8Bit (256) und das Counter Register zählt grundsätzlich von 0 bis 255. Daher sollte der geladene Wert TCNT0 = 98; oder TCNT0 = 0x62; sein Da ich die Berechnung TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); aus mehren Gründen nicht navollziehen kann. Bei mir kommt in diesem Klammerausdruck (F_CPU / 1024 * 10e-3 + 0.5) = 1,47 heraus. Ich habe 10e-3 nicht wie oben gerechnet mit der Eulereschen Zahl exponiert sondern den Ausdruck exponenziell gerechnet (10e-3 = 10^(-3) = 0.0001). Für die Euleresche Zahl muss in C die math.lib includiert werden und eine funktionsaufruf ist notwendig. Kann mir wer sagen was für ein Wert wirklich in dem Klammerausdruck herrauskommt? und wie 10e-3 zu verstehen ist? Bei den beiden Cast´s bin ich nicht ganz sicher ob ich die Schritte arithmeitsch richtig erfasst habe. Der rechte Klammerausdruck ist negativ, daher der Cast mit Vorzeichenhafteten int 16Bit. Der nächste Cast auf 8 Bit ohne vorzeichenbehftete int 8Bit müsste daher das 1er und 2er Komplement gebildet haben und vom MSB weg 8 Stellen weggeschnitten haben. Ist das so richtig? MfG Elias
Elias H. schrieb: > Eine unit8_t kann also eine Zahl die maximal 512 (Dez.) annehmen. Nein, 255. Das ganze berechnet der Compiler während der Übersetzung, das braucht keine Libs und wird zu zwei Zeilen Assembler übersetzt. Deshalb kann man hier ohne Probleme mit double und Long Long int rechnen.
Elias H. schrieb: > (10e-3 = 10^(-3) = 0.0001) Das ist schon mal falsch! Und dieser Ausdruck hat nichts mit e^x zu tun.
Elias H. schrieb: > 10e-3 = 10^(-3) = 0.0001) 2e1 sind 2*10^1=20 2e-3 sind 2*10^-3=0,002 10e-3 sind 10*10^-3=10*0,001=0,01
Elias H. schrieb: > Das bedeutet zunächst alle 0,000 102 4 Takte pro Sekunde (Tps) wird der > Timercounter um 1 erhöht. Die Einheit ist nicht "Takte pro Sekunde", sondern schlicht Sekunden. > 10 ms entsprechen 0,010 Tps 10 ms sind 0,01 Sekunden. > Eine unit8_t kann also eine Zahl die maximal 512 (Dez.) annehmen. 255. > Das Timercounter Daten Register schafft allerdings nur 8Bit (256) Auch 255. Was lässt dich eigentlich vermuten, dass ein uint8_t nicht auch 8 Bit und damit den selben Wertebereich hätte? > Ich habe 10e-3 nicht wie oben gerechnet mit der Eulereschen Zahl > exponiert sondern den Ausdruck exponenziell gerechnet (10e-3 = 10^(-3) = > 0.0001). > Für die Euleresche Zahl muss in C die math.lib includiert werden und > eine funktionsaufruf ist notwendig. Das hat mit Euler genauso wenig zu tun wie mit dem exklusiven Oder. In C wäre 10^(-3) nämlich eine exklusiv-Oder-Verknüpfung aus 10 und -3. Was du meinst, wäre auch ein Funktionaufruf: pow(10, -3). > Kann mir wer sagen was für ein Wert wirklich in dem Klammerausdruck > herrauskommt? und wie 10e-3 zu verstehen ist? Siehe https://de.wikipedia.org/wiki/Gleitkommazahl#Exponentialschreibweise > Bei den beiden Cast´s bin ich nicht ganz sicher ob ich die Schritte > arithmeitsch richtig erfasst habe. Der rechte Klammerausdruck ist > negativ, daher der Cast mit Vorzeichenhafteten int 16Bit. Der nächste > Cast auf 8 Bit ohne vorzeichenbehftete int 8Bit müsste daher das 1er und > 2er Komplement gebildet haben und vom MSB weg 8 Stellen weggeschnitten > haben. Ist das so richtig? Ja. A.S. schrieb: > 10e-3 sind 10*10^-3=10*0,001=0,01 Eigentlich ist das allerdings eine unübliche Schreibweise. Normalerweise schaut man, dass die Mantisse immer im Bereich 1 ≤ m < 10 liegt. Man schreibt also eher 1e-2.
Stefan ⛄ F. schrieb: > Das habe ich anders im Kopf. Float ist dafür bekannt (besonders bei sehr > großen und sehr kleinen Zahlen) auffällig ungenau zu sein. Uh, bist genauso alt wie ich, wie? Der Fehler hatte aber nicht float sondern war ein Designfehler weshalb eine FPU in grauer Vorzeit mal falsch rechnete (ich meine, das war im Pentium I der Fall). Interessierter schrieb: > Bewirkt das +0.5 nicht, dass hier für den ganzen Ausdruck Double genutzt > wird? Andernfalls wäre es ja sinnlos, weil 0.5 in Integer gecastet 0 > ergibt, meine ich. Das macht schon das *10^-3 ;). Die +0.5 sorgen für ein kaufmännisches Runden da so ein digitales Rechenwerk idR nur Runden durch Abschneiden kann ;) Interessierter schrieb: > Ach ja, warum eigentlich Double und nicht Float? Der Compiler macht Double draus, das ist so weil nicht zu Float gezwungen wird. Ist aber eigentlich auch wieder quatsch da das für einen AVR ist und AVR kann nur Float, die kennen gar kein Double ;) Elias H. schrieb: > Eine unit8_t kann also eine Zahl die maximal 512 (Dez.) annehmen In welchem Universium denn das? Ein uint8_t kann maximal 255 annehmen und nicht 512 ;) Elias H. schrieb: > Das > Timercounter Daten Register schafft allerdings nur 8Bit (256) Da verwechselt du etwas: Ein 8 bit Register kann 256 verschiedene Zustände annehmen aber nur maximal die Zahl 255 darstellen. Auch 0 ist eine Zahl ;) Elias H. schrieb: > TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); > aus mehren Gründen nicht navollziehen kann. Bei mir kommt in diesem > Klammerausdruck (F_CPU / 1024 * 10e-3 + 0.5) = 1,47 heraus. Den Rechenweg bei 1 MHz als F_CPU würde ich gern mal sehen ;)
M. K. schrieb: >> Das habe ich anders im Kopf. Float ist dafür bekannt (besonders bei sehr >> großen und sehr kleinen Zahlen) auffällig ungenau zu sein. > Uh, bist genauso alt wie ich, wie? Der Fehler hatte aber nicht float > sondern war ein Designfehler weshalb eine FPU in grauer Vorzeit mal > falsch rechnete (ich meine, das war im Pentium I der Fall). Den Intel Bug meinte ich nicht. Ich meine, dass Float Zahlen nur wenig signifikante Stellen haben, das vergesse ich selbst oft. Das war schon heftig damals, Massen von Intel Prozessoren in jedem dritten Computer rechneten falsch! Eine bis dahin unvorstellbare Situation. Heute haben wir Spectre. Wobei das meiner Meinung nach kein Bug ist, sondern eine Nebenwirkung von unpassenden Kombinationen aus Optimierungen und Anwendungen. Wenn ich in einem Bürogebäude die Zwischentüren vereinfache, damit man sich schneller bewegen kann, und dann dort sowohl Telekom als auch Vodafone einziehen lasse, dann darf ich mich nicht wundern, dass da ab und zu mal jemand zum Lauschen in den benachbarten Flur schleicht.
M. K. schrieb: > Ist aber eigentlich auch wieder quatsch da das für einen AVR ist und AVR > kann nur Float, die kennen gar kein Double ;) Das berechnet der Compiler und nicht der AVR, das scheint immer noch nicht klar zu sein.
Johannes S. schrieb: > Das berechnet der Compiler und nicht der AVR, das scheint immer noch > nicht klar zu sein. Da hast du recht und ich hab mich schlecht ausgedrückt ;)
Johannes S. schrieb: > M. K. schrieb: >> Ist aber eigentlich auch wieder quatsch da das für einen AVR ist und AVR >> kann nur Float, die kennen gar kein Double ;) > > Das berechnet der Compiler und nicht der AVR, das scheint immer noch > nicht klar zu sein. Was nichts daran ändert. Der Compiler darf das zwar zur Compilezeit selber ausrechenen, aber nur so, daß das gleiche Ergebnis wie zur Laufzeit herauskommt. Also muß auch der mit float rechnen. M. K. schrieb: >> TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5); >> aus mehren Gründen nicht navollziehen kann. Bei mir kommt in diesem >> Klammerausdruck (F_CPU / 1024 * 10e-3 + 0.5) = 1,47 heraus. > > Den Rechenweg bei 1 MHz als F_CPU würde ich gern mal sehen ;) (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5) Operator-Prefernz: / und * sind gleichwertig, und sind höher als + Klammern zuerst. Also: Klammerausruck: 1.000.000UL / 1024 = 976 (unsigned Intergerrechnung) 976 * 10e-3 = 9,76 (float-Berechnung, Falle: da steht nicht 1e-3, sondern 10e-3, für 10ms) 0,976+0,5 = 10,26 (float-Berechnung) -(10,26) = -10,26 (float-Berechnung) Dann casten: (int16_t)(-10,26) = -10 uint8_t(-10) = 246 Der Timer-OVF kommt beim Überlauf von 255 nach 0. 246 bis 256 (=255+1) sind 10 Schritte, also 10ms. Oliver
:
Bearbeitet durch User
M. K. schrieb: > Interessierter schrieb: >> Bewirkt das +0.5 nicht, dass hier für den ganzen Ausdruck Double genutzt >> wird? Andernfalls wäre es ja sinnlos, weil 0.5 in Integer gecastet 0 >> ergibt, meine ich. > > Das macht schon das *10^-3 ;). Die +0.5 sorgen für ein kaufmännisches > Runden da so ein digitales Rechenwerk idR nur Runden durch Abschneiden > kann ;) Die Rechenwerke können es teils schon, aber C kann es nicht, außer über die Funktion round(), wodurch es aber dann keine Compilezeit-Konstante mehr ist. Stefan ⛄ F. schrieb: > Den Intel Bug meinte ich nicht. Ich meine, dass Float Zahlen nur wenig > signifikante Stellen haben, das vergesse ich selbst oft. Das hat aber nichts mit der Größe der Zahl zu tun. Die Anzahl an signifikanten Stellen ist immer gleich, so lange es keine denormale Zahl ist. Oliver S. schrieb: > Johannes S. schrieb: >> M. K. schrieb: >>> Ist aber eigentlich auch wieder quatsch da das für einen AVR ist und >>> AVR kann nur Float, die kennen gar kein Double ;) >> >> Das berechnet der Compiler und nicht der AVR, das scheint immer noch >> nicht klar zu sein. Und es stimmt nicht ganz. Double kennt auch der avr-gcc. Aber es ist dort genauso klein wie float. > Was nichts daran ändert. Der Compiler darf das zwar zur Compilezeit > selber ausrechenen, aber nur so, daß das gleiche Ergebnis wie zur > Laufzeit herauskommt. Also muß auch der mit float rechnen. Dass double so klein ist, ist allerdings eh schon ein Verstoß gegen ISO C. > Operator-Prefernz: / und * sind gleichwertig, Und links-assoziativ. > Also: > Klammerausruck: > 1.000.000UL / 1024 = 976 (unsigned Intergerrechnung) > 976 * 10e-3 = 9,76 (float-Berechnung, Falle: da steht nicht 1e-3, > sondern 10e-3, für 10ms) double, nicht float.
:
Bearbeitet durch User
Beitrag #6158132 wurde vom Autor gelöscht.
Oliver S. schrieb: > Rolf M. schrieb: >> double, nicht float. > > Wenn schon Korintenkacken, dann "32-bit double". Hab ich ja geschrieben: Rolf M. schrieb: > Double kennt auch der avr-gcc. Aber es ist dort genauso klein wie float.
Rolf M. schrieb im Beitrag #6158129 wegen Fließkommazahlen: > Das hat aber nichts mit der Größe der Zahl zu tun. Die Anzahl an > signifikanten Stellen ist immer gleich, so lange es keine denormale Zahl > ist. Ja sicher.
Oliver S. schrieb: > Rolf M. schrieb: >> double, nicht float. > > Wenn schon Korintenkacken, dann "32-bit double". In C99 (ISO-IEC 9899 6.2.5 §10) steht:
1 | There are three real floating types, designated as float, double, and long double.42) The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. |
Die ist so zu lesen, dass alle drei Type identisch sein dürfen. Und ansonsten sind nur Untergrenzen für die Genauigkeit/Bereich festgelegt, die man mit weniger als IEEE-754-float erreichen kann.
Rolf M. schrieb: > Eigentlich ist das allerdings eine unübliche Schreibweise. Bei Technikern ist es sehr gebräuchlich, daß der Exponent ein Vielfaches von 3 ist (... p, n, m, k, M, G ...). 50ms = 50e-3 s 22MΩ = 22e6 Ω
Die Schreibweise 10e-3 kommt daher, daß der Wert die gewünschte Zykluszeit (10ms) darstellt. Die ganze Berechnung ist zwar richtig, aber ein typischen Beispiel dafür, wie man lesbaren und verständlichen Code nicht schreiben sollte. Oliver
Wilhelm M. schrieb: > In C99 (ISO-IEC 9899 6.2.5 §10) steht: > There are three real floating types, designated as float, double, and > long double.42) The set of values of the type float is a subset of the > set of values of the type double; the set of values of the type double > is a subset of the set of values of the type long double. > > Die ist so zu lesen, dass alle drei Type identisch sein dürfen. Ja. > Und ansonsten sind nur Untergrenzen für die Genauigkeit/Bereich > festgelegt, die man mit weniger als IEEE-754-float erreichen kann. Nein. float muss mindestens 6 signifikante Dezimalstellen korrekt darstellen, double mindestens 10. Das schafft man aber nicht mit einem IEEE-754 single float. Das findet man in C99 unter 5.2.4.2.2 §8.
Rolf M. schrieb: > darstellen, double mindestens 10. Das schafft man aber nicht mit einem > IEEE-754 single float. Das findet man in C99 unter 5.2.4.2.2 §8. Damit wären alle C-Implementierungen, die float als IEEE-754 single float (4 Byte) implemetieren, nicht standardkonform. Oliver
Oliver S. schrieb: > Was nichts daran ändert. Der Compiler darf das zwar zur Compilezeit > selber ausrechenen, aber nur so, daß das gleiche Ergebnis wie zur > Laufzeit herauskommt. Also muß auch der mit float rechnen. Das bezweifle ich. Der avr-gcc meckert erst wenn ich eine 12 stellige Zahl überlaufen lasse.
1 | #define C1 100000000000.0
|
2 | |
3 | int8_t m = (unsigned long long)(C1 + 1.0) - 100000000000ULL; |
Mit einer 0 weniger geht es, das passt aber nicht mehr in ein float rein.
Johannes S. schrieb: > Ja, die Aussage war aber das der Compiler auch so wie der avr in float > rechnet. Die Aussage war, dass der Compiler in float rechnet, wenn es der AVR auch tut. Tut er bei beidem nicht. Also ist die Aussage gleichzeitig wahr und mißverständlich.
Wenn man an C1 und 1.0 ein f anhängt, dann ändert das nichts an der Compilermeldung.
Viel zu kompliziert gedacht. Mach' Folgendes: #define F_CPU 1000000ul // unsigned long ist schon mal gut Jetzt bau' das ganze mal anders auf (hier Schritt für Schritt) (F_CPU / 1024 * 10e-3 + 0.5) 1. Multipliziere den Klammerausdruck mit 2, damit aus 0.5 '1' wird und schiebe im Anschluß nach rechts; außerdem ist 1/1024 ident zu '>>10' ((F_CPU>>10)/1000u*2u + 1u)>>1 2. Dann den eff. Divisor 1/500 umbauen auf 1/500~~(131>>16) (((((F_CPU>>10)*131u)>>16) + 1u)>>1) Fertig. Damit sind sämtliche Float-Werte udgl. aus der Gleichung heraußen.
Johannes S. schrieb: > Das bezweifle ich. Der avr-gcc meckert erst wenn ich eine 12 stellige > Zahl überlaufen lasse. Aha. warning: overflow in conversion from 'long long unsigned int' to 'int8_t' {aka 'signed char'} changes value from '18446744073709549568' to '0' [-Woverflow] Was genau hat das mit der double/float-Problematik zu tun? Johannes S. schrieb: > Mit einer 0 weniger geht es, das passt aber nicht mehr in ein float > rein. Aha. Klingt sehr unwahrscheinlich. Oliver
Oliver S. schrieb: > Rolf M. schrieb: >> darstellen, double mindestens 10. Das schafft man aber nicht mit einem >> IEEE-754 single float. Das findet man in C99 unter 5.2.4.2.2 §8. > > Damit wären alle C-Implementierungen, die float als IEEE-754 single > float (4 Byte) implemetieren, nicht standardkonform. Warum?
Stefan ⛄ F. schrieb: > Das ist meiner Meinung nach für Menschen unlesbarer Code Vor ein paar Tagen hatte ich dafür noch -2 bekommen, und jetzt wird schon so lange über diese eine Zeile diskutiert.
Bei meinem Test wird nicht von ULL in int8 gecastet, die diff der Berechnung ist 1. Der Compiler rechnet mit anderen floats als der avr. Korrektur: Die diff wird 0 wegen Überlauf, also doch mit float gerechnet. Komisch ist nur die Warnung die erst bei den 12 Stellen kommt.
Jürgen W. schrieb: > Mach' Folgendes: Hallo, und somit weiß keiner, dass hier mit dem Timer0 und Vorteile 1024 bei 100Hz Intervallen gearbeitet wird. Ich schreibe dies dann so, bzw. zur besseren Lesbarkeit um die 0 kongruent 256 modulo 256 erweitert:
1 | #define F_CPU 1000000ul // Beispiel zum Rechnen
|
2 | #define T0_PRESCALER 1024 // T0 Teiler
|
3 | #define T0_FREQUENCY 100 // T0 Zielfrequenz [Hz]
|
4 | #define T0_PRELOAD (uint8_t)(int16_t)(0-(1.0 * F_CPU / T0_PRESCALER / T0_FREQUENCY +0.5)) // T0 im Timer0 Overflow Mode
|
Johannes S. schrieb: > Bei meinem Test wird nicht von ULL in int8 gecastet, die diff der > Berechnung ist 1. Doch, wird es. Zumindest in dem von dir gezeigten Code. Die Compilerwarnung ist die originale von avr-gcc 9.2.0. Und das vom Compiler zur Compilezeit errechnete Ergebnis ist 0. Oliver
Rolf M. schrieb: > Warum? ??? Wenn der C-Standard für float mindestens 6 Dezimalstellen fordert, die Implementierung aber IEEE-754 single float dafür implementiert, was nach deiner Aussage keine 6 Dezimalstellen schafft, passt das irgendwie nicht zusammen. Oliver
:
Bearbeitet durch User
Oliver S. schrieb: > Wenn der C-Standard für float mindestens 6 Dezimalstellen fordert, die > Implementierung aber IEEE-754 single float dafür implementiert, was nach > deiner Aussage keine 6 Dezimalstellen schafft, passt das irgendwie nicht > zusammen. Ich hab nicht behauptet, dass IEEE single keine 6 Dezimalstellen schafft, sondern dass es keine 10 Stellen schafft. Das heißt, es ist nicht für den C-Typ double ausreichend, und daher ist die avr-gcc-Implementation in der Hinsicht nicht ISO-C-konform.
:
Bearbeitet durch User
Jürgen W. schrieb: > 1. Multipliziere den Klammerausdruck mit 2, damit aus 0.5 '1' wird und ok > schiebe im Anschluß nach rechts; / 2 ist lesbarer > außerdem ist 1/1024 ident zu '>>10' > ((F_CPU>>10)/1000u*2u + 1u)>>1 > > 2. Dann den eff. Divisor 1/500 umbauen auf 1/500~~(131>>16) > (((((F_CPU>>10)*131u)>>16) + 1u)>>1) Viel zu kompliziert und unleserlich. Das wäre ok, wenn das zur Laufzeit in einer Schleife abläuft. Hier rechnet aber der Compiler das aus
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.