Übersetzung Java => PB

Fragen zu allen anderen Programmiersprachen.
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Re: Übersetzung Java => PB

Beitrag von Syntacks_Error »

Weija, das ist ja harter Stoff. Bevor ich das richtig verstehe, werde ich es wohl noch einig Male lesen müssen, viele Dank für die Mühe, sie wird nicht umsonst sein.

Es klappt ja auch meistens, aber leider halt nicht immer:

Code: Alles auswählen

Macro intEndian
 Zahl.l = ((Zahl&$FF)<<24)+((Zahl&$FF00)<<8)+((Zahl&$FF0000)>>8)+((Zahl>>24)&$FF)
EndMacro

Dim s$(15)
;.......................................................Nach Zurückumwandlung richtig oder falsch:
s$(0) = "3 56097.28 26252.84 19.95"      ; Richtig
s$(1) = "0 139163.86 187219.19 34.98"   ; Xpos u.Ypos falsch
s$(2) = "0 166829.92 98857.92 134.99"   ; Richtig
s$(3) = "1 139071.41 187202.56 289.99"  ; Richtig
s$(4) = "2 139059.59 187209.70 205.00"  ; Richtig
s$(5) = "0 139272.58 187026.08 289.97"  ; Richtig
s$(6) = "0 139225.03 187012.44 244.97"  ; Richtig
s$(7) = "0 139248.25 187019.81 244.97"  ; Richtig
s$(8) = "0 139218.41 187091.67 304.98"  ; Richtig
s$(9) = "3 139288.42 187037.50 224.98"  ; Richtig
s$(10) = "2 203909.53 96981.09 154.99"  ; Xpos u. Ypos falsch
s$(11) = "4 139266.13 187089.95 129.98" ; Richtig
s$(12) = "1 139300.94 187019.75 219.98" ; xpos und ypos falsch
s$(13) = "1 139201.09 187055.08 309.98" ; Richtig
s$(14) = "1 139203.16 187091.14 219.98" ; Richtig
s$(15) = "1 139274.00 187118.11 144.98" ; Nur Ypos falsch

; Strings lesen und Werte in Binärformat umwandeln 
For x = 0 To 15 
  zeile$ = s$(x)
  l2.l = Val(StringField(zeile$,1," "));Gebäudetyp
  d.d = ValD(StringField(zeile$,2," "));X-Position
  d1.d = ValD(StringField(zeile$,3," "));Y-Position
  f.f = ValF(StringField(zeile$,4," "));Orientierung
  f = -f
    
  i5 = d/200
  i6 = d1/200
  j6 = (d/200 - i5)*32000 
  k6 = (d1/200 - i6)*32000
  k7 = f*32000/360
               
  j8 = i6 << 16 | i5 ; X-Position/200 und Y-Position/200
  zahl.l = j8
  intEndian
  j8 = zahl
    
  i8 = k6 << 16 | j6 ; = x-Position%200*32000 und Y-position%200 *32000
  zahl = i8
  intEndian
  i8 = zahl
    
  l7 = k7 << 16 | l2; & $7fff) ; Ausrichtung und Gebäudetyp
  zahl = l7
  intEndian
  l7l = zahl

     
  ;---------------------------
 
 
  ;Zurückverwandeln in Stringformat
  zahl.l = j8
  intEndian
  i1a = zahl 
  i2a = i1a & $ffff; xpos1
  i3a = i1a >> 16 & $ffff ;ypos1  
     
  zahl.l = i8
  intEndian
  i5a = zahl 
  i8a = i5a & $ffff; xpos2
  i9a = i5a >> 16 & $ffff;ypos2
    
  zahl = l7
  intEndian
  i4a = zahl; type
  i6a = i4a & $ffff ; type
  i7a = i4a >> 16 ; orientation

  xpos.f = i2a*200 + i8a*200/32000
  ypos.f = i3a * 200 + i9a*200/32000 
  orientation.f = -(i7a*360/32000)

  Debug  "(" + RSet(Str(x),2,"0") + ")" + "  " + Str(i6a) + "  " + StrF(xpos,2) + "  " + StrF(ypos,2) + "  " + StrF(orientation,2)
     
