Forum: Mikrocontroller und Digitale Elektronik Komische Werte werden berechnet.


von Nils K. (flying_nils)


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

von napsi (Gast)


Lesenswert?

Naja wenn Du nur mit ganzen Zahlen rechnen kannst dann ist
1000 / 255 = 3
und 3 * 255 ist halt 765.

von Bauteiltöter (Gast)


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

von Johannes M. (johannesm)


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 ;)

: Bearbeitet durch User
von Bauteiltöter (Gast)


Lesenswert?

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

von Stefan F. (Gast)


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

von Alex (Gast)


Lesenswert?

Ganzzahligkeit. 1000/255 = 3.92.. abgerundet (integer division) 3.
3 * 255 = 765

von Max M. (jens2001)


Lesenswert?

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

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Und wenns schnell gehen soll und nicht so ganz genau sein muss:

BTime = (251 * x + 32) / 64;

Gruss
WK

von Max M. (jens2001)


Lesenswert?

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.

von S. R. (svenska)


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.

von Blabla (Gast)


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

von Nils K. (flying_nils)


Lesenswert?

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

von Stefan F. (Gast)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
von F. F. (foldi)


Lesenswert?

Wenn es nicht 1000 sein müssen, mach 1020 draus und alles ist friedlich.
Wenn du unbedingt die 1000 brauchst, beende die Messung bei 1000.

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
Noch kein Account? Hier anmelden.