Ich habe diesen Java-Code gesehen, der eine perfekte 50% ige Mischung zwischen zwei RGB888 Farben extrem effizient macht:
%Vor%Das ist anscheinend äquivalent zum Extrahieren und Mitteln der Kanäle einzeln. Etwas wie das:
%Vor%Aber der erste Weg ist viel effizienter. Meine Fragen sind: Wie funktioniert diese Magie? Was kann ich sonst noch damit machen? Und gibt es mehr Tricks ähnlich?
(a ^ b) & 0x00010101
ist, was die niedrigstwertigen Bits der Kanäle in a + b
gewesen wären, wenn kein Übertrag von rechts gekommen wäre.
Das Subtrahieren von der Summe garantiert, dass das Bit, das in das höchstwertige Bit des nächsten Kanals geschoben wird, nur der Übertrag von diesem Kanal ist, der von diesem Kanal nicht beeinflusst wird. Das bedeutet natürlich auch, dass dieser Kanal nicht mehr durch den Übertrag vom nächsten Kanal beeinflusst wird.
Eine andere Möglichkeit, dies zu sehen, nicht die Art und Weise, wie es funktioniert, sondern eine Möglichkeit, die Ihnen beim Verständnis helfen kann, ist, dass die Eingänge effektiv so geändert werden, dass ihre Summe für alle Kanäle gleich ist. Die Übertragungen gehen dann gut in die niedrigstwertigen Bits (die Null sind, weil gerade), ohne etwas zu stören. Was es tatsächlich macht, ist natürlich umgekehrt, zuerst summiert es sie, und erst dann stellt es sicher, dass die Summen für alle Kanäle gleich sind. Aber die Reihenfolge spielt keine Rolle.
Genauer gesagt gibt es 4 Fälle (bevor der Übertrag vom nächsten Kanal angewendet wird):
Die ersten beiden Fälle sind trivial. Die Verschiebung bringt das getragene Bit zurück in den Kanal, zu dem es gehört, es spielt keine Rolle, ob es 0 oder 1 war.
Fall 3 ist interessanter. Wenn der Wert lsb gleich 1 ist, bedeutet dies, dass die Verschiebung dieses Bit in das höchstwertige Bit des nächsten Kanals verschiebt. Das ist schlecht. Dieses Bit muss irgendwie unscharf sein - aber du kannst es nicht einfach wegmasken, weil du vielleicht in Fall 4 bist.
Fall 4 ist am interessantesten. Wenn das lsb 1 ist und ein Übertrag in dieses Bit vorliegt, wird es auf 0 gerollt und der Übertrag wird propagiert. Das kann nicht durch Maskieren rückgängig gemacht werden, aber es kann durch Umkehrung des Prozesses gemacht werden, dh durch Subtrahieren von 1 von dem lsb (was es zurück auf 1 setzt und jeglichen durch den fortgeführten Übertrag verursachten Schaden rückgängig macht).
Wie Sie sehen können, subtrahiert in beiden Fällen 3 und 4 die Heilung 1 von der lsb, und das sind auch die Fälle, in denen die lsb wirklich 1 sein wollte (obwohl es vielleicht nicht mehr ist, aufgrund eines Übertrags vom nächsten Kanal), und in beiden Fällen 1 und 2, müssen Sie nichts (Subtraktion 0). Das entspricht genau dem Subtrahieren von "was der LSB in a + b
gewesen wäre, wenn kein Übertrag von rechts gekommen wäre".
Außerdem kann der blaue Kanal nur in die Fälle 1 oder 3 fallen (es gibt keinen nächsten Kanal, der übertragen werden könnte), und die Verschiebung würde dieses Bit einfach verwerfen, anstatt es in den nächsten Kanal zu setzen (weil es keinen gibt). Sie können also alternativ schreiben (beachten Sie, dass die Maske die am wenigsten signifikante 1 verloren hat)
%Vor%Macht aber wirklich keinen Unterschied.
Damit es für ARGB8888 funktioniert, können Sie zum guten alten "SWAR-Durchschnitt" wechseln:
%Vor% Dies ist eine Variante einer rekursiven Methode zur Definition der Addition: x + y = (x ^ y) + ((x & y) << 1)
, die die Summe ohne Übertrag berechnet und dann die Übertragungen separat addiert. Der Basisfall ist, wenn einer der Operanden Null ist.
Beide Hälften werden effektiv um 1 nach rechts verschoben, so dass die Übertragung des höchstwertigen Bits niemals verloren geht. Die Maske stellt sicher, dass Bits nicht in einen Kanal nach rechts verschoben werden und stellt gleichzeitig sicher, dass sich ein Übertrag nicht aus seinem Kanal ausbreitet.
Tags und Links language-agnostic java optimization bit-manipulation color-blending