Bits mit einer einzigen Multiplikation extrahieren

301

Ich habe eine interessante Technik gesehen, die bei der Beantwortung einer anderen Frage verwendet wurde , und möchte sie etwas besser verstehen.

Wir erhalten eine vorzeichenlose 64-Bit-Ganzzahl und interessieren uns für die folgenden Bits:

1.......2.......3.......4.......5.......6.......7.......8.......

Insbesondere möchten wir sie wie folgt auf die ersten acht Positionen verschieben:

12345678........................................................

Der Wert der durch angegebenen Bits ist uns egal .und sie müssen nicht erhalten bleiben.

Die Lösung bestand darin, die unerwünschten Bits auszublenden und das Ergebnis mit zu multiplizieren 0x2040810204081. Wie sich herausstellt, ist dies der Trick.

Wie allgemein ist diese Methode? Kann diese Technik verwendet werden, um eine Teilmenge von Bits zu extrahieren? Wenn nicht, wie kann man herausfinden, ob die Methode für einen bestimmten Satz von Bits funktioniert oder nicht?

Wie würde man schließlich den (a?) Richtigen Multiplikator finden, um die gegebenen Bits zu extrahieren?

NPE
quelle
29
Wenn Sie dieses interessant fanden, sehen Sie sich diese Liste an: graphics.stanford.edu/~seander/bithacks.html Viele von ihnen (ab) verwenden eine Multiplikation / Division mit einer breiteren Ganzzahl, um interessante Ergebnisse zu erzielen. (Der Teil "Die Bits in einem Byte mit 4 Operationen umkehren" zeigt, wie man mit dem Bitverschiebungs- / Multiplikationstrick umgeht, wenn man nicht genug Platz hat und zweimal maskieren / multiplizieren muss)
Viraptor
@ Viraptor: Ausgezeichneter Punkt. Wenn Sie die Einschränkungen dieser Methode verstehen, können Sie die Multiplikation wirklich verwenden, um viel in Bezug auf die Bitmanipulation zu erreichen.
Expedito
9
Interessanterweise gibt es in AVX2 eine Anweisung (die leider noch nicht verfügbar ist), die genau die von Ihnen beschriebene Operation
ausführt
3
Ein weiterer Ort, um nach cleveren Bit-Twiddling-Algorithmen zu suchen, ist MIT HAKMEM
Barmar
1
Um livro que conheço sobre o assunto (e gosto bastante) é o "Hacker Delight" Link
Salles

Antworten:

235

Sehr interessante Frage und kluger Trick.

Schauen wir uns ein einfaches Beispiel für die Manipulation eines einzelnen Bytes an. Der Einfachheit halber wird vorzeichenloses 8-Bit verwendet. Stellen Sie sich vor, Ihre Nummer ist xxaxxbxxund Sie wollen ab000000.

Die Lösung bestand aus zwei Schritten: einer Bitmaskierung, gefolgt von einer Multiplikation. Die Bitmaske ist eine einfache UND-Operation, die uninteressante Bits in Nullen umwandelt. Im obigen Fall wäre Ihre Maske 00100100und das Ergebnis 00a00b00.

Nun der schwierige Teil: das zu machen ab.......

Eine Multiplikation ist eine Reihe von Shift-and-Add-Operationen. Der Schlüssel ist, dass der Überlauf die nicht benötigten Bits "wegschiebt" und die gewünschten an die richtige Stelle bringt.

Die Multiplikation mit 4 ( 00000100) würde alles, was übrig bleibt, um 2 verschieben und Sie dazu bringen a00b0000. Um das bnach oben zu bringen, müssen wir mit 1 multiplizieren (um das a an der richtigen Stelle zu halten) + 4 (um das b nach oben zu bewegen). Diese Summe ist 5 und zusammen mit den früheren 4 erhalten wir eine magische Zahl von 20 oder 00010100. Das Original war 00a00b00nach dem Maskieren; Die Multiplikation ergibt:

000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......

Von diesem Ansatz aus können Sie auf größere Zahlen und mehr Bits erweitern.

