PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechenproblem mit Single



Tido
20.07.2009, 13:33
Hi,

ich stolpere gerade über ein Bascom-Rechen-Problem:

Es soll mit folgendem Programm der ADC-Wert in die akkuspannung zurückgerechnet werden, gerundet auf eine Nachkommastelle.

Warum ergibt die Berechnung 162,0 / 10 = 16,1999999 ?
Wie kann man das Problem lösen?

Dummy ist ein Word, Akku vom Typ Single:


Do
Dummy = Getadc(0)
Akku = Dummy
Print "Anfangswert : " ; Akku
Akku = Akku * 0.195
Print Dummy ; " * 0,195 = " ; Akku
Akku = Round(akku)
Print "gerundet: " ; Akku
Akku = Akku / 10
Print "geteilt durch 10: " ; Akku
Loop



Ausgabe dazu:


Anfangswert : 832.0
832 * 0,195 = 162.239990233
gerundet: 162.0
geteilt durch 10: 16.199998853

MeckPommER
20.07.2009, 14:05
Hallo Tido,

selbst Taschenrechner liegen manchmal daneben, und so weit ist 16.2 ja nicht von 16.199999999 entfernt. Genau genug ists auf jeden Fall.
Wenn du rundest, dann mache es nicht "mittendrin" und rechne dann mit diesem Ergebnis, sondern runde erst am Ende.
Einfach mal die Funktionen "Format" und "Fusing" anschauen, vielleicht eignet sich eine davon besser für dein Vorhaben. (Habe grade kein Bascom etc. griffbereit, deshalb diese waage antwort, sorry)

Gruß MeckPommER

Thomas$
20.07.2009, 14:13
probier mal double ansonstenn 1/3= 0,333 periode 0,333 periode *3 <3
mach mal nach dem runden akku=int(akku) ich weiß nicht was round alles auser runden mit akku anstellt

Tido
20.07.2009, 18:13
Hi,

wenn ich erst am Schluß runde (also 16,2xxxx) ergibt sich ein Wert von 16,0. Das ist ja noch schlimmer als 16,199999. Da ich aber nur eine Nachkommastelle anzeigen lassen kann (kein Platz), ergibt sich 16,1 und dass wäre "nicht genau genug".
Ich habe auch schon probiert, die 162,0 der Single-Variable erst in eine Word-Variable zu schieben, dann zurück, aber das Ergebnis bleibt "falsch" bei 16,1999999.

Noch jemand eine Idee dazu?

Thomas$
20.07.2009, 18:22
hast du das schin mit anderen werten probiert? wenn das über all so ist dann +0,1

Besserwessi
20.07.2009, 18:31
Wenn bei der Ausgabe mit einer Nachkommastelle einfach nur abgeschnitten wird, also aus 6.199 wird 6.1 , dann sollte man einfach 0.05 dazuaddieren um eine Normale Rundung zu bekommen.

for_ro
20.07.2009, 18:39
Was hälst du denn hiervon:

Do
Dummy = Getadc(0)
Akku = Dummy
Akku = Akku * 0.0195
Print Fusing(akku , "##.#")
Loop

Tido
20.07.2009, 18:41
Ich probiere morgen mal ein wenig rum, habe i.M. kein Bascom hier.

16,19999 ergibt gerundet zwar auch 16,2, aber dann muss ja zusätzlich am Ende etwas gerundet werden was eigentlich genau aufgeht.
Irgendwie will mir das nicht in den Kopf...

EDIT: Wenn ich mir die Hilfe zu "Fusing" ansehe, dann wird mir schlecht:

'now assign a value to the single

S = 123.45678

'when using str() you can convert a numeric value into a string

Z = Str(s)

Print Z 'prints 123.456779477

Selbst das funktioniert "nicht richtig"...

Thomas$
20.07.2009, 18:47
hast du das schin mit anderen werten probiert? wenn das über all so ist dann +0,1

for_ro
20.07.2009, 19:21
EDIT: Wenn ich mir die Hilfe zu "Fusing" ansehe, dann wird mir schlecht:

'now assign a value to the single

S = 123.45678

'when using str() you can convert a numeric value into a string

Z = Str(s)

Print Z 'prints 123.456779477

