Aufgehört mit der Beschreibung der Bullshen Algebra, wo ich gesagt hatte,
dass es da im Prinzip um die Aussagenlogik geht,
wo im Prinzip jetzt Aussagen, entweder als wahr oder als falsch,
klassifiziert werden und man eben mit den Grundoperationen der Negation und
beziehungsweise oder Verknüpfung dann daraus Ausdrücke bilden kann.
Grundverknüpfung hatte ich ja soweit vorgestellt.
Die Basisfunktion bzw. Anzahl der Binärenfunktionen,
dann entsprechend auch
Wie der Name schon sagt, bildet die Bulsche Argebra.
Ja, also mathematisch gesehene Algebra. Das heißt eben ein,
nicht formal gesehen, ist das so was dann immer ein Sex-Tupel.
Das heißt, es gibt eine Menge mit entsprechenden Wörtern, die dargestellt werden.
In diesem Fall ist es die Menge mit den beiden Elementen 0
und 1. Es gibt dann zwei Verknüpfungen auf dieser Menge.
In diesem Fall also einmal die oder Verknüpfung
quasi als Addition bzw. die Unverknüpfung
quasi als Multiplikation
Dann eben die Komplimentbildung. Und es gibt dann eben ausgezeichnete Elemente,
nämlich das neutrale Element der Addition, die Null,
beziehungsweise im Sinne der Aussagenlogik quasi, das Falls.
Und die Eins als neutrales Element der Multiplikation. So,
wenn man die Butsche Alge bereits vergleicht mit dem Ring der ganzen Zahlen,
da hatte ich ja auch schon in dem Abschnitt über Arithmetik,
was kurz zugesagt, kann man sagen, okay,
also es gelten im Prinzip bei beiden entsprechend die Kommutativgesetze für beide Operationen,
sowohl Addition als auch Multiplikation.
Es gelten die entsprechenden Assoziativgesetze, das heißt die Klammerung kann verschoben werden und
wie im Prinzip jetzt wir das also aus dem ganz normalen Arithmetik gewohnt sind,
das Distributivgesetz, also sprich das Ausklammern, gilt dann demzufolge auch genauso innerhalb der Bultschen Algebar. Identitäten,
nicht, das war eben genau das jetzt mit diesen neutralen Elementen,
sowohl der Addition beziehungsweise der Multiplikationengeld nebenentsprechend und was hier jetzt eben als Vernichtung bezeichnet ist,
also sprich Amal-0 ist null beziehungsweise A und null ist dann eben null und eben die Auslöschung,
das was also quasi jetzt die Negation bei den Zahlen ist,
wäre dann eben in der Bulschenalge, war ja quasi das Inverse,
und zwar haben wir das inverse angewendet,
ist dann eben wieder die Zahl selber.
Nee, ähm, ja,
das war natürlich genau der Fehler, also zweimal das Kompliment,
also das Inversus ist eben wieder etwas,
was jetzt eigentlich wieder nur für Zahlen gilt, weil,
also inversus ist eigentlich so definiert,
dass es eben entsprechend eine Zahl mit dem Inversen addiert
Die Null ergibt, also sprich, das neutrale Element der Addition.
Und wenn ich das jetzt also quasi jetzt hier, also als Addition,
jetzt also die Oder-Verknüpfung nehme und das damit mache,
dann muss sie eben auch sagen, was hier ist,
also oder mich da berechtigen,
weil ich das jetzt eben falsch ausgedrückt hatte.
Also im Prinzip bei der Bulschen Algebar habe ich dann eben nicht das Inverse,
sondern da wäre das dann eben entsprechend die Negation.
Dafür gelten jetzt also in der Bulschen Algebar dann aber noch
diverse andere Regeln
Im Prinzip das Destributivgesetz funktioniert eben dort auch umgekehrt.
Das heißt, wenn ich jetzt hier und, und,
oder Verknüpfung vertausche, könnte ich eben genauso ausklammern.
Nicht für das Kompliment gilt dann eben, dass ich a oder nicht a
wäre dann eben eins bzw. a und nicht a entsprechend dann null.
Wenn ich dann gilt für beide Verknüpfungen, sogenannte Idempotenz,
das heißt also eine Aussage,
entweder mit und oder mit oder mit sich selber verknüpft,
ist, wie er genau diese Aussage, die ich dann gelten, also diese Absorptionsregeln.
Das heißt, wenn ich jetzt sage, A oder,
Klammer auf, A und B,
das entspricht im Prinzip dann eben genau der Aussage A,
beziehungsweise entsprechend dann eben hier auch mit vertauschten Operationen.
Eine weitere Rechenregel, die man dann also häufig noch in der Bulschenalge braucht,
beziehungsweise die sie dann also auch in den Übungsaufgaben brauchen werden,
sind dann die Und der Morgenregeln, das heißt,
die Negation von einem Ausdruck, meinetwegen jetzt A oder B,
entspricht dann, negiert A und negiert B, beziehungsweise entsprechend umgekehrt.
Das heißt, was sich mit diesen Morgenregeln eigentlich mache,
wenn ich das jetzt mal in so eine Garda- oder Logik-Notation umsetze,
ist, dass ich quasi ein Und durch ein Oder ersetze oder eben entsprechend umgekehrt.
Das heißt, damit kann man dann solche Funktionen gegeneinander austauschen
Das, was Sie jetzt dargestellt sind,
das sind dann also nachher sagen wir mal Schalssymbole,
die ich dann also später auch, wenn ich dann,
also jetzt noch wirklich auf Realisierung von logischen Funktionen in Form von Schaltnetzen eingehen werde,
dann wird sowas also verwendet.
Im Prinzip kann man aber eben erstmal sagen,
also dieses Symbol entspricht dann quasi jetzt hier diesem Oder-Verknüpfung und die Negation ist dann eben so ein Punkt,
in diesem Fall jetzt am Ausgang,
quasi eben eine Negation am Ende,
nicht also entsprechend dann eben genau diese Negierung dieser Klammer,
mich und hier habe ich dann eben die Negation an den
einzelnen Werten A und B und dafür dann eben stattdessen oder es dann eben hier so ein und ausgedrückt.
Wie gesagt, verwendet wird das dann eben nachher bei der Minimierung
logischer Ausdrücke beziehungsweise dann eben auch beim Entwurf von Schaltung.
Ich denke mir dazu, wenn wir dann nächste,
übernächste Woche schätzensweise übernächste Woche dann kommen, da kommen dann also auch reichlich Beispiele dann dazu. Als eine Funktion,
die ich dann ja auch noch eingangs in der Bulschen Algebar vorgestellt habe,
die ist exklusiv oder beziehungsweise Man spricht dann also auch oft immer von der Antivalenz,
entspricht eigentlich, sage ich mal, so einem umgangssprachlichen,
entweder A oder B, wobei dies entweder dann eben wirklich heißt, ausschließlich.
Das heißt, wenn beide wahr sind, habe ich,
gilt eben diese Aussage nicht. Und genau damit habe ich dann eben letztendlich genau die Funktion,
die dann also auch hier jetzt in der Funktionstabelle beschrieben ist,
nicht, dass ich eben sage, also wenn beide Falls sind,
ist das Ergebnis Falls, wenn genau einer von beiden war,
ist, Sprüche an diesen beiden Stellen hätte ich dann eins,
aber wenn beide eins sind, habe ich dann eben als Ergebnis wieder null nicht und das unterschadet dann eben dieses Exklusiv-Oder von dem normalen Oder.
Wenn man das jetzt umsetzt bzw. entsprechend anders klammert,
kann ich das also auch quasi immer interpretieren mit diesem Exklusiv-Oder,
also hier jetzt gezeichnet immer durch so ein Plus und dann einen entsprechenden Kreis drumherum,
dass ich eben sage, es ist genau einer von den beiden Thermen,
A und B war Nicht,
was dann im Prinzip entweder mit diesem Ausdruck beschrieben ist,
wenn ich das jetzt eben in Bultologik umsetze,
das würde eben in diesem Fall mir hier vorne ein Wert 1 liefern, wenn B-1 ist und A-0.
Und hier in diesem Fall wurde es eben eine 1 liefern,
wenn A-1 ist und B-0 und in allen anderen Fällen dann eben entsprechende Null,
nicht oder ich kann das dann eben auch entsprechend nochmal Ausklammern, anders schreiben,
anders dann wieder zusammenfassen, hätte dann letztendlich diesen Ausdruck,
der da also auch äquivalent ist und umgangssprachlich entspricht,
dass dann eben der Aussage, dass ich sage,
entweder AS war oder B,
es war aber eben nicht beide gleichzeitig.
Also das, was ich ja gerade so als ausschließliches
Entweder A oder B bezeichnet hatte.
Gut, jetzt reden wir jetzt also wieder ein bisschen konkreter
in Bezug auf Informatik und Programmiersprachen
Butsche Algebra, also sprich logische Operationen in Programmiersprachen,
welche Ausdrucksmöglichkeiten gibt es da, was kann man dort also umsetzen,
als Datentypen für die Butsche Logik bietet die Sprache Java da eben ein,
explizit ein Datentyp Bulien, der dann eben Falls oder True sein kann.
In C sieht das so aus,
dass logische Operationen implizit für alle Entager-Typen definiert sind,
das heißt also da gibt es jetzt also nicht so was wie ein Bulienwert,
sondern da rechnet man dann eben mit Intager-Werten,
für die dann quasi auch eine Interpretation als Bullshell-Logik möglich ist.
Dazu dann also gleich noch die entsprechenden Beispiele als Vergleichsoperation,
werde ich dann also gleich noch mal was vorstellen,
was es dann in den Programmiersprachen gibt, dann eben, wie gesagt,
diese logischen Grundoperationen, die dann eben auf diesen entsprechenden Datentypen arbeiten.
Ich werde dann noch mal kurz auf so ein paar Mitweise,
logische Operationen eingehen, wo es also darum geht,
dass also dann sämtlich im Prinzip Intager-Datentypen Nicht als Zahl interpretiert werden,
sondern einfach aus einer Ansammlung einzelner Bits.
Und ich dann eben im Prinzip jetzt auf diesem Engineer-Datentypen beziehungsweise auf
dieser Folge von Bits dann eben mitweise zwei Zahlen miteinander verrechnen kann,
quasi dann ehemals parallele Berechnung. Und gut,
da werde ich dann aber jetzt nicht weiter drauf eingehen,
aber ich denke mir,
das ist dann eben auch entsprechend klar hinsichtlich der Auswertung oder
der Berechnung logischer Ausdrücke
Habe ich dann eben entweder zur Verfügung,
sowas wie Operatorprioritäten, dass die unterschiedlichen Operatoren,
beziehungsweise zumindest die Negation und die anderen Operatoren,
also unterschiedliche starke Wichtungen haben, dann in dem Programmiersprach,
noch dazu kommen noch noch Beispiele,
werdet man also typischerweise, also eben irgendwelche Butschenausdrücke,
so aus, dass ich in Strikter Reihen folge,
wie sie quasi kodiert sind,
von links nach rechts anfange,
die Ausdruck zu berechnen
Denn mir entweder diese Auswertungsreihenfolge beziehungsweise die Operatorprioritäten,
sagen wir mal so, jetzt nicht passen,
habe ich natürlich wie üblich in irgendwelchen arathmetischen Ausdrücken auch dann also die Möglichkeiten,
dort also eine Klammerung vorzunehmen, um dann eben explizit zu sagen,
in der und der Reihenfolge soll jetzt irgendwas ausgewertet werden.
Gut, welche Vergleichsoperatoren gibt es? Das sind im Prinzip dann,
genau, Gleichheit, Ungleichheit, größer gleich, größer,
kleiner oder kleiner gleich. Nicht damit werden dann jeweils Zwei Zahlen
verglichen und als Ergebnisse erhalte ich dann eben einen logischen Wert,
der dann quasi in der jeweiligen Programmiersprache beschrieben ist.
Diese Vergleichsoperatoren sind in Java im Prinzip auf allen Indiger-Werten möglich,
wobei Indiger-Werte quasi immer als Zweier-Kompliment zahlen, interpretiert werden.
In C habe ich eben die Unterscheidung, jetzt hinsichtlich eine Deklaration,
ob ich da dann eben Signed- oder Unsigned-Typen habe und dort
werden dann eben entsprechend da dann auch diese Vergleichsoperatoren anpassend interpretiert.
Gut, wie sieht das jetzt mit den logischen Operatoren aus?
In der Programmiersprache hat sie, habe ich also eben,
wie gesagt, diese sechs Vergleichsoperationen.
Zusätzlich gibt es da noch drei logische Operatoren.
Einmal die Negation, als Ausrufezeichen geschrieben,
ein logisches und durch
zwei Kaufmanns uns
Geschrieben oder ein logisches oder, was dann zwei senkrechte Striche
jeweils sind. Ganz wichtig bei der Berechnung in See,
ich hatte ja gesagt, da sieht das so aus,
dass im Prinzip alle Integerts,
also da gibt es ja keinen speziellen Typ jetzt für Bulsche Aussagen oder Bulsche Operation,
sondern dass es eben implizit dann eigentlich für alle Engels-Werte definiert.
Da sieht es jetzt von der Aussagenlogik her so aus,
dass im Prinzip der Zahlenwert null dann der logischen Null oder
quasi dem Falls entspricht und alle anderen Werte.
Egal, was dort letztendlich als Zahl hinterlegt ist oder geschrieben ist,
entsprechend dann eben der logischen Eins oder dem Two.
Das führt eben dazu, dass man da dann entsprechend aufpassen muss,
weil das eben wirklich eine völlig andere Semantik ist als das,
was man natürlich jetzt natürlich in der Mathematik oder in der mathematischen Operation gewöhnt ist.
Also das heißt, da wird immer nur unterschieden,
ist eine Zahl Null und wenn sie ungleich Null ist,
dann ist sie ihm quasi Tru. Das heißt,
wenn ich mit diesen Operatoren in irgendwelchen Ausdrücken arbeite,
musste ich das dann also letztendlich dann beide Programmierungen irgendwo im Hinterkopf haben,
dass ich da dann eigentlich jetzt eben nur diese beiden Werte unterscheide.
Gut, bei den logischen Operationen in See findet dann eben in der Regel
auch immer so eine verkürzte Auswertung statt von links nach rechts.
Es sei denn, ich habe es jetzt also explizit
mit Klammern noch irgendwie anders erzwungen. Das führt dazu,
dass wenn ich Schon definitiv das Ergebnis feststehen habe,
weil ich jetzt eben weiß,
ich habe meinetwegen als Ergebnis tue und das wird jetzt mit irgendwas anderem verodert,
dann kann dort eigentlich immer nur Truhe rauskommen.
Dann wird quasi dieser zweite Teil dann eben nicht weiter ausgewertet oder eben entsprechend andersrum,
wenn ich also False habe und das wird mit irgendwas logisch verwundet,
dann ist eben False und irgendeine andere Aussage auch immer False
Das kann, dazu kommen dann gleich noch Beispiele,
dann also auch immer ganz gerne benutzt werden,
um in irgendwelchen arathmetischen Ausdrücken quasi sowas wie irgendwelche impliziten Schutzfunktionen einzubauen.
Das heißt, ich kann eben zum Beispiel abfragen,
ob ich irgendwo einen Nullpointer habe. Und nur wenn der
eben ungleich Null ist, dann darf ich den letztendlich dir referenzieren.
Und anstatt das jetzt also irgendwie mit einer IF irgendwas gleich null Abfrage säen und dann entsprechend weiterzuarbeiten,
kann ich das dann eben über so eine verkürzte Auswertung direkt in einem Ausdruck bringen.
Das Beispiel konnte also auch gleich noch. Auf der anderen Seite muss man immer so ein bisschen aufpassen mit dieser Verkürzten Auswertung,
weil das kann letztendlich auch Seiteneffekte haben,
wenn ich quasi weiter hinten in meinem Ausdruck dann also irgendwie sowas wie Funktionsaufrufe mit drin habe,
wo ich dann also letztendlich sage, na gut,
also ich rufe deine Funktion auf,
die liefert mir dann wieder einen Bullshit-Ergebnis.
Ich kann mir dann eben nicht mehr sicher sein,
dass diese Funktion dann eben auch wirklich aufgerufen worden ist.
Und wenn diese Funktion jetzt eben noch mehr macht oder mehr tut,
als jetzt eben nur Druck oder False zurückzuliefern, kann man sich damit dann also auch gelegentlich irgendeinen Fehler einbauen. Gut,
kurze Beispiele zu logischen Operationen in C,
also dieses wäre jetzt hier mal so ein Ausdruck,
wo ich also quasi frage, ah, größer,
B oder B und Leicht C und B,
kleiner Gleich D und für kurze Auswirkungen würde eben heißen,
dass wenn also hier vorne dieser Ausdruck schon Truhe ergibt,
also A größer als B ist,
dann wird also hier hinten quasi jetzt gar nichts mehr verglichen und diese Dieser zweite Ausdruck,
der jetzt also hier explizit erst mal geklammert ist, also dann nicht weiter ausgewertet.
Nur um noch mal eben zu veranschaulichen, wie das jetzt eben mit diesem,
dieser Interpretation integernol als False und into john Leichenol als Puh ist,
wenn ich jetzt also hier ein Hexer-Dezima geschriebenen Wert,
also in diesem Fall 4-1 nehme, negiere,
oder logisch negiere, erhalte ich dann quasi als Wert null,
wenn ich die null nehme und logisch energiere,
erhalte ich dann eben Ein Wert, Ungleichnull,
in der Regel wird das dann immer gewährt eins sein,
der dann quasi dem Truh entspricht und 0-2 mal negiert ist,
null.
Hier wäre jetzt quasi irgendein eine Zahl und eine andere Zahl,
da keine dieser beiden Zahlen letztendlich null ist.
Er gibt dieser Ausdruck quasi eins, dieser Ausdruck auch.
Und dann hätte ich dann eben eins und eins
Ist dann auch wieder eins oder war. Und
hier entsprechend hätte ich dann also irgendeinen wahre Ausdruck oder ein
wahrer Ausdruck ist dann eben auch wieder eins als Truh.
Gut, hier eben nur nochmal kurze Wiederholung nochmal zur Veranschaulichung.
Also wie gesagt, der Zahlenwert null, entspricht,
waren eben der logischen Null beziehungsweise der Aussage Falls.
Alles andere ist eins. Wenn ich das jetzt hier für zwei Zahlen oder zwei Beispiele mache,
also in diesem Fall jetzt 0X66 und 0HX 93,
als Logische Operation würde dann eben jede dieser Zahlen quasi hier zu dem Wert tue oder eins,
interpretiert werden.
Wenn ich die beiden miteinander verknüpfe, wäre das Ergebnis dann eben
auch wieder eins oder war sowohl für und als auch für oder.
Wenn ich das negiere, erhalte ich dann eben null oder entsprechend den zweiten negiert,
ergibt als Ergebnis dann eben auch wieder null oder Falls.
Und hier hätte ich dann eben X selber,
also was also quasi Truh wäre und Y negiert.
Und davon an die negierte Aussage wäre dann eben False,
demzufolge das Ergebnis auch. Und das verhält sich eben grundsätzlich
anders, als wenn ich das jetzt mit Mitweisenoperationen mache.
Das ist das, was jetzt also hier auf der
linken Seite dargestellt ist
Ich also den Wert bitweise quasi interpretiert. Hätte ich dann also hier
quasi einfach ganz normal meine Zahlendarstellung. Mich und hier,
also das ist jetzt quasi schon mal vorgegriffen, es kommen gleich zwei Folien später.
Wer jetzt also die Schreibweise für so eine Bitvises und Bitvises
oder beziehungsweise die hier diese Tilde ist eine Bitvises-Negation.
NC nicht. Und wenn ich mir da dann eben hier
die entsprechenden Ausdrücke ansehe bzw. bilde,
dann hätte ich jetzt also quasi jetzt hier als Bitvises und 0 und 1 ist 0,
1 und 0 ist auch null.
Nicht und nur hier in diesem einen Fall,
wo ich eins und eins habe,
würde dann eben hier einem Ergebnis von X und Y dann
eben die 1 rauskommen beim oder hätte ich entsprechend diesen Vector und hier
die anderen Beispiele kann man sich dann eben analog dazu überlegen.
Das heißt also hier sieht man dann eben wirklich sehr schön,
wie man da jetzt nicht die gesamte Zahl als Falls beziehungsweise
null oder eben als eins, als Two interpretiert,
sondern wie dann wirklich jeweils parallel für sämtliche Bits in diesen Zahlen wert,
dann eben die entsprechende Operation angewandt wird.
Gut, die verkürzte Auswertung hatte ich ja eben auch schon angesprochen.
Heißt halt, Ausdrucke werden von links nach rechts ausgewertet.
Logischerweise, Klammern werden berücksichtigt,
wenn nicht bei der Auswertung eben schon irgendwo feststehen habe,
dass ein bestimmtes Ergebnis rauskommt
Wird das Ganze dann eben abgebrochen. Bin ich und wie gesagt, Vorteile.
Oder hier jetzt mal zwei Beispiele für solche Vorteile wären,
jetzt eben, nicht, dass ich quasi hier in diesem Ausdruck logisch und fünf durcha, berechne.
Und in diesem Fall heißt das eben, dass nur in dem Fall,
wenn A, Ungleichnull ist, also quasi hier dieser zweite Ausdruck 5 durch A, ausgewertet wird.
Und das passiert dann eben, damit sorge ich dann eben dafür,
dass ich quasi niemals in eine Division durch Null rechne,
nicht und hier entsprechend wäre dann eben dieses Beispiel mit diesem Null-Point-Ad-Zugriff,
dass eben diese der Referenzierung von dem P,
was ich dann also quasi als Pointer-Adresse interpretiere,
hier in diesem Ausdruck dann eben nur passiert,
wenn das eben Ungleichnull ist.
Gut, dann haben auch schon mal vorneweg gegriffen natürlich,
also auch beide Programmiersprachen, sowohl CIA als auch Java,
dann noch einen sogenannten ternären Operator, was dann im Prinzip sowas ist,
wo abhängig von einer Bedingung zwei Ergebnisse oder eins von zwei möglichen Ergebnissen dann quasi geliefert wird.
Nicht, was dann eben so aussieht,
dass ich also hier irgendwo einen Ausdruck für eine Bedingung habe,
der mir also eben True oder False liefert,
dann ein Fragezeichen, dann eben ein Ausdruck, der zurückgeliefert wird,
wenn dieses hier vorne True ergibt und dann mit einem Doppeltpunkt getrennt eben ein Ausdruck,
der zurückgeliefert wird oder ausgewertet wird, wenn das Ganze eben False ergibt.
Nicht nur damit kann man da also sehr einfach sehr kompakten Code schreiben.
Also wenn ich jetzt eben den Absolutwert einer Zahl X bestimmen will,
dann kann ich das eben dadurch machen,
dass ich also hier quasi in Klammern sage, X kleiner Null.
Und wenn das der Fall ist,
dann wird minus X zurückgeliefert und wenn das nicht der Fall ist,
also sprich X größer gleich Null ist, liefere ich X selber zurück.
Gut, wie sieht das in Java aus? Da gibt
es eben diesen expliziten Datentyp Bulien mit den beiden Werten,
Force and True, beziehungsweise aus der Klasse Bulien könnte ich dann also auch diese Werte nehmen.
Dort gibt es also jetzt nicht dieses Mischverhalten wie NC mit irgendwelchen Intager-Werten,
wo ich jetzt, also montagmitte Intager-Werten rechne. Das ist ja immer das,
wo dann eigentlich auch viele jetzt bei C letztendlich als Kritik anbringen,
dass es da dann keine strikte Typbindung gibt,
sondern dass sich also eine Zahl mal als Bullschen-Wert mal als arrometischen Wert,
also sprich irgendwie als Zahlenkodierung, interpretiere,
mal als eine Folge von einzelnen Bits oder eben mal als eine Adresse,
die jetzt also beispielsweise auf irgendeine Re-Element verweisen kann
Auch in Java habe ich also die üblichen sechs Vergleichsapparatoren.
Auch dort gilt dann also bei irgendwelchen Boots schon Ausdrucken.
Es gibt dann diese verkürzte Auswertung. Das heißt,
das ist eigentlich genau das,
was ich vorher schon vorgestellt hatte und eben auch diesen tiernäheren
Operator auch mit identischer Schreibweise gibt es dort entsprechend.
Gut, die mitweisen logischen Operationen hatte ich
ja eben schon an einem Beispiel
kurz vorgestellt
Grundidee ist eben wirklich, dass ich also Indiger-Datentypen doppelt nutze.
Zum einen letztendlich als Zahlenwert, wo ich dann eben sage,
das ist eben entweder eine Unsigned-Zahl oder eben eine Zweier-Kompliment,
Sciencesal oder, je nachdem, was für ein Format das ist,
dann eben irgendeine Gleitkomma dargestellte Zahl.
Und mit diesen Zahlen kann ich dann eben wirklich mit Arenhmetischen Operationen
rechnen oder auf der anderen Seite, dass ich eben sage,
der Indiger-Wert ist für mich erstmal ein Wie?
Bit breites Wort. Und ich kann dann eben mit diesen Grundfunktionen,
Negation und oder XOR dann eben direkt mit irgendwelchen Bult- und Verknüpfungen,
Bitweise auf allen Bits rechnen.
Nicht und zusätzlich gibt es dann eben auch noch als
spezielle Operation auf solchen Bit wegpornen,
also bestimmte Schiebe oder Rotationsoperationen,
die ich dann also auch gleich noch vorstelle
Gut, diese Bitweisen logischen Operationen sehen jetzt also in beiden Programmiersprachen dann eben so aus,
wie das, was hier eben auch schon auf der einen Folie kurz dastehen hatte,
also die Negation, also sprich das Invertieren,
einzelner Bits, geschieht eben durch so eine Tilde.
Das Logische unter einzelnen Bits wird durch das Kaufmannsohn kodiert,
das Logische oder als senkrechter Strich und das Exklusiv-Oder
dann eben durch so
ein Dach
Auch eingangs bei den Folien zur Bulschen Ärgerbar, hatte ich also schon gesagt,
also mit diesen Funktionen habe ich dann im Prinzip eine vollständige Basismenge,
kann damit also letztendlich sämtliche Funktionen irgendwie darstellen.
Und wenn ich generell jetzt erstmal sage,
ich habe eine mögliche Funktion mit N-Operanten,
dann gibt es jetzt eben jeweils für N-Operanten,
wenn ich jetzt also quasi mit den mitwerten 0 und 1 arbeite oder unterscheide,
zwei hoch N-Kombinationen, die diese Operanen quasi einnehmen können oder die ich unterscheiden muss.
Und für jede dieser Kombinationen habe ich dann eben zwei mögliche Ausgangswerte,
sodass insgesamt die Anzahl der Funktionen,
die ich mit in Operanten dann also letztendlich unterscheiden müsste,
dann eben entsprechend die Potenzmenge von dem zwei Hoch-N ist,
also sprich zwei hoch zwei Hoch-N. Gut,
bitweise logische Operationen waren ja eben schon in dem Beispiel,
nicht also hier nochmal für zwei Zahlen
X und
Hier einmal diese Zahn, X und Y,
Bittweise invertiert, nicht hier jetzt eben mit einem Mitweisen unverknüpft,
wo ich dann eben nur genau in dem Fall,
wo jetzt eben beide,
also sprich an dieser Stelle und an dieser Stelle eine Eins haben,
eine Eins habe, alles andere,
es wäre eine Null mit einem Mitweisen oder verknüpft,
würde eben nur an dieser Stelle,
wo beide oder die entsprechenden Bits von X und Y 0 sind,
eine Null geliefert werden in allen anderen Fällen eine Eins und das Bidvised X or
Warum man sich dann eben entsprechend aus überlegen,
also null und eins, oder null xor 1 wäre 1, 0
x or 0 ist 0, 1, Xor 0 ist auch null.
Hier wieder eine 1, 1, Xor 0,
entsprechender wieder 1, 1, 0, 1.
Womit ich das dann hier? Unten als Ergebnis hätte. Gut,
neben diesen Betweisen-Operationen kann ich jetzt bei so einer Interpretation von Integration-Zahlen
jetzt eben als ein Wort von Bits auch noch Skiva-Operationen anwenden.
Diese Schieberoperationen sind dann im Prinzip auch erst mal für alle Integrer-Datentypen verfügbar.
Unterschieden werden dabei fünf Varianten, Links schieben, logisches Rechts schieben,
arathmetisches Rechts schieben und links rotieren beziehungsweise rechts rotieren.
Solche Schieberoperationen findet man Bei den meisten Prozessoren auch irgendwo direkt im Befehlssatz,
weil die ja sind,
Hardware dann eben auch vergleichsweise leicht zu realisieren sind,
wobei man da dann auch aus, sagen wir mal,
Effizienzgrund meistens auch Einschränkungen hat,
dass dann also vielleicht nicht alle Wort oder alle Werte von möglichen Wortbreiten implementiert sind,
aber gut, dass es dann also letztendlich dann wirklich von der Hardware speziell abhängig.
Gut, wie funktioniert das Schieben?
Links schieben
Kann man sich eben so vorstellen,
wie das letztendlich hier in dieser Grafik dargestellt ist.
In diesem Fall wird jetzt also hier um ein Bett geschoben.
Das heißt, bei dieser Eingangszahl werden jetzt jeweils alle stellen und
einen nach links verschoben. Alles, was links steht,
in diesem Fall jetzt beim Schieben um ein Bett,
wird also das erste Bett hier quasi rausgeschoben und rechts,
wird dann in diesem Fall jetzt also eine einzige Null
mit zusätzlich eingefügt
Die Operation selber ist eben sowohl in Java als auch in C,
direkt als Operator verfügbar. Wird dann quasi immer kodiert durch
zwei solcher Klarzeichen und das Linksschieben um N-Bit entspricht,
mathematisch gesehene Multiplikationen mit zwei Hochennen. Das heißt, wenn ich jetzt sage,
das ist jetzt hier letztendlich eine Zahl, erst mal in Unsigned-Darstellung,
Ich würde die jetzt also um ein Bett nach links schieben,
wie das also jetzt hier angedeutet ist.
Nicht, dann wäre das,
dass es letztendlich genau diese Zahl mal zwei multipliziert,
war es ja dann also nichts anderes, ist es,
als dass sie dann eben letztendlich noch eine zusätzliche Stelle habe,
das niederwärtigste Bit ist dann nämlich genau null und entsprechender Stellenwertigkeit ist jetzt quasi jedes Bit eine Zweierpotenz letztendlich weitergerückt.
Und das, was vorher quasi zwei hoch null war,
wäre jetzt eben hier zwei hoch eins, das,
was zwei hoch eins war,
wäre jetzt hier zwei hoch zwei und so weiter
Ja. Das ist jetzt ein 6. Bestes oder so,
aber ja, wo geht jetzt das?
Was macht man mit den Bandzeiten? Das ist schlecht. Nee,
also beim, also bei diesem Linksschieben wird jetzt erstmal nichts
weiter irgendwie je nach hinten geschoben,
sondern da sieht das wirklich so aus,
dass hinten immer eine Null reingeschoben wird.
Egal was letztendlich hier vorne steht
Deswegen hatte ich jetzt ja,
also mit dieser Multiplikation mit zwei Hochend erstmal gesagt,
also ich kann jetzt natürlich wieder genau den Fall konstruieren,
wo ich also hier irgendwo eine Folge 0-1 habe,
dass die jetzt zum einen wird schieben würde und hätte dann
also hier auf einmal als Ergebnis eins und dann geht das irgendwie weiter.
Und wenn ich dann sage, okay,
das interpretiere ich jetzt als Zweierkomplimentszahl, nicht dann funktioniert das nicht,
dann muss ich aber eben auch sagen,
gut,
wenn ich jetzt bei einer Art Metik mit fester Wortbreite bin,
hätte ich dann eben durch diese Multiplikation eigentlich auch schon wieder
meinen Zahlenbereich verlassen und das entspricht dann eigentlich genau in diesem Zahlenkreis quasi einmal,
also einer Drehung um 180 Grad
Und dadurch habe ich dann eben letztendlich nachher den falschen Wert
dann erhalten. Aber egal, was hier vorne,
also in diesem Fall ist es jetzt hier eine Null,
die rausgeschoben wird, aber egal, was das hier ist,
es wählen von rechts immer Nullen nachgeschoben.
Das, was sie sonst meinten oder angesprochen haben,
kommt leicht, das sind ja diese Routierbefehle,
wo dann das, was also hier quasi rauswandert, hier reingeht.
Generell bei diesen ganzen Beispielen muss man natürlich sagen, je nachdem,
also auf was für einem Rechner oder was für einer Zahlendarstellung ich bin,
gehe ich natürlich jetzt immer von einer impliziten 16, 32 oder 64-Bit-Darstellung aus.
Und wenn ich jetzt zum Beispiel, also irgendeine variable habe
von einem bestimmten Enteger-Typ und dieser Variable jetzt eine Zahl zuweise,
dann wird die natürlich irgendwo als entsprechender Bitstring jakodiert.
Und angenommen, das wäre dann eben sowas wie jetzt,
also irgendwie Zweierkompliment wird dann eben auch wirklich passend
Entweder bei einer positiven Zahl, dann eben über Science Extension
quasi eine entsprechende Anzahl von Nullen, links eingefügt,
bei den höchstwertigsten Bits oder wenn das eben eine negative Zahl ist,
dann eben entsprechend viele A-Einzeln.
Und insgesamt habe ich dann,
aber bei diesen Schiebeoperationen dann eben wirklich immer nur einen entsprechend breiten Vektor,
wo ich dann einfach nur sage, da fliegt was raus und da kommt was rein.
Gut, beim Linksschieben, wie gesagt,
Sieht das so aus, alles, was links steht,
fällt raus und rechts werden immer nur 0 nachgeschoben.
Beim Rechtsschieben gibt es jetzt die kleine, aber feine Unterscheidung,
also ob ich ein logisches oder ein arathmetisches Rechtsschieben mache.
Das logische Rechtsschieben, nicht deswegen,
also auch oft dann als SRL-Shift Ride Logical,
abgekürzt, ist quasi das Äquivalent zu diesem Shift Left.
Da wird einfach von links nach rechts geschoben. Das,
was sie am weitesten rechts steht, egal was es auch sein mag,
Fliegt raus und links wird immer eine Null reingeschoben.
Diese Operation ist eben in der Promi-Sprache Java direkt als Operator verfügbar,
wird dann dort kodiert durch drei solcher Größerzeichen,
indem ich dann eben sage,
ich nehme jetzt hier sich hier quasi meine Zahl X und schiebe die um N. Bit.
In C ist dies logische Rechtsschieben nur für Anzahlen,
Typen definiert
Weil, wenn ich also quasi sowas wie eine Science-Zahl habe oder hätte,
dann wird die auch immer nur arethmetisch geschoben. Das heißt,
da waren das hier links eben nicht zwingend eine Null rein,
sondern da wird dann eben entsprechend das Vorzeichenbett vervielfältigt.
Wie gesagt, also bei Java gibt es dann eben wirklich explizit
diese Unterscheidung und da ist es direkt verfügbar bei Segel,
das dann also nur für Anzahl-Typen,
ist dann mit diesen beiden größer Zeichen kodiert
Und da entspricht das dann nämlich eigentlich auch von der Funktion her genau dem Arrathmetischen,
rechts schieben, wo ich dann eben entsprechend sage,
okay, hier auf der rechten Seite ändert sich nichts.
Das, was dort steht, geht dann eben entsprechend,
je nachdem, wie weit ich schiebe, N-Bit verloren, beziehungsweise werden abgeschnitten.
Es wird dann aber eben letztendlich nicht fix hier eine Null reingeschoben,
sondern das Vorzeichen-Bit, also sprich das more significant bittet,
die dort also quasi jetzt als Operant in den Schiebebefehl benutzt wird,
wird dann eben entsprechend oft hier eingefügt.
Das heißt also, beim Schieben von um eins,
wie jetzt hier in diesem Beispiel, wird das eben genau einmal verdoppelt.
Und wenn ich jetzt eben hier als Most Significant Bitner 1 stehen habe,
hätte ich dann eben hinterher 2-1. Nicht deswegen arathmeter zu schieben,
weil wenn es eine positive Zahl ist,
das heißt hier eine Null steht,
dann hätte ich hier eben auch hinterher eine Null
Da ist das Ganze dann letztendlich von der Funktion her genau das
gleiche Ergebnis wie das logische Rechtsschieben. Die Unterscheidung kommt jetzt eben nur,
wenn das eine negative Zahl ist,
wo ja dann das Most Significant Bit bei einer Zweier-Kompliment-Darstellung immer eine Eins ist,
dass die dann eben entsprechend vervielfacht wird und ich dann eben auch als Ergebnis immer eine negative Zahl erhalte.
Das aratmetische Rechtsschieben wird dann letztendlich,
also in beiden Programmiersprachen dann also beschrieben,
also durch diese beiden
Größer Zeichen. Wie gesagt,
also in Java gibt es da dann eben entsprechend noch diese Unterscheidung zwischen,
also jetzt hinsichtlich der Schreibweise,
jetzt aratthmetischem und logischen Schieben in C, kann ich sagen,
okay, da ist dieses arathmetische Rechtsschieben dann eben nur für Zahlentypen definiert,
beziehungsweise, letztendlich könnte ich auch sagen,
okay,
also bei Ansign-Typen gilt das nicht,
beziehungsweise da habe ich dann eben immer
nur ein logisches Schieben
Ähnlich wie ich jetzt sagen kann,
also quasi ein Shift Left entspricht jetzt eigentlich einer Multiplikation mit zwei Hochennen,
wenn ich jetzt also um NBit schiebe,
dann ist also quasi ein arathmetisches Rechtsschieben,
ich sage jetzt erstmal ähnlich der Division durch zwei Hochennen.
Stimmt also jetzt arathmetisch nicht ganz. Beispiel dazu kommt gleich
noch, weil also bei negativen Zahlen im Prinzip in die
falsche Richtung gerundet wird
Weil dadurch, dass ich quasi hier immer Bits abschneide,
also die dann rechts rausfallen, führt das dazu,
dass ich eben immer in Richtung der kleineren Zahlrunde.
Und bei positiven Zahlen stimmt das,
Arrethmetisch jetzt als Ergebnis, wenn ich negative Zahlen habe,
müsste ich aber in Richtung der Betragsmäßig kleineren Zahlrunden,
also sprich in Richtung der Null.
Und genau das mache ich da eben nicht.
Wie gesagt, das Beispiel dazu kommt gleich,
wo man das also dann
sehr schön sieht
Gut, arenthmetisches Recht schieben also hier jetzt eben nochmal für eine,
in diesem Fall als positive Zahl X,
wo also der Hexadezimalwert 10D3,
kurdiert hier als dieser String bzw. dezimal
4307. Nicht jetzt um ein Bit nach rechts schiebe und das
ergibt dann ihm quasi jetzt diesen String als Ergebnis bzw. wenn
ich das dann dezimal darstellen würde,
wäre das 20100
Beziehungsweise da habe ich dann entsprechend einen Wert. Und hierbei schieben wir
jetzt um drei Stellen, wo dann eben aus diesem Wert,
beziehungsweise dezimalern, minus 28.460, dann dieser String,
hier unten wird, war es dann eben minus 3.558
dezimal entsprechen würde. Wenn ich das jetzt also als Zahl interpretiere.
Ansonsten benutzt man also gerade natürlich jetzt diese Schiebeoperation dann eben
auch häufig für irgendwelche Maskierung für irgendwelche Operationen,
wo ich jetzt also aus längeren Bitstrinks jetzt also einzelne Teile herausnehmen möchte.
Also auch dazu kommt dann gleich noch Beispiele, beziehungsweise da wird dann auch teilweise in den aktuellen Übungsaufgaben dann noch ein bisschen was nachgefragt. Gut mit der mit diesem Rechtsschieben,
Division durch Zweierpotenzen, hat er ja schon gesagt, also wie gesagt,
bei positiven Werten entspricht das eigentlich genau die Division durch Zweierhoch-N,
bei negativen Werten deswegen jetzt eben genau diese Einschränkung,
passt es eben nicht ganz,
weil wenn ich jetzt also im Prinzip jetzt,
also hier für eine,
in diesem Fall jetzt mal Zahlendarstellung hier mit acht Bit nehme und sage,
ich habe hier so eine minus fünf,
die wird jetzt arm um einen geschoben,
dann erhalte ich quasi als Ergebnis minus drei Nicht wo dann also quasi statt dem minus 2,5 das dann eben in diesem Fall jetzt eben in die zunächst kleineren Zahl und nicht in Richtung zu Null.
Also in diesem Fall wäre dann nämlich das arathmetisch richtige Ergebnis,
wenn ich runde, müsste es eigentlich minus zwei sein.
Und hier dann eben entsprechend das, da sieht man das.
Als Beispiel, wie man da dann,
aber auch in diesem Fall zu arathmetisch richtigen Ergebnissen kommen kann
Hier also nur nochmal der Verweis,
also in dem Buch von Brian und nur Heilerin,
ist dann zum Beispiel noch mit angegeben,
dass man also noch über einen entsprechend eingebrachten Ausdruck,
wo ich also quasi zu dieser Zahl,
bevor ich schiebe, noch eine Korrekturzahl dazu addiere,
die dann also mal jetzt so klein ist,
dass sie dann also nachher bei dem Schieben rausfällt,
im Prinzip aber durch diese Addition an entsprechender Stelle,
dann schon einen Übertrag erzeugen kann und der führt dann dazu,
dass hinterher das Ganze dann eben Auch in die richtige Richtung gerundet wird,
während diese Korrekturzahl wäre dann eben letztendlich,
dass ich also, wenn ich um Carbit schiebe,
eine Eins nehme,
die eins erstmal um Karstellen nach links schiebe,
sodass sie also quasi entsprechend genau an der niederwähligsten Stelle von der Zahl liegt,
die dann also da nachher geschoben wird und davon dann aber wieder in einen abziehe.
Und wenn man das dann also wirklich jetzt für unterschiedlichen Beispiele
mal durchspielen würde, würde man dann eben sehen,
dass das dann eben auch für diesen Fall der negativen Werte
dann zu arenhmetisch richtigen Ergebnissen führt
Gut, neben diesen Schieberoperationen gibt es dann eben noch Rotierbefehle,
wo dann im Prinzip das, was beispielsweise jetzt beim Rotate Left links rausgeschoben wird,
also dann eben auch wirklich genau auf der rechten Seite wieder eingefügt wird.
Solche Rotierbefehle sind, sagen wir mal,
sind Java und dann C in der Regel nicht direkt als Operator verfügbar,
beziehungsweise in Java gibt es dann also in der Indiger-Klasse dann also noch einen entsprechenden Befehl, der sowas liefert.
Teilweise, wenn man jetzt also direkt noch in die drunterliegende Hardware geht,
beziehungsweise dort beim Hardwareentwurf arbeitet, da tauchen dann also solche Befehle wieder auf,
weil die im Prinzip ähnlich wie jetzt irgendwelche Schiebebefehle natürlich vergleichsweise einfach zu realisieren sind.
Nicht weil das, was dort eigentlich immer nur passieren muss,
was ja dann also auch sich hier in dieser Darstellung immer irgendwie entsprechend niederschlägt,
ist, dass ich einfach nur sage, na gut,
ich habe hier ein Register,
wo jetzt also irgendeine Zahl gespeichert ist,
Und hier ein anderes Register, in die diese Zahl reingeschrieben wird.
Und das, was also hier quasi diese Pfahldarstellung entspricht,
das wäre dann eben einfach eine Leitung, die dann eben von dem wird,
aus diesem Ausgangsregister in dieses Bit eines Quellregisters geht.
Und das ist natürlich Hardware-mäßig dann, also vergleichsweise einfach wieder zu realisieren.
Also deswegen werden solche Befehlern teilweise darin doch gerne gemacht oder eingesetzt.
Gut, beim Rechtsschieben entsprechend analog dazu, das heißt,
um Enbit nach rechts. Das, was sich rechts rausschiebe,
wird dann eben in identischer Reihenfolge links dann wieder reingefügt.
Und also auch da gelten dann eben diese entsprechenden Aussagen von eben analog zu dem Rotät-Left. Gut,
jetzt hat er ja schon gesagt,
also bei dem Schieben, zumindest beim Linksschieben,
wo ich mich also jetzt nicht irgendwie um positiv oder Negativdarstellung kümmern muss,
entspricht das dann ja eigentlich immer der Multiplikation mit zweier Potenzen,
also sprich mal zwei hochenden,
wenn ich um Enbit schiebe
Das wird hardwareseitig gerne eingesetzt,
wenn ich mit Konstanten in meinem Programm rechnen muss,
wo ich dann also im Prinzip statt irgendeiner Enager-Multiplikation mit einer Konstanten
das Ganze ersetze durch eine entsprechende Kombination von Schieberoperationen bzw. Schieberoperationen
und Additionen.
Mache ich sowas jetzt überhaupt, wo ich jetzt sage,
na gut, also ich habe auch im Prinzip einfach nur A mal B
und nicht das eine von denen ist eh eine Konstante, nicht und warum?
Er setzt sich das jetzt durch irgendwie schieben und addieren und
was weiß ich noch alles, was da gemacht werden muss.
Grund dafür ist im Prinzip das Multiplikation, also auch eine Enager-Multiplikation,
also Hardware-technisch gesehen, doch deutlich aufwendiger ist,
als also im Prinzip sowas wie Schieben oder wie Addition.
Deswegen kann man eigentlich immer sagen,
dass es also wirklich in der Hardware oder auf den Prozessoren in der Regel langsamer ist,
beziehungsweise häufig auch gerade so bei irgendwelchen sehr kleinen,
eingebetteten Systemen, also sprichst du den typischen Controllern,
die sich ja jetzt in irgendwelchen kleinen Mobilgeräten oder in Haushaltsgeräten oder was weiß ich wo befinden, sowieso gar nicht vorhanden ist.
Und dort basiert dann eben Folgendes, dass ich sage,
na gut, also für eine Addition oder für eine Subtraktion
und für irgendwelche logischen Operationen brauche ich in der Regel eben irgendwie einen Takt,
für Schiebeoperationen braucht man meistens auch einen Takt,
bei einigen krummen Sachen können das also vielleicht auch nochmal mehr werden,
aber Es ist immer noch vergleichsweise wenig aufwendig.
Und dann kann man eben folgendes machen, dass ich im Prinzip
Multiplikationen mit Konstanten durch entsprechende Kombinationen von solchen Schieben beziehungsweise Additionsoperationen ersetze.
Als Beispiel, wenn ich jetzt sage,
also ich möchte rechne neunmal x, dann kann ich sagen,
das ist acht plus eins, mal x,
nicht nur achtmal x, wäre jetzt eben x,
um drei Stellen nach links geschoben.
Und wenn ich dann sage, okay, acht x ist dieses hier,
Plus ein X. Dann habe ich im Prinzip jetzt,
also dieses 9x X ersetzt durch eine Schiebeoperation und eine Addition.
Und je nachdem, was letztendlich die Hardware da drunter liefert,
sind natürlich dann also auch Compiler in der Regel dann schon so schlau,
dass sie dann eben wirklich gucken, okay,
was kann ich auf der Hardware rechnen,
beziehungsweise wenn ich eben solche Fälle habe,
wo das jetzt eben hier konstanten sind
Und ich habe jetzt eben gar keine Hardware-Multiplikation oder die ist eben entsprechend aufwendig,
dann wird das eben durch so einen Ausdruck,
wie jetzt hier angedeutet, ersetzt.
Ich als Programmierer bekommt man davon nun glücklicherweise nichts mit.
Also da muss man sich jetzt nicht noch irgendwie Gedanken machen oder anfangen,
da was zu optimieren, beziehungsweise das kann man machen,
aber da sind eigentlich die Compiler inzwischen so gut,
dass sich das da eigentlich nicht lohnt,
beziehungsweise da dann eher nur zu irgendwelchen Programmierfehlern führt,
wenn man jetzt anfängt,
da selber irgendwelche Tricks da rein zu machen
Gut, eine andere Funktion oder Funktionalität,
die man also bei solchen Bits drinkst,
dann also häufig benötigt, ist,
dass sich an einer bestimmten Position in ein einzelnes Bit setzen möchte oder löschen möchte.
Das funktioniert eben in der Regel immer dadurch,
dass ich mir erstmal eine Maske erstelle,
die eben genau ein einziges Bit nur gesetzt hat,
was sich dann eben an passender Stelle habe.
Das erzeuge ich im Prinzip jetzt
genau mit diesem Ausdruck eins
Nach links geschoben, OP stellen. Und damit habe ich dann im Prinzip genau einen Vektor,
der dann aus lauter Nullen besteht und dann eben hier an einer Petenstelle eine Eins.
Und um jetzt also ein Bit quasi zu setzen,
also wenn ich das jetzt mal so hier als Funktion definiere,
könnte ich dann eben sagen,
ich habe hier ein Indiger X, meine Position,
nicht um das Ergebnis wäre dann X oder dann eben diese Maske hier,
und egal was dann eben letztendlich an dieser Stelle Position in meinem BitVactor X steht,
also durch diese Maske wird das dann eben mit dieser Bitweisen- oder Verknüpfung zumindest explizit an dieser einen Stelle dann gesetzt.
Nicht und zum Bit löschen,
im Prinzip genau das ähnliche oder analoge Verfahren dazu,
dass ich eben auch jetzt hier wieder eine Eins an entsprechende Stelle schiebe,
mit dem Tildo-Operator, bitweise Negation,
erzeuge ich mir damit also quasi eine Maske,
die lauter Einsen besitzt und dann eben nur an dieser einen einzigen Stelle eine Null.
Nicht und das wird jetzt quasi mit einer Unverknüpfung oder mit einem Wittweisen und mit meinem Vactor X verknüpft.
Nicht und damit ist er so quasi gewährleistet,
dass eben genau an dieser einen Stelle Position dann eben das eine Bit,
was vielleicht in X gesetzt war, gelöscht worden ist. Andere Beispiele,
wo man dann eben auch mit diesen Operationen viel arbeitet,
ist, um jetzt einzelne Bytes in Speicherworten hin und her zu tauschen,
wofür man das braucht, kommt also dann gleich nochmal das passende Beispiel,
hier nun mal ein Ausschnitt aus dem entsprechenden Code dazu,
also auf irgendein,
ich sag mal jetzt sämtlichen Linux-Rechnern wird unter User Include Bits,
Bytes 4 Punkt H,
also irgendwo unter anderem,
dann also hier sowas in der Art definiert sein
Eine Funktion, wo jetzt im Prinzip für einen,
in diesem Fall 32 Bitwort, die einzelnen Bytes vertauscht werden,
dass das am weitesten linksstehende Byte hinterher rechts landet,
dass am weitesten rechts stehende links und die beiden in der Mitte dann eben auch gegeneinander vertauscht worden sind,
nicht damals,
dass es also da jetzt hier mit diesem Swapping gemeint,
nicht und das Ganze wird eben erreicht durch folgenden Ausdruck,
von der Idee her sieht das immer so aus,
ich habe hier meinen Vector X,
in diesem Fall jetzt eben als 32 Bitwort.
Der wird quasi jetzt hier mit diesem FF 00000 maskiert.
Das ist ja das mit dem Kaufmanns- und das Bitweise.
Und führt genau dazu, dass ich also quasi von meinem Vektor X
nur das am weitesten links stehende Byte als Ergebnis erhalte.
Nicht und das wird dann um 24 Stellen nach rechts geschoben.
Und wenn man sich das überlegt,
führt das genau dazu, dass also quasi das,
was hier ausmaskiert wurde,
hinterher im Ergebnis,
also hier in diesen unteren beiden
Oder in dem unteren Byte, also in den unteren beiden Hexzahlen,
in dem unteren Byte landet. Hier wird dann eben das
zweite Byte genommen, ausmaskiert und dann um acht geschoben.
Das heißt, das Ergebnis landet dann eben hinterher im Ergebnis.
An dieser Stelle, hier wird dann eben dieses Byte genommen,
um acht nach links geschoben, landet an dieser Stelle.
Und hier habe ich ihm quasi das Äquivalent, zu dem ihr vorne,
wo ich dann eben die am weitesten rechts stehenden 8 Bett nehme und dann eben an dieser Stelle transportiere mit diesem Linksschieben um 24 Bett.
Gut, weitere Beispiele für irgendwelche Maskierungsoperationen,
also hier jetzt auch nun mal, rausgesucht,
nicht mal was anderes, Bildverarbeitung,
also ich habe jetzt irgendwie am Monitor irgendwie ein Farbdarstellung,
sage es also ein Bild oder besteht jetzt eben aus irgendwie einzelnen Pixeln,
also Breite, mal höher, Bildpunkte.
In diesem Fall ist also Arthur erst mal kodiert als RGB,
also Rot-Grün-Blau-Anteil. Typischerweise, wenn ich jetzt also nicht gerade
wirklich anspruchsvolle Bildbearbeitung mache, sage ich, okay,
da habe ich also pro Farbkanal rot-grün bzw. blau.
Acht Bit vorgesehen, habe da also quasi einen Wertebereich von 0 bis
2055. Und mit dem, was ich da dann in Abstufung unterscheiden kann,
sind es zumindest jetzt also für den Normalsterblichen,
also hinreichend genau die einzelnen Farbpunkte quasi charakterisiert.
Also wenn man jetzt entsprechend trainiert ist und da ist irgendwie Fotograf oder so, okay,
dann würde man da also noch wirklich größere Unterschiede sehen.
Aber sagen wir mal so,
sie kommt man eigentlich normal mit,
also irgendwie acht Bit-Darstellungen bei Rechnergrafik immer
Ganz gut aus und zumindest das, was wir jetzt hier so sehen,
wenn wir jetzt also hier so an solchen normalen Geräten arbeiten,
jetzt nicht gerade an irgendwelchen Workstations mit kalibrierten Farbmonitoren,
sind das auch immer jeweils nur acht Bit Farbdarstellungen. Gut,
ich habe hier eben diese drei Grundfarben bei so einer additiven Farbmischung,
wunderbar nicht, also dreimal acht, 24,
nicht dann spendiere ich vielleicht noch also irgendwie eine Maske für eine Transparenz,
was dann immer noch als zusätzlicher Alpha-Kanal mit kodiert wird und dann kann ich also im Prinzip jetzt jeden Bildpunkt in 1,
32 Bit-Indiger-Wert packen,
der dann also quasi eben entweder als 0-0 und dann R,
G, B oder wenn ich dann eben noch so einen Wert für eine Transparenz habe,
dann eben dadurch entsprechend diesen Alpha-Anteil mit drin habe und dann RGB kodiert habe.
Ich sage mal, so eine Darstellung,
wo ich dann eben auch vergleichsweise kompakt meine Bildpunkte,
dann schon so eine Integer-Zahl verpacke, gibt es dann also beispielsweise in Java,
da dann also auch schon entsprechend vordefiniert als Typ ARGB,
den man dann also live endlich benutzen kann.
Damit kann ich dann also auch mit solchen Maskierungsoperationen, beispielsweise dann Folgendes machen,
dass sie eben hier nun mal als Beispiel sowas wie so ein Rotfilter mache. Ich habe jetzt eben hier ein Buffett Image, was dann quasi als Quelle dient. Und hier mit diesen beiden ineinander geschachtelten Schleifen,
wo ich dann eben quasi jetzt über alle Bildzahlen beziehungsweise über alle spalten,
das heißt also der Reihe nach so zahlenweise über alle Bildpunkte letztendlich gehe,
mache ich hier also nichts anderes,
als dass ich quasi von diesem Quellbild,
war es also hier quasi als Source übergeben wird,
diesen RGB-Wert mir nehme, nicht,
und das Ganze jetzt eben mit einer Maske verknüpfe,
wo ich da jetzt eben nur diesen Rotanteil raushole,
was ja dann also quasi genau an entsprechender Stelle in diesem Datenformat hier als zweites Byte auftaucht,
und das ist dann eben jetzt hier mein Indiger-Wert mit dem Rotanteil,
und der wird dann eben entsprechend jetzt wieder kopiert,
in ein Ergebnis Array, was dann also in diesem Fall jetzt hier,
also als Return war dieser Funktion zurückgegeben wird.
Eine Anfrage oder hat sich? Ich weiß nicht,
ob das sinnvoll ist, es jetzt zu fangen.
Ich kenne auch Formate, wo der Ruder teilt, wie er ist.
Ja gut, also die Frage war jetzt,
weil ich habe jetzt hier immer so behauptet,
also RGB und das sieht das, das sieht immer so aus.
Das sind jetzt natürlich letztendlich Konventionen, je nachdem,
welche Bildformate man jetzt nimmt oder wie das Ganze kodiert ist
Also bei anderen Formaten sieht das also sicherlich anders aus, beziehungsweise bei vielen anderen Sachen in der Bildverarbeitung.
Also wenn man jetzt zum Beispiel wirklich sich mal ansieht,
mit welchen Formaten liefern dann auch irgendwelche Kamerabilder oder irgendwelche Kameras jetzt,
also die Datenbilder ab, da ist es dann häufig so, dass sich das jetzt nicht in einer additiven Farbmischung mache. Also auch hier kann ich natürlich sagen,
also im Prinzip kann ich also erstmal diese ganzen Bits also beliebig noch vertauschen oder verwürfeln,
aber auch grundsätzlich bei den Bildformaten ist es also häufig sinnig oder sinnvoll,
also dass jetzt vielleicht gar nicht in so einer additiven Farbmischung zu machen,
die hat also natürlich den Charme,
dass ich damit direkt jetzt also irgendwie auf eine Monitordarstellung abziele,
wo ich also quasi meine Farbinformation aus den drei Grundfarben zusammensetze,
für andere Operationen, ist es aber eigentlich sinnvoller,
also dass die Farben also ganz anders zu beschreiben oder zu kodieren und da hat man häufig,
also eben irgendwie sowas wie so eine YUV-Kodierung,
wo dann also beispielsweise im Prinzip ein Helligkeitsanteil und dann eben eine Beschreibung der Farbe quasi als Farbvektor kodiert werden,
nicht wo Man dann also einmal zu ähnlich,
kompakten Farbformaten oder Darstellungen kommt, die dann aber,
je nachdem, was man damit machen möchte,
zum Beispiel jetzt für die Berechnung, Vorurteile haben,
weil also bei so einer Trennung zwischen Helligkeitsanteil und Farbe kann ich einfach sagen,
Grauwertbild erzeuge ich damit,
dass ich die Farbe quasi wegnehme oder wegmaskiere und da einfach mit dem Helligkeitsanteil weiterrechne.
Bei so einer Y-UV-Darstellung müsste ich jetzt eben sowas wie Graufilter,
nicht, dass wir da jetzt den Michi das nächste Beispiel gewesen,
dann also dadurch machen, dass ich sage,
also im Prinzip gleiche Vorgehensweise, nicht bloß,
dass ich jetzt eben quasi aus diesen 32-Bit-Wert über entsprechende Maskierung getrennt,
Rotanteil, Grünanteil und Blauanteil ermittel.
Nicht und ein Grauwert dann dadurch berechnet,
dass ich die quasi einmal aufsummiere und dann wieder mittel,
dass ich das also dann eben auch wieder im genormten Wertebereich
habe und das ist hier jetzt natürlich vergleichsweise umständlich umzurechnen und wie gesagt,
bei anderen Bildformaten ist es dann also deutlich besser
Zu machen. Und wie gesagt,
beim Speichern dann auch in diesem Bildformat jetzt,
also das Grauwertbild, muss ich dann natürlich dann sowohl rot,
grün und blau dann jeweils mit dem Entsprechenden Vektor quasi füttern.
Das ist eben genau das,
was wir hinten dann eigentlich nur noch passiert,
wo ich dann eben sage,
da stehen dann jeweils identische Zahlen und in einer additiven Farbmischung kommt,
da dann eben ein Wert zwischen Schwarz und Weiß
bzw. ein ebenentsprechend die Grauwettern
mit raus
Gut, andere Beispiele jetzt für solche Bit-Operationen oder wie gesagt,
die sind also relativ gern genommen für irgendwelche altmetischen Operationen beziehungsweise für andere Beispiele.
Etwas, was ich jetzt,
als ich hier mal Bitcount genommen genannt habe, da geht es darum,
also quasi zu prüfen in einem Wort oder einer Zahl oder was auch immer,
wie viele Eins-Bilds kommen da drin vor?
Benutzt wird sowas beispielsweise in der Kryptologie, in der Kodierungstheorie,
das ist dann auch in der Nächsten Woche letztendlich dran,
wo es dann im Prinzip darum geht,
wie jetzt also bestimmte Infos oder wie man Informationen jetzt also entsprechend noch anders darstellen kann als das,
was ich jetzt quasi als Zahlensysteme beziehungsweise als Zeichenkodierung vorgestellt habe.
Oder auch in der Medienverarbeitung,
also ich hatte ja schon angesprochen,
also im Prinzip
so auf CD und DVD-Formaten
und sowas
Wird, was auch immer gemacht war, also gerade da brauche ich dann eben
auch für entsprechende Verschlüsselungen in diesen Formaten die Anzahl der Bits.
Gut, das kann ich jetzt natürlich relativ einfach oder slate forward machen,
indem ich sage, gut, ich habe jetzt also irgendwie ein 32-Bit. Zahl,
also jetzt hier also als Integer und ich habe zusätzlich einen Zähler,
den ich hier also quasi einmal deklariere und mit null vorgesetze und
in einer Schleife wird dann quasi geguckt,
solange meine Zahl ungleich null ist mache ich hier mit diesem Ausdruck nichts anderes,
als dass ich von meiner Zahl das mit diesem Bit Vector maskiere.
Das heißt, da wird eigentlich nur geguckt,
von der Zahl ist das unterste Bit gesetzt.
Dieser gesamte Ausdruck liefert dann letztendlich, wenn das Bit nicht gesetzt ist,
eine Null, wenn das Bit gesetzt ist, eine Eins.
Nicht diese Eins wird dann eher hier entsprechend zu dem Zähler
hinzuaddiert und anschließend wird eben die Zahl selber,
um einen mit nach rechts geschoben und ich betrachte dann
quasi bei der nächsten Schleifeniteration das nächste Bit.
Und das mache ich eben genauso lange,
bis überhaupt gar keine Eins Bits in einer Zahl mehr vorkommen.
Nicht, was also hier dann quasi als Abbruchbedingung gemacht wird,
beziehungsweise wenn ich sowieso mit einer Null als Zahl ankomme,
brauche ich die Schleife gar nicht zu durchlaufen,
weil dann habe ich hier nämlich schon mal
ein richtiges Ergebnis
Gut, das ist jetzt natürlich, also mal relativ einfach oder straightforward so runterprogrammiert.
Nur als Beispiel, wie sowas noch geht. Ich werde
das jetzt also nicht im Einzelnen vorstellen, wie das also funktioniert.
Man kann solche Bitcoins-Sachen, also auch noch mit viel Bit-Tricks da rein,
anders und deutlich effizienter machen. Dazu hier eigentlich nur ein Verweis auf diverse Quellen,
wo sowas drinsteht, weil das sind also letztendlich,
also irgendwelche Algorithmen, wo im Prinzip, sagen wir mal so,
Tricksereien mit diversen Bit-Maskierungen und Schieberoperationen genutzt werden,
wo ich teilweise Teile von meinen Wörtern ausmaskiere,
wie eine Zahl interpretiere, dann wie eine Zahl interpretiere,
damit rechne und dann durch Schieberoperationen,
die dann also auch immer gruppenweise zusammenfassen kann.
Das ist im Prinzip das, worauf also dieser Algorithmus hier letztendlich beruht. Wie gesagt,
also hier als Quellen hier von Comenet bei der Universität Stanford gibt es da so eine Referenz und sonst sehr,
sehr viele Beispiele und also auch dieses hier sind aus dem Buch von Donald Knut,
The Art of Computer Programming, wo man also hier im Prinzip sieht,
das Ganze ist eben aufgebaut über so eine Mischung von Ich habe hier meine Zahl,
U, die, oder meinen Wert, U,
den interpretiere ich als Unsigned Integrer.
Der wird dann hier teilweise um ein Bett beziehungsweise um zwei Bett nach rechts geschoben,
dann eben hier mit irgendwelchen Bit-Masken maskiert,
wo ich also quasi bei drei habe ich immer jeweils zwei Bit gesetzt.
Zwei Bit nicht gesetzt, das heißt hier die Maske besteht immer irgendwie aus,
wenn ich das jetzt von rechts nach links lesen würde,
1, 1, 0, 0 und dann wieder 1,
1, 0,
0. Nicht dann hätte ich hier eine Maske,
wo ich dann eben immer nur ein einzelnes Bit gesetzt habe
Ich bin dann irgendwo hier hinten in diesem Bereich eine Maske mit sieben,
wo dann, also immer drei Bit gesetzt sind.
Also letztendlich führt das Ganze aber immer dazu, dass ich
immer gruppenweise quasi jetzt für diese Bits mir hier Ergebnisse erzeuge.
Und das Ganze liefert dann aber letztendlich hier jetzt mit deutlich weniger Operationen als,
ich sag mal, so ein Straight Forward-Algorithmus dann das richtige Ergebnis.
Teilweise werden also solche Bitcount Sachen,
weil sie eben für viele Kodierungsalgorithmen interessant sind,
eben auch schon in einigen Prozessoren oder in DSPs.
DSP steht für Digital Single-Prozesse, also Signalprozessoren,
direkt durch spezielle Hardware-Einheiten unterstützt,
beziehungsweise zumindest im Befehl ist als eigener Befehl angeboten
Gut, zum Abschluss von solchen Bittrickserreihen,
kommen jetzt hier nochmal so einige Beispiele aus diesem Buch von Knut,
wo also jetzt wirklich nochmal gezeigt wird,
was man also mit solchen Sachen überhaupt entsprechend machen kann,
die Grundidee bei dem Ganzen ist immer,
dass ich quasi hier irgendwelche Strings oder Teile von Strings habe und dann irgendwann weiter hinten rechts folgen von Bits,
die jeweils gesetzt sind.
Und wenn ich nachher damit rechne und einen Übertrag irgendwo erzeugt wird,
dann wirkt sich dieser Übertrag natürlich dann bei so einem String so aus,
dass er quasi sämtliche Bits der Reihe nach kippen lässt,
aus dieser Eins-Folge dann eben eine Folge von Nullen wird und dafür dann aber die eine Null,
die davor steht, dann eben wieder zu einer Eins kippt.
Das, was dort letztendlich dann hier bei so einer Codierung passiert,
also wenn ich jetzt sage, ich habe eine Enteger-Zahl X,
die aufgebaut ist als irgendeinen beliebigen Big Bitstring,
also irgendeinen Vektualfall.
Und dann habe ich hier hinten rechts quasi eine Null,
dann mindestens eine Eins, also sprich A plus 1,
1, A kann dann die aber eben auch gleich Null sein.
Nicht und hinterher dann eben nur noch Nullen, wenn überhaupt.
Das ist also quasi hier die Aussage von dem hier.
Einzige Aussage für die größte negative Zahl
funktioniert das nicht
Dann gilt jetzt quasi für die normale Zahlendarstellung,
also meine Zahl X, entspricht jetzt eben genau diesem Aufbau.
Die X oder diese Zahl X-Bitweise invertiert,
ist nichts anderes, als dass ich sage,
ich habe also diesen Vector hier vorne bedweise invertiert und alles,
was hier null ist, wird eins und entsprechend umgekehrt,
dass es wäre, also genau diese Zahl hier.
Von der Zahl 1 1 1 abgezogen wirkt sich
wie aus
Ich habe hier meine Zahl, müsste einen abziehen. Das führt genau dazu,
dass wenn ich da jetzt Nullen stehen habe, ich ziehe einen ab,
hätte ich als Ergebnis eins, es würde einen Übertrag erzeugt werden.
Und das Ganze pflanzt sich dann eben entsprechend so lange fort über diese B stellen,
bis ich hier diese Eins erreicht habe und der Übertrag würde dann quasi diese Eins verschwinden lassen.
Das heißt, x minus eins wäre dann also quasi genau
dieser vordere Teil, da ändert sich nichts.
Aus dieser Eins ist eine Null geworden oder aus allem,
was dahinter noch an Nullen gestanden hat, dann eben eine Eins geworden sein. So,
die Zahl, minus x, also die Zahlen negiert,
ist dann im Prinzip nichts anderes als, dass ich sage,
x negiert, plus eins, also wie gesagt,
wir sind bei der Zweier-Kompliment-Darstellung für irgendeine Zahl x,
die Zahlen negiert oder mittweise invertiert wäre quasi einer Kompliment,
plus eins Ist Zweier-Kompliment,
das ist genau diese Aussage hier unten.
Und wenn ich das also quasi mir jetzt an Arthur überlege,
also die Zahlbettweise innovativ ist. Dieses hier plus eins hinzu,
führt dazu, dass also hier aus diesen Einsen lauter Nullen geworden sind und hieraus dann eben eine Eins.
Das heißt, minus x wäre dann eben genau diese Zahl. So,
und wenn ich jetzt diese Zahl, Zahl,
Betweise invertiert als x minus eins oder eben als negative Zahl habe,
dann kann man jetzt quasi mit diesen vier Grunddingern oder Operationen jetzt über alle möglichen arathmetischen oder Bittweisen,
arathmetischen Verknüpfungen aus diesen vier Teilen, in diesem Bitstrinks dafür sorgen,
dass ich wirklich gezielt die letzte Eins löschen kann,
alles bis auf die letzte Eins lösche,
die letzte Eins quasi dann so weit für Vielfache,
dass ich also quasi dann links davon nur noch Einsen stehen
habe und so weiter und so fort
Liest sich jetzt natürlich erstmal relativ abstrus nach dem Motto,
ja Mensch, wofür brauche ich das eigentlich?
Teilweise war man dann also wirklich jetzt in der Kodierungstheorie,
also bestimmte Masken erzeugt, beziehungsweise aus diesen Strings,
sowas wie jetzt also für bestimmte Prüfsummen,
was generieren möchte,
dann sind solche Ausdrücke schon sinnvoll oder könnten da also,
sagen wir mal,
effizient angewandt werden
Gut, also wie gesagt, wenn man sich dort mal vertiefen will,
beziehungsweise dann auch wirklich nochmal Beispiele sich ansehen will.
Also hier ist dann also nochmal die Referenz auf das Buch von Knut,
beziehungsweise die Sachen finden sich dann teilweise auch direkt im Internet zum Runterladen.
Das heißt, da kann man also direkt in die entsprechende Dokumentation dann gucken. Gut,
dann werde ich jetzt nochmal kurz anfangen, ein bisschen was zur Speicherorganisation vorzustellen,
wo es dann also auch nochmal im Prinzip um Adressierung geht,
beziehungsweise wo ich dann eben auch nochmal, also diese Unterscheidung ist mit irgendwelchen logischen Operationen brauche.
Ich hatte ja schon grundsätzlich gesagt, also das,
was man in der Regel jetzt an Informationen vom Rechner irgendwo abspeichert,
ist, sagen wir mal, als kleinster Datenwert eigentlich typischerweise ein Byte,
also wenn ich jetzt zum Beispiel an sowas wie,
also irgendeiner Asky-Darstellung denke, also mit sieben Bett,
also quetestens acht Bett brauche ich dann eigentlich, naja gut,
dann bin ich also irgendwo so beim Charakter,
nicht und war den Zahlenformaten hat man dann ja typischerweise im Prinzip,
also 16 bis 32, Bit 64,
Bit dann eben für die entsprechenden Zahlendarstellungen.
Und das ist eigentlich jetzt das, was ich an Informationen darstellen muss oder darstellen möchte.
Wie wird das Ganze dann aber in den Speicher gebracht,
beziehungsweise wie wird das also im Speicher jetzt verpackt?
Typischerweise sage ich natürlich, dass die Adressierung im Speicher dann
eigentlich auch immer beidweise passiert. Das heißt,
man spricht wirklich immer einzelne Bytes an,
um dann eben auch wirklich demzufolge auch einzelne kleinste Einheiten,
also sowas wie ein Byte oder eben ein Aski-Zeichen adressieren zu können.
Wenn ich mir die Hardware dazu ansehe,
dann sieht das aber so aus, dass der Prozessor beziehungsweise das,
was ich da dann also als Speicheradressierung nehme,
ich eigentlich wortweise arbeite und die Speicherwortlänge ist in der Regel deutlich größer,
beziehungsweise hinsichtlich der internen Rechnerarchitektur 32-Bit beziehungsweise aktuell eigentlich 64-Bit,
womit man arbeitet
Dann nochmal zum Speicher oder zur Speicherorganisation,
also wenn man sich jetzt ansieht, also Speicherkapazität,
sprich wie viel kann ich überhaupt speichern,
berechnet sich dann eigentlich immer entsprechend der Anzahl der Worte,
mal der Bits, die ich pro Worte darstellen kann,
nicht und hier jetzt nur als Beispiel,
also die Folie aus dem Tannenbaum, also nicht,
da ist es jetzt nur für etwas ungewöhnliche Größen gezeigt,
wo ich dann also im Prinzip hier 96 Bit einmal sage,
das sind also quasi hier zwölf mal acht Bit oder acht mal zwölf Bit oder eben sechs mal 16 Bit.
Also dem zuvor gibt es da dann eben entsprechend unterschiedliche Unterteilungen hinsichtlich der Speicherorganisation. Gut,
auf diese Problematik bei der Speicheradressierung,
wo ich dann eben jetzt wirklich unterscheiden muss zwischen dieser Wortlänge,
mit der ich eigentlich den einzelnen Speicheradressen unterscheide und dem,
was ich bei der Adressierung quasi beidweise unterscheiden muss,
Damit werde ich dann nächste Woche entsprechend weitermachen,
wo es dann also wirklich um die einzelnen Adressierungsschemata geht,
die man dort anwenden kann,
beziehungsweise die eben auch angewendet werden, um jetzt,
also die Zahlendarstellungen im Speicher abzulegen.
Gut, dann schönes Wochenende