Eine der Fragen, die Sie gestellt haben, war: "Kann dies mit einer beliebigen Anzahl von Bits durchgeführt werden?" Ich denke, die Antwort ist "nein", es sei denn, Sie erlauben mehrere Maskierungsoperationen oder mehrere Multiplikationen. Das Problem ist das Problem der "Kollisionen" - zum Beispiel das "Streuner b" im obigen Problem. Stellen Sie sich vor, wir müssen dies mit einer Zahl wie tun xaxxbxxcx. Nach dem früheren Ansatz würden Sie denken, wir brauchen {x 2, x {1 + 4 + 16}} = x 42 (oooh - die Antwort auf alles!). Ergebnis:

00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......

Wie Sie sehen können, funktioniert es immer noch, aber "nur gerade". Der Schlüssel hier ist, dass zwischen den Bits, die wir wollen, "genug Platz" ist, damit wir alles zusammenpressen können. Ich konnte kein viertes Bit d direkt nach c hinzufügen, da ich Fälle bekommen würde, in denen ich c + d bekomme, Bits könnten tragen, ...

Ohne formalen Beweis würde ich die interessanteren Teile Ihrer Frage wie folgt beantworten: "Nein, dies funktioniert nicht für eine beliebige Anzahl von Bits. Um N Bits zu extrahieren, benötigen Sie (N-1) Leerzeichen zwischen den gewünschten Bits extrahieren oder zusätzliche Maskenmultiplikationsschritte ausführen. "

Die einzige Ausnahme, die ich mir für die Regel "Muss (N-1) Nullen zwischen Bits haben" vorstellen kann, ist folgende: Wenn Sie zwei Bits extrahieren möchten, die im Original nebeneinander liegen, UND Sie sie in der behalten möchten gleiche Reihenfolge, dann können Sie es noch tun. Und für die Zwecke der (N-1) -Regel zählen sie als zwei Bits.

Es gibt noch eine weitere Erkenntnis - inspiriert von der Antwort von @Ternary unten (siehe meinen Kommentar dort). Für jedes interessante Bit benötigen Sie nur so viele Nullen rechts davon, wie Sie Platz für Bits benötigen, die dorthin gehen müssen. Aber es braucht auch so viele Bits links wie es Ergebnisbits links hat. Wenn also ein Bit b an der Position m von n landet, muss es links m-1 Nullen und rechts nm Nullen haben. Insbesondere wenn die Bits in der ursprünglichen Nummer nicht in der gleichen Reihenfolge sind wie nach der Neuordnung, ist dies eine wichtige Verbesserung der ursprünglichen Kriterien. Dies bedeutet zum Beispiel, dass ein 16-Bit-Wort

a...e.b...d..c..

Kann verschoben werden in

abcde...........

obwohl es nur einen Raum zwischen e und b gibt, zwei zwischen d und c, drei zwischen den anderen. Was ist mit N-1 passiert? In diesem Fall a...ewird "ein Block" - sie werden mit 1 multipliziert, um an der richtigen Stelle zu landen, und so "wir haben e kostenlos". Gleiches gilt für b und d (b benötigt drei Leerzeichen rechts, d benötigt die gleichen drei links). Wenn wir also die magische Zahl berechnen, stellen wir fest, dass es Duplikate gibt:

a: << 0  ( x 1    )
b: << 5  ( x 32   )
c: << 11 ( x 2048 )
d: << 5  ( x 32   )  !! duplicate
e: << 0  ( x 1    )  !! duplicate

Wenn Sie diese Nummern in einer anderen Reihenfolge haben möchten, müssen Sie sie natürlich weiter platzieren. Wir können die (N-1)Regel neu formulieren : "Es wird immer funktionieren, wenn mindestens (N-1) Leerzeichen zwischen den Bits vorhanden sind; oder wenn die Reihenfolge der Bits im Endergebnis bekannt ist, wenn ein Bit b in Position m von endet n, es muss links m-1 Nullen und rechts nm Nullen haben. "

@Ternary wies darauf hin, dass diese Regel nicht ganz funktioniert, da es einen Übertrag von Bits geben kann, die "rechts neben dem Zielbereich" hinzufügen - nämlich wenn die Bits, nach denen wir suchen, alle diejenigen sind. Fortsetzung des obigen Beispiels mit den fünf dicht gepackten Bits in einem 16-Bit-Wort: Wenn wir mit beginnen

a...e.b...d..c..

Der Einfachheit halber werde ich die Bitpositionen benennen ABCDEFGHIJKLMNOP

Die Mathematik, die wir machen wollten, war

ABCDEFGHIJKLMNOP

a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00

