# Zustandsbits in Zustands-Integer



## Mangokind (5 März 2009)

ne eigentlich ganz simple aufgabe, die mich gerade überfordert:

der Zustand eines Maschinenablaufs/einer Arbeitsstation einer Maschine o.ä. kann wahlweise als Integer oder in einer Folge von Bits gespeichert werden.
dabei ist jedem Bit fest eine Zustandsnummer zugeordnet.

also als integer


```
Zst      INT     5
```
 
oder als Bits


```
Zst1     Bool     FALSE
Zst2     Bool     FALSE
Zst3     Bool     FALSE
Zst4     Bool     FALSE
Zst5     Bool     TRUE
```
 
ich will nun ein programm schreiben, was variante 2 in variante 1 überführt.
es soll auch möglich sein, dass eine gewisse anzahl bits/zustände gleichzeitig aktiv sind
wenn also 5 zustandsbits gleichzeitig aktiv sind, will ich deren zugeordneten zustand in 5 Ints abspeichern


mir fällt zu dieser simplen Aufgabe gerade nix besseres ein, als


```
//IN nach TEMP
      L     #QuellDB                    //IN-Var... DB-Nummer Quelle
      T     #QDB                        //TEMP-Var... DB-Nummer Quelle
      L     #ZielDB                     //IN-Var... DB-Nummer Ziel
      T     #ZDB                        //TEMP-Var... DB-Nummer Ziel

// --- initialisieren ---
//Pointer erstellen
      L     #QuellAnfang                //Byteposition erstes Bit
      SLD   3
      L     #HoechsterZustand           //Anzahl Bits
      +D                                //Pointer auf die Zustandsbits zeigt an
      T     #Bitpointer                 //dieser Stelle noch auf das letzte Bit
//Zaehler/Merker initialisieren
      L     0
      T     #GefundeneZst
 
// --- Pruefschleife ---
//geht Bit fuer Bit durch. sollte eins der Bits true sein, steht im Schleifenzaehler die Nummer des Zustands
      L     #HoechsterZustand           //Anzahl Bits
nw1b: T     #Schleifenzaehler
      AUF   DB [#QDB]
      LAR1  #Bitpointer
      SET   
      U      [AR1,P#0.0]
      SPBN  nw1c
//wenn das Bit, auf das Bitpointer gerade zeigt, gesetzt ist
//Zielposition im Ziel-DB laden
      AUF   DB [#ZDB]
      L     #GefundeneZst               //Anzahl gefundener Zustaende
      SLD                               //*2 um 2 Bytes bzw 1 Int weiterzuspringen
      L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB
      +D                                //im akku 1 steht die Byte-Nummer des Ints, in das der Zustand gespeichert wird
      SLD   3
      LAR1  
//gefundenen Zustand abspeichern
      L     #Schleifenzaehler
      T     W [AR1,P#0.0]
//Zaehler erhoehen
      L     #GefundeneZst
      +     1
      T     #GefundeneZst
//Abbruchbedingung: speicherplatz fuer Zustandsnummern ist voll
      L     #GefundeneZst
      L     #AnzahlInteger              //IN-Var... Vorgabe der maximal gleichzeitig gesetzten Zst bzw die Anzahl Speicherplaetze
      ==I   
      BEB   
nw1c: L     #Bitpointer                 //Pointer auf die Zustandsbits um 1 verringern
      +     -1
      T     #Bitpointer
      L     #Schleifenzaehler
      LOOP  nw1b
```
 
umständlich und verbrät vermutlich zuviel Rechenzeit durch die Loopschleife mit unzähligen Durchläufen

hat vielleicht jemand ne elegantere idee?


----------



## Mangokind (5 März 2009)

zur Verbesserung der Laufzeit auf Kosten von Speicherplatz und Lesbarkeit dasselbe nochmal mit 2 verschachtelten Schleifen.

die äußere Schleife prüft den Quellbereich WORD-weise auf gesetzte Bits und wenn mindestens eins gesetzt ist, Schaut die innere Schleife, welche Bits genau gesetzt sind...


```
//IN nach TEMP
      L     #QuellDB                    //IN-Var... DB-Nummer Quelle
      T     #QDB                        //TEMP-Var... DB-Nummer Quelle
      L     #ZielDB                     //IN-Var... DB-Nummer Ziel
      T     #ZDB                        //TEMP-Var... DB-Nummer Ziel
 
// --- initialisieren ---
//Zaehler/Merker initialisieren
      L     0
      T     #GefundeneZst
 
//Offset der aeusseren Schleife 0 setzen
      L     0
      T     #OffsetAussen
 
//Zst-Ints im Ziel-DB 0 setzen
      AUF   DB [#ZDB]
      L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB
      SLD   3
      LAR1  
      L     #AnzahlInteger
nw1a: T     #SchleifeInnen
      L     0
      T     W [AR1,P#0.0]
      +AR1  P#2.0
      L     #SchleifeInnen
      LOOP  nw1a
 
 
// --- Pruefschleifen ---
//*** Pruefschleife aussen: testet je 16 bits, ob überhaupt eins davon gesetzt ist ***
 
      L     #HoechsterZustand           //Anzahl Bits
      SRW   4
      +     1                           //Anzahl Woerter
nw1b: T     #SchleifeAussen
      AUF   DB [#QDB]
      L     #OffsetAussen               //Anzahl gepruefter Bytes
      L     #QuellAnfang
      +I    
      SLD   3
      T     #QPointer                   //Pointer auf aktuell zu testenden Quellbereich
      LAR1  
 
      L     W [AR1,P#0.0]
      L     0
      ==I   
      SPB   nw1e                        //wenn kein bit true ist, muss man auch nicht schauen, welches true ist
//***Innere Schleife***
      L     16
nw1c: T     #SchleifeInnen
      AUF   DB [#QDB]
      L     #QPointer
      L     #SchleifeInnen
      +D    
      +     -1                          //weil Bits von 0..15, aber SchleifeInnen von 1..16
      LAR1  
      SET   
      U      [AR1,P#0.0]
      SPBN  nw1d
//wenn das Bit, auf das Bitpointer gerade zeigt, gesetzt ist
//Zielposition im Ziel-DB laden
      AUF   DB [#ZDB]
      L     #GefundeneZst               //Anzahl gefundener Zustaende
      SLD                               //*2 um 2 Bytes bzw 1 Int weiterzuspringen
      L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB
      +D                                //im akku 1 steht die Byte-Nummer des Ints, in das der Zustand gespeichert wird
      SLD   3
      LAR1  
//gefundenen Zustand abspeichern
      L     #OffsetAussen               //Anzahl durchsuchter Bytes
      SLW   3                           //Anzahl durchsuchter Bits
      L     #SchleifeInnen              //Position innerhalb des aktuell durchsuchten Wortes
      +I                                //Nummer des dem Bit zugewiesenen Zustands
      T     W [AR1,P#0.0]
//Zaehler erhoehen
      L     #GefundeneZst
      +     1
      T     #GefundeneZst
//Abbruchbedingung: speicherplatz fuer Zustandsnummern ist voll
      L     #GefundeneZst
      L     #AnzahlInteger              //IN-Var... Vorgabe der maximal gleichzeitig gesetzten Zst bzw die Anzahl Speicherplaetze
      ==I   
      BEB   
//Ende innere Schleife
nw1d: L     #SchleifeInnen
      LOOP  nw1c
//Ende aeussere Schleife
nw1e: L     #OffsetAussen
     + 2  
      T     #OffsetAussen               //Anzahl durchsuchter Bytes um 2 erhoehen
      L     #SchleifeAussen
      LOOP  nw1b
```
 
elegant ist aber wirklich was anderes... ich wäre für Anregungen dankbar


----------



## Ralle (5 März 2009)

Das einzige, was mir auf Anhieb einfällt, wäre, nicht jedesmal die komplette Adresse neu zu berechnen. Statt dieser Neuberechnung in der inneren Schleife könntest du einfach auf den Pointer, der auf das Bit zeigt  P#0.1 aufaddieren.


----------



## Mangokind (5 März 2009)

aber der Wert im AR1 könnte sich ändern, falls ein gesetztes Zustandsbit gefunden wurde

dann würde ja ein Ziel-DB geöffnet und irgendwo in den hineingeschrieben, wobei AR1 überschrieben würde...

ich könnte natürlich auch für das eine AR1 nehmen und für das andere AR2...

gute idee... danke dir!


----------



## Ralle (5 März 2009)

Mangokind schrieb:


> aber der Wert im AR1 könnte sich ändern, falls ein gesetztes Zustandsbit gefunden wurde
> 
> dann würde ja ein Ziel-DB geöffnet und irgendwo in den hineingeschrieben, wobei AR1 überschrieben würde...
> 
> ...



Du berechnest einmal den Pointer beim Eintritt in die Schleife. Der steht ja in einer Variable. Zu dieser einfach P#0.1 dazuaddieren, ins AR1 laden, fertig. Den Pointer würde ich schon nutzen, AR2 mag ich eher nicht so, wegen der FB- und Multiinstanzen.


----------



## Mangokind (5 März 2009)

das wird ja doch schwieriger als angenommen, da die loopschleife runterzaehlt, also vom letzten zum ersten bit vorgeht, ich aber das adressregister nicht um 1 verringern kann 

bzw ich müsste AR1 nach akku 1 laden, um 1 verringern und akku 1 zurueck nach AR1

da wäre aber dann jede ersparnis hinüber


oder ich versteh dich total falsch


----------



## Ralle (5 März 2009)

Mangokind schrieb:


> das wird ja doch schwieriger als angenommen, da die loopschleife runterzaehlt, also vom letzten zum ersten bit vorgeht, ich aber das adressregister nicht um 1 verringern kann



Probiers einfach mal, wir hatten das schon mal diskutiert. Wenn ich mich recht erinnere, geht es sagar, man kann P#0.1 auch abziehen. 
Andererseits kann die Loopschleife ja ruhig runterzählen und der Pointer erhöht werden, kommt ja nur auf die richtige Startadresse an.

PS: Ich glaube, du hast Recht, wirklich viel bringt das nicht. So wie du das geschrieben hast findet man sich wenigstens zurecht, das ist ohnehin wichtiger, als vielleicht eine Operation einzusparen.


----------



## dtsclipper (5 März 2009)

Kleiner Tipp anderer Natur:

Wenn Du die IN-Variablen der DBs als "Block-DB" ausführst brauchst Du die TEMP_VAR nicht mehr, sondern

1. kannst die Block_Dbs direkt mit AUF aufrufen

und
2. findest Du die DBs wieder in den Querverweisen...

dtsclipper


----------



## Mangokind (5 März 2009)

ich glaube, dass mein ansatz insgesamt viel zu umständlich ist.

rein mathematisch müsste ich mir nur den exponenten zur basis 2 ausgeben lassen, aber ein kurzer blick ins S7 PDF mit der ausführungszeit für logarithmen hat mich ganz schnell wieder von dieser idee abgebracht

würde den code zwar zu nem 10-zeiler vereinfachen, aber die laufzeit...



dtsclipper schrieb:


> Kleiner Tipp anderer Natur:
> 
> Wenn Du die IN-Variablen der DBs als "Block-DB" ausführst brauchst Du die TEMP_VAR nicht mehr, sondern
> 
> ...


 
danke dir! aber ich kann keine Parametertypen in DBs speichern... zumindest nicht bei AWL und der Aufruf akzeptiert dann keine Zahlenwerte mehr 
d.h. das Problem mit den TEMP-Vars würde sich in die aufrufende Funktion verlagern


----------



## dtsclipper (5 März 2009)

Ich bin einfach davon ausgegangen das die Dbs schon Existieren...
Sollen die erst mit dem SFC82 erzeugt werden da die Nummer nicht fix ist ? 

dtsclipper


----------



## Ralle (5 März 2009)

Mangokind schrieb:


> danke dir! aber ich kann keine Parametertypen in DBs speichern... zumindest nicht bei AWL und der Aufruf akzeptiert dann keine Zahlenwerte mehr



Kannst du das mal genauer ausführen, interessiert mich.

PS: Ich finde deinen Ansatz gar nicht so umständlich.


----------



## Mangokind (5 März 2009)

das man Parametertypen nicht in DBs speichern kann, ist einfach so... ich kann auch keine ANY-pointer oder sowas in DBs speichern... (oder geht sowas mit SCL?)

und wenn ich als IN-parameter BlockDB angebe, kann ich beim CALL aufruf nicht mehr einfach an die Varbiable die Zahl dranschreiben.


also wenn ich als Quell-DB DB5 nehmen will und die Funktion einen BlockDB als Quelle erwartet, kann ich beim CALL bei der variable nicht einfach = 5 hinschreiben

ich müsste also 5 in einer TEMP-variable vom typ block-DB speichern und diese dann beim Aufruf übergeben.


```
CALL  FC    XY
       BlockDBIn:=5
```
 
erzeugt bei mir zumindest den fehler


> konstantenformat zu datentyp int passt nicht zu formalem typ block_db des formalparameters BlockDBIn


 
ich finde das für die Wiederverwendbarkeit ungünstiger...

wobei das natürlich seinen charme hätte, wenns dann bei den Querverweisen auftaucht...


----------



## dtsclipper (5 März 2009)

Du musst beim Block_DB den DB eintragen...

sieht so aus:

```
CALL  FB    22 , DB25
       Stoermelde_DB   :=DB20
       Spiegel_DB      :=DB24
       Zaehl_DB        :=DB21
       Daten_DB        :=DB31
       Max_Anzahl_Bytes:=175
```

... dtsclipper


----------



## Mangokind (5 März 2009)

ne schöne lösung, aber ich darf gerade ein programm schreiben, was ganz grob folgende aufgabe hat:

eine maschine hat mehrere arbeitsstationen

jeder arbeitsstation ist jeweils 1 FC und 1 DB für ihren ablauf zugeordnet

innerhalb des DBs steht irgendwo entweder als integer oder in mehreren bits der aktuelle zustand der arbeitsstation/des ablaufs

und das programm schaut sich jeden ablauf bzw jedes ablauf-DB nacheinander an, wertet den zustand des ablaufs aus und behandelt dann den ablauf entsprechend gewisser parameter

das programm soll auf möglichst vielen maschinen von möglichst vielen herstellern mit jeweils eigener programmstruktur und pflichtenheft lauffähig sein, ohne - abgesehen vom setzen der parameter - nennenswert verändert zu werden.

daneben gibts noch die lustige forderung, dass alle DB-nummern recht problemlos angepasst werden können müssen.

heißt, jemand benennt den DB80 in DB90 um und sofern er in den kopfzeilen aller anderen FCs die nummer auch noch ändert, soll das programm immernoch gehen.

kurzum: es gibt im gesamten programm nicht eine einzige direkte adressierung (bei 35KB code) ausgenommen FC-aufrufe, weil man da mit dem parameter übergeben probleme bekommt

ist also insgesamt sehr sehr allgemein gehalten und bedarf ner unmenge an einstellungen...

ich kann also die im hiesigen problem genutzten Quell-(bzw ablauf-)DBs nicht absolut übergeben, sondern muss deren nummer aus irgendwelchen Arrays auslesen, weil die Anzahl und nummern der ABlauf-DBs von hersteller zu hersteller schwanken...

ein spaß...

irgendwie sind mir da integer lieber als BLOCK_DB

damit kann ich umgehen 

aber danke trotzdem für den tipp


----------



## StefanK (5 März 2009)

*Logarithmus*

Hi, die Idee mit dem Logarithmus (ein paar Posts vorher) habe hab ich schon mal in SCL gemacht. Die Funktion ist allerdings nur für ein Wort, kann aber problemlos erweitert werden.

FUNCTION FC202 : INT
VAR_INPUT
  m_word : INT; // zu prüfendes Wort
END_VAR
VAR_TEMP
  i_temp : INT;  // temporäre Variable
END_VAR
  IF m_word = 0 THEN
    i_temp := 0;    
  ELSIF m_word = -32768 THEN
    // Anweisungsteil_ELSIF
    i_temp := 16;
  ELSE
    i_temp := 1 + REAL_TO_INT (ROUND (LN (INT_TO_REAL (m_word)) / LN (2.000000e+000)));
  END_IF;
  FC202 := i_temp;
END_FUNCTION

Gruß
Stefan


----------



## Mangokind (5 März 2009)

mathematisch ganz klar die schönste lösung, aber 1 einziger LN befehl bedarf 227 microsekunden auf ner 315er und man braucht mindestens 2 dieser befehle
http://www.fer.hr/_download/repository/s7300_operation_list_en.pdf
d.h. ne halbe ms weg für so nen FC, der eigentlich kaum was macht und zig mal aufgerufen wird... das kann ich mir nicht leisten


----------



## Larry Laffer (5 März 2009)

Hallo,
wie wäre es denn dann mit :
	
	



```
FUNCTION FC202 : INT
VAR_INPUT
m_word : INT; // zu prüfendes Wort
END_VAR
VAR_TEMP
i_temp : INT; // temporäre Variable
END_VAR
IF m_word = 0 THEN
i_temp := 0; 
ELSIF m_word = -32768 THEN
// Anweisungsteil_ELSIF
i_temp := 16;
ELSE
[B][COLOR=green]i_temp := 2**(m_word -1) ;[/COLOR][/B]
END_IF;
FC202 := i_temp;
END_FUNCTION
```
Gruß
LL


----------



## Mangokind (5 März 2009)

ich kann kein SCL

was macht denn die grüne zeile?

^^ hab ich noch in keiner anderen hochsprache gesehn


----------



## Larry Laffer (5 März 2009)

Hallo,
die beiden ^^ entsprechen der hoch-Funktion. Also :

```
2^^4 = 16
2^^8 = 256
etc.
```
Gruß
LL


----------



## Kai (5 März 2009)

S7-SCL kennt die Anweisung ^^ nicht.

Meinst Du vielleicht die die Anweisung 2**() für eine Zweierpotenz?

Gruß Kai


----------



## Kai (5 März 2009)

Da das Ergebnis einer Potenz vom Datentyp REAL ist, muss der Programmcode noch etwas geändert werden:


```
FUNCTION FC202 : INT
VAR_INPUT
m_word : INT; // zu prüfendes Wort
END_VAR
VAR_TEMP
i_temp : INT; // temporäre Variable
END_VAR
IF m_word = 0 THEN
i_temp := 0; 
ELSIF m_word = -32768 THEN
// Anweisungsteil_ELSIF
i_temp := 16;
ELSE
[B][COLOR=green]i_temp := REAL_TO_INT (2**(m_word - 1)) ;[/COLOR][/B]
END_IF;
FC202 := i_temp;
END_FUNCTION
```
 
Gruß Kai


----------



## Larry Laffer (5 März 2009)

Opps ...

Danke Kai, da habe ich mich jetzt direkt vertan. Natürlich meinte ich die **-Geschichte für die Potenz-Bildung ...

Übrigens, du brauchst m.E. keine Typ-Konvertierung machen ...


----------



## Kai (5 März 2009)

Ohne Typkonvertierung bekomme ich die Fehlermeldung: Ungültiger Datentyp.

Gruß Kai


----------



## Larry Laffer (5 März 2009)

@Kai:
Stimmt - ** liefert als Ergebnis ein REAL zurück.

@Mangokind:
Die dargestellte Funktion entspricht im Grunde dem AWL-Befehl SLW (oder besser vielleicht SLD). Meinst du nicht, dass sich deine Aufgabenstellung durch einfaches Linksschieben eines Startwertes auch schon machen läßt ? Also etwa so :
	
	



```
L 1
L #Arbeitsstation
SLD
T #Statusmeldung
```
Gruß
LL


----------



## vierlagig (5 März 2009)

Larry Laffer schrieb:


> @Mangokind:
> Die dargestellte Funktion entspricht im Grunde dem AWL-Befehl SLW (oder besser vielleicht SLD). Meinst du nicht, dass sich deine Aufgabenstellung durch einfaches Linksschieben eines Startwertes auch schon machen läßt ? Also etwa so :
> 
> 
> ...


 
mein lieber larry, du sollst nicht am sinn und unsinn eines ansatzes zweifeln!


----------



## Larry Laffer (5 März 2009)

vierlagig schrieb:


> mein lieber larry, du sollst nicht am sinn und unsinn eines ansatzes zweifeln!


Das verstehe ich nun nicht ... erklär mal ...


----------



## StefanK (5 März 2009)

*Eine andere Idee...*

ist evtl. das:


```
// Erzeuge Datenkopie
      CALL  "BLKMOV"
       SRCBLK :=P#DB50.DBX0.0 BYTE 16
       RET_VAL:=#RET_VAL_SFC20
       DSTBLK :=P#DB50.DBX148.0 BYTE 16
 
// 1. gesetztes Bit ermitteln
      L     1
      T     #Schleife
m01:  NOP   0
      L     DB50.DBD  160
      RRDA  
      T     DB50.DBD  160
      L     DB50.DBD  156
      RRDA  
      T     DB50.DBD  156
      L     DB50.DBD  152
      RRDA  
      T     DB50.DBD  152
      L     DB50.DBD  148
      RRDA  
      T     DB50.DBD  148
      SPP   Fehl                        // Bei gesetztem A1
      L     #Schleife
      INC   1
      T     #Schleife
      L     #Schleife
      L     129
      <>I   
      SPB   m01
      L     0
      T     #Schleife
Fehl: NOP   0
      L     #Schleife
      T     DB59.DBB    6
```
 
Hier werden z.Bsp. 16 Byte durchwühlt. Allerdings ist es fraglich ob ein Schleifenkonstrukt wirklich schneller ist als ein Logarithmus..!?
Dieses Stück Programm kann man sicherlich noch schneller machen, indem man den Datenbereich in den lokalen Bereich umkopiert. Hab's halt aus nem rel. alten Proj. rauskopiert .


----------



## Ralle (5 März 2009)

StefanK schrieb:


> ist evtl. das:
> 
> 
> ```
> ...



@StefanK

Ok, über indirekte Adressierung ist der Aufwand aber auch nicht größer.

PS: Muß man den den Logarithmus-Ansatz nicht auch in einer Schleife machen, wenn man alle Einsen eines Wortes als Zahl irgendwohin schreiben will? Ich kann grad noch nicht sehen, daß der Aufwand da wirklich geringer wäre, als einfach durchzuzählen.

PS2: Das gilt auch für den obigen FC202, bei einem gesetzten Bit sehe ich ja den nutzen durchaus. Oder habe ich die Aufgabenstellung nicht mehr richtig in Erinnerung?


----------



## StefanK (5 März 2009)

@Ralle
ja, hast recht, hier geht's ja um mehr als nur ein gesetztes Bit, da passen meine Vorschläge in der Form (leider) nicht .​


----------



## Gebs (5 März 2009)

Mangokind schrieb:


> rein mathematisch müsste ich mir nur den exponenten zur basis 2 ausgeben lassen, aber ein kurzer blick ins S7 PDF mit der ausführungszeit für logarithmen hat mich ganz schnell wieder von dieser idee abgebracht
> 
> würde den code zwar zu nem 10-zeiler vereinfachen, aber die laufzeit...



Wenn Du nur den Exponenten zur Basis 2 brauchst, versuchs mal so:

```
L #i_temp  // Integerwert
ITR // in Realzahl wandeln
SLD 1 // Vorzeichen rausschieben
SRD 24 // Mantisse rausschieben
T #Exponent // da ist der Exponent zur Basis 2
```

Ich hab' jetzt aber nicht geguckt, wie lang die Ausführungszeit ist.

Grüße
Gebs


----------



## Mangokind (5 März 2009)

Gebs schrieb:


> Wenn Du nur den Exponenten zur Basis 2 brauchst, versuchs mal so:
> 
> ```
> L #i_temp  // Integerwert
> ...



coole sache wenns funktioniert... die ausführungszeit laut tabelle ist vernachlässigbar klein (DTR -> 2,7 microsek. auf ner 315) 

mal sehen, ob ich da nicht morgen n fixen ansatz draus gebacken bekomme...

wenn nur 1 bit gesetzt werden dürfte, wärs mit dem exponenten ja schon getan...

aber bei mehreren sollte man gefundene bits eigentlich per XOW wegmaskieren können und das ganze einfach nochmal machen können

danke an alle!


----------



## Gebs (5 März 2009)

Mangokind schrieb:


> coole sache wenns funktioniert...



Also in S5 hat es funktioniert. Aber da war es ja KG. Ich hab' noch mal nachgesehen und
wenn ich mich nicht verguckt hab, unterscheiden sich KG und REAL nur beim BIAS, und das ist
bei natürlichen Zahlen nicht relevant. 

Grüße
Gebs


----------



## Ralle (5 März 2009)

Mangokind schrieb:


> aber bei mehreren sollte man gefundene bits eigentlich per XOW wegmaskieren können und das ganze einfach nochmal machen können



Aber mir ist immer noch unklar, was das wirklich bringt (an Vereinfachung und/oder Rechenzeitersparnis). Hängt sicher davon ab, wieviele Bits so im Durchschnitt gesetzt sind. Der resultierende Code würde mich dann mal interessieren.


----------



## Gebs (5 März 2009)

Mangokind schrieb:


> aber bei mehreren sollte man gefundene bits eigentlich per XOW wegmaskieren können und das ganze einfach nochmal machen können



Warum so umständlich?
Du kannst Dir doch den Exponenten merken und dann mit

```
SRW 1 / SLW 1
SPZ M001
T #Exponent
```
arbeiten.

Grüße
Gebs


----------



## Mangokind (6 März 2009)

mal ein beispiel:

ich habe ein WORD, indem bit 4 und bit 8 gesetzt sind... (beim ersten word also bspw Zustand 5 und 9 der maschine)

also 2^4+2^8=272 als integerwert

wenn man sich den dualen logarithmus davon ausrechnet kommt wie zu erwarten immer der größeren der beiden exponenten raus... also 8,087...
wenn man den teil nach dem komma auswertet, weiß man, ob es mehrere gesetzte bits gibt, der teil vor dem komma gibt (innerhalb des wortes) das höchstwertigste gesetzte bit an.


müsste ich dann nicht, um das nächste gesetzte bit zu finden, eine 1 in den akku laden, diese in einer schleife so oft, wie der gefundene größte exponent war, nach links verschieben (SLW akzeptiert keine variable), dann das ursprungs-WORD XOR mit akku 1 verknüpfen bzw subtrahieren und dann das ganze nochmal machen, solange der Nachkommateil des exponenten nicht 0 ist, es also noch weitere gesetzte bits gibt?

alternativ könnte man den gefundenen größten exponenten natürlich auch auf nen pointer addieren, der auf einen vergleichsinteger zeigt und das bit dann 0 setzen... kann ich gerade nicht abschätzen, was günstiger ist.

---------------------------------

habe mir mal das Real-format angeschaut...

wenn 1 bit gesetzt ist, habe ich also immer eine mantisse von 1

ich müsste demnach nicht den exponenten, sondern die mantisse überprüfen, ob sie glatt 1 ist

aber das problem bleibt doch: wie berechne ich weitere bits, wenn die mantisse ungleich 1 ist?

das höchste gesetzte bit ist immernoch das was im exponenten steht, aber den rest muss ich ja trotzdem gesondert behandeln


mal zurück zum beispiel von vorhin: 2^4+2^8=272

wenn ich jetzt 272 in eine real-zahl wandle, bekomme ich vermutlich 1,0625*2^8 als real-zahl, wenn ich den datentyp richtig verstanden habe

ich müsste doch also 2^8 von den 272 abziehen und dann das ganze nochmal machen, oder? und zwar solange, bis meine mantisse mal 1,0 wäre bzw ich alle gesetzten bits in dem wort gefunden habe

so langsam bekomme ich auch zweifel, ob der ursprüngliche ansatz so schlecht war... denn ich bekomme hier ja wieder die verschachtelte schleife aus post #2, nur dass die innere schleife hier mit den exponenten rumrechnet, statt bitweise zu prüfen

bitte korrigier mich, wenn ich mich irre...

LG


P.S.:

wie sieht eigentlich 0.0 als REAL-Zahl aus?

da man die Vorkommastelle nicht beeinflussen kann, wäre das ja 1,X*2^Y

1,X kann nicht 0 werden, 2^Y kann auch nicht 0 werden... mhhhh


------------------------------------------

habs mal schnell zusammengetippert:

über Exponenten auswerten:

(nur der rot markierte teil hat sich geändert)


```
TAR1  #AR1Merker
      TAR2  #AR2Merker
//IN nach TEMP
      L     #QuellDB                    //IN-Var... DB-Nummer Quelle
      T     #QDB                        //TEMP-Var... DB-Nummer Quelle
      L     #ZielDB                     //IN-Var... DB-Nummer Ziel
      T     #ZDB                        //TEMP-Var... DB-Nummer Ziel
// --- initialisieren ---
//Zaehler/Merker initialisieren
      L     0
      T     #GefundeneZst
//Offset der aeusseren Schleife 0 setzen
      L     0
      T     #OffsetAussen
//Zst-Ints im Ziel-DB 0 setzen
      AUF   DB [#ZDB]
      L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB
      SLD   3
      LAR1  
      L     #AnzahlInteger
nw1a: T     #SchleifeInnen
      L     0
      T     W [AR1,P#0.0]
      +AR1  P#2.0
      L     #SchleifeInnen
      LOOP  nw1a
 
// --- Pruefschleifen ---
//*** Pruefschleife aussen: testet je 16 bits, ob überhaupt eins davon gesetzt ist ***
      L     #HoechsterZustand           //Anzahl Bits
      SRW   4
      +     1                           //Anzahl Woerter
nw1b: T     #SchleifeAussen
      AUF   DB [#QDB]
      L     #OffsetAussen               //Anzahl gepruefter Bytes
      L     #QuellAnfang
      +I    
      SLD   3
      T     #QPointer                   //Pointer auf aktuell zu testenden Quellbereich
      LAR1  
      L     W [AR1,P#0.0]
      L     0
      ==I   
      SPB   nw1e                        //wenn kein bit true ist, muss man auch nicht schauen, welches true ist
[COLOR=red]//***Innere Schleife***[/COLOR]
[COLOR=red]//hoechstes gesetztes Bit ermitteln[/COLOR]
[COLOR=red]   L     W [AR1,P#0.0]               //das gerade zu pruefende WORD[/COLOR]
[COLOR=red]nw1c: T     #WORDMerker                 //gemerkt (noetig bei mehreren Durchlaeufen)[/COLOR]
[COLOR=red]   DTR                               //als REAL[/COLOR]
[COLOR=red]   T     #REALMerker                 //merken[/COLOR]
[COLOR=red]   SLD                               //Vorzeichen weg[/COLOR]
[COLOR=red]   SRD   24                          //bleibt nur noch der Exponent bzw das hoechste gesetzte bit[/COLOR]
[COLOR=red]   T     #Exponent[/COLOR]
[COLOR=red]//noch weitere Bits gesetzt?[/COLOR]
[COLOR=red]   L     #REALMerker                 //REAL wieder Laden[/COLOR]
[COLOR=red]   SLD   9                           //Vorzeichen und Exponent weg... [/COLOR]
[COLOR=red]   SRD   9                           //bleiben noch 23 Bit Nachkommastelle der Mantisse[/COLOR]
[COLOR=red]   L     0[/COLOR]
[COLOR=red]   ==D                               //wenn Nachkommastellen ==0 wurde das letzte gesetzte Bit gefunden[/COLOR]
[COLOR=red]   =     #MerkerLetzteStelle[/COLOR]
[COLOR=red]//Zielposition im Ziel-DB laden[/COLOR]
[COLOR=red]   AUF   DB [#ZDB][/COLOR]
[COLOR=red]   L     #GefundeneZst               //Anzahl gefundener Zustaende[/COLOR]
[COLOR=red]   SLD                               //*2 um 2 Bytes bzw 1 Int weiterzuspringen[/COLOR]
[COLOR=red]   L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB[/COLOR]
[COLOR=red]   +D                                //im akku 1 steht die Byte-Nummer des Ints, in das der Zustand gespeichert wird[/COLOR]
[COLOR=red]   SLD   3[/COLOR]
[COLOR=red]   LAR1  [/COLOR]
[COLOR=red]//gefundenen Zustand abspeichern[/COLOR]
[COLOR=red]   L     #OffsetAussen               //Anzahl durchsuchter Bytes[/COLOR]
[COLOR=red]   SLW   3                           //Anzahl durchsuchter Bits[/COLOR]
[COLOR=red]   L     #Exponent                   //Position innerhalb des aktuell durchsuchten Wortes[/COLOR]
[COLOR=red]   +I    [/COLOR]
[COLOR=red]   +     1                           //Nummer des dem Bit zugewiesenen Zustands[/COLOR]
[COLOR=red]   T     W [AR1,P#0.0][/COLOR]
[COLOR=red]//Zaehler erhoehen[/COLOR]
[COLOR=red]   L     #GefundeneZst[/COLOR]
[COLOR=red]   +     1[/COLOR]
[COLOR=red]   T     #GefundeneZst[/COLOR]
[COLOR=red]//Abbruchbedingung: speicherplatz fuer Zustandsnummern ist voll[/COLOR]
[COLOR=red]   L     #GefundeneZst[/COLOR]
[COLOR=red]   L     #AnzahlInteger              //IN-Var... Vorgabe der maximal gleichzeitig gesetzten Zst bzw die Anzahl Speicherplaetze[/COLOR]
[COLOR=red]   ==I   [/COLOR]
[COLOR=red]   BEB   [/COLOR]
[COLOR=red]// ggf. das gefundene Bit vom zu pruefenden WORD abziehen und die ganze Show nochmal[/COLOR]
[COLOR=red]   SET   [/COLOR]
[COLOR=red]   U     #MerkerLetzteStelle[/COLOR]
[COLOR=red]   SPB   nw1e                        //Innere Schleife verlassen[/COLOR]
[COLOR=red]//wenns noch ein weiteres gesetztes bit gibt:[/COLOR]
[COLOR=red]   SET                               //VKE auf 1[/COLOR]
[COLOR=red]   L     P##WORDMerker[/COLOR]
[COLOR=red]   L     #Exponent[/COLOR]
[COLOR=red]   +D    [/COLOR]
[COLOR=red]   LAR1  [/COLOR]
[COLOR=red]   R      [AR1,P#0.0]                //Das gefundene Bit wird zurueckgesetzt[/COLOR]
[COLOR=red]   L     #WORDMerker[/COLOR]
[COLOR=red]   SPA   nw1c                        //und nochn Durchlauf der inneren Schleife[/COLOR]
[COLOR=red]//Ende innere Schleife[/COLOR]
 
//Ende aeussere Schleife
nw1e: L     #OffsetAussen
      +     2
      T     #OffsetAussen               //Anzahl durchsuchter Bytes um 2 erhoehen
      L     #SchleifeAussen
      LOOP  nw1b
      LAR1  #AR1Merker
      LAR2  #AR2Merker
```


----------



## Mangokind (6 März 2009)

Zum vergleich aus Post #2: Loopschleife Bitweise auswerten:


```
TAR1  #AR1Merker
      TAR2  #AR2Merker
 
//IN nach TEMP
      L     #QuellDB                    //IN-Var... DB-Nummer Quelle
      T     #QDB                        //TEMP-Var... DB-Nummer Quelle
      L     #ZielDB                     //IN-Var... DB-Nummer Ziel
      T     #ZDB                        //TEMP-Var... DB-Nummer Ziel
// --- initialisieren ---
//Zaehler/Merker initialisieren
      L     0
      T     #GefundeneZst
//Offset der aeusseren Schleife 0 setzen
      L     0
      T     #OffsetAussen
//Zst-Ints im Ziel-DB 0 setzen
      AUF   DB [#ZDB]
      L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB
      SLD   3
      LAR1  
      L     #AnzahlInteger
nw1a: T     #SchleifeInnen
      L     0
      T     W [AR1,P#0.0]
      +AR1  P#2.0
      L     #SchleifeInnen
      LOOP  nw1a
 
// --- Pruefschleifen ---
//*** Pruefschleife aussen: testet je 16 bits, ob überhaupt eins davon gesetzt ist ***
      L     #HoechsterZustand           //Anzahl Bits
      SRW   4
      +     1                           //Anzahl Woerter
nw1b: T     #SchleifeAussen
      AUF   DB [#QDB]
      L     #OffsetAussen               //Anzahl gepruefter Bytes
      L     #QuellAnfang
      +I    
      SLD   3
      T     #QPointer                   //Pointer auf aktuell zu testenden Quellbereich
      LAR1  
      L     W [AR1,P#0.0]
      L     0
      ==I   
      SPB   nw1e                        //wenn kein bit true ist, muss man auch nicht schauen, welches true ist
[COLOR=red]//***Innere Schleife***[/COLOR]
[COLOR=red]L     16[/COLOR]
[COLOR=red]nw1c: T     #SchleifeInnen[/COLOR]
[COLOR=red]AUF   DB [#QDB][/COLOR]
[COLOR=red]L     #QPointer[/COLOR]
[COLOR=red]L     #SchleifeInnen[/COLOR]
[COLOR=red]+D    [/COLOR]
[COLOR=red]+     -1                          //weil Bits von 0..15, aber SchleifeInnen von 1..16[/COLOR]
[COLOR=red]LAR1  [/COLOR]
[COLOR=red]SET   [/COLOR]
[COLOR=red]U      [AR1,P#0.0][/COLOR]
[COLOR=red]SPBN  nw1d[/COLOR]
[COLOR=red]//wenn das Bit, auf das Bitpointer gerade zeigt, gesetzt ist[/COLOR]
[COLOR=red]//Zielposition im Ziel-DB laden[/COLOR]
[COLOR=red]AUF   DB [#ZDB][/COLOR]
[COLOR=red]L     #GefundeneZst               //Anzahl gefundener Zustaende[/COLOR]
[COLOR=red]SLD                               //*2 um 2 Bytes bzw 1 Int weiterzuspringen[/COLOR]
[COLOR=red]L     #ZielAnfang                 //IN-Var... Byteposition des ersten Zst-Ints im Ziel-DB[/COLOR]
[COLOR=red]+D                                //im akku 1 steht die Byte-Nummer des Ints, in das der Zustand gespeichert wird[/COLOR]
[COLOR=red]SLD   3[/COLOR]
[COLOR=red]LAR1  [/COLOR]
[COLOR=red]//gefundenen Zustand abspeichern[/COLOR]
[COLOR=red]L     #OffsetAussen               //Anzahl durchsuchter Bytes[/COLOR]
[COLOR=red]SLW   3                           //Anzahl durchsuchter Bits[/COLOR]
[COLOR=red]L     #SchleifeInnen              //Position innerhalb des aktuell durchsuchten Wortes[/COLOR]
[COLOR=red]+I                                //Nummer des dem Bit zugewiesenen Zustands[/COLOR]
[COLOR=red]T     W [AR1,P#0.0][/COLOR]
[COLOR=red]//Zaehler erhoehen[/COLOR]
[COLOR=red]L     #GefundeneZst[/COLOR]
[COLOR=red]+     1[/COLOR]
[COLOR=red]T     #GefundeneZst[/COLOR]
[COLOR=red]//Abbruchbedingung: speicherplatz fuer Zustandsnummern ist voll[/COLOR]
[COLOR=red]L     #GefundeneZst[/COLOR]
[COLOR=red]L     #AnzahlInteger              //IN-Var... Vorgabe der maximal gleichzeitig gesetzten Zst bzw die Anzahl Speicherplaetze[/COLOR]
[COLOR=red]==I   [/COLOR]
[COLOR=red]BEB   [/COLOR]
[COLOR=red]//Ende innere Schleife[/COLOR]
[COLOR=red]nw1d: L     #SchleifeInnen[/COLOR]
[COLOR=red]LOOP  nw1c[/COLOR]
//Ende aeussere Schleife
nw1e: L     #OffsetAussen
      +     2
      T     #OffsetAussen               //Anzahl durchsuchter Bytes um 2 erhoehen
      L     #SchleifeAussen
      LOOP  nw1b
      LAR1  #AR1Merker
      LAR2  #AR2Merker
```
 
bin ja mal gespannt, was die SPS Zykluszeit dann dazu sagt...


------------------------------------------------------------------------------------------


gleich noch eine frage:

wie bildet man am schlausten eine eindeutige Prüfsumme über erstmal unbegrenzt viele wörter, wenn nur Wertänderung interessiert?




-------------------------------------------------------------------------------------------



Larry Laffer schrieb:


> @Kai:
> Stimmt - ** liefert als Ergebnis ein REAL zurück.
> 
> @Mangokind:
> ...


 
war meine allererste idee, ist aber noch langsamer als bitweise prüfen, weil WORD-vergleiche deutlich langsamer sind als bit-vergleiche und sich abgesehen davon nicht viel ändert


----------

