Das Modul geht dabei weit über die in Perl bereits integrierten Fähigkeiten zur Behandlung von Bitvektoren hinaus (siehe dazu auch die weiter unten folgende Methodenliste!).
Außerdem können Sie die C-Bibliothek, die den Kern dieses Moduls bildet, auch in anderen C-Anwendungen einsetzen. Perl ist dazu nicht erforderlich!
Das Modul ist als Basisklasse für andere Anwendungen oder Anwendungsklassen gedacht, etwa für die Implementierung von Mengen oder für die Arithmetik mit beliebig großen ganzen Zahlen ("Big Integer"-Arithmetik).
Alle Methoden sind intern in C realisiert, um eine möglichst hohe Performanz zu gewährleisten.
Das Modul stellt zusätzlich zu den Methoden auch überladene arithmetische und relationale Operatoren zur Verfügung, um die Handhabung des Moduls so einfach wie möglich zu gestalten (diese sind jedoch nur unter Perl verfügbar).
Denken Sie aber daran, daß überladene Operatoren (natürlich) mit einem kleinen Geschwindigkeitsverlust verbunden sind. Wenn die Geschwindigkeit für Ihre Anwendung ausschlaggebend ist, sollten Sie ausschließlich mit den Methoden dieses Moduls arbeiten, statt die überladenen Operatoren zu benutzen!
Dieses Modul ist für viele unterschiedliche Aufgaben geeignet:
(Die Komplexität der Methoden dieses Moduls ist in der Regel entweder O(1) oder O(n/b), wobei "b" der Anzahl von Bits entspricht, die ein Maschinenwort auf Ihrem System besitzt.)
und vieles mehr.
(Eine Reihe von Beispielanwendungen ist über meine Website unter der URL http://www.engelschall.com/u/sb/download/ verfügbar.)
Eine große Anzahl von verfügbaren Import/Export-Methoden erlaubt den direkten Zugriff auf einzelne Bits, auf fortlaufende Bereiche (Intervalle) von Bits, auf Maschinenwörter, auf beliebige Chunks ("Bitpakete"), auf Listen (Arrays) von Chunks von Bits oder Maschinenwörtern sowie den gesamten Bitvektor auf einmal (z.B. für blockorientierte Schreib-/Lesezugriffe auf Dateien).
Außerdem können Sie den Inhalt eines Bitvektors in binärer, hexadezimaler und dezimaler Form sowie als Aufzählung im ".newsrc"-Stil importieren und exportieren.
Beachten Sie, daß dieses Modul mit dem Ziel möglichst hoher Effizienz entwickelt wurde, weshalb alle seine Methoden auch in C implementiert sind.
Um die Ausführungsgeschwindigkeit noch weiter zu erhöhen, verwendet das Modul nicht Bytes als kleinste Speichereinheit, sondern Maschinenwörter.
Dabei wird davon ausgegangen, daß ein Maschinenwort auf allen Maschinen der am effizientesten verarbeitete skalare Datentyp ist (was der ANSI C-Standard sowieso vorschlägt und implizit annimmt).
Um dies zu ermöglichen, wird auf jedem System automatisch die Anzahl der Bits in einem Maschinenwort bestimmt und werden die entsprechenden internen Konfigurationskonstanten automatisch angepaßt.
Je größer diese kleinste Speichereinheit ist, desto besser ist die Komplexität (d.h. Ausführungsgeschwindigkeit) der Methoden dieses Moduls. Allerdings steigt damit auch die durchschnittliche Zahl der verschwendeten (ungenutzten) Bits im letzten Maschinenwort.
Das Modul "Math::MatrixBool" ist ein Beispiel für die effiziente Implementierung Boolescher Matrizen und der dazugehörigen Operationen.
(Beide Module sind über meine Website unter der URL http://www.engelschall.com/u/sb/download/ bzw. über jeden CPAN-Server (http://www.perl.com/CPAN/authors/id/STBEY/) verfügbar.)
Eine ohne das "Bit::Vector"-Modul undenkbare Anwendung ist "Slice": Mit diesem Werkzeug können mit Hilfe von Booleschen Ausdrücken ("erzeuge die englische Version des Textes mit allen Beispielen, aber ohne ...") unterschiedliche Varianten eines Dokuments aus derselben Quell-Datei erzeugt werden.
(Siehe dazu auch http://www.engelschall.com/sw/slice/.)
Dieses Werkzeug ist selbst wiederum Teil eines anderen Werkzeugs namens "Website META Language" ("WML"), mit dem ganze Websites aus Vorlagen und Schablonen generiert und verwaltet werden können.
Unter anderem können Sie damit Ihre eigenen HTML-Tags definieren, die je nach Wunsch entweder bei der Generierung oder zur Laufzeit expandiert bzw. ausgeführt werden.
(Siehe dazu auch http://www.engelschall.com/sw/wml/.)
Version $version = Bit::Vector->Version(); Word_Bits $bits = Bit::Vector->Word_Bits(); # Anzahl Bits in Maschinenwort Long_Bits $bits = Bit::Vector->Long_Bits(); # Anzahl Bits in "unsigned long" new $vector = Bit::Vector->new($bits); # Bitvektor-Konstruktor new_Hex $vector = Bit::Vector->new_Hex($bits,$string); new_Bin $vector = Bit::Vector->new_Bin($bits,$string); new_Dec $vector = Bit::Vector->new_Dec($bits,$string); new_Enum $vector = Bit::Vector->new_Enum($bits,$string); Concat_List $vector = Bit::Vector->Concat_List(@vectors);
new $vec2 = $vec1->new($bits); # Alternativer Aufruf des Konstruktors Shadow $vec2 = $vec1->Shadow(); # Neuer Bitvektor, gleiche Größe, aber leer Clone $vec2 = $vec1->Clone(); # Neuer Bitvektor, exaktes Duplikat Concat $vector = $vec1->Concat($vec2); Concat_List $vector = $vec1->Concat_List($vec2,$vec3,...); Size $bits = $vector->Size(); Resize $vector->Resize($bits); $vector->Resize($vector->Size()+5); $vector->Resize($vector->Size()-5); Copy $vec2->Copy($vec1); Empty $vector->Empty(); Fill $vector->Fill(); Flip $vector->Flip(); Primes $vector->Primes(); # Sieb des Erathostenes Reverse $vec2->Reverse($vec1); Interval_Empty $vector->Interval_Empty($min,$max); Interval_Fill $vector->Interval_Fill($min,$max); Interval_Flip $vector->Interval_Flip($min,$max); Interval_Reverse $vector->Interval_Reverse($min,$max); Interval_Scan_inc if (($min,$max) = $vector->Interval_Scan_inc($start)) Interval_Scan_dec if (($min,$max) = $vector->Interval_Scan_dec($start)) Interval_Copy $vec2->Interval_Copy($vec1,$offset2,$offset1,$length); Interval_Substitute $vec2->Interval_Substitute($vec1,$off2,$len2,$off1,$len1); is_empty if ($vector->is_empty()) is_full if ($vector->is_full()) equal if ($vec1->equal($vec2)) Lexicompare (vorzeichenlos) if ($vec1->Lexicompare($vec2) == 0) if ($vec1->Lexicompare($vec2) != 0) if ($vec1->Lexicompare($vec2) < 0) if ($vec1->Lexicompare($vec2) <= 0) if ($vec1->Lexicompare($vec2) > 0) if ($vec1->Lexicompare($vec2) >= 0) Compare (vorzeichenbehaftet) if ($vec1->Compare($vec2) == 0) if ($vec1->Compare($vec2) != 0) if ($vec1->Compare($vec2) < 0) if ($vec1->Compare($vec2) <= 0) if ($vec1->Compare($vec2) > 0) if ($vec1->Compare($vec2) >= 0) to_Hex $string = $vector->to_Hex(); from_Hex $vector->from_Hex($string); to_Bin $string = $vector->to_Bin(); from_Bin $vector->from_Bin($string); to_Dec $string = $vector->to_Dec(); from_Dec $vector->from_Dec($string); to_Enum $string = $vector->to_Enum(); # z.B. "2,3,5-7,11,13-19" from_Enum $vector->from_Enum($string); Bit_Off $vector->Bit_Off($index); Bit_On $vector->Bit_On($index); bit_flip $bit = $vector->bit_flip($index); bit_test, contains $bit = $vector->bit_test($index); $bit = $vector->contains($index); if ($vector->bit_test($index)) if ($vector->contains($index)) Bit_Copy $vector->Bit_Copy($index,$bit); LSB (least significant bit) $vector->LSB($bit); MSB (most significant bit) $vector->MSB($bit); lsb (least significant bit) $bit = $vector->lsb(); msb (most significant bit) $bit = $vector->msb(); rotate_left $carry = $vector->rotate_left(); rotate_right $carry = $vector->rotate_right(); shift_left $carry = $vector->shift_left($carry); shift_right $carry = $vector->shift_right($carry); Move_Left $vector->Move_Left($bits); # Links-Shift um "$bits" Positionen Move_Right $vector->Move_Right($bits); # Rechts-Shift um "$bits" Positionen Insert $vector->Insert($offset,$bits); Delete $vector->Delete($offset,$bits); increment $carry = $vector->increment(); decrement $carry = $vector->decrement(); add $carry = $vec3->add($vec1,$vec2,$carry); subtract $carry = $vec3->subtract($vec1,$vec2,$carry); Negate $vec2->Negate($vec1); Absolute $vec2->Absolute($vec1); Sign if ($vector->Sign() == 0) if ($vector->Sign() != 0) if ($vector->Sign() < 0) if ($vector->Sign() <= 0) if ($vector->Sign() > 0) if ($vector->Sign() >= 0) Multiply $vec3->Multiply($vec1,$vec2); Divide $quot->Divide($vec1,$vec2,$rest); GCD (Greatest Common Divisor) $vec3->GCD($vec1,$vec2); Block_Store $vector->Block_Store($buffer); Block_Read $buffer = $vector->Block_Read(); Word_Size $size = $vector->Word_Size(); # Anzahl Maschinenwörter in "$vector" Word_Store $vector->Word_Store($offset,$word); Word_Read $word = $vector->Word_Read($offset); Word_List_Store $vector->Word_List_Store(@words); Word_List_Read @words = $vector->Word_List_Read(); Word_Insert $vector->Word_Insert($offset,$count); Word_Delete $vector->Word_Delete($offset,$count); Chunk_Store $vector->Chunk_Store($chunksize,$offset,$chunk); Chunk_Read $chunk = $vector->Chunk_Read($chunksize,$offset); Chunk_List_Store $vector->Chunk_List_Store($chunksize,@chunks); Chunk_List_Read @chunks = $vector->Chunk_List_Read($chunksize); Index_List_Remove $vector->Index_List_Remove(@indices); Index_List_Store $vector->Index_List_Store(@indices); Index_List_Read @indices = $vector->Index_List_Read(); Union $set3->Union($set1,$set2); Intersection $set3->Intersection($set1,$set2); Difference $set3->Difference($set1,$set2); ExclusiveOr $set3->ExclusiveOr($set1,$set2); Complement $set2->Complement($set1); subset if ($set1->subset($set2)) # Wahr, wenn $set1 Teilmenge von $set2 Norm $norm = $set->Norm(); Min $min = $set->Min(); Max $max = $set->Max(); Multiplication $matrix3->Multiplication($rows3,$cols3, $matrix1,$rows1,$cols1, $matrix2,$rows2,$cols2); Closure $matrix->Closure($rows,$cols); Transpose $matrix2->Transpose($rows2,$cols2,$matrix1,$rows1,$cols1);
Configuration $config = Bit::Vector->Configuration(); Bit::Vector->Configuration($config); $oldconfig = Bit::Vector->Configuration($newconfig);
String-Konvertierung $string = "$vector"; # Abhängig von der Konfiguration print "\$vector = '$vector'\n"; Leerheit if ($vector) # wenn nicht leer (nicht Null) if (! $vector) # wenn leer (Null) unless ($vector) # wenn leer (Null) Komplement (Einerkomplement) $vector2 = ~$vector1; $vector = ~$vector; Negation (Zweierkomplement) $vector2 = -$vector1; $vector = -$vector; Norm $norm = abs($vector); # Abhängig von der Konfiguration Absolutwert $vector2 = abs($vector1); # Abhängig von der Konfiguration Verkettung $vector3 = $vector1 . $vector2; $vector1 .= $vector2; $vector1 = $vector2 . $vector1; $vector2 = $vector1 . $scalar; # Abhängig von der Konfiguration $vector2 = $scalar . $vector1; $vector .= $scalar; Duplizieren $vector2 = $vector1 x $factor; $vector x= $factor; Links-Shift $vector2 = $vector1 << $bits; $vector <<= $bits; Rechts-Shift $vector2 = $vector1 >> $bits; $vector >>= $bits; Vereinigungsmenge $vector3 = $vector1 | $vector2; $vector1 |= $vector2; $vector2 = $vector1 | $scalar; $vector |= $scalar; $vector3 = $vector1 + $vector2; # Abhängig von der Konfiguration $vector1 += $vector2; $vector2 = $vector1 + $scalar; $vector += $scalar; Schnittmenge $vector3 = $vector1 & $vector2; $vector1 &= $vector2; $vector2 = $vector1 & $scalar; $vector &= $scalar; $vector3 = $vector1 * $vector2; # Abhängig von der Konfiguration $vector1 *= $vector2; $vector2 = $vector1 * $scalar; $vector *= $scalar; Exklusiv-Oder (Symmetrische Differenzmenge) $vector3 = $vector1 ^ $vector2; $vector1 ^= $vector2; $vector2 = $vector1 ^ $scalar; $vector ^= $scalar; Differenzmenge $vector3 = $vector1 - $vector2; # Abhängig von der Konfiguration $vector1 -= $vector2; $vector1 = $vector2 - $vector1; $vector2 = $vector1 - $scalar; $vector2 = $scalar - $vector1; $vector -= $scalar; Addition $vector3 = $vector1 + $vector2; # Abhängig von der Konfiguration $vector1 += $vector2; $vector2 = $vector1 + $scalar; $vector += $scalar; Subtraktion $vector3 = $vector1 - $vector2; # Abhängig von der Konfiguration $vector1 -= $vector2; $vector1 = $vector2 - $vector1; $vector2 = $vector1 - $scalar; $vector2 = $scalar - $vector1; $vector -= $scalar; Multiplikation $vector3 = $vector1 * $vector2; # Abhängig von der Konfiguration $vector1 *= $vector2; $vector2 = $vector1 * $scalar; $vector *= $scalar; Division $vector3 = $vector1 / $vector2; $vector1 /= $vector2; $vector1 = $vector2 / $vector1; $vector2 = $vector1 / $scalar; $vector2 = $scalar / $vector1; $vector /= $scalar; Modulo $vector3 = $vector1 % $vector2; $vector1 %= $vector2; $vector1 = $vector2 % $vector1; $vector2 = $vector1 % $scalar; $vector2 = $scalar % $vector1; $vector %= $scalar; Inkrement ++$vector; $vector++; Dekrement --$vector; $vector--; Lexikalischer Vergleich (vorzeichenlos) $cmp = $vector1 cmp $vector2; if ($vector1 lt $vector2) if ($vector1 le $vector2) if ($vector1 gt $vector2) if ($vector1 ge $vector2) $cmp = $vector cmp $scalar; if ($vector lt $scalar) if ($vector le $scalar) if ($vector gt $scalar) if ($vector ge $scalar) Vergleich (vorzeichenbehaftet) $cmp = $vector1 <=> $vector2; if ($vector1 < $vector2) # Abhängig von der Konfiguration if ($vector1 <= $vector2) if ($vector1 > $vector2) if ($vector1 >= $vector2) $cmp = $vector <=> $scalar; if ($vector < $scalar) # Abhängig von der Konfiguration if ($vector <= $scalar) if ($vector > $scalar) if ($vector >= $scalar) Gleichheit if ($vector1 eq $vector2) if ($vector1 ne $vector2) if ($vector eq $scalar) if ($vector ne $scalar) if ($vector1 == $vector2) if ($vector1 != $vector2) if ($vector == $scalar) if ($vector != $scalar) Teilmengen-Beziehung if ($vector1 <= $vector2) # Abhängig von der Konfiguration Echte Teilmengen-Beziehung if ($vector1 < $vector2) # Abhängig von der Konfiguration Obermengen-Beziehung if ($vector1 >= $vector2) # Abhängig von der Konfiguration Echte Obermengen-Beziehung if ($vector1 > $vector2) # Abhängig von der Konfiguration
Vollständig klein geschriebene Methodennamen zeigen Boolesche Rückgabewerte an.
(Natürlich mit Ausnahme der Bitvektor-Konstruktormethode new().)
Die Booleschen Werte dieses Moduls sind immer numerisch Null (0) für "falsch" und numerisch Eins (1) für "wahr".
Alle numerischen Eingabeparameter, die an irgendeine Methode dieses Moduls oder (im allgemeinen, jedoch siehe auch weiter unten) an überladene Operatoren übergeben werden, werden als vorzeichenlos betrachtet.
Mit anderen Worten, sowohl positive als auch negative Zahlen werden als positive Zahlen interpretiert. Dadurch werden negative Zahlen aufgrund ihrer internen binären Darstellung im Zweierkomplement plötzlich zu sehr großen positiven Zahlen.
Überladene Operatoren sind allerdings nur betroffen, wo numerische Faktoren (etwa bei <<, >> und x) im Spiel sind oder wenn die Konfiguration festlegt (beachten Sie hierzu auch den unmittelbar folgenden Abschnitt "Konfiguration überladener Operatoren"), daß numerische Eingaben (anstelle eines Bitvektor-Objekts für einen der beiden Operanden des Operators) als Bitnummern betrachtet werden sollen (was allerdings der Voreinstellung entspricht).
Die Konsequenz hieraus ist, daß die Übergabe einer negativen Zahl als Argument an eine der Methoden dieses Moduls oder als Bitnummer an einen der überladenen Operatoren in der Regel zu einem Überlauf mit entsprechender Fehlermeldung ("index out of range") und zum Programmabbruch führt.
Beachten Sie, daß das nicht für "Big Integer"-Dezimalzahlen gilt, die (normalerweise) als Strings übergeben werden und natürlich auch negativ sein dürfen (beachten Sie hierzu auch den Abschnitt "Big Integer"-Arithmetik etwas weiter unten).
Beachten Sie, daß das Verhalten bestimmter überladener Operatoren mit Hilfe der Methode Configuration() auf verschiedene Weise verändert werden kann (Details finden Sie weiter unten bei der Beschreibung dieser Methode).
Zum Beispiel werden Skalare (d.h. Zahlen und Strings), die als Operanden an überladene Operatoren übergeben werden, intern automatisch in Bitvektoren umgewandelt.
Diese Skalare werden dabei je nach Konfiguration entweder als Bitnummern betrachtet oder als hexadezimale, binäre oder dezimale Zahlen oder als Aufzählung.
Ebenso verhält es sich mit der Konvertierung von Bitvektoren in Strings mit Hilfe von Anführungszeichen (""), d.h., das Ausgabeformat hängt ebenfalls von der gewählten Konfiguration ab.
Schließlich haben einige der überladenen Operatoren je nach Konfiguration sogar eine unterschiedliche Semantik: Zum Beispiel kann der Operator "+" für den "Vereinigungsmenge"-Operator stehen oder aber den arithmetischen Additionsoperator bedeuten.
In allen Fällen (Eingabe- und Ausgabe-Umwandlung sowie der Operator-Semantik) wurden die Voreinstellungen so gewählt, daß das Verhalten der aktuellen Version des Moduls mit dem von früheren Versionen erst einmal identisch ist.
Solange die "Großen Ganzen Zahlen" ("Big Integers", für die "Big Integer"-Arithmetik) klein genug sind, um von Perl intern ohne wissenschaftliche Notation (Exponenten) dargestellt werden zu können, dürfen Sie sie in numerischer Form (d.h. als numerische Perl-Konstante, als numerischer Ausdruck oder als Perl-Variable mit numerischem Inhalt) an die überladenen Operatoren dieses Moduls (oder an die Methode from_Dec()) übergeben.
Nur diejenigen Zahlen, die für die interne Darstellung als ganze Zahl in Perl zu groß sind, müssen Sie unbedingt als Strings angeben.
Beachten Sie, daß eine Fehlermeldung erfolgt (mit Programmabbruch), wenn Ihre "Big Integer"-Werte größer werden als die größte auf Ihrem System noch darstellbare ganze Zahl, d.h. wenn zu ihrer Darstellung intern auf das "float"- bzw. "double"-Format (mit Exponenten) zurückgegriffen werden muß!
Weil dieses Limit jedoch maschinenabhängig und nicht einfach zu ermitteln ist, wird dringend empfohlen, alle "Big Integer"-Werte in Ihren Programmen in Anführungszeichen zu setzen (Hochkommata oder doppelte Anführungszeichen).
Beispiele:
$vector /= 10; # OK, weil Zahl klein ist $vector /= -10; # Aus dem gleichen Grund OK $vector /= "10"; # Immer korrekt $vector += "1152921504606846976"; # Anführungszeichen unbedingt erforderlich!
Die obigen Beispiele setzen alle voraus, daß zuvor
Bit::Vector->Configuration("input=decimal");
gesetzt wurde.
Beachten Sie, daß dieses Modul keine wissenschaftliche Notation (Exponenten) für "Big Integer"-Zahlen unterstützt, weil Sie jeden Bitvektor stets so groß machen können, daß die gesamte Zahl ohne Genauigkeitsverluste (die bei der Verwendung von Exponenten und einer begrenzten Anzahl von Dezimalstellen immer auftreten) hineinpaßt.
Beachten Sie schließlich auch, daß die einzigen erlaubten Zeichen in Strings für "Big Integer"-Konstanten die Ziffern 0..9 sowie optional ein Vorzeichen (+ oder -) sind.
Alle anderen Zeichen erzeugen einen (fatalen) Syntaxfehler.
Alle überladenen Operatoren verlangen mindestens einen Bitvektor-Operanden, um erkennen zu können, daß nicht die standardmäßige, sondern die überladene Variante einer Operation ausgeführt werden soll.
Das gilt insbesondere natürlich für alle unären Operatoren:
"$vector" if ($vector) if (!$vector) ~$vector -$vector abs($vector) ++$vector $vector++ --$vector $vector--
Aus offensichtlichen Gründen muß auch der linke Operand (der sogenannte "L-Wert") aller Zuweisungsoperatoren ein Bitvektor sein:
.= x= <<= >>= |= &= ^= += -= *= /= %=
Im Fall dreier spezieller Operatoren, nämlich <<, >> und x, sowie bei den entsprechenden Zuweisungsvarianten <<=, >>= und x= ist der linke Operand immer ein Bitvektor und der rechte Operand immer eine Zahl (die angibt, wie oft der Operator anzuwenden ist).
Bei allen echten binären Operatoren, d.h. bei
.
|
&
^
+
-
*
/
%
<=> cmp
== eq
!= ne
< lt
<= le
> gt
>= ge
kann jeweils einer von beiden Operanden durch einen Perl-Skalar ersetzt werden, d.h. durch eine Zahl oder einen String. Diese Werte können als Perl-Konstante, als Perl-Ausdruck oder als Perl-Variable (die eine Zahl oder einen String ergeben) angegeben werden.
Das gleiche gilt analog für die rechte Seite (den "R-Wert") der übrigen Zuweisungsoperatoren:
.= |= &= ^= += -= *= /= %=
Beachten Sie, daß dieser Perl-Skalar für die gewählte Konfiguration vom richtigen Typ (numerisch oder String) sein sollte, da anderenfalls eine Warnung ausgegeben wird, falls Ihr Programm mit dem Perl-Schalter -w ausgeführt wird.
Nachfolgend eine Übersicht der erlaubten Skalartypen für alle möglichen Konfigurationen:
input = bit indices : numerisch (Voreinstellung) input = hexadecimal : String input = binary : String input = decimal : String (im allgemeinen) input = decimal : numerisch (falls klein genug) input = enumeration : String
Beachten Sie, daß diese skalaren Operanden intern in Bitvektoren umgewandelt werden, die die gleiche Anzahl von Bits besitzen wie der jeweils andere Operand oder "L-Wert" (die ja Bitvektoren sein müssen!).
Die einzige Ausnahme von dieser Regel ist der Verkettungsoperator (.) und seine Zuweisungsvariante (.=).
Ist einer der beiden Operanden des Verkettungsoperators (.) kein Bitvektor, sondern ein Perl-Skalar, wird der Inhalt des jeweils anderen Operanden (des Bitvektors) in einen String umgewandelt(!), dessen Format wiederum von der mittels der Configuration()-Methode gewählten Konfiguration abhängt. Dieser String wird dann in der richtigen Reihenfolge (d.h. der Reihenfolge der beiden Operanden entsprechend) mit dem Perl-Skalar verkettet. (Mit anderen Worten: Es wird in diesem Fall ein String anstelle eines Bitvektors zurückgegeben!)
Ist der rechte Operand ("R-Wert") der Zuweisungsvariante des Verkettungsoperators (.=) ein Perl-Skalar, wird er intern in einen Bitvektor umgewandelt. Die Länge dieses Bitvektors hängt dabei von der gewählten Konfiguration ab:
Der resultierende Bitvektor hat die gleiche Anzahl von Bits wie der linke Operand, falls die Konfiguration festlegt, daß Skalare in der Eingabe als Bitnummern, Dezimalzahlen oder Aufzählungen zu betrachten sind.
Legt die Konfiguration hingegen fest, daß Skalare in der Eingabe als hexadezimale oder binäre Strings zu behandeln sind, wird der skalare Operand in einen Bitvektor umgewandelt, dessen Anzahl von Bits eine Funktion der Länge des Eingabe-Strings ist: Viermal die Länge eines hexadezimalen Strings (weil jede hexadezimale Ziffer 4 Bits codiert) und die einfache Länge eines binären Strings.
Ist eine Dezimalzahl ("Big Integer") zu groß, um in einem Bitvektor der gegebenen Größe abgespeichert werden zu können, kommt es zu einem numerischen Überlauffehler ("numeric overflow error") mit Programmabbruch.
Liegt die gegebene Bitnummer außerhalb des gültigen Bereichs, der durch die Anzahl von Bits der an der Operation beteiligten Bitvektoren festgelegt wird, kommt es zu einem Indexfehler ("index out of range") mit Programmabbruch.
Kann ein skalarer Operand aufgrund von Syntaxfehlern nicht erfolgreich umgewandelt werden, kommt es ebenfalls zu einem fatalen Fehler ("input string syntax error") (mit Programmabbruch).
Sind die beiden Operanden der Operatoren <<, >> oder x vertauscht, kommt es zu einem fatalen "Vertauschte Operanden"-Fehler ("reversed operands error").
Ist ein Operand weder ein Bitvektor noch ein Skalar, kommt es zu einem fatalen "Falscher Operanden-Typ"-Fehler ("illegal operand type error").
Beachten Sie, daß die Bits in den Bitvektoren dieses Moduls intern in aufsteigender Folge gespeichert sind, d.h. das Bit mit der Nummer 0 ist mit dem niederstwertigen Bit im niederstwertigen (ersten!) Maschinenwort des Bitvektors identisch.
Mit anderen Worten, das Bit Nummer 0 eines Bitvektors ist im Bit Nummer 0 des Wortes Nummer 0 des Arrays von Maschinenwörtern gespeichert, aus dem ein Bitvektor intern besteht.
(Wobei das Wort Nummer 0 in diesem Array das erste Wort ist, d.h. das mit der kleinsten Speicheradresse innerhalb des Arrays.)
Beachten Sie aber, daß Maschinenwörter (abhängig von der Implementierung des jeweiligen Systems!) intern mit unterschiedlichen Byte-Reihenfolgen abgespeichert sein können, z.B. in der "low order byte first"- oder der "high order byte first"-Reihenfolge!
Aus diesem Grund erfolgt bei den beiden Methoden Block_Store() und Block_Read() (die zum Im- und Exportieren eines ganzen Bitvektors auf einmal dienen) eine entsprechende Umwandlung aus der und in die "low order byte first"-Reihenfolge, respektive.
Was also Block_Store() als Eingabe erwartet und Block_Read() zurückliefert, ist immer die "low order byte first"-Reihenfolge, unabhängig davon, in welcher Reihenfolge die Bytes eines Maschinenwortes tatsächlich auf der jeweiligen Maschine abgespeichert werden.
Auf diese Weise ist sichergestellt, daß die mit Block_Read() auf einer Maschine exportierten Daten auf einer anderen Maschine (möglicherweise mit einer anderen Byte-Reihenfolge!) mit Block_Store() stets korrekt wieder eingelesen werden können.
Beachten Sie weiterhin, daß jedoch bei der Darstellung von Bitvektoren als binäre oder hexadezimale Strings das niederstwertige Bit immer ganz rechts steht, das erste Bit (also das ganz links stehende) daher das höchstwertige Bit ist.
Das ist so, weil in der westlichen Kultur alle Zahlen auf diese Weise dargestellt werden (die Wertigkeit der Ziffern steigt von rechts nach links an).
Das erfordert natürlich bei der Umwandlung aus einem oder in einen binären oder hexadezimalen String eine Umstellung der Reihenfolge, die die entsprechenden Umwandlungsmethoden (günstigerweise sogar ohne zusätzlichen Aufwand!) automatisch erledigen.
Beachten Sie, daß alle Methoden, deren Namen mit Word_ beginnen, maschinenabhängig sind!
Diese Methoden sind alle von der Größe (der Anzahl der Bits) eines Maschinenworts, d.h. des C-Datentyps "unsigned int", auf Ihrer Maschine abhängig.
Aus diesem Grund sollten Sie diese Methoden nur dann verwenden, wenn Sie absolut sicher sind, daß die Portabilität Ihres Programms keine Rolle spielt!
Bedenken Sie, daß Sie beliebig große Chunks ("Bitpakete") mit bis zu 32 Bits auf einmal auf portable Weise nutzen können, wenn Sie statt dessen die Methoden verwenden, deren Namen mit Chunk_ beginnen.
Der erlaubte Bereich für Chunk-Größen (für alle Methoden, deren Namen mit Chunk_ beginnen) reicht von 1 bis Bit::Vector->Long_Bits(). Die Chunk-Größe 0 ist also nicht erlaubt; jeder Versuch, diese Chunk-Größe zu verwenden, führt zu einem fatalen Fehler!
Um Ihre Programme portabel zu machen, dürfen Sie jedoch keine Chunk-Größen von mehr als 32 Bits verwenden, da dies die maximale, garantiert auf jedem System verfügbare Anzahl von Bits des C-Datentyps "unsigned int", also eines Maschinenwortes, ist (dies wird durch den ANSI C-Standard gewährleistet!).
Generell gilt für alle Methoden, bei denen mehrere Bitvektoren beteiligt sind, daß diese Bitvektoren übereinstimmende Größen (Anzahlen von Bits) haben müssen. Anderenfalls tritt ein fataler "Abweichende Größen"-Fehler ("size mismatch error") auf.
Eine Ausnahme von dieser Regel bilden die Methoden Concat(), Concat_List(), Interval_Copy() und Interval_Substitute(), bei denen keine Bedingungen an die Größe der beteiligten Bitvektoren geknüpft sind. Die Multiply()-Methode bildet eine Ausnahme besonderer Art: Zwar muß auch hier prinzipiell die Regel übereinstimmender Größen eingehalten werden, aber der das Ergebnis der Multiplikation aufnehmende Bitvektor darf ausnahmsweise auch größer sein als die beiden Bitvektoren, die die Faktoren der Multiplikation enthalten.
Alle Bitnummern müssen zwischen 0 und $vector->Size()-1 liegen, sonst tritt ein fataler Indexfehler ("index out of range") auf.
$version = Bit::Vector->Version();
Liefert die Versionsnummer des Moduls zurück.
$bits = Bit::Vector->Word_Bits();
Liefert die Anzahl der Bits zurück, die der C-Datentyp "unsigned int" auf der aktuellen Maschine hat.
(Ein "unsigned int" wird auch als ein "Maschinenwort" bezeichnet; daher der Name dieser Methode.)
$bits = Bit::Vector->Long_Bits();
Liefert die Anzahl der Bits zurück, die der C-Datentyp "unsigned long" auf der aktuellen Maschine hat.
$vector = Bit::Vector->new($bits);
Dies ist die Bitvektor-Konstruktormethode.
Rufen Sie diese Methode auf, um einen neuen Bitvektor mit $bits Bits (mit Nummern im Bereich von 0 bis $bits-1) zu erzeugen.
Beachten Sie, daß im Gegensatz zu früheren Versionen dieses Moduls jetzt auch Bitvektoren der Länge Null (also mit $bits = 0) zugelassen sind.
Die Methode gibt eine Referenz auf den neu erzeugten Bitvektor zurück.
Ein neuer Bitvektor wird immer so initialisiert, daß alle Bits gelöscht (aus) sind.
Eine Ausnahme wird ausgelöst, wenn die Methode nicht in der Lage ist, den benötigten Speicherplatz zu allozieren.
Beachten Sie, daß die Angabe eines negativen Wertes für $bits als eine (in der Regel sehr große!) positive Zahl interpretiert wird. Der Grund dafür ist die interne Binärdarstellung im Zweierkomplement.
Im Fall einer solchen negativen Anzahl von Bits versucht der Bitvektor-Konstruktor trotzdem pflichtschuldigst, einen Bitvektor dieser Größe zu erzeugen, was in der Regel zu dem oben erwähnten Fehler führt.
$vector = Bit::Vector->new_Hex($bits,$string);
Diese Methode ist ein alternativer Konstruktor, der es Ihnen erlaubt, in einem einzigen Schritt sowohl einen neuen Bitvektor (mit $bits Bits) anzulegen als auch, ihn sofort mit einem Wert zu initialisieren.
Diese Methode ist dabei außerdem noch effizienter als die getrennte Durchführung dieser beiden Schritte, weil diese Methode den neuen Bitvektor nicht zuerst mit Nullen initialisiert (was ja in diesem Fall unnötig ist) und weil der mit einem zusätzlichen Methodenaufruf verbundene Aufwand vermieden wird.
Die Methode ruft dazu allerdings intern zuerst die C-Funktion new() auf und übergibt anschließend den Eingabe-String an die C-Funktion from_Hex().
Eine Ausnahme wird ausgelöst, wenn der benötigte Speicherplatz nicht alloziert werden kann oder wenn der übergebene String nicht erfolgreich umgewandelt werden kann (Erläuterungen zu möglichen Ursachen hierfür finden Sie weiter unten bei der Beschreibung der Methode from_Hex()).
Im letzteren Fall wird der durch den neuen Bitvektor belegte Speicherplatz zuerst freigegeben (mittels free()), bevor der Fehler ausgelöst wird.
$vector = Bit::Vector->new_Bin($bits,$string);
Diese Methode ist ein alternativer Konstruktor, der es Ihnen erlaubt, in einem einzigen Schritt sowohl einen neuen Bitvektor (mit $bits Bits) anzulegen als auch, ihn sofort mit einem Wert zu initialisieren.
Diese Methode ist dabei außerdem noch effizienter als die getrennte Durchführung dieser beiden Schritte, weil diese Methode den neuen Bitvektor nicht zuerst mit Nullen initialisiert (was ja in diesem Fall unnötig ist) und weil der mit einem zusätzlichen Methodenaufruf verbundene Aufwand vermieden wird.
Die Methode ruft dazu allerdings intern zuerst die C-Funktion new() auf und übergibt anschließend den Eingabe-String an die C-Funktion from_Bin().
Eine Ausnahme wird ausgelöst, wenn der benötigte Speicherplatz nicht alloziert werden kann oder wenn der übergebene String nicht erfolgreich umgewandelt werden kann (Erläuterungen zu möglichen Ursachen hierfür finden Sie weiter unten bei der Beschreibung der Methode from_Bin()).
Im letzteren Fall wird der durch den neuen Bitvektor belegte Speicherplatz zuerst freigegeben (mittels free()), bevor der Fehler ausgelöst wird.
$vector = Bit::Vector->new_Dec($bits,$string);
Diese Methode ist ein alternativer Konstruktor, der es Ihnen erlaubt, in einem einzigen Schritt sowohl einen neuen Bitvektor (mit $bits Bits) anzulegen als auch, ihn sofort mit einem Wert zu initialisieren.
Diese Methode ist dabei außerdem noch effizienter als die getrennte Durchführung dieser beiden Schritte, weil diese Methode den neuen Bitvektor nicht zuerst mit Nullen initialisiert (was ja in diesem Fall unnötig ist) und weil der mit einem zusätzlichen Methodenaufruf verbundene Aufwand vermieden wird.
Die Methode ruft dazu allerdings intern zuerst die C-Funktion new() auf und übergibt anschließend den Eingabe-String an die C-Funktion from_Dec().
Eine Ausnahme wird ausgelöst, wenn der benötigte Speicherplatz nicht alloziert werden kann oder wenn der übergebene String nicht erfolgreich umgewandelt werden kann (Erläuterungen zu möglichen Ursachen hierfür finden Sie weiter unten bei der Beschreibung der Methode from_Dec()).
Im letzteren Fall wird der durch den neuen Bitvektor belegte Speicherplatz zuerst freigegeben (mittels free()), bevor der Fehler ausgelöst wird.
$vector = Bit::Vector->new_Enum($bits,$string);
Diese Methode ist ein alternativer Konstruktor, der es Ihnen erlaubt, in einem einzigen Schritt sowohl einen neuen Bitvektor (mit $bits Bits) anzulegen als auch, ihn sofort mit einem Wert zu initialisieren.
Diese Methode ist dabei außerdem noch effizienter als die getrennte Durchführung dieser beiden Schritte, weil diese Methode den neuen Bitvektor nicht zuerst mit Nullen initialisiert (was ja in diesem Fall unnötig ist) und weil der mit einem zusätzlichen Methodenaufruf verbundene Aufwand vermieden wird.
Die Methode ruft dazu allerdings intern zuerst die C-Funktion new() auf und übergibt anschließend den Eingabe-String an die C-Funktion from_Enum().
Eine Ausnahme wird ausgelöst, wenn der benötigte Speicherplatz nicht alloziert werden kann oder wenn der übergebene String nicht erfolgreich umgewandelt werden kann (Erläuterungen zu möglichen Ursachen hierfür finden Sie weiter unten bei der Beschreibung der Methode from_Enum()).
Im letzteren Fall wird der durch den neuen Bitvektor belegte Speicherplatz zuerst freigegeben (mittels free()), bevor der Fehler ausgelöst wird.
$vector = Bit::Vector->Concat_List(@vectors);
Diese Methode erzeugt einen neuen Bitvektor, der alle Bitvektoren der Argumentliste in verketteter Form enthält.
Die Argumentliste kann dabei beliebig viele Argumente (auch keine!) enthalten. Die einzige Bedingung ist, daß alle Argumente Bitvektoren sein müssen.
Eine die Länge (Anzahl der Bits) dieser Argumente betreffende Bedingung gibt es nicht.
Die Bitvektoren der Argumentliste werden in keiner Weise verändert.
Ist die Argumentliste leer, oder besitzen alle Argumente die Länge Null, hat auch der resultierende Bitvektor die Länge Null.
Beachten Sie, daß der ganz rechts stehende Bitvektor der Argumentliste zum niederstwertigen Teil des resultierenden Bitvektors wird, während der ganz links stehende Bitvektor der Argumentliste zum höchstwertigen Teil des resultierenden Bitvektors wird.
$vec2 = $vec1->new($bits);
Eine alternative Art des Aufrufs der Bitvektor-Konstruktormethode.
Der Bitvektor $vec1 wird hiervon nicht beeinflußt; er dient nur als Anker für den Methodenaufruf.
Tatsächlich können alle Klassenmethoden dieses Moduls auf diese Weise aufgerufen werden, auch wenn das von OO-Verfechtern wohl nicht als "politisch korrekt" :-)) betrachtet werden dürfte.
Auch wenn Sie zu faul sind, um Bit::Vector-> anstelle von $vec1-> einzutippen (obwohl die Faulheit ja - laut Perl-Motto! - eine Programmierertugend ist :-)), sollten Sie dieses Feature vielleicht besser nicht verwenden, wenn Sie nicht als OO-Ignorant gelten wollen... ;-)
$vec2 = $vec1->Shadow();
Erzeugt einen neuen Bitvektor $vec2. Dieser besitzt die gleiche Anzahl von Bits wie $vec1, ist aber leer (d.h., alle Bits sind gelöscht).
Genau wie ein Schatten, der den Umriß des Objekts besitzt, von dem er abstammt. Nur ist er im Gegensatz zu diesem Objekt völlig flach und hat kein Volumen, d.h., er enthält nichts.
$vec2 = $vec1->Clone();
Erzeugt einen neuen Bitvektor $vec2. Dieser besitzt die gleiche Anzahl von Bits wie $vec1 und ist eine exakte Kopie desselben.
$vector = $vec1->Concat($vec2);
Diese Methode gibt ein neues Bitvektor-Objekt zurück, das aus der Verkettung von $vec1 und $vec2 entsteht.
Beachten Sie, daß der Inhalt von $vec1 zum höchstwertigen Teil und $vec2 zum niederstwertigen Teil des resultierenden Bitvektors wird.
Haben beide Bitvektor-Argumente die Länge Null, hat auch der resultierende Bitvektor die Länge Null.
$vector = $vec1->Concat_List($vec2,$vec3,...);
Eine alternative Möglichkeit, diese (Klassen-)Methode als Objektmethode aufzurufen.
Die Methode gibt ein neues Bitvektor-Objekt zurück, das aus der Verkettung von $vec1 . $vec2 . $vec3 . usw. entsteht.
Eine detailliertere Beschreibung dieser Methode finden Sie im obigen Abschnitt "Klassenmethoden".
Beachten Sie, daß die Argumentliste leer sein kann und daß alle Argumente Bitvektoren sein müssen, falls sie das nicht ist.
$bits = $vector->Size();
Gibt die Größe (Anzahl der Bits) zurück, mit der der gegebene Bitvektor erzeugt wurde oder die er mittels der Methode Resize() erhalten hat.
$vector->Resize($bits);
Setzt die Größe des gegebenen Bitvektors auf die angegebene Anzahl von Bits.
Mit dieser Methode können Sie die Größe eines bereits existierenden Bitvektors verändern. Dabei bleiben so viele Bits des alten Bitvektors wie nur irgend möglich erhalten, d.h. so viele wie noch in den neuen Bitvektor hineinpassen. (Dies sind alle Bits, deren Nummern kleiner sind als das Minimum aus den Größen des alten und des neuen Bitvektors, d.h alle niederstwertigen Bits.)
Ist dabei die Anzahl der zur Speicherung des neuen Bitvektors erforderlichen Maschinenwörter kleiner oder gleich der Anzahl der vom alten Bitvektor benötigten Maschinenwörter, wird der von dem alten Bitvektor belegte Speicherplatz für den neuen Bitvektor wiederverwendet. Nur die zugehörigen Verwaltungsinformationen werden entsprechend angepaßt.
Das bedeutet, daß nicht notwendigerweise neuer Speicher alloziert werden muß, wenn sich die Anzahl der Bits erhöht, nämlich solange die alte und die neue Anzahl von Bits in die gleiche Anzahl von Maschinenwörtern paßt.
Ist die Anzahl der zur Speicherung des neuen Bitvektors benötigten Maschinenwörter größer als die des alten Bitvektors, wird für den neuen Bitvektor neuer Speicher alloziert, der alte Bitvektor wird in den neuen Bitvektor kopiert, die restlichen (höchstwertigen) Bits des neuen Bitvektors werden mit Nullen initialisiert (also gelöscht), und der Speicherplatz für den alten Bitvektor wird wieder freigegeben.
Beachten Sie dabei, daß wenn Sie die Größe eines Bitvektors soweit verringern, daß weniger Maschinenwörter benötigt werden als vorher, und wenn Sie dann die Größe des Bitvektors wieder erhöhen, so daß mehr Maschinenwörter als unmittelbar vorher, aber immer noch weniger als ursprünglich benötigt werden, muß trotzdem neuer Speicher alloziert werden, weil die Information über die Größe des ursprünglichen Bitvektors bereits mit der ersten Größenänderung verlorengegangen ist.
Eine Ausnahme wird ausgelöst, wenn die Methode nicht in der Lage ist, den für den neuen Bitvektor benötigten Speicherplatz zu allozieren.
Denken Sie auch daran, daß eine negative Anzahl von Bits aufgrund der internen binären Darstellung im Zweierkomplement als (in der Regel sehr große!) positive Zahl interpretiert wird.
Im Fall einer solchen negativen Anzahl von Bits versucht die Resize()-Methode trotzdem pflichtschuldigst, einen Bitvektor dieser Größe zu erzeugen, was in der Regel zu einem fatalen Fehler mit Programmabbruch führt.
Beachten Sie schließlich noch, daß im Gegensatz zu früheren Versionen dieses Moduls jetzt auch Bitvektoren der Länge Null (also mit $bits = 0) zugelassen sind.
$vec2->Copy($vec1);
Kopiert den Inhalt von $vec1 in den Bitvektor $vec2.
Der vorherige Inhalt des Bitvektors $vec2 wird dabei überschrieben, er geht also verloren.
Beide Bitvektoren müssen bereits existieren, das heißt, diese Methode erzeugt kein neues Bitvektor-Objekt.
$vector->Empty();
Löscht alle Bits im angegebenen Bitvektor.
$vector->Fill();
Setzt alle Bits im angegebenen Bitvektor.
$vector->Flip();
Komplementiert alle Bits im angegebenen Bitvektor.
$vector->Primes();
Löscht den angegebenen Bitvektor und setzt alle Bits, deren Bitnummern Primzahlen sind.
Diese Methode verwendet intern den Algorithmus, der unter dem Namen Sieb des Erathostenes bekannt ist.
$vec2->Reverse($vec1);
Diese Methode kopiert den Bitvektor $vec1 in den Bitvektor $vec2 und kehrt dabei die Reihenfolge aller Bits um.
Das niederstwertige Bit von $vec1 wird also zum höchstwertigen Bit von $vec2, während das höchstwertige Bit von $vec1 zum niederstwertigen Bit von $vec2 wird usw.
Eine Verarbeitung "auf derselben Stelle" ist ebenfalls möglich, d.h., $vec1 und $vec2 können identisch sein.
(Intern ist das jedoch dasselbe, als würde man statt dessen $vec1->Interval_Reverse(0,$vec1->Size()-1); aufrufen.)
$vector->Interval_Empty($min,$max);
Löscht alle Bits des angegebenen Bitvektors im Intervall [$min..$max] (inklusive beider Grenzen).
$min und $max können auch denselben Wert annehmen. Dies entspricht dem Löschen eines einzelnen Bits mit Bit_Off(), ist aber weniger effizient.
Beachten Sie auch, daß $vector->Interval_Empty(0,$vector->Size()-1); mit $vector->Empty(); äquivalent ist (aber ebenfalls weniger effizient).
$vector->Interval_Fill($min,$max);
Setzt alle Bits des angegebenen Bitvektors im Intervall [$min..$max] (inklusive beider Grenzen).
$min und $max können auch denselben Wert annehmen. Dies entspricht dem Setzen eines einzelnen Bits mit Bit_On(), ist aber weniger effizient.
Beachten Sie auch, daß $vector->Interval_Fill(0,$vector->Size()-1); mit $vector->Fill(); äquivalent ist (aber ebenfalls weniger effizient).
$vector->Interval_Flip($min,$max);
Komplementiert alle Bits des angegebenen Bitvektors im Intervall [$min..$max] (inklusive beider Grenzen).
$min und $max können auch denselben Wert annehmen. Dies entspricht der Komplementierung eines einzelnen Bits mit bit_flip(), ist aber weniger effizient.
Beachten Sie auch, daß $vector->Interval_Flip(0,$vector->Size()-1); mit $vector->Flip(); und $vector->Complement($vector); äquivalent ist (aber ebenfalls weniger effizient).
$vector->Interval_Reverse($min,$max);
Kehrt die Reihenfolge der Bits des angegebenen Bitvektors im Intervall [$min..$max] (inklusive beider Grenzen) um.
D.h., die Bits mit den Nummern $min und $max tauschen ihre Plätze und alle dazwischen liegenden Bits entsprechend.
$min und $max können auch denselben Wert annehmen. Eine solche Operation hat allerdings keinerlei Effekt.
if (($min,$max) = $vector->Interval_Scan_inc($start))
Gibt die niedrigste und die höchste Bitnummer des (in aufsteigender Richtung) nächstfolgenden, zusammenhängenden Blocks von (auf eins) gesetzten Bits zurück.
Die Suche beginnt bei der Bitnummer $start (d.h. "$min" >= "$start") und verläuft von da ab aufwärts (d.h. "$max" >= "$min"), wobei der Suchzeiger $start (intern) fortwährend inkrementiert wird.
Der Inhalt der Variable (oder der Skalar-Konstanten) $start wird dabei jedoch nicht verändert. Das heißt, daß Sie den gewünschten Wert selbst einstellen müssen, bevor Sie Interval_Scan_inc() aufrufen (beachten Sie hierzu auch das nachfolgende Beispiel).
In Wirklichkeit wird der Bitvektor nicht Bit für Bit durchsucht, sondern jeweils ein Maschinenwort auf einmal, um die Ausführungsgeschwindigkeit zu erhöhen (diese Methode ist daher ziemlich effizient).
Eine leere Liste wird zurückgegeben, wenn kein weiterer solcher Block gefunden werden konnte.
Beachten Sie, daß ein einzelnes gesetztes Bit (beidseitig von gelöschten Bits eingeschlossen) dieser Definition nach ein gültiger Block ist. In einem solchen Fall wird in $min und $max der identische Wert zurückgegeben (nämlich die Nummer des betreffenden Bits).
Eine typische Anwendung:
$start = 0;
while (($start < $vector->Size()) &&
(($min,$max) = $vector->Interval_Scan_inc($start)))
{
$start = $max + 2;
# Verarbeite $min und $max in geeigneter Weise.
}
if (($min,$max) = $vector->Interval_Scan_dec($start))
Gibt die niedrigste und die höchste Bitnummer des (in absteigender Richtung) nächstfolgenden, zusammenhängenden Blocks von (auf eins) gesetzten Bits zurück.
Die Suche beginnt bei der Bitnummer $start (d.h. "$max" <= "$start") und verläuft von da an abwärts (d.h. "$min" <= "$max"), wobei der Suchzeiger $start (intern) fortwährend dekrementiert wird.
Der Inhalt der Variable (oder der Skalar-Konstanten) $start wird dabei jedoch nicht verändert. Das heißt, daß Sie den gewünschten Wert selbst einstellen müssen, bevor Sie Interval_Scan_dec() aufrufen (beachten Sie hierzu auch das nachfolgende Beispiel).
In Wirklichkeit wird der Bitvektor nicht Bit für Bit durchsucht, sondern jeweils ein Maschinenwort auf einmal, um die Ausführungsgeschwindigkeit zu erhöhen (diese Methode ist daher ziemlich effizient).
Eine leere Liste wird zurückgegeben, wenn kein weiterer solcher Block gefunden werden konnte.
Beachten Sie, daß ein einzelnes gesetztes Bit (beidseitig von gelöschten Bits eingeschlossen) dieser Definition nach ein gültiger Block ist. In einem solchen Fall wird in $min und $max der identische Wert zurückgegeben (nämlich die Nummer des betreffenden Bits).
Eine typische Anwendung:
$start = $vector->Size() - 1;
while (($start >= 0) &&
(($min,$max) = $vector->Interval_Scan_dec($start)))
{
$start = $min - 2;
# Verarbeite $min und $max in geeigneter Weise.
}
$vec2->Interval_Copy($vec1,$offset2,$offset1,$length);
Mit dieser Methode können Sie ein Intervall von Bits (beginnend an einer beliebigen, von Ihnen gewählten Position $offset1 und mit einer Länge von $length Bits) von einem Quell-Bitvektor $vec1 an die Position $offset2 in einem Ziel-Bitvektor $vec2 kopieren.
Beachten Sie, daß die beiden Bitvektoren $vec1 und $vec2 nicht die gleiche Größe haben müssen!
Sowohl $offset1 + $length als auch $offset2 + $length können daher die tatsächliche Länge des entsprechenden Bitvektors ($vec1->Size() bzw. $vec2->Size()) übersteigen.
In einem solchen Fall wird intern automatisch der Längenparameter $length so angepaßt, daß die beiden obigen Terme durch die Anzahl der Bits von beiden Bitvektoren nach oben begrenzt werden, d.h. so, daß sowohl $offset1 + $length <= $vec1->Size() als auch $offset2 + $length <= $vec2->Size() gilt.
Das kann auch zu einer Länge von Null Bits führen; in diesem Fall hat diese Methode keinerlei Effekt.
(Selbstverständlich darf der Längenparameter $length auch von vornherein null betragen!)
Beachten Sie auch, daß $offset1 und $offset2 innerhalb des Bereichs 0 und $vec1->Size()-1 bzw. $vec2->Size()-1 liegen müssen, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Beachten Sie weiterhin, daß $vec1 und $vec2 identisch sein können, d.h., Sie können Bits von einem Ort innerhalb desselben Bitvektors an einen anderen Ort kopieren (und die dortigen Bits damit überschreiben).
Das Quell- und das Ziel-Intervall dürfen sich dabei sogar überlappen. Der Kopiervorgang erfolgt dann automatisch in auf- oder absteigender Richtung, je nachdem ob das Quell- oder das Ziel-Intervall zuunterst liegt (bezogen auf Bitnummern). Es werden also keine Bits überschrieben, bevor diese nicht selbst kopiert wurden.
$vec2->Interval_Substitute($vec1,$off2,$len2,$off1,$len1);
Diese Methode ist für Bitvektoren (also Arrays von Bits) in etwa das gleiche, was die Perl-Funktion splice() für Listen (also Arrays von Skalaren) ist.
(Details zur Funktion splice() finden Sie in perlfunc(1).)
Mit dieser Methode können Sie ein Intervall von Bits (ab der Position $off2 und mit einer Länge von $len2 Bits) in einem Ziel-Bitvektor $vec2 durch ein anderes Intervall von Bits (ab der Position $off1 und mit einer Länge von $len1 Bits) aus einem Quell-Bitvektor $vec1 ersetzen.
Beachten Sie, daß die beiden Bitvektoren $vec1 und $vec2 nicht die gleiche Länge haben müssen!
Beachten Sie auch, daß $off1 und $off2 innerhalb des Bereichs 0 und $vec1->Size() bzw. $vec2->Size() liegen müssen, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Aufmerksame Leser werden sicherlich bemerkt haben, daß diese Obergrenzen hier nicht $vec1->Size()-1 und $vec2->Size()-1 lauten, wie das bei allen anderen Methoden dieses Moduls (wo anwendbar) der Fall ist. Tatsächlich können diese Offsets auf die Stelle genau eine Position hinter dem Ende des jeweiligen Bitvektors zeigen.
Das ist deswegen unbedingt notwendig, damit man ein gegebenes Quell-Intervall gegebenenfalls auch hinten an den Ziel-Bitvektor anhängen kann, anstatt ein bestehendes Intervall darin nur zu ersetzen.
Aus Gründen der Symmetrie und der Einheitlichkeit gilt das gleiche auch für den Offset im Quell-Bitvektor, auch wenn ein solcher Offset (eine Position hinter dem Ende des Bitvektors) hier keinerlei praktischen Zwecken dient (aber auch keinen Schaden anrichtet).
(Tatsächlich erspart das jedoch unter bestimmten Umständen einen Test für diesen Sonderfall.)
Übersteigt der Term $off1 + $len1 die Größe $vec1->Size() des Bitvektors $vec1 (oder $off2 + $len2 die Größe $vec2->Size()), wird die entsprechende Länge ($len1 bzw. $len2) intern automatisch so weit reduziert, daß sowohl $off1 + $len1 <= $vec1->Size() als auch $off2 + $len2 <= $vec2->Size() gilt.
(Beachten Sie, daß sich dadurch am gewünschten Ergebnis nichts ändert, auch wenn das auf den ersten Blick nicht der Fall zu sein scheint!)
Das kann sogar zu einer Länge ($len1 oder $len2) von null Bits führen.
Die Länge Null für das Intervall im Quell-Bitvektor ($len1 == 0) bewirkt, daß das Intervall im Ziel-Bitvektor (beginnend an Position $off2) durch nichts ersetzt, also gelöscht wird.
Die Länge Null für das Intervall im Ziel-Bitvektor ("$len2 == 0") bedeutet, daß nichts ersetzt werden soll, d.h., das Intervall aus dem Quell-Bitvektor wird im Ziel-Bitvektor an der angegebenen Stelle ($off2) einfach nur eingefügt.
Sind dagegen beide Längenparameter null, hat diese Methode keinerlei Effekt.
Beachten Sie, daß diese Methode im Gegensatz zu allen anderen Methoden dieses Moduls (speziell zu Interval_Copy(), Insert() und Delete()) die Länge des resultierenden Bitvektors implizit und automatisch wie folgt verändert:
$size = $vec2->Size(); # vorher $size += $len1 - $len2; # nachher
(Die einzige andere Methode dieses Moduls, die die Größe eines Bitvektors verändert, ist Resize().)
Mit anderen Worten, das Ersetzen eines Bitintervalls im Ziel-Bitvektor durch ein längeres oder kürzeres Intervall aus dem Quell-Bitvektor führt dazu, daß die Länge des Ziel-Bitvektors automatisch vergrößert bzw. verringert wird. Das gleiche gilt auch für das Einfügen eines Bitintervalls in ($len2 == 0) und das Löschen eines Bitintervalls aus ($len1 == 0) dem Ziel-Bitvektor.
Aus Gründen der Allgemeinheit ("OBdA"... :-)) und Einheitlichkeit kann das sogar zu einem Bitvektor der Länge Null führen (also zu einem Bitvektor, der wirklich keinerlei Bits mehr enthält, also nicht etwa nur auf Null gesetzte Bits!).
Hierin liegt auch der Grund, warum dieses Modul seit der Version 5.0 überhaupt Bitvektoren der Länge Null zuläßt(!).
Beachten Sie schließlich auch, daß $vec1 und $vec2 identisch sein können, d.h., eine Verarbeitung "auf derselben Stelle" ist möglich.
(Wenn Sie eine Weile darüber nachdenken oder sich den Code anschauen, werden Sie erkennen, daß das alles andere als trivial ist!)
if ($vector->is_empty())
Überprüft, ob der Bitvektor vollständig "leer" ist, d.h., ob alle Bits gelöscht ("aus") sind.
Bei "Big Integer"-Arithmetik entspricht das dem Test, ob die im Bitvektor abgelegte Zahl eine Null (0) ist.
Gibt "wahr" (1) zurück, wenn der Bitvektor leer ist, anderenfalls wird "falsch" (0) zurückgegeben.
Beachten Sie, daß die Methode z.B. auch dann "wahr" (1) zurückgibt, wenn der Bitvektor die Länge Null hat (also überhaupt keine Bits enthält).
if ($vector->is_full())
Überprüft, ob der Bitvektor "voll" ist, d.h., ob alle Bits gesetzt ("an") sind.
Bei "Big Integer"-Arithmetik entspricht das dem Test, ob die im Bitvektor abgelegte Zahl eine -1 ist.
Gibt "wahr" (1) zurück, wenn der Bitvektor voll ist, anderenfalls wird "falsch" (0) zurückgegeben.
Hat der Bitvektor die Länge Null (sind also darin überhaupt keine Bits enthalten), gibt die Methode immer "falsch" (0) zurück.
if ($vec1->equal($vec2))
Überprüft, ob die beiden übergebenen Bitvektoren gleich sind.
Gibt "wahr" (1) zurück, wenn die beiden Bitvektoren identische Kopien voneinander sind, anderenfalls wird "falsch" (0) zurückgegeben.
$cmp = $vec1->Lexicompare($vec2);
Vergleicht die beiden übergebenen Bitvektoren, die als vorzeichenlos angesehen werden.
Die Methode gibt -1 zurück, wenn der erste Bitvektor kleiner ist als der zweite, 0, falls die beiden Bitvektoren identische Kopien voneinander sind, und 1, wenn der erste Bitvektor größer ist als der zweite.
$cmp = $vec1->Compare($vec2);
Vergleicht die beiden übergebenen Bitvektoren, die als vorzeichenbehaftet angesehen werden.
Die Methode gibt -1 zurück, wenn der erste Bitvektor kleiner ist als der zweite, 0, falls die beiden Bitvektoren identische Kopien voneinander sind, und 1, wenn der erste Bitvektor größer ist als der zweite.
$string = $vector->to_Hex();
Liefert einen String zurück, der die dem gegebenen Bitvektor entsprechende Hexadezimalzahl enthält.
Diese Darstellung ist übrigens recht kompakt (platzsparend), da sie maximal nur doppelt so viele Bytes benötigt, wie zur internen Speicherung des Bitvektors selbst notwendig sind.
Beachten Sie, daß der resultierende String immer einem Vielfachen von vier Bits entspricht, da jede hexadezimale Ziffer genau vier Bits repräsentiert. Diese Anzahl von Bits kann daher gegebenenfalls von der des gegebenen Bitvektors (um maximal drei Bits) abweichen, falls die Länge des Bitvektors kein Vielfaches von vier ist. Das ist jedoch nicht weiter schlimm, da es sich dabei lediglich um führende (und zudem unsichtbare) Null-Bits handelt.
Beachten Sie schließlich noch, daß die niederstwertige hexadezimale Ziffer am rechten Ende des resultierenden Strings zu finden ist, während die höchstwertige hexadezimale Ziffer am linken Ende steht.
$vector->from_Hex($string);
Erlaubt das Einlesen des Inhalts eines Bitvektors über einen hexadezimalen String, wie er beispielsweise von der Methode to_Hex() (siehe oben) zurückgegeben wird.
Denken Sie daran, daß die niederstwertigen Ziffern immer rechts im hexadezimalen String zu finden sind, während die höchstwertigen Ziffern am linken Ende stehen. Aus diesem Grund wird der String auch immer von rechts nach links eingelesen, wobei der Bitvektor währenddessen in aufsteigender Richtung aufgefüllt wird. Dabei werden immer jeweils vier Bits auf einmal verarbeitet, angefangen vom niederstwertigen Bit bis hin zum höchstwertigen.
Enthält ein String weniger hexadezimale Ziffern, als zum vollständigen Füllen des Bitvektors erforderlich wären, werden die übrigen (höchstwertigen) Bits des Bitvektors alle gelöscht.
Das bedeutet auch, daß der vorherige Inhalt des Bitvektors vollständig gelöscht wird, selbst wenn der String nicht genug Ziffern enthält, um den Bitvektor ganz zu füllen.
Ist der String dagegen länger, als für das vollständige Füllen des Bitvektors erforderlich ist, werden die überflüssigen Bits und/oder Zeichen einfach ignoriert.
Tatsächlich werden sie völlig ignoriert - sie werden nicht einmal auf korrekte Syntax untersucht. (Mehr hierzu finden Sie auch weiter unten.)
Dieses Verhalten ermöglicht es, einen Bitvektor in einen String umzuwandeln und diesen String in einem anderen Bitvektor mit unter Umständen einer ganz anderen Größe wieder einzulesen (zumindest soviel davon, wie in den zweiten Bitvektor hineinpaßt!).
Wird während des Einlesens des Strings ein Zeichen gefunden, das keine hexadezimale Ziffer ist, hat das einen fatalen Syntaxfehler ("input string syntax error") mit Programmabbruch zur Folge.
$string = $vector->to_Bin();
Liefert einen String zurück, der die dem gegebenen Bitvektor entsprechende Binärzahl enthält.
Beispiel:
$vector = Bit::Vector->new(8); $vector->Primes(); $string = $vector->to_Bin(); print "'$string'\n";
Dies führt zu folgender Ausgabe:
'10101100'
(Die Bits 7, 5, 3 und 2 sind gesetzt, also die ersten paar Primzahlen.)
Beachten Sie, daß das niederstwertige Bit am rechten Ende des resultierenden Strings steht, während das höchstwertige Bit am linken Ende steht.
$vector->from_Bin($string);
Diese Methode erlaubt das Einlesen eines Bitvektors aus einem Binär-String, wie er beispielsweise von der Methode to_Bin() (siehe oben) zurückgegeben wird.
Beachten Sie, daß die Methode davon ausgeht, daß das niederstwertige Bit am rechten Ende des Binär-Strings steht und das höchstwertige Bit am linken Ende. Aus diesem Grund wird der String auch immer von rechts nach links eingelesen, wobei der Bitvektor währenddessen in aufsteigender Richtung aufgefüllt wird, angefangen beim niederstwertigen Bit bis hin zum höchstwertigen.
Enthält der String weniger Binärziffern (0 oder 1), als zum vollständigen Füllen des gegebenen Bitvektors notwendig sind, werden die übrigen (höchstwertigen) Bits des Bitvektors alle gelöscht.
Das bedeutet auch, daß der vorherige Inhalt des Bitvektors vollständig gelöscht wird, selbst wenn der String nicht genug Ziffern enthält, um den Bitvektor ganz zu füllen.
Ist ein String länger als zum Füllen des gegebenen Bitvektors notwendig, werden die überflüssigen Zeichen einfach ignoriert.
Tatsächlich werden sie völlig ignoriert - sie werden nicht einmal auf korrekte Syntax untersucht. (Mehr hierzu finden Sie auch weiter unten.)
Dieses Verhalten ermöglicht es, einen Bitvektor in einen String umzuwandeln und diesen String in einem anderen Bitvektor mit unter Umständen einer ganz anderen Größe wieder einzulesen (zumindest soviel davon, wie in den zweiten Bitvektor hineinpaßt!).
Wird während des Einlesens des Strings ein Zeichen gefunden, das nicht 0 oder 1 ist, hat das einen fatalen Syntaxfehler ("input string syntax error") mit Programmabbruch zur Folge.
$string = $vector->to_Dec();
Diese Methode gibt einen String zurück, der den Inhalt des gegebenen Bitvektors als Dezimalzahl (Zahl zur Basis 10) enthält.
Beachten Sie, daß diese Methode davon ausgeht, daß der gegebene Bitvektor vorzeichenbehaftet ist (und eine Zahl in binärer Zweierkomplementdarstellung enthält).
Das hat zur Folge daß jeder Bitvektor, dessen höchstwertiges Bit gesetzt ist, als eine negative Zahl betrachtet wird.
Der zurückgegebene String kann an from_Dec() (siehe unten) übergeben werden, um z.B. den Inhalt dieses Bitvektors in einen anderen Bitvektor zu kopieren (oder um den Inhalt eines Bitvektors wiederherzustellen). Von diesem Vorgehen wird aber dringend abgeraten, weil das extrem ineffizient ist (dieses Modul bietet wesentlich effizientere Methoden zum Abspeichern, Kopieren und Wiedereinlesen von Bitvektoren an!).
Beachten Sie, daß diese Umwandlung von der internen binären Darstellung nach dezimal sehr aufwendig und somit vergleichsweise langsam ist, da der Bitvektor dafür solange durch 10 (mit Rest) geteilt werden muß, bis der Quotient null ergibt (jeder Rest stellt dabei nur eine einzige Dezimalziffer des resultierenden Strings dar!). Mit anderen Worten, für jede Dezimalziffer des Ergebnisses muß der ganze Bitvektor einmal durch 10 dividiert werden!
Das gilt im Prinzip auch für die Implementierung dieser Methode in diesem Modul. Es wurden hier jedoch noch einige Maßnahmen getroffen, um die Effizienz zu steigern: Statt wiederholt durch 10 zu teilen, wird der Bitvektor laufend durch die höchste 10er-Potenz dividiert, die noch in ein Maschinenwort hineinpaßt. Der Rest dieser Division wird dann wiederholt durch 10 geteilt, wobei nur noch Maschinenwort-Arithmetik eingesetzt zu werden braucht, was natürlich wesentlich günstiger ist, als den gesamten Bitvektor durch 10 zu teilen (Prinzip "Teile und Herrsche"!).
Meinen Messungen zufolge ist diese Variante etwa 8mal schneller als der naive Ansatz.
Nichtsdestotrotz sollte die Umwandlung von Bitvektoren in Dezimalzahlen so spärlich wie möglich verwendet werden, da diese Umwandlung trotz der effizienzsteigernden Maßnahmen bei sehr großen Bitvektoren (z.B. einige tausend Bits) ein bis zwei Sekunden dauern kann!
Legen Sie den zurückgegebenen String daher in irgendeiner Variablen ab, falls Sie ihn nochmals benötigen sollten, anstatt den Bitvektor erneut zu konvertieren.
Bedenken Sie, daß, wenn Sie die Konfiguration für überladene Operatoren auf output=decimal setzen, diese Methode für jeden in Anführungszeichen stehenden Bitvektor ausgeführt wird!
$vector->from_Dec($string);
Diese Methode erlaubt Ihnen die Umwandlung einer gegebenen Dezimalzahl (positiv oder negativ) in eine binäre Zweierkomplementdarstellung, die im gegebenen Bitvektor abgelegt wird.
Die Dezimalzahl sollte dabei immer als String übergeben werden, um einem möglichen Genauigkeitsverlust durch Abschneiden von Dezimalstellen vorzubeugen, der durch die interne Darstellung von großen Zahlen in Perl im Fließkommaformat (mit Exponenten) auftreten kann.
Ist die Binärdarstellung der gegebenen Dezimalzahl zu groß, um in den gegebenen Bitvektor zu passen (besitzt der Bitvektor also nicht genug Bits, um diesen Wert aufzunehmen), kommt es zu einem fatalen numerischen Überlauffehler ("numeric overflow error").
Um diesen Fehler zu vermeiden, machen Sie den Bitvektor vorher einfach größer!
Enthält der Eingabe-String andere Zeichen als die Dezimalziffern 0..9 sowie ggfs. ein führendes Vorzeichen (+ oder -), so führt dies zu einem fatalen Syntaxfehler ("input string syntax error").
Ist ein möglicher Programmabbruch unerwünscht oder von Ihrer Anwendung her nicht tolerierbar, können Sie eval wie folgt einsetzen, um diesen Fehler abzufangen:
eval { $vector->from_Dec("1152921504606846976"); };
if ($@)
{
# Fehlerbehandlung
}
Es gibt vier mögliche Fehlermeldungen:
if ($@ =~ /item is not a string/) if ($@ =~ /input string syntax error/) if ($@ =~ /numeric overflow error/) if ($@ =~ /unable to allocate memory/)
Beachten Sie, daß die Umwandlung von Dezimalzahlen in die interne Binärdarstellung relativ aufwendig ist und somit langsam, da hierfür eine Vielzahl von Multiplikationen ausgeführt werden muß. (Im Prinzip muß dazu jede Dezimalziffer mit der binären Entsprechung derjenigen 10er-Potenz multipliziert werden, die der Position dieser Dezimalziffer in der Dezimalzahl (also ihrem Wert) entspricht, also 1, 10, 100, 1000, 10000 usw.)
Auch hier (wie bei der Methode to_Dec()) wird jedoch zur Steigerung der Effizienz das Prinzip "Teile und Herrsche" angewandt: Es werden zuerst so viele Dezimalstellen in einem Maschinenwort akkumuliert wie möglich, bevor dieses Maschinenwort mit einer geeigneten 10er-Potenz multipliziert und zum gegebenen Bitvektor hinzuaddiert wird (dieser wird natürlich anfangs mit Null initialisiert).
Diese Umwandlung ist zwar nicht ganz so zeitaufwendig wie die umgekehrte Umwandlung von Binär nach Dezimal (bei der anstelle von Multiplikationen noch zeitintensivere Divisionen durchgeführt werden müssen), aber dennoch vergleichsweise langsam.
Aus diesem Grunde sollten Sie diese Methode so spärlich wie nur möglich verwenden und lieber nach der Umwandlung eine identische Kopie des betreffenden Bitvektors anlegen, als denselben String noch einmal zu konvertieren.
Bedenken Sie, daß, wenn Sie die Konfiguration für überladene Operatoren auf input=decimal setzen, diese Methode auf jeden skalaren Operanden angewendet wird!
$string = $vector->to_Enum();
Wandelt den gegebenen Bitvektor in eine Aufzählung einzelner Bitnummern oder zusammenhängender Bereiche von Bitnummern (im ".newsrc"-Stil) um, die alle (auf 1) gesetzten Bits des Bitvektors enthalten.
Beispiel:
$vector = Bit::Vector->new(20); $vector->Bit_On(2); $vector->Bit_On(3); $vector->Bit_On(11); $vector->Interval_Fill(5,7); $vector->Interval_Fill(13,19); print "'", $vector->to_Enum(), "'\n";
Dies ergibt:
'2,3,5-7,11,13-19'
Ist der gegebene Bitvektor leer, so ist der resultierende String ebenfalls leer.
Das obige Beispiel kann man übrigens auch noch etwas kompakter formulieren:
Bit::Vector->Configuration("out=enum");
$vector = Bit::Vector->new(20);
$vector->Index_List_Store(2,3,5,6,7,11,13,14,15,16,17,18,19);
print "'$vector'\n";
$vector->from_Enum($string);
Diese Methode löscht zunächst den gegebenen Bitvektor und setzt dann die Bits zu den im String angegebenen Bitnummern und Bereichen von Bitnummern auf 1.
Der String $string darf dabei nur positive ganze Zahlen oder Bereichsangaben (zwei durch "-" miteinander verbundene, positive ganze Zahlen) enthalten, die durch Kommata (",") jeweils voneinander getrennt sind.
Alle anderen Zeichen (auch Leerzeichen!) sind nicht erlaubt und führen zu einem fatalen Syntaxfehler ("input string syntax error").
Bei jeder Bereichsangabe muß die erste Zahl (die untere Grenze des Bereichs) stets kleiner oder gleich der zweiten Zahl (der oberen Grenze) sein, sonst tritt ein fataler Indexfehler ("minimum > maximum index") auf.
Alle Bitnummern müssen außerdem im erlaubten Bereich des gegebenen Bitvektors liegen, d.h. zwischen 0 und $vector->Size()-1.
Ist diese Bedingung nicht erfüllt, kommt es ebenfalls zu einem fatalen Indexfehler ("index out of range").
Ist ein möglicher Programmabbruch unerwünscht oder von Ihrer Anwendung her nicht tolerierbar, können Sie eval wie folgt einsetzen, um diesen Fehler abzufangen:
eval { $vector->from_Enum("2,3,5-7,11,13-19"); };
if ($@)
{
# Fehlerbehandlung
}
Es gibt vier mögliche Fehlermeldungen:
if ($@ =~ /item is not a string/) if ($@ =~ /input string syntax error/) if ($@ =~ /index out of range/) if ($@ =~ /minimum > maximum index/)
Die Reihenfolge der Bitnummern und der Bereiche ist übrigens unerheblich, d.h.,
eval { $vector->from_Enum("11,5-7,3,13-19,2"); };
führt zu dem gleichen Bitvektor wie im obigen Beispiel.
Bereiche und Bitnummern können sich auch überlappen.
Das liegt daran, daß intern jede (einzelne) Bitnummer aus dem String an die Methode Bit_On() übergeben wird und jede Bereichsangabe an die Methode Interval_Fill().
Der resultierende Bitvektor ist also einfach die Vereinigungsmenge aller Bitnummern und Bereiche, die im String angegeben wurden.
$vector->Bit_Off($index);
Löscht das Bit mit der Nummer $index im gegebenen Bitvektor.
$vector->Bit_On($index);
Setzt das Bit mit der Nummer $index im gegebenen Bitvektor.
$vector->bit_flip($index)
Komplementiert das Bit mit der Nummer $index im gegebenen Bitvektor.
Darüber hinaus gibt die Methode den neuen Zustand des fraglichen Bits zurück, d.h., sie gibt 0 zurück, wenn das Bit gelöscht ist, und 1, wenn es gesetzt ist (beides nachdem das Bit komplementiert wurde).
if ($vector->bit_test($index)),
if ($vector->contains($index))
Liefert den aktuellen Zustand des Bits mit der Nummer $index im gegebenen Bitvektor, d.h., es gibt 0 zurück, wenn das Bit gelöscht ("aus") ist, bzw. 1, wenn es gesetzt ("an") ist.
$vector->Bit_Copy($index,$bit);
Setzt das Bit mit der Nummer $index im gegebenen Bitvektor auf den (Booleschen) Wert $bit.
$vector->LSB($bit);
Setzt das niederstwertige Bit im gegebenen Bitvektor auf den (Booleschen) Wert $bit.
Dies ist eine (effizientere) Abkürzung für $vector->Bit_Copy(0,$bit);.
$vector->MSB($bit);
Setzt das höchstwertige Bit im gegebenen Bitvektor auf den (Booleschen) Wert $bit.
Dies ist eine (effizientere) Abkürzung für $vector->Bit_Copy($vector->Size()-1,$bit);.
$bit = $vector->lsb();
Gibt das niederstwertige Bit im gegebenen Bitvektor zurück.
Dies ist eine (effizientere) Abkürzung für $bit = $vector->bit_test(0);.
$bit = $vector->msb();
Gibt das höchstwertige Bit im gegebenen Bitvektor zurück.
Dies ist eine (effizientere) Abkürzung für $bit = $vector->bit_test($vector->Size()-1);.
$carry_out = $vector->rotate_left();
carry MSB vector: LSB
out:
+---+ +---+---+---+--- ---+---+---+---+
| | <---+--- | | | | ... | | | | <---+
+---+ | +---+---+---+--- ---+---+---+---+ |
| |
+------------------------------------------------+
Das niederstwertige Bit (LSB) ist das Bit mit der Nummer 0, das höchstwertige Bit (MSB) ist das Bit mit der Nummer $vector->Size()-1.
$carry_out = $vector->rotate_right();
MSB vector: LSB carry
out:
+---+---+---+--- ---+---+---+---+ +---+
+---> | | | | ... | | | | ---+---> | |
| +---+---+---+--- ---+---+---+---+ | +---+
| |
+------------------------------------------------+
Das niederstwertige Bit (LSB) ist das Bit mit der Nummer 0, das höchstwertige Bit (MSB) ist das Bit mit der Nummer $vector->Size()-1.
$carry_out = $vector->shift_left($carry_in);
carry MSB vector: LSB carry out: in: +---+ +---+---+---+--- ---+---+---+---+ +---+ | | <--- | | | | ... | | | | <--- | | +---+ +---+---+---+--- ---+---+---+---+ +---+
Das niederstwertige Bit (LSB) ist das Bit mit der Nummer 0, das höchstwertige Bit (MSB) ist das Bit mit der Nummer $vector->Size()-1.
$carry_out = $vector->shift_right($carry_in);
carry MSB vector: LSB carry in: out: +---+ +---+---+---+--- ---+---+---+---+ +---+ | | ---> | | | | ... | | | | ---> | | +---+ +---+---+---+--- ---+---+---+---+ +---+
Das niederstwertige Bit (LSB) ist das Bit mit der Nummer 0, das höchstwertige Bit (MSB) ist das Bit mit der Nummer $vector->Size()-1.
$vector->Move_Left($bits);
Verschiebt den gegebenen Bitvektor um $bits Bits nach links, d.h., fügt $bits neue Bits am unteren Ende (LSB) des Bitvektors ein, bewegt alle anderen Bits um $bits Positionen nach oben, wodurch die $bits höchstwertigen Bits verlorengehen.
Die neu eingefügten Bits werden alle gelöscht (auf "aus" gesetzt).
Die Methode hat keinerlei Wirkung, falls $bits null ist.
Beachten Sie, daß der gesamte Bitvektor ohne Warnung gelöscht wird, wenn $bits größer oder gleich der Größe des Bitvektors ist!
Diese Methode ist äquivalent zu
for ( $i = 0; $i < $bits; $i++ ) { $vector->shift_left(0); }
ist aber - bei einer Anzahl $bits, die größer oder gleich der Anzahl von Bits in einem Maschinenwort ist - wesentlich effizienter als dieser naive Ansatz.
$vector->Move_Right($bits);
Verschiebt den gegebenen Bitvektor um $bits Bits nach rechts, d.h., löscht die $bits niederstwertigen Bits des Bitvektors, bewegt alle anderen Bits um $bits Positionen nach unten und erzeugt somit $bits neue Bits am oberen Ende (MSB) des Bitvektors.
Diese freiwerdenden Bits werden alle gelöscht (auf "aus" gesetzt).
Die Methode hat keinerlei Wirkung, falls $bits null ist.
Beachten Sie, daß der gesamte Bitvektor ohne Warnung gelöscht wird, wenn $bits größer oder gleich der Größe des Bitvektors ist!
Diese Methode ist äquivalent zu
for ( $i = 0; $i < $bits; $i++ ) { $vector->shift_right(0); }
ist aber - bei einer Anzahl $bits, die größer oder gleich der Anzahl von Bits in einem Maschinenwort ist - wesentlich effizienter als dieser naive Ansatz.
$vector->Insert($offset,$bits);
Diese Methode fügt $bits neue Bits an der Position $offset in den gegebenen Bitvektor ein.
Die $bits höchstwertigen Bits gehen dabei verloren, und alle Bits von Bit Nummer $offset bis einschließlich Bit Nummer $vector->Size()-$bits-1 werden um $bits Positionen nach oben verschoben.
Die nun freigewordenen $bits Bits von Bit Nummer $offset bis einschließlich Bit Nummer $offset+$bits-1 werden anschließend auf null gesetzt (gelöscht).
Beachten Sie, daß diese Methode die Größe des gegebenen Bitvektors nicht erhöht, d.h., der Bitvektor wird nicht an seinem oberen (höchstwertigen) Ende erweitert, um die $bits höchstwertigen Bits zu "retten" - vielmehr gehen diese Bits für immer verloren.
Falls Sie das nicht wollen, müssen Sie die Größe des gegebenen Bitvektors explizit erhöhen, und zwar bevor Sie die Einfügeoperation durchführen. Dies ist mit der folgenden Anweisung möglich:
$vector->Resize($vector->Size() + $bits);
Alternativ können Sie anstelle von Insert() die Methode Interval_Substitute() verwenden. Diese nimmt eine automatische Vergrößerung (bzw. Verkleinerung) des Ziel-Bitvektors vor.
Beachten Sie auch, daß $offset im erlaubten Bereich zwischen 0 und $vector->Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Ist der Term $offset + $bits größer als $vector->Size()-1, werden einfach nur alle Bits von Bit Nummer $offset bis zu Bit Nummer $vector->Size()-1 gelöscht (d.h. auf Null gesetzt).
$vector->Delete($offset,$bits);
Diese Methode löscht (d.h. entfernt) alle Bits im gegebenen Bitvektor ab Bit Nummer $offset bis einschließlich Bit Nummer $offset+$bits-1.
Die höchstwertigen Bits ab Bit Nummer $offset+$bits bis einschließlich Bit Nummer $vector->Size()-1 werden dabei um $bits Positionen nach unten verschoben (rücken also nach).
Die nun freigewordenen $bits höchstwertigen Bits werden anschließend auf null gesetzt (gelöscht).
Beachten Sie, daß diese Methode die Größe des gegebenen Bitvektors nicht verringert, d.h., der Bitvektor wird nicht an seinem oberen (höchstwertigen) Ende abgeschnitten, um die überschüssigen $bits höchstwertigen Bits "loszuwerden".
Falls Sie das nicht wollen, müssen Sie die Größe des gegebenen Bitvektors explizit verringern, und zwar nach der Löschoperation. Dies ist mit den folgenden Anweisungen möglich:
$size = $vector->Size();
if ($bits > $size) { $bits = $size; }
$vector->Resize($size - $bits);
Alternativ können Sie anstelle von Delete() die Methode Interval_Substitute() verwenden. Diese nimmt eine automatische Verkleinerung (bzw. Vergrößerung) des Ziel-Bitvektors vor.
Beachten Sie auch, daß $offset im erlaubten Bereich zwischen 0 und $vector->Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Ist der Term $offset + $bits größer als $vector->Size()-1, werden einfach nur alle Bits von Bit Nummer $offset bis zu Bit Nummer $vector->Size()-1 gelöscht (d.h. auf Null gesetzt).
$carry = $vector->increment();
Diese Methode inkrementiert den gegebenen Bitvektor.
Beachten Sie, daß diese Methode Bitvektoren als vorzeichenlos betrachtet, d.h. auf die größtmögliche positive Zahl folgt direkt die kleinstmögliche (oder, absolut gesehen, die größtmögliche) negative Zahl:
vorher: 2 ^ (b-1) - 1 (= "0111...1111") nachher: 2 ^ (b-1) (= "1000...0000")
(Hierbei steht b für die Anzahl der Bits des gegebenen Bitvektors.)
Die Methode gibt stets "falsch" (0) zurück, außer bei einem Übertrag, der beim Inkrementieren von "1111...1111" auftritt (was "0000...0000" plus den Übertrag ergibt); in diesem Fall wird statt dessen "wahr" (1) zurückgegeben.
Dies kann für die Abbruchbedingung in einer "while"-Schleife genutzt werden, z.B., wenn Sie einen Bitvektor alle seine möglichen Werte durchlaufen lassen wollen.
$carry = $vector->decrement();
Die Methode dekrementiert den gegebenen Bitvektor.
Beachten Sie, daß diese Methode Bitvektoren als vorzeichenlos betrachtet, d.h. auf die kleinstmögliche (oder, absolut gesehen, die größtmögliche) negative Zahl folgt direkt die größtmögliche positive Zahl:
vorher: 2 ^ (b-1) (= "1000...0000") nachher: 2 ^ (b-1) - 1 (= "0111...1111")
(Hierbei steht b für die Anzahl der Bits des gegebenen Bitvektors.)
Die Methode gibt stets "falsch" (0) zurück, außer bei einem Übertrag, der beim Dekrementieren von "0000...0000" auftritt (was "1111...1111" sowie den Übertrag ergibt); in diesem Fall wird statt dessen "wahr" (1) zurückgegeben.
Dies kann für die Abbruchbedingung in einer "while"-Schleife genutzt werden, z.B., wenn Sie einen Bitvektor alle seine möglichen Werte durchlaufen lassen wollen.
$carry = $vec3->add($vec1,$vec2,$carry);
Diese Methode addiert die beiden Zahlen in den Bitvektoren $vec1 und $vec2, unter Berücksichtigung des Übertrags $carry, legt das Ergebnis im Bitvektor $vec3 ab und liefert einen neuen Übertrag als Rückgabewert.
Mit anderen Worten:
$vec3 = $vec1 + $vec2 + $carry
Beachten Sie, daß der Eingabeparameter $carry ein Boolescher Wert ist, d.h., nur das niederstwertige Bit davon wird berücksichtigt (alle anderen Bits werden intern mit Hilfe von $carry &= 1; abgeschnitten).
Die Methode gibt einen Booleschen Wert zurück, der anzeigt, ob ein Übertrag (in das nächsthöhere Bit) stattgefunden hat.
Die Ein- und Ausgabe des Übertrags wird hauptsächlich zur Kaskadierung benötigt, d.h. zur Addition von Zahlen, die in mehrere Teile zerlegt sind:
# Initialisierung
for ( $i = 0; $i < $n; $i++ )
{
$a[$i] = Bit::Vector->new($bits);
$b[$i] = Bit::Vector->new($bits);
$c[$i] = Bit::Vector->new($bits);
}
# Fülle @a und @b.
# $a[ 0 ] ist niederstwertiger Teil,
# $a[$n-1] ist höchstwertiger Teil.
# Das gleiche gilt für @b.
# Addiere
$carry = 0;
for ( $i = 0; $i < $n; $i++ )
{
$carry = $c[$i]->add($a[$i],$b[$i],$carry);
}
Beachten Sie, daß es für diese Methode keine Rolle spielt, ob die Zahlen in den beiden Bitvektoren ($vec1 und $vec2) vorzeichenbehaftet sind oder vorzeichenlos, da sie intern mittels des Zweierkomplements dargestellt werden und die Addition dadurch automatisch für beide Arten von Zahlen korrekt ist.
Beachten Sie allerdings auch, daß der Rückgabewert (der Übertrag bzw. "Carry") bedeutungslos ist, falls die Zahlen vorzeichenbehaftet sind!
Außerdem kann bei vorzeichenbehafteten Zahlen eine besondere Art von Fehler auftreten, die meist als Überlauffehler ("overflow error") bezeichnet wird:
Ein solcher Überlauffehler tritt dann ein, wenn das Vorzeichen des Ergebnisses (das höchstwertige Bit) durch einen Übertrag aus der direkt darunterliegenden Bitposition verändert (d.h. verfälscht) wird.
Sie sind selbst dafür verantwortlich, daß kein solcher Überlauffehler auftreten kann, falls Ihre Zahlen vorzeichenbehaftet sind, indem Sie den Bitvektor vorher einfach groß genug machen.
Um ganz sicher zu gehen, daß kein Überlauffehler auftreten kann, machen Sie entweder Ihre Bitvektoren von Anfang an um mindestens ein Bit größer, als zur Darstellung der größten Zahl notwendig ist, die Sie verwenden wollen, oder verfahren Sie wie folgt:
$msb1 = $vec1->msb(); $msb2 = $vec2->msb(); $vec1->Resize($vec1->Size()+1); $vec2->Resize($vec2->Size()+1); $vec3->Resize($vec3->Size()+1); $vec1->MSB($msb1); $vec2->MSB($msb2); $c_o = $vec3->add($vec1,$vec2,$c_i);
$carry = $vec3->subtract($vec1,$vec2,$carry);
Diese Methode subtrahiert die beiden Zahlen in den Bitvektoren $vec1 und $vec2, unter Berücksichtigung des Übertrags $carry, legt das Ergebnis im Bitvektor $vec3 ab und liefert einen neuen Übertrag als Rückgabewert.
Mit anderen Worten:
$vec3 = $vec1 - $vec2 - $carry
Beachten Sie, daß der Eingabeparameter $carry ein Boolescher Wert ist, d.h., nur das niederstwertige Bit davon wird berücksichtigt (alle anderen Bits werden intern mit Hilfe von $carry &= 1; abgeschnitten).
Die Methode gibt einen Booleschen Wert zurück, der anzeigt, ob ein Übertrag (in das nächsthöhere Bit) stattgefunden hat.
Dieser Wert ist "wahr" (1), wenn von der nächsthöheren Bitposition "geborgt" wurde, ansonsten "falsch" (0).
Die Ein- und Ausgabe des Übertrags wird hauptsächlich zur Kaskadierung benötigt, d.h. zur Subtraktion von Zahlen, die in mehrere Teile zerlegt sind:
# Initialisierung
for ( $i = 0; $i < $n; $i++ )
{
$a[$i] = Bit::Vector->new($bits);
$b[$i] = Bit::Vector->new($bits);
$c[$i] = Bit::Vector->new($bits);
}
# Fülle @a und @b.
# $a[ 0 ] ist niederstwertiger Teil,
# $a[$n-1] ist höchstwertiger Teil.
# Das gleiche gilt für @b.
# Subtrahiere
$carry = 0;
for ( $i = 0; $i < $n; $i++ )
{
$carry = $c[$i]->subtract($a[$i],$b[$i],$carry);
}
Beachten Sie, daß es für diese Methode keine Rolle spielt, ob die Zahlen in den beiden Bitvektoren ($vec1 und $vec2) vorzeichenbehaftet sind oder vorzeichenlos, da sie intern mittels des Zweierkomplements dargestellt werden und die Subtraktion dadurch automatisch für beide Arten von Zahlen korrekt ist.
Beachten Sie allerdings auch, daß der Rückgabewert (der Übertrag bzw. "Carry") bedeutungslos ist, falls die Zahlen vorzeichenbehaftet sind!
Außerdem kann bei vorzeichenbehafteten Zahlen eine besondere Art von Fehler auftreten, die meist als Überlauffehler ("overflow error") bezeichnet wird:
Ein solcher Überlauffehler tritt dann ein, wenn das Vorzeichen des Ergebnisses (das höchstwertige Bit) durch einen Übertrag aus der direkt darunterliegenden Bitposition verändert (d.h. verfälscht) wird.
Sie sind selbst dafür verantwortlich, daß kein solcher Überlauffehler auftreten kann, falls Ihre Zahlen vorzeichenbehaftet sind, indem Sie den Bitvektor vorher einfach groß genug machen.
Um ganz sicher zu gehen, daß kein Überlauffehler auftreten kann, machen Sie entweder Ihre Bitvektoren von Anfang an um mindestens ein Bit größer, als zur Darstellung der größten Zahl notwendig ist, die Sie verwenden wollen, oder verfahren Sie wie folgt:
$msb1 = $vec1->msb(); $msb2 = $vec2->msb(); $vec1->Resize($vec1->Size()+1); $vec2->Resize($vec2->Size()+1); $vec3->Resize($vec3->Size()+1); $vec1->MSB($msb1); $vec2->MSB($msb2); $c_o = $vec3->subtract($vec1,$vec2,$c_i);
$vec2->Negate($vec1);
Diese Methode berechnet das Zweierkomplement der Zahl in Bitvektor $vec1 und legt das Ergebnis in Bitvektor $vec2 ab.
Eine Verarbeitung "auf derselben Stelle" ist ebenfalls möglich, d.h. $vec1 und $vec2 können identisch sein.
Das Zweierkomplement einer Zahl in Binärdarstellung ist gegeben durch das Invertieren aller Bits und das Inkrementieren dieses Ergebnisses um eins.
Das entspricht dem Wechseln des Vorzeichens einer gegebenen Zahl von + nach - oder umgekehrt. Die zweimalige Anwendung dieser Operation liefert also wieder die ursprüngliche Zahl.
Beachten Sie, daß diese Methode ein Ihrer Intuition möglicherweise widersprechendes Ergebnis liefert, wenn die in dem gegebenen Bitvektor enthaltene Zahl den Wert 2 ^ (n-1) (also "1000...0000") hat (wobei n hier die Anzahl der Bits im gegebenen Bitvektor angibt): Der negative Wert dieser Zahl ist diese Zahl selbst!
$vec2->Absolute($vec1);
Abhängig vom Vorzeichen (d.h. dem höchstwertigen Bit) der Zahl in Bitvektor $vec1, wird der Inhalt von Bitvektor $vec1 entweder mit der Methode Copy() (wenn die Zahl in Bitvektor $vec1 positiv ist) oder mit Negate() (wenn die Zahl in Bitvektor $vec1 negativ ist) in den Bitvektor $vec2 kopiert.
Eine Verarbeitung "auf derselben Stelle" ist ebenfalls möglich, d.h., $vec1 und $vec2 können identisch sein.
Die Methode berechnet also den Absolutwert der Zahl in Bitvektor $vec1 und speichert das Ergebnis in Bitvektor $vec2.
Beachten Sie, daß diese Methode ein Ihrer Intuition möglicherweise widersprechendes Ergebnis liefert, wenn die in dem gegebenen Bitvektor enthaltene Zahl den Wert 2 ^ (n-1) (also "1000...0000") hat (wobei n hier die Anzahl der Bits im gegebenen Bitvektor angibt): Der Absolutwert dieser Zahl ist diese Zahl selbst, obwohl diese Zahl nach dieser Operation per Definition immer noch negativ ist (das höchstwertige Bit ist ja nach wie vor gesetzt)!
$sign = $vector->Sign();
Diese Methode gibt den Wert Null (0) zurück, wenn alle Bits des gegebenen Bitvektors gelöscht (d.h. auf null gesetzt) sind, oder mit anderen Worten, wenn der gegebene Bitvektor die Zahl Null (0) enthält. Dieser Wert wird auch dann zurückgegeben, wenn der Bitvektor die Länge Null hat (also gar keine Bits enthält).
Sind nicht alle Bits gelöscht, gibt die Methode den Wert -1 zurück, falls das höchstwertige Bit gesetzt ist (d.h., wenn der Bitvektor eine negative Zahl enthält), oder den Wert 1, falls der Bitvektor eine positive Zahl enthält.
$vec3->Multiply($vec1,$vec2);
Diese Methode multipliziert die beiden Zahlen in den Bitvektoren $vec1 und $vec2 und speichert das Ergebnis in Bitvektor $vec3.
Beachten Sie, daß diese Methode ihre Argumente als vorzeichenbehaftet ansieht.
Wenn Sie sicherstellen wollen, daß eine sehr große Zahl niemals versehentlich als negativ angesehen werden kann, machen Sie entweder Ihre Bitvektoren von Anfang an um mindestens ein Bit größer, als zur Darstellung der größten Zahl notwendig ist, die in Ihren Berechnungen auftreten kann, oder verfahren Sie wie folgt:
$msb1 = $vec1->msb(); $msb2 = $vec2->msb(); $vec1->Resize($vec1->Size()+1); $vec2->Resize($vec2->Size()+1); $vec3->Resize($vec3->Size()+1); $vec1->MSB($msb1); $vec2->MSB($msb2); $vec3->Multiply($vec1,$vec2);
Beachten Sie auch, daß im Prinzip alle drei Bitvektoren der Regel übereinstimmender Größen genügen müssen, daß aber der Bitvektor $vec3 zur Aufnahme des Ergebnisses ausnahmsweise auch größer sein darf als die beiden Faktoren $vec1 und $vec2!
Denn schließlich kann die Multiplikation zweier Binärzahlen mit je n Bits ein Ergebnis liefern, das bis zu 2n Bits lang ist.
Es ist daher eine gute Idee, den Bitvektor $vec3 doppelt so groß zu machen wie die beiden Bitvektoren $vec1 und $vec2, es sei denn, Sie sind absolut sicher, daß das Ergebnis in einen Bitvektor paßt, der die gleiche Größe hat wie die Bitvektoren der beiden Faktoren.
Sollten Sie sich dabei allerdings geirrt haben, kommt es zu einem fatalen Überlauffehler ("numeric overflow error") mit Programmabbruch.
Beachten Sie schließlich noch, daß eine Verarbeitung "auf derselben Stelle" möglich ist, d.h., $vec3 kann mit $vec1 oder $vec2 (oder beiden) identisch sein.
$quot->Divide($vec1,$vec2,$rest);
Diese Methode dividiert die beiden Zahlen in den Bitvektoren $vec1und $vec2. Der Quotient dieser Division wird dabei in Bitvektor $quot abgelegt und der Rest in Bitvektor $rest.
Mit anderen Worten:
$quot = $vec1 / $vec2; # Division $rest = $vec1 % $vec2; # Modulo
Aus diesem Grund müssen $quot und $rest unbedingt zwei unterschiedliche Bitvektoren sein, sonst kommt es zu einem fatalen Fehler ("Q and R must be distinct")!
Ein fataler "Division-durch-Null"-Fehler ("division by zero error") tritt auf, falls $vec2 den Wert Null hat.
Beachten Sie, daß diese Methode ihre Argumente als vorzeichenbehaftet ansieht.
Wenn Sie sicherstellen wollen, daß eine sehr große Zahl niemals versehentlich als negativ angesehen werden kann, machen Sie entweder Ihre Bitvektoren von Anfang an um mindestens ein Bit größer, als zur Darstellung der größten Zahl notwendig ist, die Sie verwenden wollen, oder verfahren Sie wie folgt:
$msb1 = $vec1->msb(); $msb2 = $vec2->msb(); $vec1->Resize($vec1->Size()+1); $vec2->Resize($vec2->Size()+1); $quot->Resize($quot->Size()+1); $rest->Resize($rest->Size()+1); $vec1->MSB($msb1); $vec2->MSB($msb2); $quot->Divide($vec1,$vec2,$rest);
Beachten Sie schließlich noch, daß eine Verarbeitung "auf derselben Stelle" möglich ist, d.h., $quot kann identisch sein mit $vec1 oder $vec2 (oder beiden), und $rest kann ebenfalls mit $vec1 oder $vec2 (oder beiden) identisch sein, solange $quot und $rest verschieden sind.
$vec3->GCD($vec1,$vec2);
Diese Methode berechnet den "ggT" ("größten gemeinsamen Teiler" oder "Greatest Common Divisor") der beiden Zahlen in den Bitvektoren $vec1 und $vec2 und legt das Ergebnis in Bitvektor $vec3 ab.
Die Methode benutzt dazu intern den Euklidischen Algorithmus:
int GCD(int a, int b)
{
int t;
while (b != 0)
{
t = a % b; /* = Rest von (a div b) */
a = b;
b = t;
}
return(a);
}
Beachten Sie, daß es zu einem fatalen "Division-durch-Null"-Fehler ("division by zero error") kommt, falls eine der beiden Zahlen Null ist!
Beachten Sie auch, daß diese Methode ihre beiden Argumente als vorzeichenbehaftet ansieht, intern aber mit den Absolutwerten der beiden Zahlen arbeitet, d.h., das Ergebnis dieser Methode ist immer positiv.
$vector->Block_Store($buffer);
Diese Methode erlaubt es, den Inhalt eines ganzen Bitvektors auf einmal (als Block) zu importieren.
Das kann nützlich sein, um z.B. Bitvektoren in einer Datei im (platzsparenden) Binärformat abzuspeichern (siehe dazu auch die direkt hierunter anschließende Beschreibung der Methode Block_Read()) und später wieder einzulesen.
Beachten Sie, daß das Argument $buffer hier unbedingt ein String sein muß - anderenfalls tritt ein fataler "Ist kein String"-Fehler ("item is not a string") auf!
Eine automatische Umwandlung von Zahlen in Strings, wie sonst in Perl üblich, ist hier nicht möglich (und macht hier auch keinerlei Sinn)!
Dieser String muß die Daten des Bitvektors in der "low order byte first"-Reihenfolge enthalten.
(Intern findet dann eine Umwandlung in die auf dem jeweiligen System verwendete Byte-Reihenfolge statt.)
Ist der gegebene String kürzer als zum vollständigen Füllen des gegebenen Bitvektors erforderlich, werden die übrigbleibenden (höchstwertigen) Bytes des Bitvektors mit Nullen aufgefüllt. Das bedeutet, daß der vorherige Inhalt des Bitvektors immer vollständig gelöscht (überschrieben) wird.
Ist der gegebene String länger als zum vollständigen Füllen des gegebenen Bitvektors erforderlich, werden die überzähligen Bytes einfach ignoriert.
Wie Sie den Inhalt von $buffer aus einer Datei einlesen können, können Sie im Abschnitt zu read() bzw. sysread() in perlfunc(1) nachlesen.
$buffer = $vector->Block_Read();
Diese Methode erlaubt es, den Inhalt eines ganzen Bitvektors auf einmal (als Block) zu exportieren.
Das ist nützlich, wenn Sie beispielsweise den Inhalt eines Bitvektors für einen späteren Zeitpunkt in einer Datei sichern wollen.
Der Vorteil dieser Methode liegt darin, daß dies mit dem geringstmöglichen Speicherplatzbedarf geschehen kann, nämlich im Binärformat.
Die Methode liefert einen Perl-String zurück, der eine exakte Kopie des Inhalts des gegebenen Bitvektors ist, allerdings in die "low order byte first"-Reihenfolge umgewandelt, um sicherzustellen, daß diese Daten auch auf einem anderen Rechner mit einer anderen internen Byte-Reihenfolge genauso wieder eingelesen werden können (mit Hilfe der oben beschriebenen Methode Block_Store()).
Wie Sie diesen String in eine Datei schreiben können, können Sie im Abschnitt zu syswrite() in perlfunc(1) nachlesen.
$size = $vector->Word_Size();
Jeder Bitvektor ist intern als ein Array von Maschinenwörtern organisiert.
Die Methoden, deren Namen mit "Word_" beginnen, erlauben Ihnen den Zugriff auf dieses interne Array von Maschinenwörtern.
Beachten Sie, daß diese Methoden alle maschinenabhängig sind, weil die Größe eines Maschinenwortes vom jeweiligen System abhängt!
Aus diesem Grund sollten Sie diese Methoden nur dann verwenden, wenn die Portabilität Ihres Codes ohne Bedeutung ist!
(Aber können Sie wirklich sicher sein, daß Sie Ihr Programm nicht eines Tages vielleicht doch auf einem anderen Rechner einsetzen wollen?!)
Sie sind jedenfalls gewarnt worden! :-)
Um maschinenunabhängig zu sein, sollten Sie statt dessen lieber die Methoden verwenden, deren Namen mit Chunk_ beginnen, und dabei keine Chunk-Größen von mehr als 32 Bit verwenden.
Die Methode Word_Size() gibt die Anzahl der Maschinenwörter zurück, die das interne Array des gegebenen Bitvektors enthält.
Diese Methode ist das Äquivalent zu dem Ausdruck scalar(@array) für ein Perl-Array.
$vector->Word_Store($offset,$word);
Diese Methode erlaubt es Ihnen, einen gegebenen Wert $word an einer gegebenen Position $offset im internen Wortarray des gegebenen Bitvektors zu speichern.
Beachten Sie, daß $offset innerhalb des gültigen Bereichs von 0 bis $vector->Word_Size()-1 liegen muß, anderenfalls kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Diese Methode ist das Äquivalent zu dem Ausdruck $array[$offset] = $word; für ein Perl-Array.
$word = $vector->Word_Read($offset);
Diese Methode erlaubt Ihnen das Auslesen des Maschinenwortes an der Position $offset im internen Wortarray des gegebenen Bitvektors.
Beachten Sie, daß $offset innerhalb des gültigen Bereichs von 0 bis $vector->Word_Size()-1 liegen muß, anderenfalls kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Diese Methode ist das Äquivalent zu dem Ausdruck $word = $array[$offset]; für ein Perl-Array.
$vector->Word_List_Store(@words);
Diese Methode erlaubt es Ihnen, eine Liste von Werten @words im internen Wortarray des gegebenen Bitvektors abzuspeichern.
Dabei wird der ganz links stehende Wert in der Liste ($words[0]) im niederstwertigen Wort des internen Wortarrays (also in dem Wort mit dem Offset 0) gespeichert. Der nächste Wert der Liste ($words[1]) wird dann im Wort mit dem Offset 1 abgelegt usw.
Wenn die Liste @words weniger Elemente umfaßt, als das interne Wortarray des gegebenen Bitvektors Maschinenwörter enthält, werden die restlichen (höchstwertigen) Maschinenwörter mit Nullen aufgefüllt.
Wenn die Liste @words mehr Elemente besitzt, als das interne Wortarray des gegebenen Bitvektors Maschinenwörter enthält, werden die überschüssigen Werte einfach ignoriert.
Diese Methode ist das Äquivalent zu dem Ausdruck @array = @words; für ein Perl-Array.
@words = $vector->Word_List_Read();
Diese Methode erlaubt es Ihnen, das interne Array von Maschinenwörtern eines gegebenen Bitvektors als Ganzes auf einen Schlag auszulesen.
Dabei ist der ganz links stehende Wert in der zurückgegebenen Liste ($words[0]) das niederstwertige Wort und der ganz rechts stehende Wert ($words[$#words]) das höchstwertige Wort des gegebenen Bitvektors.
Diese Methode ist das Äquivalent zu dem Ausdruck @words = @array; für ein Perl-Array.
$vector->Word_Insert($offset,$count);
Diese Methode fügt $count neue, leere Maschinenwörter an der Position $offset in das interne Array des gegebenen Bitvektors ein.
Die $count höchstwertigen Maschinenwörter gehen dabei verloren, und alle Maschinenwörter von Wort Nummer $offset bis einschließlich Wort Nummer $vector->Word_Size()-$count-1 werden um $count Positionen nach oben verschoben.
Die nun freigewordenen $count Maschinenwörter von Wort Nummer $offset bis einschließlich Wort Nummer $offset+$count-1 werden anschließend auf null gesetzt (gelöscht).
Beachten Sie, daß diese Methode die Größe des gegebenen Bitvektors nicht erhöht, d.h., der Bitvektor wird nicht an seinem oberen (höchstwertigen) Ende erweitert, um die $count höchstwertigen Maschinenwörter zu "retten" - vielmehr gehen diese Maschinenwörter für immer verloren.
Falls Sie das nicht wollen, müssen Sie die Größe des gegebenen Bitvektors explizit erhöhen, und zwar bevor Sie die Einfügeoperation durchführen. Dies ist mit der folgenden Anweisung möglich:
$vector->Resize($vector->Size() + $count * Bit::Vector->Word_Bits());
Beachten Sie auch, daß $offset im erlaubten Bereich zwischen 0 und $vector->Word_Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Ist der Term $offset + $count größer als $vector->Word_Size()-1, werden einfach nur alle Maschinenwörter von Wort Nummer $offset bis zu Wort Nummer $vector->Word_Size()-1 gelöscht (d.h. auf Null gesetzt).
$vector->Word_Delete($offset,$count);
Diese Methode löscht (d.h. entfernt) alle Maschinenwörter aus dem internen Array des gegebenen Bitvektors ab Wort Nummer $offset bis einschließlich Wort Nummer $offset+$count-1.
Die höchstwertigen Maschinenwörter ab Wort Nummer $offset+$count bis einschließlich Wort Nummer $vector->Word_Size()-1 werden dabei um $count Positionen nach unten verschoben (rücken also nach).
Die nun freigewordenen $count höchstwertigen Maschinenwörter werden anschließend auf null gesetzt (gelöscht).
Beachten Sie, daß diese Methode die Größe des gegebenen Bitvektors nicht verringert, d.h., der Bitvektor wird nicht an seinem oberen (höchstwertigen) Ende abgeschnitten, um die überschüssigen $count höchstwertigen Maschinenwörter "loszuwerden".
Falls Sie das nicht wollen, müssen Sie die Größe des gegebenen Bitvektors explizit verringern, und zwar nach der Löschoperation. Dies ist mit den folgenden Anweisungen möglich:
$bits = $vector->Size();
$count *= Bit::Vector->Word_Bits();
if ($count > $bits) { $count = $bits; }
$vector->Resize($bits - $count);
Beachten Sie auch, daß $offset im erlaubten Bereich zwischen 0 und $vector->Word_Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Ist der Term $offset + $count größer als $vector->Word_Size()-1, werden einfach nur alle Maschinenwörter von Wort Nummer $offset bis zu Wort Nummer $vector->Word_Size()-1 gelöscht (d.h. auf null gesetzt).
$vector->Chunk_Store($chunksize,$offset,$chunk);
Diese Methode erlaubt das gleichzeitige Setzen mehrerer nebeneinanderliegender Bits auf einmal auf individuell unterschiedliche Werte (im Unterschied beispielsweise zu den Methoden Interval_Empty() und Interval_Fill(), die nur das gleichzeitige Setzen von nebeneinanderliegenden Bits auf denselben Wert gestatten).
Sie können dabei auf Chunks (d.h. Blöcke zusammenhängender Bits) mit einer Länge von ein bis maximal Bit::Vector->Long_Bits() Bits auf einmal zugreifen.
Um portabel zu sein, sollten Sie jedoch nie Chunks von mehr als 32 Bits verwenden.
Liegt die gegebene Chunk-Größe $chunksize nicht zwischen 1 und Bit::Vector->Long_Bits(), kommt es zu einem fatalen Bereichsfehler ("chunk size out of range").
Die Methode kopiert die $chunksize niederstwertigen Bits aus $chunk in den gegebenen Bitvektor, beginnend bei Bitposition $offset und weiter bis Bit Nummer $offset+$chunksize-1.
(Das bedeutet, daß Bit Nummer 0 von $chunk zu Bit Nummer $offset im gegebenen Bitvektor wird, und so weiter bis Bit Nummer $chunksize-1, welches zu Bit Nummer $offset+$chunksize-1 des Bitvektors wird. Die genannten Bits des Bitvektors werden also durch diese Operation überschrieben.)
Ist der Term $offset+$chunksize-1 größer als $vector->Size()-1, werden die überschüssigen (höchstwertigen) Bits aus $chunk einfach ignoriert.
Beachten Sie, daß $offset selbst innerhalb des erlaubten Bereichs von 0 bis $vector->Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
Die Chunk_-Methoden sind nützlich, wenn Sie beispielsweise Daten in Blöcken von z.B. 8 Bits einlesen wollen, auf die Sie später in Blöcken von (beispielsweise) 16 Bit gleichzeitig zugreifen müssen (wie etwa bei Audio-CD-Wave-Dateien).
$chunk = $vector->Chunk_Read($chunksize,$offset);
Diese Methode erlaubt das gleichzeitige Auslesen mehrerer nebeneinanderliegender Bits auf einmal.
Sie können dabei auf Chunks (d.h. Blöcke zusammenhängender Bits) mit einer Länge von ein bis maximal Bit::Vector->Long_Bits() Bits auf einmal zugreifen.
Um portabel zu sein, sollten Sie jedoch nie Chunks von mehr als 32 Bits verwenden.
Liegt die gegebene Chunk-Größe $chunksize nicht zwischen 1 und Bit::Vector->Long_Bits(), kommt es zu einem fatalen Bereichsfehler ("chunk size out of range").
Die Methode liefert die $chunksize Bits beginnend bei Bitposition $offset und weiter bis Bit Nummer $offset+$chunksize-1 zurück.
(Das bedeutet, daß Bit Nummer $offset des gegebenen Bitvektors zu Bit Nummer 0 des Rückgabewertes wird, und so weiter bis Bit Nummer $offset+$chunksize-1, welches zu Bit Nummer $chunksize-1 des Ergebnisses wird.)
Ist der Term $offset+$chunksize-1 größer als $vector->Size()-1, werden die entsprechenden, nicht existierenden Bits natürlich nicht zurückgegeben, und die entsprechenden Bits des Rückgabewertes bleiben leer.
Beachten Sie, daß $offset selbst innerhalb des erlaubten Bereichs von 0 bis $vector->Size()-1 liegen muß, sonst kommt es zu einem fatalen Offset-Fehler ("offset out of range").
$vector->Chunk_List_Store($chunksize,@chunks);
Diese Methode erlaubt es Ihnen, den gegebenen Bitvektor mit einer Liste von Bitpaketen ("Chunks") nahezu beliebiger Größe $chunksize (innerhalb bestimmter Grenzen) zu füllen.
Tatsächlich muß die gegebene Chunk-Größe $chunksize innerhalb des Bereichs zwischen 1 und Bit::Vector->Long_Bits() liegen, sonst kommt es zu einem fatalen Bereichsfehler ("chunk size out of range").
Um portabel zu sein, sollten Sie jedoch nie Chunks von mehr als 32 Bits verwenden.
Der gegebene Bitvektor wird von dieser Methode in aufsteigender Richtung gefüllt: Das erste Bitpaket der Liste ($chunks[0]) füllt die $chunksize niederstwertigen Bits des gegebenen Bitvektors, das nächste Bitpaket aus der Liste ($chunks[1]) füllt die Bits von Nummer $chunksize bis Nummer 2*$chunksize-1, das dritte Bitpaket ($chunks[2]) füllt die Bits von Nummer 2*$chunksize bis Nummer 3*$chunksize-1, usw. usf.
Sind weniger Chunks in der Liste enthalten, als zum Füllen des gesamten Bitvektors notwendig sind, werden die verbleibenden (höchstwertigen) Bits des Bitvektors gelöscht, d.h., der vorherige Inhalt des gegebenen Bitvektors wird immer vollständig überschrieben.
Sind mehr Chunks in der Liste vorhanden, als zum Füllen des gesamten Bitvektors notwendig sind, oder ragt ein Chunk über die Grenze $vector->Size()-1 hinaus (was immer dann passiert, wenn $vector->Size() kein ganzzahliges Vielfaches von $chunksize ist), dann werden die überzähligen Chunks bzw. Bits einfach ignoriert.
Die Methode eignet sich (neben vielen anderen Anwendungen) zum Beispiel für die Umwandlung von Paketgrößen in einem Datenstrom.
Diese Methode kann übrigens auch dazu benutzt werden, um einen oktalen String in einem gegebenen Bitvektor abzulegen:
$vector->Chunk_List_Store(3, split(//, reverse $string));
Beachten Sie allerdings, daß hier, im Gegensatz zu den Konvertierungsmethoden from_Hex(), from_Bin(), from_Dec() und from_Enum(), keinerlei Syntaxprüfung stattfindet, d.h., daß die obige Anweisung ohne Warnung fehlschlagen kann.
Um eine Syntaxüberprüfung durchzuführen, nehmen Sie einfach noch die folgenden Anweisungen in Ihr Programm mit auf:
if ($string =~ /^[0-7]+$/)
{
# Okay, Konvertierung wie oben beschrieben durchführen.
}
else
{
# Fehler, String enthält nicht-oktale Zeichen.
}
Eine weitere Anwendung ist die Speicherung eines sich wiederholenden Musters in einem Bitvektor:
$pattern = 0xDEADBEEF;
$length = 32; # = Länge des Musters "$pattern" in Bits
$size = $vector->Size();
$factor = int($size / $length);
if ($size % $length) { $factor++; }
$vector->Chunk_List_Store($length, ($pattern) x $factor);
@chunks = $vector->Chunk_List_Read($chunksize);
Diese Methode erlaubt das Auslesen des Inhalts eines gegebenen Bitvektors in Form einer Liste von Bitpaketen ("Chunks") mit einer (innerhalb bestimmter Grenzen) frei wählbaren Anzahl von Bits $chunksize.
Tatsächlich muß die gegebene Chunk-Größe $chunksize innerhalb des Bereichs zwischen 1 und Bit::Vector->Long_Bits() liegen, sonst kommt es zu einem fatalen Bereichsfehler ("chunk size out of range").
Um portabel zu sein, sollten Sie jedoch nie Chunks von mehr als 32 Bits verwenden.
Der gegebene Bitvektor wird von dieser Methode in aufsteigender Richtung ausgelesen: Die $chunksize niederstwertigen Bits des Bitvektors (Bits Nummer 0 bis Nummer $chunksize-1) werden zum ersten Bitpaket der zurückgelieferten Liste (also $chunks[0]). Die Bits von Nummer $chunksize an bis 2*$chunksize-1 bilden das nächste Bitpaket der Liste ($chunks[1]) und so weiter.
Falls $vector->Size() kein ganzzahliges Vielfaches von $chunksize ist, enthält das letzte Bitpaket der Liste entsprechend weniger Bits als $chunksize.
Beachten Sie, daß bei sehr großen Bitvektoren und/oder sehr kleinen Werten von $chunksize die Anzahl der zurückgelieferten Listenelemente unter Umständen extrem hoch sein kann! Vorsicht!
Sie können damit wahrscheinlich Ihre Anwendung aufgrund fehlenden Speichers zum Absturz bringen (jedes Listenelement ist intern ein vollwertiger Perl-Skalar mit einem entsprechenden Speicher-Overhead zu dessen Verwaltung!) oder zumindest ein (mehr oder weniger lang andauerndes) "Einfrieren" Ihrer Anwendung verursachen!
Mögliche Anwendungen:
Diese Methode ist besonders nützlich zur Konvertierung von Paketgrößen in einem Datenstrom.
Die Methode kann übrigens auch dazu verwendet werden, um einen gegebenen Bitvektor in einen String von Oktalzahlen umzuwandeln:
$string = reverse join('', $vector->Chunk_List_Read(3));
$vector->Index_List_Remove(@indices);
Diese Methode ermöglicht es Ihnen, eine Liste von Bitnummern anzugeben, die in einem gegebenen Bitvektor gelöscht werden sollen.
Tatsächlich ist diese Methode eine Abkürzung für
foreach $index (@indices)
{
$vector->Bit_Off($index);
}
Im Gegensatz zu allen anderen Importmethoden dieses Moduls löscht diese Methode den gegebenen Bitvektor nicht, bevor diese Operation durchgeführt wird.
Vielmehr ermöglicht es diese Methode, die Ergebnisse verschiedener aufeinanderfolgender Aufrufe zu akkumulieren.
(Das gleiche gilt auch für die Methode Index_List_Store(). Sie können deshalb damit alle mit Index_List_Remove() durchgeführten Änderungen wieder rückgängig machen, indem Sie die gleiche Liste von Argumenten an Index_List_Store() übergeben.)
$vector->Index_List_Store(@indices);
Diese Methode ermöglicht es Ihnen, eine Liste von Bitnummern anzugeben, die in einem gegebenen Bitvektor gesetzt werden sollen.
Tatsächlich ist diese Methode eine Abkürzung für
foreach $index (@indices)
{
$vector->Bit_On($index);
}
Im Gegensatz zu allen anderen Importmethoden dieses Moduls löscht diese Methode den gegebenen Bitvektor nicht, bevor diese Operation durchgeführt wird.
Vielmehr ermöglicht es diese Methode, die Ergebnisse verschiedener aufeinanderfolgender Aufrufe zu akkumulieren.
(Das gleiche gilt auch für die Methode Index_List_Remove(). Sie können deshalb damit alle mit Index_List_Store() durchgeführten Änderungen wieder rückgängig machen, indem Sie die gleiche Liste von Argumenten an Index_List_Remove() übergeben.)
@indices = $vector->Index_List_Read();
Diese Methode gibt eine Liste von Bitnummern von allen in dem gegebenen Bitvektor gesetzten Bits zurück.
Diese Bitnummern werden immer in aufsteigender Reihenfolge zurückgegeben.
Ist der gegebene Bitvektor leer (enthält er also nur gelöschte Bits), oder hat er die Länge Null (sind also überhaupt keine Bits vorhanden), gibt die Methode eine leere Liste zurück.
Beachten Sie, daß bei sehr großen Bitvektoren unter Umständen eine geradezu überwältigende Anzahl von Listenelementen zurückgeliefert werden kann! Vorsicht!
Sie können dadurch einen Programmabbruch durch Speicherüberlauf verursachen oder zumindest Ihre Anwendung für mehrere Sekunden zum Stocken bringen, also die Geschwindigkeit Ihrer Anwendung erheblich herabsetzen!
Diese Methode ist zum Beispiel nützlich, um eine Liste von Primzahlen zu erzeugen:
$limit = 1000; # oder was auch immer $vector = Bit::Vector->new($limit+1); $vector->Primes(); @primes = $vector->Index_List_Read();
$set3->Union($set1,$set2);
Diese Methode berechnet die Vereinigungsmenge von $set1 und $set2 und legt das Ergebnis in $set3 ab.
In der Mengentheorie schreibt man das üblicherweise als $set3 = $set1 u $set2.
(Auf Rechnern ohne ein Zeichen für die Vereinigungsmenge wird dieser Operator häufig durch ein Pluszeichen ("+") ersetzt.)
Eine Verarbeitung "auf derselben Stelle" ist möglich, d.h., $set3 kann mit $set1 oder $set2 identisch sein (oder beiden).
$set3->Intersection($set1,$set2);
Diese Methode berechnet den Durchschnitt der beiden Mengen $set1 und $set2 und legt das Ergebnis in $set3 ab.
In der Mengentheorie schreibt man das üblicherweise als $set3 = $set1 n $set2.
(Auf Rechnern ohne ein Zeichen für den (Mengen-) Durchschnitt wird dieser Operator häufig durch ein Sternchen ("*") ersetzt.)
Eine Verarbeitung "auf derselben Stelle" ist möglich, d.h., $set3 kann mit $set1 oder $set2 identisch sein (oder beiden).
$set3->Difference($set1,$set2);
Diese Methode berechnet die Differenzmenge von $set1 ohne $set2 und legt das Ergebnis in $set3 ab.
In der Mengentheorie schreibt man das üblicherweise als $set3 = $set1 \ $set2.
Eine Verarbeitung "auf derselben Stelle" ist möglich, d.h., $set3 kann mit $set1 oder $set2 identisch sein (oder beiden).
$set3->ExclusiveOr($set1,$set2);
Diese Methode berechnet die symmetrische Differenzmenge von $set1 und $set2 und legt das Ergebnis in $set3 ab.
In der Mengentheorie kann das als $set3 = ($set1 u $set2) \ ($set1 n $set2) geschrieben werden (die Vereinigungsmenge beider Mengen ohne deren Durchschnitt).
Wenn Mengen als Bitvektoren implementiert sind, entspricht die obige Formel einem EXKLUSIV-ODER zwischen den sich entsprechenden Bits der beiden Bitvektoren (daher der Name dieser Methode).
Beachten Sie, daß diese Methode wesentlich effizienter ist als die explizite Evaluierung der obigen Formel, weil sie intern eine (in den Prozessor eingebaute) Anweisung in Maschinensprache verwendet.
Eine Verarbeitung "auf derselben Stelle" ist möglich, d.h., $set3 kann mit $set1 oder $set2 identisch sein (oder beiden).
$set2->Complement($set1);
Diese Methode berechnet das Komplement von $set1 und legt das Ergebnis in $set2 ab.
Bei der "Big Integer"-Arithmetik entspricht das der Berechnung des Einerkomplements der im Bitvektor $set1 in Binärdarstellung gespeicherten Zahl.
Eine Verarbeitung "auf derselben Stelle" ist ebenfalls möglich, d.h., $set2 kann mit $set1 identisch sein.
if ($set1->subset($set2))
Gibt "wahr" (1) zurück, wenn $set1 eine Teilmenge von $set2 ist (d.h. in $set2 vollständig enthalten ist), und "falsch" (0) sonst.
Das bedeutet, daß jedes in $set1 gesetzte Bit auch in $set2 gesetzt sein muß, damit die Bedingung erfüllt ist, während $set2 gesetzte Bits enthalten kann, die in $set1 nicht gesetzt sind.
Beachten Sie, daß, wenn beide Mengen identisch sind, diese per Definition auch jeweils sowohl Teilmengen als auch Obermengen voneinander sind. Dies gilt auch dann, wenn beide Mengen keinerlei gesetzte Bits enthalten, wenn sie also beide die "leere Menge" darstellen (dies gilt jedoch nicht, wenn die beiden Bitvektoren die Länge Null haben, wenn sie also gar keine Bits enthalten!).
$norm = $set->Norm();
Gibt die Norm (d.h. die Anzahl der gesetzten Bits) des gegebenen Bitvektors zurück.
Das entspricht der Anzahl der in einer gegebenen Menge enthaltenen Elemente, also der "Kardinalität" dieser Menge.
$min = $set->Min();
Gibt das Minimum der gegebenen Menge zurück, d.h. das Minimum der Bitnummern aller gesetzten Bits im gegebenen Bitvektor $set.
Ist die Menge leer (d.h., enthält der gegebene Bitvektor keinerlei gesetzte Bits), wird plus Unendlich zurückgegeben (was von dieser Methode durch die Konstante MAX_LONG auf Ihrem System symbolisiert wird).
(Diese Konstante ist üblicherweise 2 ^ (n-1) - 1, wobei n die Anzahl der Bits ist, die der C-Datentyp "unsigned long" auf Ihrem System hat.)
$max = $set->Max();
Gibt das Maximum der gegebenen Menge zurück, d.h. das Maximum der Bitnummern aller gesetzten Bits im gegebenen Bitvektor $set.
Ist die Menge leer (d.h. enthält der gegebene Bitvektor keinerlei gesetzte Bits), wird minus Unendlich zurückgegeben (was von dieser Methode durch die Konstante MIN_LONG auf Ihrem System symbolisiert wird).
(Diese Konstante ist üblicherweise -(2 ^ (n-1) - 1) oder -(2 ^ (n-1)), wobei n die Anzahl der Bits ist, die der C-Datentyp "unsigned long" auf Ihrem System hat.)
$m3->Multiplication($r3,$c3,$m1,$r1,$c1,$m2,$r2,$c2);
Diese Methode multipliziert zwei (als Bitvektoren gespeicherte) Boolesche Matrizen $m1 und $m2 und legt das Ergebnis in der Matrix $m3 ab.
Eine Ausnahme wird ausgelöst, wenn das Produkt aus Zeilen- und Spaltenanzahl einer der drei Matrizen nicht mit der Größe des jeweils zugrundeliegenden Bitvektors übereinstimmt.
Eine Ausnahme wird auch ausgelöst, wenn die Anzahlen der Zeilen und Spalten der drei Matrizen nicht in der notwendigen Weise harmoniert:
rows3 == rows1 # "rows" = "Zeilen"
cols3 == cols2 # "cols" ("colums") = "Spalten"
cols1 == rows2
Diese Methode wird vom Modul "Math::MatrixBool" verwendet.
Nähere Details zu dieser Methode finden Sie in Math::MatrixBool(3).
$matrix->Closure($rows,$cols);
Diese Methode berechnet mit Hilfe des Kleene-Algorithmus die reflexive transitive Hülle einer (als Bitvektor gespeicherten) Booleschen Matrix.
(Eine kurze Einführung in die Theorie hinter Kleenes Algorithmus finden Sie in Math::Kleene(3).)
Mit Hilfe der reflexiven transitiven Hülle läßt sich die Frage beantworten, ob zwischen je zwei beliebigen Knoten eines Graphen (dessen Kanten als Matrix gegeben sind) ein Pfad existiert.
Wenn eine (gerichtete) Kante von Knoten "i" nach Knoten "j" existiert, dann wird das Element in der Matrix mit den Koordinaten (i,j) auf 1 gesetzt, anderenfalls bleibt es 0.
Falls die Kanten ungerichtet sind, ist die resultierende Matrix symmetrisch, d.h., die Elemente (i,j) und (j,i) enthalten immer denselben Wert.
Diese Matrix (die die Kanten des Graphen repräsentiert) kann dabei nur die Frage beantworten, ob es zwischen je zwei Knoten des Graphen eine Kante gibt, während die reflexive transitive Hülle die Frage beantwortet, ob es einen Pfad (eine Folge zusammenhängender, aufeinanderfolgender Kanten) zwischen diesen beiden Knoten des Graphen gibt!
Beachten Sie, daß der Inhalt der gegebenen Matrix durch diese Methode verändert wird! Machen Sie also rechtzeitig eine Kopie der ursprünglichen Matrix, wenn Sie diese später noch benötigen!
Eine Ausnahme wird ausgelöst, falls die gegebene Matrix nicht quadratisch ist, d.h., wenn die Anzahl der Zeilen nicht mit der Anzahl der Spalten der Matrix übereinstimmt.
Eine Ausnahme wird ebenfalls ausgelöst, wenn das Produkt aus der Anzahl der Zeilen und Spalten der gegebenen Matrix von der tatsächlichen Größe des zugrundeliegenden Bitvektors abweicht.
Diese Methode wird vom Modul "Math::MatrixBool" verwendet.
Nähere Details zu dieser Methode finden Sie in Math::MatrixBool(3).
$matrix2->Transpose($rows2,$cols2,$matrix1,$rows1,$cols1);
Diese Methode berechnet die Transponierte einer (als Bitvektor gespeicherten) Booleschen Matrix $matrix1 und legt das Ergebnis im Bitvektor $matrix2 ab.
Die Transponierte einer Booleschen Matrix (welche die Kanten eines Graphen repräsentiert) kann dazu verwendet werden, um die stark verbundenen Komponenten des Graphen zu finden.
Eine Ausnahme wird ausgelöst, wenn das Produkt aus Zeilen- und Spaltenanzahl einer der beiden Matrizen nicht mit der Größe des jeweils zugrundeliegenden Bitvektors übereinstimmt.
Eine Ausnahme wird ebenfalls ausgelöst, wenn eine der folgenden Bedingungen nicht erfüllt ist:
rows2 == cols1 # "rows" = "Zeilen"
cols2 == rows1 # "cols" ("colums") = "Spalten"
Beachten Sie, daß eine Verarbeitung "auf derselben Stelle" ($matrix1 und $matrix2 sind identisch) nur möglich ist, falls die Matrix quadratisch ist. Anderenfalls kommt es zu einem fatalen Matrixfehler ("matrix is not quadratic").
Diese Methode wird vom Modul "Math::MatrixBool" verwendet.
Nähere Details zu dieser Methode finden Sie in Math::MatrixBool(3).
$config = Bit::Vector->Configuration();
Bit::Vector->Configuration($config);
$oldconfig = Bit::Vector->Configuration($newconfig);
Diese Methode dient der Änderung der Semantik (d.h. des Verhaltens) bestimmter überladener Operatoren (die übrigens alle in Perl implementiert sind).
Diese Methode hat keinen wie auch immer gearteten Einfluß auf irgendwelche anderen Dinge. Insbesondere hat sie keinerlei Einfluß auf die in C implementierten Methoden.
Die Methode erlaubt einen (optionalen) String als Eingabe, in dem bestimmte Schlüsselwörter erwartet werden. Diese Schlüsselwörter beeinflussen mehrere Aspekte der überladenen Operatoren und betreffen teils nur einige, teils fast alle überladenen Operatoren auf einmal.
Die Methode gibt außerdem immer einen String zurück, der eine vollständige Aufzählung (in menschenlesbarer Form) der jeweils gerade aktuellen Konfiguration enthält (und zwar der Konfiguration vor der Durchführung jeglicher, durch den Eingabe-String möglicherweise diktierten Änderungen).
Dieser Ausgabe-String kann stets zu einem späteren Zeitpunkt wieder als Eingabe-String an diese Methode übergeben werden, um eine frühere Konfiguration wiederherzustellen.
Sie können diesen Ausgabe-String aber auch ignorieren, wenn Sie nur an der Veränderung der bestehenden Konfiguration und nicht an den ursprünglichen Einstellungen interessiert sind.
Es gibt drei Aspekte, die mit dieser Methode kontrolliert werden können:
Jeder dieser Aspekte wird mit Hilfe einer Zuweisung innerhalb des Eingabe-Strings verändert.
Der Eingabe-String kann dabei beliebig viele dieser Zuweisungen enthalten. Von mehreren Zuweisungen, die sich auf denselben Aspekt beziehen, hat jedoch nur die letzte Gültigkeit.
Jede Zuweisung hat die Form <was>=<wert>.
<was> und <wert> dürfen dabei sowohl aus Buchstaben ([a-zA-Z]) als auch aus Leerzeichen bestehen.
Mehrere Zuweisungen müssen durch eines (oder mehrere) der folgenden Zeichen voneinander getrennt werden:
Komma (","), Semikolon (";"), Doppelpunkt (":"), vertikaler Strich ("|"), Schrägstrich ("/"), Neue Zeile ("\n"), kaufmännisches Und ("&"), Plus ("+"), Bindestrich ("-").
Leere Zeilen oder Anweisungen (die nur aus Leerzeichen bestehen) sind erlaubt, werden aber ignoriert.
<was> kann im Prinzip ein beliebiger Text sein, er muß aber ein (oder mehrere) Schlüsselwörter aus einer der folgenden drei Gruppen enthalten (und zwar ausschließlich aus ein- und derselben Gruppe!):
(Jede Gruppe steht dabei für einen der drei Aspekte, die von der Configuration()-Methode kontrolliert werden.)
(Die Zeichen "^" und "$" stehen hier für eine Wortgrenze, d.h. für den Anfang und das Ende eines Wortes.)
Beachten Sie, daß die Groß- und Kleinschreibung hier nicht unterschieden wird(!).
Mit Hilfe dieser Schlüsselwörter können Sie beliebige Sätze bilden, vorausgesetzt daß kein Schlüsselwort aus einer der anderen beiden Gruppen darin vorkommt - anderenfalls kommt es zu einem fatalen Syntaxfehler (mit anderen Worten, Mehrdeutigkeiten sind nicht erlaubt!).
Ein Syntaxfehler tritt auch dann auf, wenn keines der obigen Schlüsselwörter paßt.
Das gleiche Prinzip gilt auch für <wert>; auch hier können Sie aus einer Reihe von Schlüsselwörtern sowie sonstigen, neutralen Wörtern beliebige Sätze bilden, und auch hier dürfen die Schlüsselwörter nur aus ein- und derselben Gruppe kommen.
Abhängig davon, welchen Aspekt Sie mit <was> ausgewählt haben, stehen unterschiedliche Gruppen von Schlüsselwörtern zur Verfügung, die bestimmen, auf welchen Wert der betreffende Aspekt eingestellt werden soll:
"<wert>" =
"<wert>" =
"<wert>" =
Beispiele:
"Any scalar input I provide should be considered to be = a bit index" "I want to have operator semantics suitable for = arithmetics" "Any bit vector in double quotes is to be output as = an enumeration"
^bit$, ^index oder ^indice, daß alle skalaren Operanden intern als Bitnummern aufgefaßt werden, d.h., $vector ^= 5; wechselt in diesem Fall den Zustand von Bit Nummer 5 im gegebenen Bitvektor (dieser Befehl entspricht übrigens genau dem Methodenaufruf $vector->bit_flip(5);).
Dies ist die Voreinstellung für dieses Modul.
Das Schlüsselwort ^hex hingegen bewirkt, daß alle skalaren Operanden als hexadezimale Zahlen aufgefaßt werden, d.h., $vector ^= 5; wechselt in diesem Fall den Zustand der Bits Nummer 0 und 2 (da eine hexadezimale 5 dem binären Wert 0101 entspricht).
(Beachten Sie, daß hexadezimale Eingaben jedoch immer zwischen Anführungszeichen stehen sollten, weil sie von Perl sonst als Dezimalzahlen interpretiert werden! Das obige Beispiel macht sich lediglich die Tatsache zunutze, daß hexadezimal 0..9 und dezimal 0..9 dasselbe sind!)
Das Schlüsselwort ^bin bewirkt, daß alle skalaren Operanden als Zahl in Binärdarstellung aufgefaßt werden. Alle Zeichen außer 0 und 1 sind in diesem Fall verboten (und führen zu einem fatalen Syntaxfehler).
Der Befehl $vector ^= '0101'; wechselt in diesem Fall beispielsweise den Zustand der beiden Bits Nummer 0 und 2.
Das Schlüsselwort ^dec bewirkt, daß alle skalaren Operanden als ganze Zahlen im Dezimalsystem aufgefaßt werden, d.h., $vector ^= 5; wechselt in diesem Fall den Zustand der Bits Nummer 0 und 2 (da eine dezimale 5 dem binären Wert 0101 entspricht).
(Beachten Sie, daß diese dezimalen Eingaben ebenfalls immer in Anführungszeichen stehen sollten, weil es sonst aufgrund der internen Darstellung von großen Zahlen in Perl im Fließkommaformat (mit Exponenten) zum Verlust von Dezimalstellen und darüber hinaus zu einem fatalen Syntaxfehler kommen kann, da die wissenschaftliche Notation (Exponentenschreibweise) nicht der vom Modul erwarteten Syntax entspricht!)
(Beachten Sie auch, daß die mit dieser Verwendung von Dezimalzahlen verbundene (notwendige!) Umwandlung von dezimal in die interne Binärdarstellung relativ zeitaufwendig ist und Ihre Anwendung verlangsamen kann!)
Das Schlüsselwort ^enum schließlich bewirkt, daß alle skalaren Operanden als eine Liste (Aufzählung) von Bitnummern und Bereiche von (fortlaufenden) Bitnummern aufgefaßt werden, d.h., der Befehl $vector |= '2,3,5,7-13,17-23'; setzt in diesem Fall die Bits mit den Nummern 2, 3, 5, 7 bis 13 und 17 bis 23.
Die betroffenen Operatoren sind: +, -, *, <, <=, >, >= und abs().
Bei der Einstellung "Mengenoperationen" ("ops=set") - das ist die Voreinstellung! - werden die folgenden Operationen ausgeführt:
+ Vereinigungsmenge ( set1 u set2 )
- Differenzmenge ( set1 \ set2 )
* Durchschnitt ( set1 n set2 )
< echte Teilmenge ( set1 < set2 )
<= Teilmenge ( set1 <= set2 )
> echte Obermenge ( set1 > set2 )
>= Obermenge ( set1 >= set2 )
abs() Norm ( = |{ 1,2,.. }| )
Mit der alternativen Einstellung "arithmetische Operationen" ("ops=arithmetic") werden die folgenden Operationen ausgeführt:
+ Addition ( num1 + num2 ) - Subtraktion ( num1 - num2 ) * Multiplikation ( num1 * num2 ) < "kleiner als" ( num1 < num2 ) <= "kleiner oder gleich" ( num1 <= num2 ) > "größer als" ( num1 > num2 ) >= "größer oder gleich" ( num1 >= num2 ) abs() Absolutwert ( = | z | )
Beachten Sie, daß die obigen Vergleichsoperatoren (<, <=, > und >=) ihre Operanden als vorzeichenbehaftet ansehen.
Um Vergleiche mit vorzeichenlosen Operanden durchzuführen, müssen Sie statt dessen die Operatoren lt, le, gt und ge verwenden. (Im Gegensatz zu den obigen Operatoren sind letztere von der "Operator-Semantik"-Einstellung nicht betroffen!)
to_Hex(), to_Bin(), to_Dec() und to_Enum() (die Methode Block_Read() wird hier nicht mitgezählt, weil sie keinen menschenlesbaren String erzeugt).
(Für die Umwandlung eines Bitvektors in Oktalzahlen siehe die Beschreibung der Methode Chunk_List_Read()!)
Dementsprechend gibt es vier mögliche Formate, in die ein Bitvektor bei der Ausgabe umgewandelt werden kann, d.h. wenn er in (doppelten) Anführungszeichen steht:
print "\$vector = '$vector'\n"; $string = "$vector";
Dementsprechend gibt es vier mögliche Einstellungen für den Aspekt "String-Ausgaben" ("string output"):
Beachten Sie, daß die Umwandlung in Dezimalzahlen von Natur aus extrem zeitaufwendig ist und Ihre Anwendung beträchtlich verlangsamen kann!
Daher sollten Sie diese Einstellung nur äußerst sparsam einsetzen und die zurückgelieferten Strings (mit den Dezimalzahlen) wo nötig zwischenspeichern, anstatt einen Bitvektor ein zweites Mal umzuwandeln.
Configuration() zurückgegebene Voreinstellung lautet wie folgt:
Scalar Input = Bit Index Operator Semantics = Set Operators String Output = Hexadecimal
Die Ausführung der beiden Anweisungen
Bit::Vector->Configuration("in=bin,ops=arithmetic,out=bin");
print Bit::Vector->Configuration(), "\n";
liefert die folgende Ausgabe:
Scalar Input = Binary Operator Semantics = Arithmetic Operators String Output = Binary
Sie können diese Ausgabe auch wieder an die Configuration()-Methode übergeben, um diese Einstellung später wiederherzustellen.
Beachten Sie, daß alle nicht explizit angegebenen Aspekte auch nicht verändert werden, d.h., die Anweisung
Bit::Vector->Configuration("operators = arithmetic");
läßt alle anderen Aspekte außer der "Operator-Semantik" unverändert.
"$vector"
Denken Sie daran, daß Perl alle in (doppelten) Anführungszeichen stehenden Variablen expandiert, oder, um im Perl-Jargon zu bleiben, "interpoliert".
Wann immer eine Perl-Variable, die eine Referenz auf ein "Bit::Vector"-Objekt enthält, in (doppelten) Anführungszeichen steht (egal ob für sich alleine oder zusammen mit anderem Text und/oder Variablen), wird der Inhalt des zugehörigen Bitvektors in einen druckbaren String umgewandelt und die betreffende Variable durch diesen String ersetzt.
Welche der vier vorhandenen Konvertierungsmethoden (to_Hex(), to_Bin(), to_Dec() oder to_Enum()) dabei verwendet wird, hängt von der mit Hilfe der Methode Configure() eingestellten Konfiguration ab (siehe dazu auch die Erläuterungen im vorangegangenen Kapitel).
Zu Programmbeginn ist die Umwandlung in Hexadezimalzahlen (also to_Hex()) voreingestellt.
if ($vector)
Es ist möglich, einen Bitvektor als Booleschen Ausdruck zu verwenden.
Die Bedingung ist wahr, wenn in dem betreffenden Bitvektor mindestens ein Bit gesetzt ist. Die Bedingung ist falsch, wenn alle Bits des betreffenden Bitvektors gelöscht sind.
if (!$vector)
Da es möglich ist, einen Bitvektor als Booleschen Ausdruck zu verwenden, können Sie diesen Ausdruck natürlich auch negieren und damit das Ergebnis dieser Auswertung umkehren.
Die Bedingung ist wahr, wenn alle Bits des betreffenden Bitvektors gelöscht sind. Sie ist falsch, wenn im betreffenden Bitvektor mindestens ein Bit gesetzt ist.
Beachten Sie, daß dies nicht das gleiche ist wie die Abfrage mit Hilfe der Methode is_full(), die "wahr" zurückgibt, wenn alle Bits des betreffenden Bitvektors gesetzt sind!
~$vector
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Einerkomplement des gegebenen Bitvektors enthält.
Dies entspricht dem Invertieren aller Bits.
-$vector (unäres Minus)
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Zweierkomplement des gegebenen Bitvektors enthält.
Das entspricht dem Invertieren aller Bits und der anschließenden Inkrementierung dieses Ergebnisses um eins.
(Das entspricht außerdem dem Vorzeichenwechsel der in dem Bitvektor enthaltenen Zahl.)
abs($vector)
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) die Anzahl der im gegebenen Bitvektor gesetzten Bits zurück (was der Anzahl von Elementen einer Menge, also ihrer "Kardinalität", entspricht), oder er gibt ein neues Bitvektor-Objekt zurück, das den Absolutwert der in dem gegebenen Bitvektor gespeicherten Zahl enthält.
$vector1 . $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Ergebnis der Verkettung der beiden Bitvektor-Operanden ist.
Der linke Operand wird dabei zum höchstwertigen, der rechte zum niederstwertigen Teil des neuen Bitvektors.
Ist einer der beiden Operanden hingegen kein Bitvektor-Objekt, sondern ein Perl-Skalar, wird der Inhalt des Bitvektor-Operanden in einen String umgewandelt (die dabei verwendete Konvertierungsmethode hängt von der mit der Configuration()-Methode eingestellten Konfiguration ab), der dann wiederum in der richtigen Reihenfolge (d.h. in der Reihenfolge der beiden Operanden) mit dem Perl-Skalar zu einem String verkettet wird.
(Es wird also in diesem Fall kein neues Bitvektor-Objekt zurückgegeben, sondern ein String!)
$vector x $factor
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das die Verkettung von so vielen Kopien des gegebenen Bitvektors (also des linken Operanden) ist, wie der Faktor (der rechte Operand) angibt.
Hat dieser Faktor den Wert Null, wird ein Bitvektor-Objekt mit einer Länge von null Bits zurückgegeben.
Hat der Faktor den Wert Eins, wird einfach eine neue Kopie des Bitvektors zurückgegeben.
Beachten Sie, daß es zu einem fatalen "Vertauschte Operanden"-Fehler ("reversed operands error") kommt, falls die beiden Operanden vertauscht werden.
$vector << $bits
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das eine Kopie des gegebenen Bitvektors (linker Operand) ist, die um so viele Bitpositionen nach links geschoben wurde (in Richtung zum höchstwertigen Bit), wie der rechte Operand $bits angibt.
Das bedeutet, daß die $bits höchstwertigen Bits verlorengehen, alle anderen Bits um $bits Positionen nach oben verschoben und die freiwerdenden $bits niederstwertigen Bits auf null gesetzt werden.
Ist $bits größer als die Anzahl der Bits im gegebenen Bitvektor, gibt dieser Term einen leeren Bitvektor zurück (d.h. alle Bits sind gelöscht), der die gleiche Länge hat wie der gegebene Bitvektor.
Beachten Sie, daß es zu einem fatalen "Vertauschte Operanden"-Fehler ("reversed operands error") kommt, falls die beiden Operanden vertauscht werden.
$vector >> $bits
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das eine Kopie des gegebenen Bitvektors (linker Operand) ist, die um so viele Bitpositionen nach rechts geschoben wurde (in Richtung zum niederstwertigen Bit), wie der rechte Operand $bits angibt.
Das bedeutet, daß die $bits niederstwertigen Bits verlorengehen, alle anderen Bits um $bits Positionen nach unten verschoben und die freiwerdenden $bits höchstwertigen Bits auf null gesetzt werden.
Ist $bits größer als die Anzahl der Bits im gegebenen Bitvektor, gibt dieser Term einen leeren Bitvektor zurück (d.h. alle Bits sind gelöscht), der die gleiche Länge hat wie der gegebene Bitvektor.
Beachten Sie, daß es zu einem fatalen "Vertauschte Operanden"-Fehler ("reversed operands error") kommt, falls die beiden Operanden vertauscht werden.
$vector1 | $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Ergebnis einer bitweisen ODER-Verknüpfung der beiden Bitvektor-Operanden ist.
Das ist äquivalent zu der Berechnung der Vereinigungsmenge dieser beiden Mengen.
$vector1 & $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Ergebnis einer bitweisen UND-Verknüpfung der beiden Bitvektor-Operanden ist.
Das ist äquivalent zu der Berechnung der Schnittmenge (des Durchschnitts) dieser beiden Mengen.
$vector1 ^ $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Ergebnis einer bitweisen EXKLUSIV-ODER-Verknüpfung der beiden Bitvektor-Operanden ist.
Das ist äquivalent zu der Berechnung der symmetrischen Differenz dieser beiden Mengen.
$vector1 + $vector2
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) ein neues Bitvektor-Objekt zurück, das das Ergebnis einer bitweisen ODER-Verknüpfung der beiden Bitvektor-Operanden ist (was der Berechnung der Vereinigungsmenge dieser beiden Mengen entspricht), oder es wird ein Bitvektor-Objekt zurückgegeben, das die Summe der beiden Bitvektor-Operanden enthält.
$vector1 - $vector2
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) ein neues Bitvektor-Objekt zurück, das die Differenzmenge der beiden Bitvektor-Operanden darstellt, oder es wird ein Bitvektor-Objekt zurückgegeben, das die Differenz der beiden Zahlen in den beiden Bitvektor-Operanden enthält.
$vector1 * $vector2
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) ein neues Bitvektor-Objekt zurück, das das Ergebnis einer bitweisen UND-Verknüpfung der beiden Bitvektor-Operanden ist (was der Berechnung der Schnittmenge dieser beiden Mengen entspricht), oder es wird ein Bitvektor-Objekt zurückgegeben, das das Produkt aus den beiden Bitvektor-Operanden enthält.
$vector1 / $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das das Ergebnis der Division der beiden Zahlen in den beiden Bitvektor-Operanden enthält.
$vector1 % $vector2
Dieser Term gibt ein neues Bitvektor-Objekt zurück, das den Rest der Division der beiden Zahlen in den beiden Bitvektor-Operanden enthält.
$vector1 .= $vector2;
Diese Anweisung hängt den rechten Operanden an den linken Bitvektor-Operanden an.
Der vorherige Inhalt des linken Operanden wird dabei zum höchstwertigen Teil des resultierenden Bitvektors, der rechte Operand zum niederstwertigen Teil.
Da Bitvektoren mit den niederstwertigen Bits zuunterst im Speicher abgelegt werden, muß der linke Operand dabei in Wahrheit um die Länge des rechten Operanden nach oben verschoben werden. Anschließend wird der rechte Operand in den nun freigewordenen niederstwertigen Teil des linken Operanden hineinkopiert.
Handelt es sich bei dem rechten Operanden um einen Perl-Skalar, wird dieser zuvor in einen Bitvektor umgewandelt.
Ist die Konfiguration so eingestellt, daß skalare Operanden als Bitnummern, Dezimalzahlen oder Aufzählungen interpretiert werden, wird der rechte Operand in einen Bitvektor umgewandelt, der die gleiche Länge hat wie der linke Operand.
Ist die Konfiguration hingegen so eingestellt, daß skalare Operanden als Hexadezimal- oder Binärzahlen interpretiert werden, wird der rechte Operand in einen Bitvektor umgewandelt, dessen Länge von der des rechten (skalaren) Operanden abhägt, und zwar viermal so lang bei einem Hexadezimal-String (weil jede hexadezimale Ziffer 4 Bits codiert) und genauso lang bei einem Binär-String.
$vector x= $factor;
Diese Anweisung ersetzt den gegebenen Bitvektor durch die Verkettung von so vielen Kopien des ursprünglichen Inhalts dieses Bitvektors, wie das der Faktor (der rechte Operand) angibt.
Hat der Faktor den Wert Null, wird die Länge des Bitvektors auf null Bits gesetzt.
Hat der Faktor den Wert Eins, wird der Bitvektor nicht verändert.
$vector <<= $bits;
Diese Anweisung verschiebt den Inhalt des gegebenen Bitvektors um so viele Bitpositionen nach links (in Richtung zum höchstwertigen Bit), wie der rechte Operand $bits angibt.
Das bedeutet, daß die $bits höchstwertigen Bits verlorengehen, alle anderen Bits um $bits Positionen nach oben verschoben und die freiwerdenden $bits niederstwertigen Bits auf null gesetzt werden.
Ist $bits größer als die Anzahl der Bits im gegebenen Bitvektor, wird der Bitvektor vollständig gelöscht.
$vector >>= $bits;
Diese Anweisung verschiebt den Inhalt des gegebenen Bitvektors um so viele Bitpositionen nach rechts (in Richtung zum niederstwertigen Bit), wie der rechte Operand $bits angibt.
Das bedeutet, daß die $bits niederstwertigen Bits verlorengehen, alle anderen Bits um $bits Positionen nach unten verschoben und die freiwerdenden $bits höchstwertigen Bits auf null gesetzt werden.
Ist $bits größer als die Anzahl der Bits im gegebenen Bitvektor, wird der Bitvektor vollständig gelöscht.
$vector1 |= $vector2;
Diese Anweisung führt eine bitweise ODER-Verknüpfung der beiden Bitvektor-Operanden durch und legt das Ergebnis dieser Operation im linken Operanden ab.
Das ist äquivalent zu der Berechnung der Vereinigungsmenge dieser beiden Mengen.
$vector1 &= $vector2;
Diese Anweisung führt eine bitweise UND-Verknüpfung der beiden Bitvektor-Operanden durch und legt das Ergebnis dieser Operation im linken Operanden ab.
Das ist äquivalent zu der Berechnung der Schnittmenge (des Durchschnitts) dieser beiden Mengen.
$vector1 ^= $vector2;
Diese Anweisung führt eine bitweise EXKLUSIV-ODER-Verknüpfung der beiden Bitvektor-Operanden durch und legt das Ergebnis dieser Operation im linken Operanden ab.
Das ist äquivalent zu der Berechnung der symmetrischen Differenz dieser beiden Mengen.
$vector1 += $vector2;
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), führt diese Anweisung entweder (Voreinstellung) eine bitweise ODER-Verknüpfung der beiden Bitvektor-Operanden durch (was der Berechnung der Vereinigungsmenge dieser beiden Mengen entspricht), oder es wird die Summe der beiden Zahlen in den beiden Bitvektoren berechnet.
Das Ergebnis dieser Operation wird im linken Operanden abgelegt.
$vector1 -= $vector2;
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), berechnet diese Anweisung entweder (Voreinstellung) die Differenzmenge der beiden Bitvektor-Operanden, oder es wird die Differenz der beiden Zahlen in den beiden Bitvektoren berechnet.
Das Ergebnis dieser Operation wird im linken Operanden abgelegt.
$vector1 *= $vector2;
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), führt diese Anweisung entweder (Voreinstellung) eine bitweise UND-Verknüpfung der beiden Bitvektor-Operanden durch (was der Berechnung der Schnittmenge dieser beiden Mengen entspricht), oder es wird das Produkt aus den beiden Zahlen in den beiden Bitvektoren berechnet.
Das Ergebnis dieser Operation wird im linken Operanden abgelegt.
$vector1 /= $vector2;
Diese Anweisung legt das Ergebnis der Division der beiden Zahlen aus den beiden Bitvektor-Operanden im linken Operanden ab.
$vector1 %= $vector2;
Diese Anweisung legt den Rest der Division der beiden Zahlen aus den beiden Bitvektor-Operanden im linken Operanden ab.
++$vector, $vector++
Dieser Operator führt ein Pre- bzw. Postinkrement des gegebenen Bitvektors durch.
Der von diesem Term zurückgelieferte Wert ist eine Referenz auf das gegebene Bitvektor-Objekt (nach bzw. vor der Inkrementierung).
--$vector, $vector--
Dieser Operator führt ein Pre- bzw. Postdekrement des gegebenen Bitvektors durch.
Der von diesem Term zurückgelieferte Wert ist eine Referenz auf das gegebene Bitvektor-Objekt (nach bzw. vor der Dekrementierung).
($vector1 cmp $vector2)
Dieser Term gibt -1 zurück, falls $vector1 kleiner ist als $vector2, 0, falls $vector1 und $vector2 gleich sind, und 1, falls $vector1 größer ist als $vector2.
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenlos sind.
($vector1 eq $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn die beiden Bitvektor-Operanden gleich sind, ansonsten "falsch" (0).
($vector1 ne $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn sich die beiden Bitvektor-Operanden unterscheiden, ansonsten "falsch" (0).
($vector1 lt $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn $vector1 kleiner ist als $vector2, ansonsten "falsch" (0).
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenlos sind.
($vector1 le $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn $vector1 kleiner als oder gleich $vector2 ist, ansonsten "falsch" (0).
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenlos sind.
($vector1 gt $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn $vector1 größer ist als $vector2, ansonsten "falsch" (0).
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenlos sind.
($vector1 ge $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn $vector1 größer als oder gleich $vector2 ist, ansonsten "falsch" (0).
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenlos sind.
($vector1 <=> $vector2)
Dieser Term gibt -1 zurück, falls $vector1 kleiner ist als $vector2, 0, falls $vector1 und $vector2 gleich sind, und 1, falls $vector1 größer ist als $vector2.
Dieser Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenbehaftet sind.
($vector1 == $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn die beiden Bitvektor-Operanden gleich sind, ansonsten "falsch" (0).
($vector1 != $vector2)
Dieser Term gibt "wahr" (1) zurück, wenn sich die beiden Bitvektor-Operanden unterscheiden, ansonsten "falsch" (0).
($vector1 < $vector2)
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) "wahr" (1) zurück, falls $vector1 eine echte Teilmenge von $vector2 ist (ansonsten "falsch" bzw. 0), oder er gibt "wahr" (1) zurück, falls $vector1 kleiner ist als $vector2 (ansonsten "falsch" bzw. 0).
Dieser letztere Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenbehaftet sind.
($vector1 <= $vector2)
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) "wahr" (1) zurück, falls $vector1 eine Teilmenge von $vector2 ist (ansonsten "falsch" bzw. 0), oder er gibt "wahr" (1) zurück, falls $vector1 kleiner ist als $vector2 (ansonsten "falsch" bzw. 0).
Dieser letztere Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenbehaftet sind.
($vector1 > $vector2)
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) "wahr" (1) zurück, falls $vector1 eine echte Obermenge von $vector2 ist (ansonsten "falsch" bzw. 0), oder er gibt "wahr" (1) zurück, falls $vector1 kleiner ist als $vector2 (ansonsten "falsch" bzw. 0).
Dieser letztere Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenbehaftet sind.
($vector1 >= $vector2)
Abhängig von der Konfiguration (Details hierzu finden Sie in der Beschreibung der Configuration()-Methode), gibt dieser Term entweder (Voreinstellung) "wahr" (1) zurück, falls $vector1 eine Obermenge von $vector2 ist (ansonsten "falsch" bzw. 0), oder er gibt "wahr" (1) zurück, falls $vector1 kleiner ist als $vector2 (ansonsten "falsch" bzw. 0).
Dieser letztere Vergleich geht davon aus, daß die beiden Bitvektoren vorzeichenbehaftet sind.
perl(1), perlsub(1), perlmod(1),
perlref(1), perlobj(1), perlbot(1),
perltoot(1), perlxs(1),
perlxstut(1), perlguts(1),
overload(3)
Steffen Beyer Ainmillerstr. 5 / App. 513 D-80801 München mailto:sb@engelschall.com http://www.engelschall.com/u/sb/download/
Kontaktieren Sie mich bitte möglichst nur per E-Mail!
Die C-Bibliothek, die den Kern dieses Perl-Moduls bildet, kann darüber hinaus auch unter den Lizenzbedingungen der "GNU Library General Public License" benutzt, modifiziert und weitergegeben werden.
Bitte beachten Sie die Dateien "Artistic.txt", "GNU_GPL.txt" und "GNU_LGPL.txt" in dieser Distribution für die entsprechenden Details!
Siehe dazu auch die "GNU General Public License" für weitere Details.