Bis jetzt dachten wir, dass alles unten abcde(Positionen ABCDE) keine Rolle spielen würde, aber tatsächlich, wie @Ternary hervorhob, wenn b=1, c=1, d=1dann (b+c)in Position Gein bisschen in Position gebracht wird F, was bedeutet, dass (d+1)in Position Fein bisschen in E- und unsere Ergebnis ist verwöhnt. Beachten Sie, dass der Platz rechts neben dem niedrigstwertigen interessierenden Bit ( cin diesem Beispiel) keine Rolle spielt, da die Multiplikation ein Auffüllen mit Nullen von jenseits des niedrigstwertigen Bits verursacht.

Wir müssen also unsere (m-1) / (nm) -Regel ändern. Wenn es mehr als ein Bit gibt, das "genau (nm) unbenutzte Bits rechts hat (ohne das letzte Bit im Muster zu zählen -" c "im obigen Beispiel), müssen wir die Regel verstärken - und wir müssen mach das iterativ!

Wir müssen nicht nur die Anzahl der Bits betrachten, die das (nm) -Kriterium erfüllen, sondern auch diejenigen, die bei (n-m + 1) usw. liegen. Nennen wir ihre Anzahl Q0 (genau n-mzum nächsten Bit), Q1 ( n-m + 1) bis zu Q (N-1) (n-1). Dann riskieren wir zu tragen, wenn

Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
... 

Wenn Sie sich das ansehen, können Sie das sehen, wenn Sie einen einfachen mathematischen Ausdruck schreiben

W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)

und das Ergebnis ist W > 2 * N, dann müssen Sie das RHS-Kriterium um ein Bit auf erhöhen (n-m+1). Zu diesem Zeitpunkt ist der Betrieb sicher, solange W < 4; Wenn dies nicht funktioniert, erhöhen Sie das Kriterium noch einmal usw.

Ich denke, dass das Befolgen der obigen Anweisungen einen langen Weg zu Ihrer Antwort bringt ...

Floris
quelle
1
Toll. Ein subtileres Problem: Der m-1 / nm-Test schlägt manchmal aufgrund von Übertragsbits fehl. Versuchen Sie a ... b..c ... d - Sie landen mit b + c im fünften Bit, was, wenn beide 1 sind, ein Übertragsbit ergibt, das d (!)
Ternary
1
Fazit: n-1 Bit Speicherplatz verbietet Konfigurationen, die funktionieren sollten (iea ... b..c ... d), und m-1 / nm erlaubt solche, die nicht funktionieren (a ... b..c ... d). Ich konnte keine einfache Methode finden, um zu charakterisieren, welche funktionieren und welche nicht.
Ternary
Du bist gut! Das Übertragsproblem bedeutet, dass wir rechts von jedem Bit etwas mehr Platz als "Schutz" benötigen. Auf den ersten Blick müssen Sie, wenn es mindestens zwei Bits gibt, die genau das Minimum nm rechts haben, den Abstand um 1 erhöhen. Wenn P solche Bits vorhanden sind, benötigen Sie im Allgemeinen log2 (P) zusätzliche Bits zu Recht von jedem, der das Minimum hatte (mn). Scheint dir richtig zu sein?
Floris
Nun, dieser letzte Kommentar war zu simpel. Ich denke, meine zuletzt bearbeitete Antwort zeigt, dass log2 (P) nicht der richtige Ansatz ist. @ Ternarys eigene Antwort (unten) zeigt elegant, wie Sie für eine bestimmte Bitkombination feststellen können, ob Sie keine garantierte Lösung haben - ich glaube, die obige Arbeit geht noch etwas näher darauf ein.
Floris
1
Es ist wahrscheinlich ein Zufall, aber diese Antwort wurde akzeptiert, als die Anzahl der Upvotes 127 erreichte. Wenn Sie so weit gelesen haben, werden Sie mit mir lächeln ...
Floris
154

Sehr interessante Frage. Ich stimme meinen zwei Cent zu, das heißt, wenn Sie es schaffen, Probleme wie diese in Bezug auf die Logik erster Ordnung über die Bitvektortheorie zu erklären, dann sind Theorembeweiser Ihr Freund und können Sie möglicherweise sehr schnell versorgen Antworten auf Ihre Fragen. Lassen Sie uns das gestellte Problem als Theorem wiederholen:

"Es gibt einige 64-Bit-Konstanten 'mask' und 'multiplicand', so dass wir für alle 64-Bit-Bitvektoren x im Ausdruck y = (x & mask) * multiplicand y.63 == x.63 haben , y.62 == x.55, y.61 == x.47 usw. "

Wenn dieser Satz tatsächlich ein Theorem ist, dann ist es wahr, dass einige Werte der Konstanten 'mask' und 'multiplicand' diese Eigenschaft erfüllen. Lassen Sie uns dies in Bezug auf etwas formulieren, das ein Theorembeweiser verstehen kann, nämlich die Eingabe von SMT-LIB 2:

(set-logic BV)

(declare-const mask         (_ BitVec 64))
(declare-const multiplicand (_ BitVec 64))

(assert
  (forall ((x (_ BitVec 64)))
    (let ((y (bvmul (bvand mask x) multiplicand)))
      (and
        (= ((_ extract 63 63) x) ((_ extract 63 63) y))
        (= ((_ extract 55 55) x) ((_ extract 62 62) y))
        (= ((_ extract 47 47) x) ((_ extract 61 61) y))
        (= ((_ extract 39 39) x) ((_ extract 60 60) y))
        (= ((_ extract 31 31) x) ((_ extract 59 59) y))
        (= ((_ extract 23 23) x) ((_ extract 58 58) y))
        (= ((_ extract 15 15) x) ((_ extract 57 57) y))
        (= ((_ extract  7  7) x) ((_ extract 56 56) y))
      )
    )
  )
)

(check-sat)
(get-model)

Und jetzt fragen wir den Theorembeweiser Z3, ob dies ein Theorem ist:

z3.exe /m /smt2 ExtractBitsThroughAndWithMultiplication.smt2

Das Ergebnis ist:

