PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechnen mit double-Variablen



robodriver
24.02.2008, 13:31
Hallo Leute,

ich kämpfe hier momentan an einer Rechnung in Bascom und komm einfach nimmer weiter.

Also zunächst mal der Sub um den es geht:



Sub Refresh_koordinaten
Toggle Error_led
Statusbit.calc_koordinaten = 0

X = Links / 12.143
Y = Rechts / 12.143

Cls
Locate 1 , 1
Lcd str(x)

Locate 2 , 1
Lcd str(y)

Return
End Sub


Die Variablen sind wie folgt deklariert:
x as double
y as double
links as byte
rechts as byte

Anhand der LED sehe ich, das der Sub desinitif immer genau dann aufgerufen wird, wenn ich das möchte.

Allerdings wird mir dann auf dem Display auf beiden Zeilen immer nur eine 0 angezeigt.
Wenn ich mir variablen "links" und "rechts" anzeigen lasse, dann haben die immer einen Wert zwischen 0 und 20. (Eine von beiden hat immer !00%ig genau 20, denn genau dann wird das Sub aufgerufen, die andere Variable ist dann <=20)

Nun hab ich schon etwas rum brobiert und mit die Variablen x und y runden lassen, in eine Byte-Varaible schreiben lassen und dann das Byte anzeigen lassen. Als ergebnis gabs aber auch hier immer 0
Auch eine Formatierung durch int(x) und int(y) brachte keine Veränderung: nach wie vor 0 :(

Ich muss dazu sagen, das es das erste mal ist, das ich in Bascom mit double-Variablen arbeite.
Kann mir jemand sagen was ich falsch mache?

Gruß Robodriver

PicNick
24.02.2008, 15:13
Versuch mal
$swstack=
$framesize=
zu erhöhen.
https://www.roboternetz.de/wissen/index.php/Bascom_Inside

fumir
24.02.2008, 16:37
- das hilft jetzt zwar nicht weiter, aber auch wenn die sprache keinen unterschied zwischen groß und klein macht, sollte man nicht für ein und dieselbe sache verschiedene schreibweisen verwenden. das ist schlechter stil und für andere schwer zu lesen. so was sollte man sich erst gar nicht angewöhnen, und sei es auch nur, weil es zwangsläufig zu fehlern führt, wenn du später mal mit einer programmiersprache arbeitest, die zwischen groß und klein unterscheidet!

- warum double und nicht single ?

- du gehst davon aus, das der fehler in der sub liegt, dass muss aber nicht sein. besser auch den code drumrum posten. das erhöht die chancen, das ein fehler gefunden wird.

- nur zum test würd ich mal die (beiden) operanten der division vorher explizit in double wandeln lassen und dann erst die division durchführen.

-multiplizier mal x und y nach der division wieder mit 12.143, konvertier es in byte und lass es anzeigen. kommen jetzt wieder werte zwischen 0 und 20 ?

robodriver
24.02.2008, 18:02
Also danke erstmal für die Antworten

@PicNick:
hwstack ist schon bei 64
swstack bei 32

habs mal auf hwstack=128 und swstack=32 erhöht
Das Ergebnis bleibt bei null :(

@fumir:
1.: was meinst du mit groß/klein schreibung? Weil das x und y in den klammern klein ist und weiter oben groß geschrieben?
Da muss ich dich enttäuschen. Aber das geht bei BASCOM nicht anders.
Wenn ich variablen klein schreibe, dann ändert Bascom den ersten Buchstabe IMMER AUTOMATISCH auf große Schreibweise.
Wenn ich aber hingegen bei dem str() das x groß schreibe, dann wird es AUTOMATISCH auf ein kleines x umgeschrieben. Da kann man absolut nichts gegen machen. Sobald der Cursor die Zeile verlässt, wird es vom Compiler geändert.
2.: double habe ich gewählt, weil ich eine größtmögliche Genauigkeit erreichen muss. Denn kleinste Fehler addieren sich hier auf und bewirken dann größeres nach 1000 Rechnungen.
3.: Ich habe absichtlich nicht das komplette Programm gepostet, denn es umfasst 829 Programmzeilen (22kB Hex-File). Ich denke das wird sich hier keiner Durchlesen. Und ich wüsste jetzt auch nicht weswegen der restliche Programmcode hier stören sollte. Denn die Variablen x und y gibt es ausschließlich in diesem Sub. sie existieren an keiner anderen Stelle im Code. Die Variablen "links" und "rechts" existieren an zwei anderen stelle nochmal und das sind 2 Interrupts. Die schaun wie folgt aus:


Overflow_links:
Links = 20
Rechts = Enc_rechts - 236 ' - 243
Load Timer0 , 20
Load Timer1 , 20
Statusbit.calc_koordinaten = 1
Return

Overflow_rechts:
Rechts = 20
Links = Enc_links - 236 ' - 256-20
Load Timer0 , 20
Load Timer1 , 20
Statusbit.calc_koordinaten = 1
Return

Dieser Interrupt wird bei einem Timer Overflow aufgerufen. Der Timer ist als Counter konfiguriert. Es kommt also alle 20 Takte zu einem Interrupt. Momentan zum Testen wird der Interrupt nur einmal aufgerufen (Ich gebe einfach 23 Takte auf den einen Counter.

4.: Habe die Berechnung jetzt mal wie folgt umgeschrieben:


X = Links
Y = Rechts

X = X / 12.143
Y = Y / 12.143

Auch dabei kommt für x und y Null heraus

5.:
Wenn ich es so schreibe:


X = Links
Y = Rechts

X = X / 12.143
Y = Y / 12.143

X = X * 12.143
Y = Y * 12.143


Dann kommt für x und y auch Null heraus. Das verstehe ich nicht :(

Hab jetzt aber doch mal versucht x und y als Single zu deklarieren (In dem Code den ich im ersten Post geschickt hatte).
Und siehe da: Es funktioniert einwandfrei.
Aber warum nicht mit Double? Das verstehe ich nicht :(


PS: Ich schreib mal noch dazu das ich einen ATMega 32 verwende. Das hatt ich noch vergessen...

for_ro
24.02.2008, 18:42
Da muss ich dich enttäuschen. Aber das geht bei BASCOM nicht anders.
Wenn ich variablen klein schreibe, dann ändert Bascom den ersten Buchstabe IMMER AUTOMATISCH auf große Schreibweise.
Wenn ich aber hingegen bei dem str() das x groß schreibe, dann wird es AUTOMATISCH auf ein kleines x umgeschrieben. Da kann man absolut nichts gegen machen. Sobald der Cursor die Zeile verlässt, wird es vom Compiler geändert.


Das kannst du schon verhindern. Schau mal unter
Options -> Environment -> Editor -> Don't change case.

Ich kann dein Problem bei mir auch sehen. Ist also vollkommen unabhängig vom drumherum. Im Simulator sieht man gut was passiert.
Wenn ich die Variablen Links und Rechts zuerst in eine Single Variable schiebe und dann diese durch 12.143 teile und in X speichere, dann funktioniert es. Vielleicht als workaround.



- nur zum test würd ich mal die (beiden) operanten der division vorher explizit in double wandeln lassen und dann erst die division durchführen.

Wie soll das gehen?

Gruß

Rolf

fumir
25.02.2008, 07:51
@robodriver
zu 1: so was hätte ich nie für möglich gehalten, aber man lernt eben nie aus :-) zum glück kann man es wohl abschalten, wie for_ro schreibt.

zu2: wenn x und y wirklich nur in der sub stehen, dann sollte single aber reichen: wenn man ne zahl zwischen 0 und 20 durch ne 5 stellige dezimalzahl dividiert, dann kann das ergebnis auch nur ne genauigkeit von etwa 5 bis 6 stellen haben, oder? wie auch immer, es spricht ja auser speicherplatz und rechengeschwindigkeit erst mal nix gegen die verwendung von double.

zu3: naja, das ist eher ein genereller tip. es ist einfach kontraproduktiv jemanden der nen fehler suchen soll von anfang an in ne bestimmte richtung zu lenken. in dem fall ists ja prima, wenn die variablen sonst nirgens auftauchen. aber das haben schon viele leute geglaubt, bis sie später irgendwo nen tipfehler in ihrem programm gefunden haben :-)
auserdem sieht die sub ja eigentlich ganz ok aus, da liegts nahe nach irgendwelchen unerwünschten seiteneffekten zu suchen.

zu4: ja, so meinte ich das. aber ich hätte die konstante auch noch vorher in ne double variable gespeichert.

zu5: na dann weist du jetzt schon mal, das bereits die berechnung fehlschlägt und das problem nicht erst beim umwandeln in den string bzw. die übergabe an lcd stattfindet!
ich hätte zwar jetzt nicht vermutet, das es mit single besser geht als mit double, aber es wundert mich auch nicht. möglicherweise wandelt bascom die konstante in nen single und bekommt dann probleme weil die division zwischen verschiedenen typen stattfindet. bascom ist eben nicht vergleichbar mit nem compiler wie gcc. da gibt es immer die möglichkeit, das der compiler nen fehler hat (oder so schlecht dokumentiert ist, das es zu mißverständnissen kommt) ich hab z.b. in der bascom doku gelesen, das operanten einer arithm. operation immer gleichen typ haben müssen. an anderer stelle steht, das die operation immer im typ des ergebnisses ausgeführt wird. das widerspricht sich teilweise bzw. ist unklar formuliert. dazu kommt, dass double wohl eher selten verwendet wird, und deshalb compilerfehler in dem zusammenhang nicht so schnell gefunden werden.

@for_ro
na einfach beide operanten erst mal einzeln ner double variable zuweisen und dann die division mit den double variablen durchführen.

ich hab mal lange in nem c/c++ programm nach nem fehler gesucht, bis mir klar wurde, das eine konstante (in nem #define) eben nicht wie ich dachte in ne 64bit integer sondern nur in ne 32bit integer umgewandelt wurde. deshalb sollte man eben #define vermeiden (keine typprüfung) aber das ist jetzt ein anderes thema.

robodriver
25.02.2008, 08:09
Okay, das heißt also das hier scheinbar ein Compiler-Fehler vor liegt?

Habs mir aber nochmal durchgerechnet. Vielleicht komm ich mit Single auch hin. Die umrechnung /12.143 ist die Umrechnung von Incrementen in cm. Wenn dieses Ergebnis auf 6 Stellen nach dem Komma genau ist, dann habe ich bei 10Metern eine Fehlergenauigkeit von 0,001 cm (0,01mm).
Ich denke damit kann man leben.
Die Ganzen Daten sind dann zur Berechnung von Winkel und Position in einem Koorinatensystem. Dazu die hohe Genauigkeit ;)


@fumir:
Naja, ich habs ja auch mal versucht vorher die Variablem links und rechts in eine Double-Variable zu schreiben und dann die Division durch zu führen:



X = Links
Y = Rechts

X = X / 12.143
Y = Y / 12.143

x und y sind ja als Double deklariert.
Also wäre diese Rechnung im Ergebnis und von den Werten her Double.
Was aber vielleicht noch sein könnte, das er mit der 12.143 nicht so ganz klar kommt... vielleicht sollte man die vorher erst noch in eine extra Variable bzw. Constante schreiben.

mlgahoc
25.02.2008, 08:23
Hallo,

mein Eindruck ist, dass Double nur mit Double rechnen kann.
Habe aber nur eine Demo Version.
Das folgende Beispiel im Einzelschritt im Simulator ausführen
und dabei die Variablen anzeigen lassen.
Dazu sollte man sich die Hilfe zu Double ansehen.

Gruß Manfred




'BASCOM-AVR 1.11.8.7 DEMO Edition

$regfile = "m32def.dat"
$crystal = 1000000
$hwstack = 64
$swstack = 8
$framesize = 24

Dim X As Double
Dim Y As Double
Dim Z As Double

Dim Rechts As Double
Dim Links As Byte

Dim Help1 As Long
Dim Help2 As Double

Links = 20
Rechts = 20

X = Links / 12.143
Y = Rechts / 12.143

Help1 = Links 'Byte --> Long
Help2 = Help1 'Long --> Double
Z = Help2 / 12.143

End

for_ro
25.02.2008, 15:23
mein Eindruck ist, dass Double nur mit Double rechnen kann.

Wie schon oben geschrieben funktioniert double mit single auch. Da sind halt floating point unter sich.
Byte und Integer geht nur nach single, der Zwischenschritt muss wohl sein.

Gruß

Rolf

Testus
17.02.2010, 08:18
Hallo,
die Einträge sind schon etwas älter, allerdings haben immer noch einige die gleichen Problem. So wie ich diese Woche :-s

Letztendlich habe ich herausgefunden, dass Double nicht mit Byte rechnen kann! Auch nicht umwandeln.

Wenn man also ein Register (wie Counter1) oder eine Byte-Variable in die Berechnung einbeziehen will, muß man sie zuerst in Long überführen.

Dann läuft Double prima und schön genau.

Vielleicht hilft es jemandem, der auf der Suche ist;-)

Grüße
Testus


hier ein Schnipsel, Temp ist eine Long :

N_base_float = 73.0
Temp = Capture1
Temp_float = Temp
N_base_float = N_base_float + Temp_float
Temp = Tim1_16
Temp_float = Temp
Temp_float = 65536.0 * Temp_float