無限線形バイナリストレージがあると仮定して、0から無限大までの整数を表す適切なスキーマですか?


10

スキーマに0から始まる整数を制限なしで表すことを望みます(無限線形ストレージへのアクセスを想定)。

以下は、0から255までの数値を表すことができるスキーマです。

ストレージの最初のバイト(アドレス0)を使用して整数を格納します。

ここで、255より大きい数値を表現したいとします。もちろん、整数を表すために1バイト以上を使用することもできますが、それが固定数である限り、最終的に、元のスキーマ。

これは、タスクを実行できる別のスキーマですが、おそらく効率的ではありません。

ある種の一意の「数値の終わり」バイトを使用し、前のすべてのバイトを使用して数値を表します。明らかに、この「数値の終わり」バイトは数値表現のどこにも使用することはできませんが、これは(256の代わりに)255を基数とする番号付けシステムを使用して実現できます。

しかし、それは遅く、おそらく非効率的です。低い値でうまく機能し、適切にスケーリングできる、より優れたものが欲しいです。

基本的に、それはUUIDシステムです。再設計することなく、理論的に何年、何千年、何百万年も使用できるように拡張できる、高速に実行できるUUIDシステムを作成できるかどうかを知りたいです。


1
(オープニングの場合のように)無限に、または(クロージングの場合のように)数百万年にわたって拡張できる何かが必要ですか?2つの要件は(明らかに)完全に異なります。64ビットマシン上の2の補数はなり何百万年もの間スケール。
user16764 2012年

1
@ user16764、単一の64ビット整数変数を意味しますか?これは確かに機能しません。600万人が1秒あたり100万個のUUIDを消費している場合、1か月以上続くことはほとんどありません。
ドミトリシュラリョフ

1
また、128ビットマシンではどれくらい時間がかかりますか?
user16764 2012年

2
RFC 2550のアイデアは、任意に大きい正の整数に対して辞書式順序のASCII表現を提供しますが、これに適応できる場合があります。最終的には、base-10セグメントの長さをエンコードするbase-26セグメントの長さをエンコードする単項セグメントに分解されます。後者の2つのベースは、スキームの基本的なものよりもASCII表現に関係しています。
Random832 2012年

1
128ビットの数値を順番に生成するとします。すべての人間にペタフロップコンピュータを与えてすべてのコンピュータの計算能力を上限にすると、これらの数値がなくなるまでに900万年かかります。一方、すべての人間がランダムに6億個の128ビット数を生成する場合、50%の確率で1つの複製が生成されます。それで十分ですか?(en.wikipedia.org/wiki/Universally_unique_identifier)そうでない場合は、256ビットを使用すると、これらの両方の数値に2 ^ 128 = 3.4 * 10 ^ 38が乗算されます。これは、秒単位の宇宙の年齢の2乗を超えています。
アレックステンブリンク

回答:


13

私が使用したアプローチ:先頭の1ビットの数を数えますn。数値のサイズは2 ^ nバイト(先頭の1ビットを含む)になります。最初の0ビットの後のビットを整数として、このエンコードを使用して数値で表すことができる最大値(プラス1)を2 ^(n-1)バイトで追加します。

したがって、

                  0 = 0b00000000
                   ...
                127 = 0b01111111
                128 = 0b1000000000000000
                   ...
              16511 = 0b1011111111111111
              16512 = 0b11000000000000000000000000000000
                   ...
          536887423 = 0b11011111111111111111111111111111
          536887424 = 0b1110000000000000000000000000000000000000000000000000000000000000
                   ...
1152921505143734399 = 0b1110111111111111111111111111111111111111111111111111111111111111
1152921505143734400 = 0b111100000000000000000000000000000000000000000000 ...

このスキームでは、負でない値を正確に1つの方法で表すことができます。

(同等に、先行する0ビットの数を使用しました。)


1
どの回答が承認済みとしてマークされるかを理解するのは困難でした。それらの多くは非常に有益で優れていると思います。しかし、私はこれが私が尋ねた質問に最も適していると思います(おそらく、私が考えていた根本的なものではなく、表現するのが難しい)。
ドミトリシュラリョフ2012年

2
実装例と設計上の考慮事項について、より詳細な記事を書きました。
2012年

10

あなたがやろうとしていることに基づいた理論はたくさんあります。ユニバーサルコードに関するwikiページをご覧ください。整数のエンコード方式のかなり網羅的なリストがあります(その一部は実際に実際に使用されています)。

データ圧縮では、整数のユニバーサルコードは、正の整数をバイナリコードワードにマッピングするプレフィックスコードです。

または、最初の8バイトを使用して、数値の長さをいくつかの単位(ほとんどの場合はバイト)で格納し、データバイトを配置することもできます。実装は非常に簡単ですが、少数の場合は非効率的です。そして、人類が利用できるすべてのデータドライブを埋めるのに十分な長さの整数をコーディングすることができるでしょう:)


それをありがとう、それは非常に興味深いです。これを承認済みの回答としてマークしたかったのですが、2位になりました。これは、理論的な観点から見ると非常に良い答えです、IMO。
ドミトリシュラリョフ2012年

4

先頭の1と最初の0の数を、ビット単位の数値サイズ(numSize)のサイズ(sizeSize)としましょう。numSizeは、サイズビットを含むバイト単位の数値表現のサイズを示す2進数です。残りのビットは、バイナリの数値(num)です。正の整数スキームの場合、サンプルの数値の例をいくつか示します。

