Ich möchte, dass ein Schema ganzzahlige Zahlen beginnend mit 0 ohne Einschränkung darstellt (vorausgesetzt, der Zugriff auf unendlichen linearen Speicher).
Hier ist ein Schema, das Zahlen von 0 bis 255 darstellen kann:
Verwenden Sie das erste Byte des Speichers (Adresse 0), um die Ganzzahl zu speichern.
Angenommen, ich möchte Zahlen darstellen, die größer als 255 sind. Natürlich könnte ich mehr als 1 Byte verwenden, um die Ganzzahl darzustellen, aber solange es sich um eine feste Zahl handelt, wird es schließlich eine Ganzzahl geben, die so groß ist, dass sie nicht durch dargestellt werden kann das ursprüngliche Schema.
Hier ist ein weiteres Schema, das die Aufgabe ausführen sollte, aber wahrscheinlich alles andere als effizient ist.
Verwenden Sie einfach eine Art eindeutiges "Ende der Zahl" -Byte und verwenden Sie alle vorherigen Bytes, um die Zahl darzustellen. Offensichtlich kann dieses "Ende der Zahl" -Byte nirgendwo in der Zahlendarstellung verwendet werden, aber dies kann erreicht werden, indem ein Nummerierungssystem der Basis 255 (anstelle der Nummer 256) verwendet wird.
Das ist jedoch langsam und wahrscheinlich ineffizient. Ich möchte eine bessere haben, die mit niedrigen Werten besser abschneidet und gut skaliert.
Im Wesentlichen handelt es sich um ein UUID-System. Ich möchte sehen, ob es möglich ist, ein schnelles UUID-System zu erstellen, das theoretisch für Jahre, Tausende von Jahren, Millionen von Jahren skaliert werden kann, ohne dass es neu gestaltet werden muss.
Antworten:
Ein Ansatz, den ich verwendet habe: Zählen Sie beispielsweise die Anzahl der führenden 1 Bits
n
. Die Größe der Zahl beträgt dann 2 ^ n Bytes (einschließlich der führenden 1 Bits). Nehmen Sie die Bits nach dem ersten 0-Bit als Ganzzahl und addieren Sie den Maximalwert (plus eins), der durch eine Zahl dargestellt werden kann, indem Sie diese Codierung in 2 ^ (n-1) Bytes verwenden.Somit,
Mit diesem Schema kann jeder nicht negative Wert auf genau eine Weise dargestellt werden.
(Entspricht entsprechend der Anzahl der führenden 0-Bits.)
quelle
Es gibt eine Menge Theorie, die darauf basiert, was Sie versuchen zu tun. Werfen Sie einen Blick auf die Wiki-Seite über universelle Codes - es gibt eine ziemlich ausführliche Liste von Ganzzahl-Codierungsmethoden (von denen einige tatsächlich in der Praxis verwendet werden).
Oder Sie können einfach die ersten 8 Bytes verwenden, um die Länge der Nummer in einigen Einheiten (höchstwahrscheinlich Bytes) zu speichern und dann die Datenbytes abzulegen. Es wäre sehr einfach zu implementieren, aber für kleine Zahlen eher ineffizient. Und Sie könnten eine Ganzzahl lange genug codieren, um alle Datenlaufwerke zu füllen, die der Menschheit zur Verfügung stehen :)
quelle
Wie wäre es, wenn die Anzahl der führenden Einsen plus der ersten 0 die Größe (sizeSize) der Zahlengröße (numSize) in Bits ist? Die numSize ist eine Binärzahl, die die Größe der Zahlendarstellung in Bytes einschließlich der Größenbits angibt. Die verbleibenden Bits sind die binäre Zahl (num). Für ein positives Ganzzahlschema sind hier einige Beispielbeispielnummern aufgeführt:
quelle
Wie wäre es damit: Ein Byte für die Länge, dann n Bytes für die Zahl (niedrigstwertiges Byte zuerst). Wiederholen Sie Länge + Nummer, solange die vorherige Länge 255 betrug.
Dies ermöglicht beliebig große Zahlen, ist aber dennoch einfach zu handhaben und verschwendet nicht zu viel Speicher.
quelle
Warum nicht einfach 7 Bits pro Byte verwenden und mit dem 8. Bit angeben, ob ein weiteres Byte folgen soll? 1-127 wäre also in einem Byte, 128 würde durch 0x80 0x01 usw. dargestellt.
quelle
UUID-Systeme basieren auf endlicher (aber großer) Rechenleistung in einem endlichen (aber großen) Universum. Die Anzahl der UUIDs ist groß, selbst im Vergleich zu absurd großen Dingen wie der Anzahl der Partikel im Universum. Die Anzahl der UUIDs mit einer beliebigen Anzahl fester Bits ist jedoch im Vergleich zur Unendlichkeit gering.
Das Problem bei der Verwendung von 0xFFFF zur Darstellung Ihres End-of-Number-Flags besteht darin, dass Ihre Nummerncodierung bei großen Zahlen weniger effizient ist. Es scheint jedoch, dass Ihr UUID-Schema dieses Problem noch verschlimmert. Anstatt eines von 256 Bytes zu überspringen, wird jetzt der gesamte UUID-Speicherplatz verschwendet. Die Effizienz der Berechnung / Erkennung (anstelle des Speicherplatzes) hängt stark von Ihrem theoretischen Computer ab (den Sie vermutlich haben, wenn Sie über Unendlichkeit sprechen). Bei einem TM mit einem Band und einem Finite-State-Controller ist es unmöglich, ein UUID-Schema effizient zu skalieren (im Grunde verhindert das Pump-Lemma, dass Sie sich effizient über einen Endmarker mit fester Bitlänge hinausbewegen). Wenn Sie keinen Finite-State-Controller annehmen, trifft dies möglicherweise nicht zu, Sie müssen jedoch darüber nachdenken, wohin die Bits beim Decodierungs- / Erkennungsprozess gehen.
Wenn Sie nur eine bessere Effizienz als 1 von 256 Bytes wünschen, können Sie die Bitlänge von 1s verwenden, die Sie für Ihr UUID-Schema verwenden wollten. Das ist 1 von 2 ^ Bit Länge in Ineffizienz.
Beachten Sie jedoch, dass es andere Codierungsschemata gibt. Die Bytecodierung mit Trennzeichen ist einfach am einfachsten zu implementieren.
quelle
Ich würde vorschlagen, ein Array von Bytes (oder Ints oder Longs) und ein Längenfeld zu haben, das angibt, wie lang die Zahl ist.
Dies ist ungefähr der Ansatz von Javas BigInteger . Der daraus mögliche Adressraum ist riesig - leicht genug, um jedem einzelnen Atom im Universum eine andere UUID zu geben :-)
Sofern Sie keinen guten Grund haben, etwas anderes zu tun, würde ich vorschlagen, BigInteger direkt (oder in anderen Sprachen gleichwertig) zu verwenden. Keine besondere Notwendigkeit, das große Zahlenrad neu zu erfinden ....
quelle
Zunächst einmal vielen Dank an alle, die großartige Antworten auf meine relativ vage und abstrakte Frage gegeben haben.
Ich möchte eine mögliche Antwort einbringen, an die ich gedacht habe, nachdem ich über andere Antworten nachgedacht habe. Es ist keine direkte Antwort auf die gestellte Frage, aber es ist relevant.
Wie einige Leute betonten, bietet die Verwendung einer Ganzzahl mit einer Bitgröße von 64/128/256 bereits einen sehr großen Platz für UUIDs. Offensichtlich ist es nicht unendlich, aber ...
Vielleicht ist es eine gute Idee, nur eine feste Größe int zu verwenden (z. B. 64-Bit, um zu beginnen), bis 64-Bit nicht mehr ausreicht (oder nahe daran liegt). Angenommen, Sie haben einen solchen Zugriff auf alle vorherigen Instanzen der UUIDs, aktualisieren Sie sie einfach alle auf 128-Bit-Ints und nehmen Sie dies als Ihre feste Ganzzahlgröße.
Wenn das System solche Pausen / Unterbrechungen des Dienstes zulässt und solche "Wiederherstellungs" -Operationen ziemlich selten auftreten sollten, überwiegen möglicherweise die Vorteile (ein sehr einfaches, schnelles und einfach zu implementierendes System) die Nachteile (alle zuvor zugewiesenen Ganzzahlen müssen neu erstellt werden) auf eine neue ganzzahlige Bitgröße).
quelle