Next
Bei der ganzen Sache geht es um Binärdateien eines Spiels, in denen diverse Angaben über Karten, darunter auch über den Typ, die x- und y-Position (in Metern, Zentimeter, 2 Dezimalstellen) und die Ausrichtung (In Grad, gleichfalls zwei Nachkommastellen) von Gebäuden enthalten sind. Die diversen Angaben sollen in verschiedene editierbare Textdateien ausgelesen, geändert oder ergänzt (oder auch neu erstellt) werden und dann natürlich in das Binärformat zurückgeschrieben werden. Mit allen anderen Daten kann ich das schon, nur die Gebäude haken ... Im PB-Beispiel (stark vereinfacht) gehe ich von einer Textdatei aus, simuliert durch die Strings, wandle das in das Binärformat um und dann wieder zurück in das Textformat. Dann müßten wieder die Strings herauskommen.Tun sie aber machmal nicht. Die Strings sind als nach der Zurückumwandlung mit "Richtig" oder ".. falsch" gekenzeichnet. Die Ausrichtung und der Typ stimmen immer. Außerdem ist sicher, daß die Richtung Binär => String stimmt. Der Fehler muß also im erstenl Teil, String => Binär, stecken.

Der Java-Code sieht, soweit von Belang, so aus:

; Binär in Stringforma

int i3 = datainputstream.readInt();
int i4 = i3 & 0xffff; x-Position/200
int i6 = i3 >> 16 & 0xffff;y-Position/200
int j7 = datainputstream.readInt(); Wiederholungsfaktor, habe ich weggelassen
float f7 = 0.0F;
int l8 = 0;
While(l8 < j7)
{
int j9 = datainputstream.readInt();
int l9 = datainputstream.readInt();
int i10 = j9 & 0xffff; Gebäudetyp
int j10 = (short)(j9 >> 16); Orientierung
int k10 = l9 & 0xffff; WMod" der x-Position
int l10 = l9 >> 16 & 0xffff; "Mod" der y-Position
NumberFormat numberformat = NumberFormat.getNumberInstance(Locale.US);
numberformat.setGroupingUsed(false);
numberformat.setMaximumFractionDigits(2);
numberformat.setMinimumFractionDigits(2);
double d = (double)i4 * 200D + (double)(k10 * 200) / 32000D; Xposition
double d1 = (double)i6 * 200D + (double)(l10 * 200) / 32000D; yPosition
float f20 = -(((float)j10 * 360F) / 32000F); Orientierung

}



;Stringformat in Binär
; Gebäudetyp ermitteln, bei mir unmittelbar im String
int l2 = arraylist.indexOf(s);
; String lesen und Position/Orientierung berechnen
s = s1.substring(j2);
StringTokenizer stringtokenizer = new StringTokenizer(s);
boolean flag = Integer.parseInt(stringtokenizer.nextToken()) == 1;
double d = Double.parseDouble(stringtokenizer.nextToken());
double d1 = Double.parseDouble(stringtokenizer.nextToken());
float f;

For(f = Float.parseFloat(stringtokenizer.nextToken()); f >= 360F; f -= 360F); Ausrichtung kleiner als 360 Grad
f = -1F * f;
int i5 = (int)(d / 200D); xPos/200
int i6 = (int)(d1 / 200D); yPos/200
int j6 = (int)((d / 200D - (double)i5) * 32000D); sozusagen mod xPosition/200 *32000
int k6 = (int)((d1 / 200D - (double)i6) * 32000D); sozusagen mod yPosition/200 *32000
int k7 = (int)((f * 32000F) / 360F);
int l7 = k7 << 16 | l2 & 0x7fff;
int i8 = k6 << 16 | j6 & 0xffff;
int j8 = i6 << 16 | i5 & 0xffff;
;Ende

