Folgendes Problem:
Ich möchte einen Wert von 0 bis 255 zu einem Wert von 0 bis 1000 mappen.
Dies übernimmt folgende Zeile.
1
BTime=1000/255*x
Wenn x 255 ist, ist BTime laut dem ATtiny "765", laut meinem Kopf und
Taschenrechner "1000".
Wie kommt der Chip auf diesen komischen Wert und wie kann ich dies
beheben?
Danke im voraus,
Nils
Also mein Taschenrechner sagt da auch 765. Der Attiny hat recht.
Du rechnest 1000/255 was 3 entspricht, 3*255 ist 765.
Du hast überall Integer, die können keine Kommawerte darstellen. Alles
rechts vom Komma wird abgeschnitten (nicht gerundet!)
Du willst das als Floatingpoint rechnen.
BTime scheint ein Integer zu sein, dann ist das Ergebnis
nachvollziehbar:
1000 / 255 = 3,9... --> Die Nachkommastelle wird abgeschnitten, weil sie
nicht in den Integer passt. Dann die Multiplikation:
255 * 3 = 765
BTime = (1000 * x) / 255;
sollte das Problem beheben, wenn 1000 * 255 in BTime reinpasst.
Edit: Mist zu langsam ;)
Johannes M. schrieb:> BTime scheint ein Integer zu sein, dann ist das Ergebnis> nachvollziehbar:
Der Datentyp vom BTime ist egal, der L-Value einer Zuweisung hat keinen
Einfluss auf die Berechnung.
Die Datentypen auf der rechten Seite sind wichtig
Der Compiler wählt einen Algorithmus für 16bit Integer aus, weil deine
Zahlen alle in einen 16bit Integer passen. Wenn du eine 32bit CPU
verwendest, könnte es auch ein 32bit Integer sein.
1000 / 255 = 3
3 * 255 = 765
Wenn du einen Algorithmus für Fließkommazahlen erzwingen willst, musst
du das so schreiben:
BTime = 1000.0 / 255 * x
oder
BTime = (double) 1000 / 255 * x
Sicher wirst du bald auch auf einen Interger-Überlauf stoßen. Zum
Beispiel hierbei:
x=14000;
result = 16000 * 15000 / x;
Auch hier ist das Ergebnis anders als erwartet, weil ein Integer
Algorithmus zum Einsatz kommt:
16000 * 15000 = irgendwas, das garantiert nicht in einen Integer passt
irgendwas / x = nur noch Müll
Nils K. schrieb:> BTime = 1000 / 255 * x
"1000 / 255" ist ein konstanter Wert und wird vom (intelligenten)
Compiler vorberechnet. Aber ebend nur als Integewert 3.
Wenn du intelligenter sein willst als der Compiler schreibst du
BTime = 3,9215686 * x
Dergute W. schrieb:> Und wenns schnell gehen soll und nicht so ganz genau sein muss:>> BTime = (251 * x + 32) / 64;
Und wie soll das schneller sein?
Da kann der Compiler nicht viel vorausberechnen.
Max M. schrieb:>> BTime = (251 * x + 32) / 64;> Und wie soll das schneller sein?
Die Multiplikation kann ohne Überlauf in 16 Bit erfolgen.
Die Division ist ein Bitshift, die Addition für die CPU trivial.
> Da kann der Compiler nicht viel vorausberechnen.
Bei "(1000 * x) / 255" muss die Multiplikation in 32 Bit ausgeführt
werden, sonst läuft (1000 * x) über. Ein ATtiny kann nicht
multiplizieren, also ist die Multiplikation teuer.
In der Variante "(1000.0/255.0) * x" kann zwar der Faktor
vorausberechnet werden, aber es bleibt eine Float-Multiplikation übrig.
Ein ATtiny kann kein Float, also ist diese Multiplikation auch teuer.
Die Variante oben dürfte ein gutes Stück schneller und im Flash kleiner
sein.
Max M. schrieb:> Und wie soll das schneller sein?> Da kann der Compiler nicht viel vorausberechnen.
Ernst gemeinte Frage??
Es geht nicht darum was der Compiler vereinfachen kann, sondern um die
Platform!
Es geht um einen ATTiny Mal abgesehen von den fehlenden C Kenntnissen.
Dem Tiny fehlt die Floating Point Unit wie den meisten kleinen
Controllern, daher kann er keine Zahlen mit Komma in Hardware berechnen.
Der Compiler zaubert die da eine schicke Software Emulation hin um deine
Multiplikation in meistens vielen Zyklen zu berechnen.
Daher ist es meist schneller ganz Zahl Berechnungen durchzuführen da
diese nur wenige Zyklen und wenig Ram beanspruchen, zudem braucht man
nicht die ganze emulations Software im Flash abzulegen.
Zu langsam...egal
Dergute W. schrieb:> Moin,>> Und wenns schnell gehen soll und nicht so ganz genau sein muss:>> BTime = (251 * x + 32) / 64;>> Gruss> WK
Danke für die Zahlreiche Hilfe bei diesem dämlichen Fehler. Ich habe gar
nicht an die Nachkommastellen gedacht.
Ich habe letztendlich die Zitierte variante verwendet.
Gruß,
Nils
Max M. schrieb:> "1000 / 255" ist ein konstanter Wert und wird vom (intelligenten)> Compiler vorberechnet. Aber ebend nur als Integewert 3.
Das ist richtig, aber auch wenn der Compiler es nicht vorberechnen
würde, käme das gleiche Ergebnis heraus.
Der Punkt ist, dass C je nach Datentyp andere Algorithmen auswählt. Wenn
ein Teilausdruck nur Integer Parameter hat, dann wird mit einem Integer
Algorithmus gerechnet. Der Rest einer Division wird dabei verworfen.
Das ist jetzt auch kein Special in C, das machen viele andere
Programmiersprachen ebenso.
Nils K. schrieb:> BTime = 1000 / 255 * x
Ich mach das so:
BTime = (1000l*x) / 255;
Man beachte hier das kleine "l" hinter den 1000, das dafür sorgt, dass
die gesamte Rechenoperation in long ausgeführt wird.
Wobei ich hier die 255 noch stark anzweifeln möchte. Das sieht mir nach
einem Fehler aus. In der binären Welt steht da üblicherweise ein 256.
Eine eigene Frage?
Dieser Thread ist über 7 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.