Selbst das funktioniert "nicht richtig"...
Das kannst du aber erwarten, wenn du Dezimalzahlen in ein anderes Format überträgst. Intern arbeiten die meisten Computer nun mal binär. Da gibt es für die Zahl 123.45678 keine Darstellung mit der vorgegebenen Anzahl Binärstellen. Das ist kein Bascom Problem.
Du rechnest hier mit einer maximalen Anzahl von 1024 verschiedenen Werten und beklagst dich über einen Fehler auf der 1/10.000.000stel Stelle.

Tido
20.07.2009, 19:30
und beklagst dich über einen Fehler auf der 1/10.000.000stel Stelle.

Eigentlich beklage ich mich über das sehr enttäuschende Ergebnis von 162.0 /10 = 16.199999...

Das bekomme ich ohne Controller/Computer genauer hin!
Morgen teste ich mal &B10100010 / &B1010 = ???

Besserwessi
20.07.2009, 20:36
Das Problem ist wie oben schon mal erwähnt, dass sich einige zahlen, die als Dezimalzahl noch ganz einfach aussehen sich nicht exakt im binären Fließkommaformat darstellen lassen. Wenn da beim Umwandeln zurück ins Dezimalformat nich genügend gerundet wird, sieht man halt den kleinen Unterschied. Eine typische Zahl die nicht geht ist 0,1. Dafür geht so etwas wie 7/8192 ohne Probleme.


Als ein altes recht krasses Beispiel, gab es bein C64 den effekt, das man wenn man 20 mal 0,1 aufaddiert hat nicht genau 2 rausbekommen hat.

for_ro
20.07.2009, 20:46
und beklagst dich über einen Fehler auf der 1/10.000.000stel Stelle.

Eigentlich beklage ich mich über das sehr enttäuschende Ergebnis von 162.0 /10 = 16.199999...

Das bekomme ich ohne Controller/Computer genauer hin!
Morgen teste ich mal &B10100010 / &B1010 = ???
Auch für die Dezimalzahl 16,2 gibt es Binärsystem keine Darstellung. Du kommst zwar beliebig genau heran, aber treffen kannst du sie nicht. Schon gar nicht mit 16 oder 32 Stellen. Wenn du 32 Stellen hinter dem Komma hättest (Single hat insgesamt 32 Stellen), dann wäre dein Ergebnis 16,199999999953434. Alle Systeme werden sich von unten "herantasten". Denn wenn du einmal drüber bist, kannst du durch weiteres hinzufügen nicht mehr drunter kommen.

Aber wie ich dir oben schon geraten habe, nimm einfach die Fusing Funktion und gut ist. Man muss lernen, die Beschränkungen eines Systems zu verstehen und diese zu nutzen.

Tido
20.07.2009, 21:42
Ok,

ich gebe mich mit diesen Einschränkungen zufrieden.
Hauptsache ich habe hinterher in der Variable Akku irgendwie den Wert 16,2.
Leider funktioniert das mit round nicht, denn dann gibt's keine Nachkommastellen (deshalb ja auch die Idee, erst zu runden und dann durch 10 zu teilen).

Ich denke, ich werde mir die Division durch 10 sparen und später bei der LCD-Ausgabe einfach das Komma an der richtigen Stelle einfügen.
Den Umweg über einen string sehe ich gar nicht ein.

for_ro
20.07.2009, 22:23
Was hälst du denn hiervon:

Do
Dummy = Getadc(0)
Akku = Dummy
Akku = Akku * 0.0195
Print Fusing(akku , "##.#")
Loop
Hast du das mal probiert? Es macht exakt das, wonach du seit Stunden fragst.
Warum muss in Akku der Wert 16,2 sein? Wo es sowieso nicht möglich ist, wie ich dir gezeigt habe. Lass doch den scheinbar ungenauen Wert drin. Nur wenn du ihn ausgibst, machst du den Wert für Menschen leichter lesbar.

Tido
21.07.2009, 10:26
Der Wert von Akku muss mit einem Byte per I²C übertragen werden, also bleibt nur der Wertebereich von 0 - 255. Deshalb benötige ich ganzzahlige Werte für Akku, also z.B. 162 (nicht 16,2 wie ich geschrieben hatte).
Für die Ausgabe kann ich dann ja Fusing nehme.