Komische Werte werden berechnet.

#5638004
Lesenswert?

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
Gast #5638008
Lesenswert?

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.
1
BTime = 1000.0/255.0 * x

sollte das gewünschte Ergebnis bringen
#5638011
Lesenswert?

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 ;)
Gast #5638017
Lesenswert?

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
#5638104
Lesenswert?

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.
Gast #5638105
Lesenswert?

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
Gast #5638204
Lesenswert?

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.
Moderator (Firma: Titel) Persönliche Seite #5638238
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren