TIA genau ein Bit true

Zuviel Werbung?
-> Hier kostenlos registrieren
Ich finde den Code eher schlecht lesbar/unverständlich für Instandhalter oder andere Programmierer...

Wäre nicht ein Aufruf von BITSUM mit Auswertung auf =1 verständlicher oder habe ich etwas falsch verstanden.
Für Instandhalter oder andere Programmierer, die BITSUM kennen oder richtig vermuten, was es tut, wäre Deine Variante vermutlich besser verständlich, Michael.

Meine Vermutung, wie BITSUM realisiert sein dürfte, wäre eine Schleife, die das niederwertigste Bit zählt und löscht. Von der RechenZeit her also - je nach Anzahl der 1-Bits - deutlich aufwändiger.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
hier eine SCL-Variante für TIA-Portal:

Code:
xResult := (wTest <> 0) AND ((wTest AND ([COLOR="#FF0000"]wTest - 1[/COLOR])) [COLOR="#FF0000"]= 0[/COLOR]);

@Harald: irgendwie komme ich nicht dahinter, warum Du für Codesys-ST statt "= 0" "= wTest" schreibst. Genauso ist mir das -wTest unklar, aber ich denke das liegt in der Eigenart der Codesys-ST-Syntax?
Dieser Code ist eine total falsche Umsetzung meiner Vorlage (xResult := wTest <> 0 AND ((wTest AND -wTest) = wTest);).
• mein "-wTest" darfst Du nicht nach "wTest - 1" umformen. "-x" bedeutet in der Mathematik "x * -1". ST und SCL kennen diese Operation, da darf man direkt "-x" schreiben.
• der Vergleich am Ende darf nicht auf "= 0" gemacht werden, sondern soll vergleichen, ob das Ergebnis = Eingangswert ist (ob "wTest AND -wTest" = "wTest" ist). Siehe die ausführlichere Erklärung des Algorithmus in #7

Harald
 
Moin DMA,

intern werte ich das so aus (Pseudocode, da ich gerade TIA-Komponenten installiere):

Code:
case Iv_value of

byte, char, usint, sint:
VariantGet(Src: Iv_value
                Dst => Tb_value);
Tdw_value := byte_to_dword(Tb_value);

uint, int, word:
VariantGet(Src: Iv_value
                Dst => Tw_value);
Tdw_value := word_to_dword(Tw_value);

udint, dint, dword:
VariantGet(Src: Iv_value
                Dst => Tdw_value);

end_case;


VG

MFreiberger
 
Moin Harald,

Dieser Code ist eine total falsche Umsetzung meiner Vorlage (xResult := wTest <> 0 AND ((wTest AND -wTest) = wTest);).
• mein "-wTest" darfst Du nicht nach "wTest - 1" umformen. "-x" bedeutet in der Mathematik "x * -1". ST und SCL kennen diese Operation, da darf man direkt "-x" schreiben.
• der Vergleich am Ende darf nicht auf "= 0" gemacht werden, sondern soll vergleichen, ob das Ergebnis = Eingangswert ist (ob "wTest AND -wTest" = "wTest" ist). Siehe die ausführlichere Erklärung des Algorithmus in #7

Harald

das -wTest als -1*wTest zu verstehen ist, dachte ich mir. Irgendwie hatte ich Deine ausführlichere Erklärung nicht registriert. Jetzt ist es klar, danke! Wobei meine Variante für mich näher an der Variante aus den Bit Twiddling Hacks ist.

VG

Mario
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Dieser Code ist eine total falsche Umsetzung meiner Vorlage (xResult := wTest <> 0 AND ((wTest AND -wTest) = wTest);).
Es ist nicht eine falsche Umsetzung Deines Ansatzes, Harald, sondern ein ganz anderer Ansatz!
Dein Ansatz liefert an der Position des niederwertigsten 1-Bits eine 1 und Marios Ansatz liefert an der Position des niederwertigsten 1-Bits eine 0.
 
Moin,

jetzt habe ich Haralds Variante verstanden. Da muss das Ergebnis aus

Code:
(wTest and -wTest) = wTest

nicht invertiert werden.

bei

Code:
(wTest and (wTest - 1)) = 0

schon.


Die Auswertung, ob wTest = 0 ist, muss natürlich jeweils noch hinzugefügt werden.

VG

MFreiberger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wobei meine Variante für mich näher an der Variante aus den Bit Twiddling Hacks ist.
OK Mario, Du hast recht. Mein Algorithmus ist ein anderer als der den ich dazu verlinkt hatte. Dein Code ist die genaue Umsetzung des verlinkten Codes.
icon14.png

Die Grundlage für meinen hier gezeigten Algorithmus hatte ich damals bei der Ermittlung der Bitnummer des niedrigsten gesetzten Bits über REAL/Float abgeschaut und neu abgemixt. ;)

Harald
 
Ja, das war auch ein schöner cleverer Algorithmus - für ein ähnliches Standard-Problem.
Achtung, der verlinkte Code ermittelt nicht, ob genau ein Bit gesetzt ist, sondern ob mehr als ein Bit gesetzt ist. Die Negation davon ist nicht "genau ein Bit gesetzt" sondern "höchstens ein Bit gesetzt". Für "genau ein Bit gesetzt" müsste man noch den Spezialfall "kein Bit gesetzt" (der Eingangswert ist 0) abfangen. Außerdem geht der Algorithmus über REAL/Float nur für 16 Bit, nicht 32 Bit. Ein paar Beiträge weiter im Beitrag #13 findet man dann den hier in #4 verwendeten Algorithmus in AWL, der zunächst das niedrigste gesetzte Bit maskiert/isoliert mittels "wTest AND -wTest" (*), und dann schaut, ob das eine isolierte Bit das einzige Bit war, wenn also das Ergebnis = Eingangswert ist. Leider liefert auch der Eingangswert 0 das Ergebnis 0, so daß dieser Spezialfall für "genau ein Bit gesetzt" noch abgefangen werden muß.
Mit ein bisschen "um die Ecke denken" kann man solche cleveren Zahlenspiele für verschiedene Aufgaben ausbauen. :cool:

(*) Der Ausdruck (v & -v) extrahiert das niedrigstwertige 1-Bit aus v

Harald
Hallo Harald,

leider verstehe ich nicht wie der Code funktioniert. Insbesondere nicht wieso der negierte Wert Und-Verknüpft wird.
Klnntest Du mir das bitte nochmal ausfürlicher erklären?

Vielen Dank
 
Das beruht auf einem uralten Algorithmus, von C nach SCL umgesetzt.
The expression (v & -v) extracts the least significant 1 bit from v.

Wenn (wTest AND -wTest) = wTest, dann ist das niedrigstwertige 1-Bit zugleich auch das einzige 1-Bit. Der Ausdruck liefert allerdings auch TRUE bei wTest = 0, deshalb muß dieser Fall noch ausgeschlossen werden: wTest <> 0

Code:
//xResult ist true, wenn genau 1 Bit gesetzt ist
IF wTest = 0 THEN
  xResult := 0;
ELSE
  xResult := (wTest AND -wTest) = wTest;
END_IF;

//oder eleganter ohne IF..THEN
xResult := wTest <> 0 AND ((wTest AND -wTest) = wTest);

Man kann auch diesen Algorithmus nehmen: schauen, ob der Wert eine Potenz von 2 ist (dann ist genau 1 Bit gesetzt)
http://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
Determining if an integer is a power of 2

f = v && !(v & (v - 1));

Ausführliche Erklärungen siehe auch hier im Thread die Beiträge #4 und #7

leider verstehe ich nicht wie der Code funktioniert. Insbesondere nicht wieso der negierte Wert Und-Verknüpft wird.
Das hängt mit der Zweierkomplement-Darstellung von Ganzzahlen zusammen. Da ergibt sich, daß nur höchstens ein Bit 1 bleibt (das niedrigstwertige 1-Bit), wenn man einen Wert und seinen negierten Wert bitweise UND-verknüpft.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Könntest Du mir das bitte nochmal ausfürlicher erklären?
Ruf Dir mal den Windows Rechner auf und wähle die Variante 'Programmierer' aus.
Klick hier auf 'Dec' und gib eine Zahl zum testen ein.
Mit Klick auf '+/-' Kannst Du (beliebig oft) das Vorzeichen umkehren, also auf das ZweierKomplement umschalten bzw. vom ZweierKomplement zurückschalten.
Du wirst sehen:
- die Bits unterhalb des kleinsten gemeinsamen 1-Bits sind in beiden Fällen 0,
- die Bits oberhalb des kleinsten gemeinsamen 1-Bits haben den "umgekehrten" Zustand und
- nur das niederwertigste Bit ist in beiden Fällen 1.
Die UND-Verknüpfung von beiden ergibt also genau das niederwertigste Bit.
Ausser - natürlich - bei der Zahl 0, bei der es kein "niederwertigstes" 1-Bit gibt.
 
