2013-03-02 5 views
6

Ich suche nach einer glatten Funktion, die die Ziffern der Binärdarstellung einer Zahl umkehrt.Slick Weg, um die (Binär-) Ziffern einer Zahl in Python umzukehren?

Wenn f waren solche Funktion würde ich

int(reversed(s),2) == f(int(s,2)), wenn s eine Folge von Nullen und Einsen ist, beginnend mit 1.

Im Moment bin ich mit lambda x: int(''.join(reversed(bin(x)[2:])),2)

die so weit in Ordnung ist wie Prägnanz betrifft, aber es scheint eine schöne Umwegsweise zu sein.

Ich fragte mich, ob es einen schöneren (vielleicht schneller) Weg mit bitweisen Operatoren gab und was nicht.

+1

Warum haben Sie den Aufruf von 'list()' da drin? 'str.join()' nimmt alle iterablen Werte an. Ich sehe das auch nicht als Karussell - es ist fast genau so geschrieben, wie du es erklärst. –

+0

@Lattyware Richtig, das war nicht nötig. Ich habe das Gefühl, es war ein Karussell in dem Sinne, dass ich Strings manipuliere, wenn es wirklich wie ein numerisches Problem aussieht. Obwohl, Vorschläge zur Verbesserung der String-Methode ist auch cool. – math4tots

+0

@ math4tots: Es scheint unwahrscheinlich, dass irgendeine Methode, die Bitmanipulation mit einbezieht, schneller wäre, da dies zwangsläufig interpretierte Schleifen involvieren würde. Dies steht natürlich in starkem Kontrast zu Sprachen wie C, in denen das Bit-Twiddeln der natürliche Weg wäre. – NPE

Antwort

6

Wie wäre es

int('{0:b}'.format(n)[::-1], 2) 

oder

int(bin(n)[:1:-1], 2) 

Die zweite Methode, desto schneller der beiden zu sein scheint, aber beide sind viel schneller als die aktuelle Methode:

import timeit 

print timeit.timeit("int('{0:b}'.format(n)[::-1], 2)", 'n = 123456') 

print timeit.timeit("int(bin(n)[:1:-1], 2)", 'n = 123456') 

print timeit.timeit("int(''.join(reversed(bin(n)[2:])),2)", 'n = 123456') 
 
1.13251614571 
0.710681915283 
2.23476600647 
+0

Funktioniert nicht für negative Zahlen ... '>>> int (bin (-128) [: 1: - 1], 2) ' ' ValueError: ungültiges Literal für int() mit Basis 2: '00000001b'' –

+0

Auch sehr seltsam, dass jede Potenz von 2 den gleichen umgekehrten Wert von' 1 'hat. '>>> int (bin (4) [: 1: -1], 2) = 1',' >>> int (bin (8) [: 1: -1], 2) = 1', '> >> int (bin (16) [: 1: -1], 2) = 1' usw. Diese Umkehrung ist in Python definitiv nicht transitiv. –

+0

@AndrewMao Ja, weil eine Zweierpotenz eine binäre Darstellung der Form '10000 ... 00' hat, also ist die Umkehrung immer '1'. – arshajii

2

Hier ist mein Vorschlag:

In [83]: int(''.join(bin(x)[:1:-1]), 2) 
Out[83]: 9987 

gleiche Methode, etwas vereinfacht.

+0

Ich sehe nicht wirklich, dass das besser ist. Es verwendet nur eine obskurere Methode, es umzukehren. Persönlich würde ich eher die marginal ausführlichere, aber größtenteils lesbarere Version sehen. –

+1

Noch einfacher ohne Join: 'int (bin (n) [: 1: -1], 2)' –

2

Ich würde Ihre aktuelle Methode ist völlig in Ordnung argumentieren, aber Sie können den list() Anruf, als str.join() verlieren akzeptieren jede iterable:

def binary_reverse(num): 
    return int(''.join(reversed(bin(num)[2:])), 2) 

Es wäre auch abraten lambda für etwas anderes als die einfachsten Funktionen, wo es nur einmal verwendet wird und den umgebenden Code durch Inlining klarer macht.

Der Grund, warum ich das fühle, ist gut, da es beschreibt, was Sie tun möchten - nehmen Sie die binäre Darstellung einer Zahl, umkehren Sie, dann erhalten Sie eine Nummer wieder. Das macht diesen Code sehr lesbar, und das sollte eine Priorität sein.

1

Es gibt ein ganzes halbes Kapitel von Hacker's Delight diesem Thema gewidmet (Abschnitt 7-1: Reversieren von Bits und Bytes) mit binären Operationen, Bit-Verschiebungen und anderen Goodies. Scheint wie these are all possible in Python und es sollte viel schneller sein als die Binär-zu-String-und-Reverse-Methoden.

Das Buch ist nicht öffentlich verfügbar, aber ich fand diesen Blogeintrag, der einige davon diskutiert.Das Verfahren in dem Blog-Eintrag gezeigt folgt das folgende Zitat aus dem Buch:

Bit reversal can be done quite efficiently by interchanging adjacent single bits, then interchanging adjacent 2-bit fields, and so on, as shown below. These five assignment statements can be executed in any order.

http://blog.sacaluta.com/2011/02/hackers-delight-reversing-bits.html

+0

Das macht Vermutungen über die mögliche Größe von Zahlen, die nicht in Python halten. –

+0

Nun, wenn Sie 32-Bit-Ganzzahlen haben, tun Sie 5 Operationen, und wenn Sie 64-Bit-Ganzzahlen haben, tun Sie 6. Nicht zu schwer ... –

+0

Außer Python wird automatisch Zahlen zu unendlich großen Darstellungen fördern - [die Dokumente state * 'Ganzzahlen haben eine unbegrenzte Genauigkeit.' *] (http://docs.python.org/3.3/library/stdtypes.html#numeric-types-int-float-complex). Sie würden unendlich viele Operationen benötigen. –

7

Man könnte es mit Shift-Operatoren wie folgt tun:

def revbits(x): 
    rev = 0 
    while x: 
     rev <<= 1 
     rev += x & 1 
     x >>= 1 
    return rev 

Es scheint nicht schneller als deine Methode, (tatsächlich, etwas langsamer für mich).

1
>>> def bit_rev(n): 
...  return int(bin(n)[:1:-1], 2) 
... 
>>> bit_rev(2) 
1 
>>>bit_rev(10) 
5 
Verwandte Themen