Der Code stammt übrigens nicht aus dem Spiel selbst, sondern von einem Tool zum Spiel, das frei verfügbar ist. Seine Funktionalität ist aber stark eingeschränkt und es ist darüber hinaus schwer zu bedienen, deshalb will ich es mit ein paar Verbesserungen nachprogrammieren. Zum Code sollte ich vieleicht noch bemerken, daß das Spiel auf einem Raster von 200 Metern beruht (daher die 200, die da immer auftauchen) und daß beim Schreiben der Binärdatei im Original zunächst alle Gebäude gesammelt werden, die im selben Rasterfeld stehen (i4 und i6) und dann entspechend dieser Gebäudezahl (j7) nur noch so häufig die Gebäudeart und, sozusagen, die %200-Werte der x und y-Positionen und die Ausrichtung geschrieben werden. Darauf kommt es bei meinem Problem aber nicht an, ich habe es also weggelassen.

Warum also zum Henker, kommen manchmal, aber nur manchmal. falsche Ergebnissse heraus? Kann eigentlich nur ein Rundungsfehler sein, aber mehr als Quad geht nicht, und auf- und Abrunden habe ich schon probiert, das bringt nicht.
Benutzeravatar
TomS
Beiträge: 1508
Registriert: 23.12.2005 12:41
Wohnort: München

Re: Übersetzung Java => PB

Beitrag von TomS »

Es gibt eine gewisse Ungenauigkeit bei Floats auf Grund des binären Formats. Ob sich das in Java anders (oder nicht) auswirkt, weiß ich nicht.

Lösung: Alle Floats in Long/Integer umwandeln (long = float * (10*AnzahlDerNachKommaStellen)). Dann klappt's auch mit dem Nachbarn.
Wobei die Anzahl der Nachkommastellen konstant sein sollte. Dabei muss man beachten, dass die Zahl dann trotzdem ein ein Word passt (also kleiner als 32767 ist (Words in PB sind signed. Also Vorzeichenbehaftet. Daher nur 2^15 anstatt 2^16)).
Aber das ist mit den Werten aus deinem Beispiel kein Problem. Die passen alle locker rein.
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Re: Übersetzung Java => PB

Beitrag von Syntacks_Error »

Und wie funktioniert das praktisch? Ich muß ja die "richtigen" Werte in die Binärdatei schreiben, sonst stehen die Gebäude irgendwo in der Gegend herum, wo sie nicht hingehören. Wenn ich irgendetwas multiplziere, muß ich es ja wieder irgendwo teilen. - Ich glaube inzwischen nicht mehr, daß es sich um einen Rundungsfehler handelt, denn wenn ich statt Doubles Floats nehme, kommt exakt das selbe Ergebnis heraus, obwohl ich nur noch die halben Stellen habe. Festgestellt habe ich noch, daß die Ergebnisse immer dann falsch sind, wenn die Wert in i8 nach dem Zurückverwandeln 3-stellig sind. Das sieht man, wenn man j8 (also die glatten int(Positionen/200) auf 0 setzt, so daß nur noch die "Mod"-Werte der x/y-Positionen angezeigt werden. Hilft das vielleicht weiter?

Wenn es aber kein Rundungsfehler ist, muß es irgendetwas mit der Auswertung zu tun haben.

int j6 = (int)((d / 200D - (double)i5) * 32000D);
int k6 = (int)((d1 / 200D - (double)i6) * 32000D);

macht anscheinend irgendetwas anders als

j6 = (d/200 - i5) * 32000
k6 = (d1/200 - i6) * 32000

aber was?
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Übersetzung Java => PB

Beitrag von Danilo »

TomS hat geschrieben:Lange Rede kurzer Sinn:
Auch wenn ich oben gezeigt habe, wie man eine Maskierung von $XYZ anwendet: Weglassen geht genauso.

Code: Alles auswählen

i5.i = 312
i6.i = -3109
j8.i = i6 << 16 | i5
Debug j8.i
Debug j8 >> 16
Debug j8  & $FFFF
In diesem Beispiel geht das natürlich, aber normalerweise sollte man in der 3. Zeile
hinter dem 'i5' immer noch das $FFFF mit Klammern benutzen. Damit stellt man sicher
das wirklich nur ein *Word* OR-verknüpft wird, denn hier werden ja Integer zur
Speicherung benutzt.
Belegt der Wert im Integer mehr als die unteren 16 Bits, würde man ohne das $FFFF
ins HighWord reinschreiben, was natürlich fatal wäre.

Von daher lieber immer das $FFFF dazu. Vermeidet unnötige Fehler und
erhöht auch noch die Lesbarkeit und Wartung des Codes, da man dann
wirklich sofort sieht das nur ein Word OR-verknüpft wird.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
TomS
Beiträge: 1508
Registriert: 23.12.2005 12:41
Wohnort: München

Re: Übersetzung Java => PB

Beitrag von TomS »

Eine vorherige Überprüfung des Wertes wäre imho sinnvoller.
Dafür reicht es schon i5 und i6 als .w zu deklarieren anstatt .i

Wenn ich ein einen Wert, der größer als ein Word ist verwenden will, wird der einfach "abgeschnitten" und stellt damit eine Fehlerquelle da.
Siehe mein Beispiel mit $C als Maskierung.

=> Wenn ich ausschließen kann, dass der Wert größer als ein Word ist, kann ich diese Maskierung weglassen.
Ob er den Code dann noch lesen kann, muss jeder selber wissen.
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Übersetzung Java => PB

Beitrag von Danilo »

Ist ja OK für Dich, aber in anderen Sprachen ist es halt so üblich.
Was Syntacks_Error machen will ist ja MAKELONG() und danach
wieder zurück mit LOWORD() und HIWORD().

Das wird unter anderem auch bei der WinAPI-Programmierung
öfters mal gebraucht und sieht in WinDef.h als *Macro* so aus:

Code: Alles auswählen

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
#define MAKELONG(a, b)      ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
#define LOWORD(l)           ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l)           ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define LOBYTE(w)           ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w)           ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
Bei der Suche nach "makelong" in diesem Forum findet man die verschiedensten
Versionen davon, zum Beispiel:

Code: Alles auswählen

Macro MAKELONG(low,high)
  (low | (high<<16))
EndMacro

Procedure.l MakeLong(low,high)
  ProcedureReturn low + (high << 16)
EndProcedure
Beide Versionen funktionieren, sind aber sehr fehleranfällig und können
dadurch zu schwer auffindbaren Fehlern führen.
Als Procedure mit .w ist es wohl sicher, findet man auch in der Forensuche:

Code: Alles auswählen

Procedure MakeLong(low.w, high.w)
  ProcedureReturn low + (high<<16)
EndProcedure
Da Macros aber keine Typüberprüfung haben, sollte man das lieber mit
reinmachen:

Code: Alles auswählen

Macro MAKELONG(a, b)
    ( ((a) & $FFFF) | ((b) & $FFFF) << 16 )
EndMacro

Macro LOWORD(l)
    ( (l) & $FFFF )
EndMacro
    
Macro HIWORD(l)
    ( ( (l) >> 16) & $FFFF )
EndMacro


a.l = MAKELONG(200,300)
Debug a
Debug LOWORD(a)
Debug HIWORD(a)
Soll nur ein gut gemeinter Hinweis sein. ;)
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Syntacks_Error
Beiträge: 107
Registriert: 08.03.2009 16:08

Re: Übersetzung Java => PB

Beitrag von Syntacks_Error »

Hurra, ich habs geschafft. Ein beherztes

i5 = Round(d/200, #PB_Round_Down)
i6 = Round(d1/200,#PB_Round_Down)

brachte die Lösung. Offenbar rundet Java Ausdrücke wie x.l = y.l/z.f (oder z.d) anders als PB (oder umgekehrt). Und für so etwas brauche ich 2 bis 3 Tage und einen Lehrgang in Sachen Bitschieberei. Ohne den wäre es aber nicht gegangen, also allen Beteiligten nochmals vielen Dank.
Antworten