sat
(model
  (define-fun mask () (_ BitVec 64)
    #x8080808080808080)
  (define-fun multiplicand () (_ BitVec 64)
    #x0002040810204081)
)

Bingo! Es reproduziert das im ursprünglichen Beitrag angegebene Ergebnis in 0,06 Sekunden.

Wenn wir dies aus einer allgemeineren Perspektive betrachten, können wir dies als ein Beispiel für ein Programmsyntheseproblem erster Ordnung betrachten, das ein aufstrebendes Forschungsgebiet ist, über das nur wenige Artikel veröffentlicht wurden. Eine Suche nach "program synthesis" filetype:pdfsollte Ihnen den Einstieg erleichtern.

Syzygy
quelle
2
Ich bin beeindruckt! Ich wusste nicht, dass "Logik erster Ordnung über die Bitvektortheorie" sogar ein echtes Thema war, das die Leute studierten - geschweige denn, dass es so interessante Ergebnisse liefern könnte. Vielen Dank für das Teilen.
Floris
@ AndrewBacker: Könnte mich jemand beleuchten, welchen Punkt es in dieser sogenannten "SO-as-a-Job" -Sache gibt? Ich meine, es zahlt nichts. Sie können nicht allein von SO rep leben. Vielleicht kann es Ihnen einige Punkte in Interviews geben. Vielleicht. Wenn der Arbeitsplatz gut genug ist, um den Wert von SO rep zu erkennen, und das ist nicht
selbstverständlich
3
Sicher. SO ist auch ein Spiel (alles mit Punkten ist) für viele Leute. Nur die menschliche Natur, wie die Jagd in / r / new, damit Sie den ersten Kommentar posten und Karma erhalten können. Nichts schlechtes daran, solange die Antworten noch gut sind. Ich bin nur glücklicher, wenn ich jemandem Zeit und Mühe geben kann, wenn er wahrscheinlich tatsächlich bemerkt, dass es jemand getan hat. Ermutigung ist gutes Zeug :) Und ... das war ein wirklich alter Kommentar und immer noch wahr. Ich sehe nicht, wie es nicht klar ist.
Andrew Backer
88

Jedes 1-Bit im Multiplikator wird verwendet, um eines der Bits an die richtige Position zu kopieren:

  • 1ist bereits in der richtigen Position, also multiplizieren Sie mit 0x0000000000000001.
  • 2muss um 7 Bitpositionen nach links verschoben werden, damit wir mit multiplizieren 0x0000000000000080(Bit 7 ist gesetzt).
  • 3muss um 14 Bitpositionen nach links verschoben werden, damit wir mit multiplizieren 0x0000000000000400(Bit 14 ist gesetzt).
  • und so weiter bis
  • 8muss um 49 Bitpositionen nach links verschoben werden, damit wir mit multiplizieren 0x0002000000000000(Bit 49 ist gesetzt).

Der Multiplikator ist die Summe der Multiplikatoren für die einzelnen Bits.

Dies funktioniert nur, weil die zu sammelnden Bits nicht zu nahe beieinander liegen, so dass die Multiplikation von Bits, die in unserem Schema nicht zusammengehören, entweder über das 64-Bit oder im unteren, nicht interessierenden Teil hinausgeht.

Beachten Sie, dass die anderen Bits in der ursprünglichen Nummer sein müssen 0. Dies kann erreicht werden, indem sie mit einer UND-Operation maskiert werden.

Sternenblau
quelle
2
Tolle Erklärung! Ihre kurze Antwort ermöglichte es, den Wert der "magischen Zahl" schnell zu finden.
Expedito
4
Dies ist wirklich die beste Antwort, aber es wäre nicht so hilfreich gewesen, ohne zuerst (die erste Hälfte) von @ floris 'Antwort gelesen zu haben.
Andrew Backer
29

(Ich hatte es noch nie gesehen. Dieser Trick ist großartig!)

Ich werde ein wenig auf Floris 'Behauptung eingehen, dass Sie beim Extrahieren von nBits n-1Platz zwischen nicht aufeinanderfolgenden Bits benötigen :

Mein erster Gedanke (wir werden gleich sehen, dass dies nicht ganz funktioniert) war, dass Sie es besser machen könnten: Wenn Sie nBits extrahieren möchten , kommt es beim Extrahieren / Verschieben von Bits zu einer Kollision, iwenn Sie jemanden haben (nicht -konsekutiv mit Bit i) in deri-1 vorhergehenden oder n-inachfolgenden Bits.

Ich werde einige Beispiele zur Veranschaulichung geben:

...a..b...c...Funktioniert (niemand in den 2 Bits nach a, das Bit vor und das Bit nach b, und niemand ist in den 2 Bits vor c):

  a00b000c
+ 0b000c00
+ 00c00000
= abc.....

...a.b....c...Schlägt fehl, weil bes in den 2 Bits danach ist a(und beim Verschieben an die Stelle eines anderen gezogen wird a):

  a0b0000c
+ 0b0000c0
+ 00c00000
= abX.....

...a...b.c...Schlägt fehl, weil bes sich um die 2 vorhergehenden Bits handelt c(und beim Verschieben an die Stelle eines anderen geschoben wird c):

  a000b0c0
+ 0b0c0000
+ b0c00000
= Xbc.....

...a...bc...d... Funktioniert, weil aufeinanderfolgende Bits zusammen verschoben werden:

  a000bc000d
+ 0bc000d000
+ 000d000000
= abcd000000

Aber wir haben ein Problem. Wenn wir n-istattdessen verwenden n-1, könnten wir das folgende Szenario haben: Was ist, wenn wir eine Kollision außerhalb des Teils haben, die uns wichtig ist, etwas, das wir am Ende maskieren würden, dessen Übertragsbits jedoch den wichtigen nicht maskierten Bereich stören ? (und Hinweis: Die n-1Anforderung stellt sicher, dass dies nicht geschieht, indem sichergestellt wird, dass die i-1Bits nach unserem nicht maskierten Bereich klar sind, wenn wir das ith-Bit verschieben.)

...a...b..c...d...Ein möglicher Fehler bei Übertragsbits cliegt im n-1Nachhinein b, erfüllt jedoch die n-iKriterien:

  a000b00c000d
+ 0b00c000d000
+ 00c000d00000
+ 000d00000000
= abcdX.......

Warum kehren wir nicht einfach zu dieser n-1Anforderung an " Platz" zurück? Weil wir es besser machen können :

...a....b..c...d.. Dern-1 Test " Bits of Space" schlägt fehl , funktioniert jedoch für unseren Trick zum Extrahieren von Bits:

+ a0000b00c000d00
+ 0b00c000d000000
+ 00c000d00000000
+ 000d00000000000
= abcd...0X......

Ich kann nicht mit einem guten Weg, um diese Felder zu charakterisieren , die nicht haben n-1, Raum zwischen wichtigen Bits , aber immer noch für unsere Operation funktionieren würde. Da wir es aber vorher wissen welchen Bits wir interessiert sind, können wir unseren Filter überprüfen, um sicherzustellen, dass keine Carry-Bit-Kollisionen auftreten:

Vergleichen Sie (-1 AND mask) * shiftmit dem erwarteten All-One-Ergebnis,-1 << (64-n) (für 64-Bit ohne Vorzeichen).

Die magische Verschiebung / Multiplikation zum Extrahieren unserer Bits funktioniert genau dann, wenn beide gleich sind.

Ternär
quelle
Ich mag es - Sie haben Recht, dass Sie für jedes Bit nur so viele Nullen rechts davon benötigen, wie Sie Platz für Bits benötigen, die dorthin gehen müssen. Aber es braucht auch so viele Bits links wie es Ergebnisbits links hat. Wenn also ein Bit ban der Position mvon landet n, muss es m-1links n-m-1Nullen und rechts Nullen haben. Insbesondere wenn die Bits in der ursprünglichen Nummer nicht in der gleichen Reihenfolge sind wie nach der Neuordnung, ist dies eine wichtige Verbesserung der ursprünglichen Kriterien. Das macht Spaß.
Floris
13

Zusätzlich zu den bereits hervorragenden Antworten auf diese sehr interessante Frage könnte es nützlich sein zu wissen, dass dieser bitweise Multiplikationstrick in der Computerschach-Community seit 2007 bekannt ist und unter dem Namen Magic BitBoards firmiert .

Viele Computerschach-Engines verwenden mehrere 64-Bit-Ganzzahlen (sogenannte Bitboards), um die verschiedenen Stückmengen darzustellen (1 Bit pro belegtem Quadrat). Angenommen, ein Gleitstück (Turm, Bischof, Königin) auf einem bestimmten Ursprungsfeld kann sich auf höchstens KFelder bewegen, wenn keine blockierenden Teile vorhanden sind. Die Verwendung von bitweisen und dieser gestreuten KBits mit dem Bitboard der belegten Quadrate ergibt ein spezifisches KBit-Wort, das in eine 64-Bit-Ganzzahl eingebettet ist.

Die magische Multiplikation kann verwendet werden, um diese gestreuten KBits den unteren KBits einer 64-Bit-Ganzzahl zuzuordnen . Diese unteren KBits können dann verwendet werden, um eine Tabelle vorberechneter Bitboards zu indizieren, die die zulässigen Quadrate darstellen, zu denen sich das Teil auf seinem Ursprungsquadrat tatsächlich bewegen kann (wobei darauf geachtet wird, Teile zu blockieren usw.).

Eine typische Schachmaschine, die diesen Ansatz verwendet, verfügt über 2 Tabellen (eine für Türme, eine für Bischöfe, Königinnen, die beide kombinieren) mit 64 Einträgen (eine pro Ursprungsquadrat), die solche vorberechneten Ergebnisse enthalten. Sowohl die Closed Source ( Houdini ) mit der höchsten Bewertung als auch die Open Source-Schachengine ( Stockfish ) verwenden diesen Ansatz derzeit für seine sehr hohe Leistung.

Das Finden dieser magischen Multiplikatoren erfolgt entweder mithilfe einer umfassenden Suche (optimiert mit frühen Cutoffs) oder mit Trial and Erorr (z. B. Ausprobieren zufälliger 64-Bit-Ganzzahlen). Während der Bewegungsgenerierung wurden keine Bitmuster verwendet, für die keine magische Konstante gefunden werden konnte. Bitweise Übertragseffekte sind jedoch typischerweise erforderlich, wenn die abzubildenden Bits (fast) benachbarte Indizes haben.

AFAIK, der sehr allgemeine SAT-Löser-Ansatz von @Syzygy, wurde im Computerschach nicht verwendet, und es scheint auch keine formale Theorie bezüglich der Existenz und Einzigartigkeit solcher magischen Konstanten zu geben.

TemplateRex
quelle
Ich hätte gedacht, dass jeder, der einen vollständigen formalen CS-Hintergrund hat, direkt auf den SAT-Ansatz gesprungen wäre, wenn er dieses Problem gesehen hätte. Vielleicht finden CS-Leute Schach uninteressant? :(
Stellen Sie Monica
@KubaOber Es ist meistens umgekehrt: Computerschach wird von Bit-Twiddlern dominiert, die in C oder Assembly programmieren und jede Art von Abstraktion (C ++, Vorlagen, OO) hassen. Ich denke, das macht den echten CS-Leuten Angst :-)
TemplateRex