Wie Einerkomplement mit Rubys Bit-Operatoren berechnen?
-
05-07-2019 - |
Frage
Was ich will:
assert_equal 6, ones_complement(9) # 1001 => 0110
assert_equal 0, ones_complement(15) # 1111 => 0000
assert_equal 2, ones_complement(1) # 01 => 10
Die Größe des Eingangs wird, wie in 4 Bits oder 8 Bits nicht festgelegt. vielmehr ist es ein Binärstroms.
Was ich sehe:
v = "1001".to_i(2) => 9
Es ist ein bisschen Flipping Operator ~
(~v).to_s(2) => "-1010"
sprintf("%b", ~v) => "..10110"
~v => -10
Ich denke, das hat etwas mit einem Bit zu tun verwendet wird, um die Zeichen oder etwas zu speichern ... kann jemand diese Ausgabe erklären? Wie erhalte ich ein Einerkomplement, ohne wie in String-Manipulationen zurückgreifen, die letzten n Zeichen aus der sprintf Ausgabe Schneiden „0110“ oder ersetzen 0 mit 1 und umgekehrt
zu bekommenLösung
Es klingt wie Sie nur vier Bits spiegeln möchten (die Länge Ihrer Eingabe) - so möchten Sie wahrscheinlich mit 1111 bis XOR
.Andere Tipps
Rubin speichert nur eine (signiert) Nummer. Die interne Darstellung dieser Zahl ist nicht relevant: es könnte sonst ein Fixnum, BigNum oder so etwas. Daher ist die Anzahl der Bits in einer Reihe auch nicht definiert: es schließlich nur eine Zahl ist. Dies steht im Gegensatz zu beispielsweise C, wo ein int wahrscheinlich 32 Bit (fest) sein.
Was bedeutet der Operator ~ dann tun? Wel, nur so etwas wie:
class Numeric
def ~
return -self - 1
end
end
... denn das ist, was ‚~‘ darstellt, wenn bei 2-Komplement-Zahlen suchen.
Also, was aus Ihrer Eingabe Aussage fehlt, ist die Anzahl von Bits, die Sie wechseln möchten: a. 32-Bit ~ unterscheidet sich von einem allgemeinen ~ wie es ist in Ruby
Nun, wenn Sie wollen einfach nur Bit-Flip-n-Bits, die Sie etwas tun können, wie:
class Numeric
def ones_complement(bits)
self ^ ((1 << bits) - 1)
end
end
... aber Sie haben die Anzahl der Bits zu spezifizieren zu kippen. Und das wird nicht das Zeichen Flagge beeinflussen, da, dass man außerhalb Ihrer Reichweite mit XOR ist:)
Siehe diese Frage warum.
Ein Problem mit Ihrer Methode ist, dass Ihre erwartete Antwort nur wahr, wenn Sie nur die vier Bits kippen. 1001 -> 0110
Aber die Zahl mit führenden Nullen gespeichert, und der Operator ~ Flips alle führenden Bits zu: 00001001 -> 11110110
. Dann wird die führende 1 als negatives Vorzeichen interpretiert.
Sie müssen wirklich angeben, was die Funktion sollte mit Zahlen wie 0b101
und 0b11011
tun, bevor Sie entscheiden können, wie es zu implementieren. Wenn Sie immer nur 4 Bits kippen möchten, können Sie v^0b1111
, wie in eine andere Antwort vorgeschlagen. Aber wenn Sie alle Bits spiegeln möchten, wird es komplizierter.
Bearbeiten
Hier ist ein Weg, um alle Bits zu kippen:
def maskbits n
b=1
prev=n;
mask=prev|(prev>>1)
while (mask!=prev)
prev=mask;
mask|=(mask>>(b*=2))
end
mask
end
def ones_complement n
n^maskbits(n)
end
Das gibt
p ones_complement(9).to_s(2) #>>"110"
p ones_complement(15).to_s(2) #>>"0"
p ones_complement(1).to_s(2) #>>"0"
Dies ist nicht die gewünschte Ausgabe für ones_compliment (1) erhalten, weil es 1 als „1“ nicht „01“ behandelt. Ich weiß nicht, wie die Funktion könnte folgern, wie viele führende Nullen Sie wollen, ohne die Breite als Argument zu nehmen.
Was Sie tun, Operator (die ~
verwendet wird), ist in der Tat ein Einerkomplement. Sie sind diese Werte erhalten, die Sie wegen der Art und Weise nicht erwartet werden die Zahl von Ruby interpretiert wird.
Was Sie brauchen, um tatsächlich hängt zu tun, was Sie diese verwenden für. Das heißt, warum brauchen Sie ein 1-Komplement?
Wenn Sie Arbeit mit Strings sind Sie tun können:
s = "0110"
s.gsub("\d") {|bit| bit=="1"?"0":"1"}
:
Wenn Sie mit Zahlen arbeiten, werden Sie die Anzahl der Bits, weil definieren müssen
0110 = 6; 1001 = 9;
110 = 6; 001 = 1;
Auch das Zeichen zu ignorieren, werden Sie wahrscheinlich zu handhaben sind.
Beachten Sie, dass Sie den Einerkomplement jetzt mit ~ bekommen, wenn Sie in einer Fixnum passieren: die Anzahl der Bits, die die Zahl ist eine feste Größe im Interpreter darstellen und somit gibt es führenden 0en vor der Binärdarstellung die Nummer 9 (binär 1001). Sie können diese Anzahl von Bits finden, indem die Größe jeder Fixnum zu untersuchen. (Die Antwort wird in Bytes zurückgegeben)
1.size #=> 4
2147483647.size #=> 4
~ ist auch über Bignum definiert. In diesem Fall verhält sich, als ob alle Bits, die in der Bignum angegeben wurden umgedreht, und dann, wenn es eine unendliche Folge von 1en vor diesem Bignum waren. Sie können, schieben denkbar Ihre Bitstrom in eine Bignum und das Ganze umkehren. Sie müssen jedoch die Größe des Bitstrom wissen, vor der Inversion ein brauchbares Ergebnis zu erhalten, nachdem es invertiert wird.
Um die Frage zu beantworten, wie Sie es rechts von der Fledermaus darstellen, können Sie die größte Leistung von 2 weniger als der Eingang finden, verdoppeln, 1 subtrahiert, dann XOR das Ergebnis, dass mit Ihrer Eingabe und immer einen bekommt Einerkomplement nur die Bits in der Eingangsnummer.
def sig_ones_complement(num)
significant_bits = num.to_s(2).length
next_smallest_pow_2 = 2**(significant_bits-1)
xor_mask = (2*next_smallest_pow_2)-1
return num ^ xor_mask
end