Number              sizeSize  numSize    num
63:                 0 (1)     1 (1)      111111
1048575:            10 (2)    11 (3)     1111 11111111 11111111
1125899906842623:   110 (3)   111 (7)    11 11111111 11111111 11111111 11111111 11111111 11111111
5.19.. e+33:        1110 (4)  1111 (15)  11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

4

それはどうですか:1バイトの長さ、次にnバイトの数(最下位バイトが最初)。前の長さが255である限り、長さ+数を繰り返します。

これにより、任意の大きな数が可能になりますが、処理は簡単で、メモリを無駄に消費しません。


fNek:上限はありません。たとえば、数値に513バイトが必要な場合、バイトシーケンスは[255、b0、...、b255,255、b256、...、b511,2、b512、b513]
user281377

ごめんなさい。もっと注意深く読むことを学ぶべきです。
fNek 2014年

3

なぜ各バイトのうち7ビットを使用し、8番目のビットを使用して、次のバイトがあるかどうかを示すのではないのですか?したがって、1〜127は1バイトで、128は0x80 0x01などで表されます。


1
このスキームは、8ビットごとに128個の値のみをエンコードします。これは、質問者によって提案された2番目のエンコードスキームよりもスペース効率が低く、255ビットの値が8ビットごとにエンコードされます。どちらの方式も、整数を読み取って、それを格納するために必要なストレージの量を調べる必要があるという事実に悩まされています。
マークブース

3
そのため、コピーを作成するために番号を2回スキャンする必要があります。1つの無限に大きな数を待つことができれば、2回待つことができます。
ラッセル

細心の注意を払って指定していませんが、できるだけ効率的に実行できるソリューションを探しています(要件に単純に一致するソリューションではなく、潜在的な非効率的な答えを質問ですでに説明しました)。
ドミトリシュラリョフ2012年

3

UUIDシステムは、有限(しかし大きい)宇宙における有限(しかし大きい)計算能力に基づいています。UUIDの数は、宇宙の粒子の数などの不条理に大きなものと比較した場合でも多くなります。ただし、固定ビットの数に関係なく、UUIDの数は無限大に比べて少ないです。

数値の終わりフラグを表すために0xFFFFを使用する場合の問題は、数値が大きい場合に数値エンコーディングの効率が低下することです。ただし、UUIDスキームによってこの問題がさらに悪化しているようです。256バイトのうち1バイトがスキップされる代わりに、UUIDスペース全体が無駄になりました。(空間ではなく)計算/認識の効率は、理論上のコンピューターに大きく依存します(無限大について話をしている場合は、それが想定されます)。テープと有限状態コントローラーを備えたTMの場合、UUIDスキームを効率的にスケーリングすることは不可能です(基本的に、ポンピングレンマは、固定ビット長のエンドマーカーを超えて効率的に移動できません)。有限状態コントローラーを想定していない場合、これは当てはまらない可能性がありますが、ビットがデコード/認識プロセスのどこに行くかについて考える必要があります。

256バイト中の1バイトよりも効率を上げたい場合は、UUIDスキームに使用する1のビット長を使用できます。これは、非効率の2 ^ bit-lengthのうちの1つです。

ただし、他のエンコードスキームがあることに注意してください。デリミタ付きのバイトエンコーディングは、実装が最も簡単です。


2

バイト(またはintまたはlong)の配列と、数値の長さを示す長さフィールドを持つことをお勧めします。

これはおおよそJavaのBigIntegerで使用されているアプローチです。これから可能なアドレス空間は巨大です-宇宙のすべての個々の原子に異なるUUIDを与えるのに十分簡単です:-)

特に理由がない限り、直接BigInteger(または他の言語では同等のもの)を使用することをお勧めします。特に大きな数字のホイールを再発明する必要はありません...


フィールド数が無限になる可能性がある場合、配列の長さをエンコードすることはできません。
Slawek、2012年

可能な場合は、特定の問題に対して既存のソリューション(特に専門家による調査を受けたもの)を使用することをお勧めします。ありがとう。
ドミトリシュラリョフ2012年

@Slawek:true、ただしOPが記述しているユースケース(つまりUUID)では、BigIntegerは事実上無限です。いずれにせよ、有限サイズのメモリを搭載したコンピュータで無限情報をエンコードすることはできないので、BigIntegerは他のどんなものよりも優れています。
mikera

2

まず第一に、私の漠然とした抽象的な質問に素晴らしい答えを提供してくれた皆さんに感謝します。

他の答えを考えた後、考えていた潜在的な答えを投稿したいと思います。質問に対する直接的な回答ではありませんが、関連性があります。

一部の人々が指摘したように、64/128/256ビットサイズの整数を使用すると、UUID用の非常に大きなスペースがすでに得られます。明らかに無限ではありませんが...

おそらく、64ビットでは不十分(またはそれに近い)になるまで、固定サイズのint(たとえば、最初は64ビット)を使用することをお勧めします。次に、UUIDの以前のすべてのインスタンスにそのようなアクセス権があると仮定して、それらすべてを128ビットの整数にアップグレードし、それを整数の固定サイズにします。

システムがそのようなサービスの一時停止/中断を許可し、そのような「再構築」操作が非常にまれに発生する必要があるため、おそらく利点(非常に単純で高速で実装が簡単なシステム)が欠点(以前に割り当てられたすべての整数を再構築する必要がある)を上回ります。新しい整数のビットサイズに変換します)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.