Du wirst sehen:
- die Bits unterhalb des kleinsten gemeinsamen 1-Bits sind in beiden Fällen 0,
- die Bits oberhalb des kleinsten gemeinsamen 1-Bits haben den "umgekehrten" Zustand und
- nur das niederwertigste Bit ist in beiden Fällen 1.
Hat dieses Verhalten jemand lediglich entdeckt oder kann man das irgendwie herleiten oder beweisen?
 
... oder kann man das irgendwie herleiten oder beweisen?
Ich würde es so anpacken:
- zunächstmal vorausschicken, dass es die 0 nur 1-mal gibt, also nicht zwischen -0 und +0 unterschieden wird,
- die Zahl +1 bilden, indem man zur 0 eine 1 hinzuaddiert, --> 00000000 00000001
- die Zahl -1 bilden, indem man von der 0 eine 1 subtrahiert, --> 11111111 11111111
- die beiden Zahlen vergleichen und feststellen, dass wir es hier nicht mit dem EinerKomplement zu tun haben, bei dem jede 0 durch eine 1 und jede 1 durch eine 0 ersetzt würde, sondern mit dem ZweierKomplement. Das ZweierKomplement ist dem EinerKomplement zwar sehr ähnlich, aber es liegt immer um 1 neben dem EinerKomplement. Diese Verschiebung kommt sozusagen daher, dass, wie oben bereits gesagt, es nur 1 Codierung für die 0 gibt und nicht zwischen -0 und +0 unterschieden wird. +0 ist 00000000 00000000 und für die -0 könnte man dann die 11111111 11111111 wählen. Diese Codierung entspricht aber der -1.
Dass wir für die 0 nur eine vorzeichenlose Codierung benutzen, das sorgt übrigens auch dafür, dass die ZahlenStrahlen der darstellbaren Zahlen, also die ZahlenBereiche "asymmetrisch" sind.
Z.B. bei 8 Bit -128..0..127, bei 16 Bit -32768..0..32767 u.s.w. ...
Im negativen Bereich gibt es immer eine Zahl (die kleinste darstellbare negative Zahl), die kein Pendant im positiven Bereich hat, jedenfalls nicht, wenn man nicht mindestens 1 Bit mehr spendiert, um die Zahl darzustellen.
Sooo, das VerUNDen einer Zahl mit ihrem EinerKomplement ergibt immer 0 ... das hilft uns also nicht weiter.
Zum Glück haben wir aber beim ZweierKomplement eine Differenz von 1 gegenüber dem EinerKomplement, so dass wir uns beim VerUNDen von Zahl und ZweierKomplement darauf verlassen können, dass beim niederwertigsten 1-Bit das eine 1-Bit genau an dieser Stelle durch das VerUNDen isoliert wird.
Betrachtet man dies zunächst für 1 und -1, dann für 2 und -2, dann sieht man schnell, dass bei 3 und -3 dasgleiche wieder gilt, u.s.w. ...

Edit:
Statt mit der Taste '+/-' das Vorzeichen umzuknipsen, kann man ersatzweise das ZweierKomplement aus einer logischen Verknüpfung und einer arithmetischen Operation zusammensetzen:
- entweder:
1. das EinerKomplement bilden (im Windows Rechner z.B. durch Anklicken von 'bitweise' und dann 'NOT') und
2. danach noch eine 1 addieren.
- oder:
1. eine 1 subtrahieren und danach noch
2. das EinerKomplement bilden (s.o.).
 
Zuletzt bearbeitet:
Zurück
Oben