2

辞書の最大サイズが64000のCで辞書コンプレッサーを作成しています。このため、エントリを16ビット整数として格納しています。

現在行っていること: 「a」をエンコードするには、ASCII値97を取得し、この数値を16ビット整数97の文字列表現に変換します。したがって、「0000000001100001」を「a」にエンコードすることになります。 '、これは明らかに短期的には多くのスペースを節約していません。

このアルゴリズムのより効率的なバージョンは、より小さな整数サイズ(より多くが必要になるまでストレージのビット数が少ない)から始まることを知っていますが、どちらかを行うためのより良い方法があるかどうか疑問に思っています

  1. 整数「97」を、16ビットのデータを格納できる固定長のASCII文字列に変換します(97はx桁、46347もx桁になります)

  2. 1と0のみを保存できるファイルへの書き込み。なぜなら、テキストファイルに16個のASCII文字を書き込んでいるように見えるからです。各文字は8ビットです...それでは、あまり役に立たないのではないでしょうか。

何か明確にできるかどうか教えてください。私はこのサイトにかなり慣れていません。ありがとうございました!

編集:私の知る限り、辞書をどのように保存するかは完全に私次第です。エンコードされたファイルを簡単に読み戻して、そこから整数を取得できる必要があることを知っています。

また、プログラム用に作成したstdio.h、stdlib.h、string.h、およびヘッダーファイルのみをインクルードできます。

4

2 に答える 2

1

「ファイルに直接書き込む」ことを提案しているこれらの人々を無視してください。これには多くの問題があり、最終的には「整数表現」のカテゴリに分類されます。整数を外部ストレージに直接書き込むfwriteかどうかには、いくつかの説得力のある理由があるようです。ここでは、いくつかの確かな事実があります。

ボトルネックは外部ストレージコントローラーです。それ、またはネットワークアプリケーションを作成している場合はネットワーク。したがって、2バイトを単一fwriteまたは2つの別個fputcのとして書き込むことは、メモリプロファイルがプラットフォームに適切であれば、ほぼ同じ速度である必要があります。FILE *を使用して、使用するバッファーの量をある程度調整できますsetvbuf(注:2の累乗である必要があります)。したがって、プロファイラーの指示に基づいてプラットフォームごとに常に微調整できますが、この情報はおそらく適切にフロートするはずです。他のプロジェクトにも役立つ穏やかな提案を通じて、標準ライブラリの上流にあります

基礎となる整数表現は、今日のコンピューター間で一貫性がありません。32ビットintとビッグエンディアン表現を使用するシステムXを使用してファイルに直接sを書き込むとするとunsigned int、16ビットintとリトルエンディアン表現を使用するシステムY、またはシステムZでそのファイルを読み取る際に問題が発生します。混合エンディアン表現と32パディングビットを備えた64ビットintを使用します。今日では、15年前のこのようなコンピューターの組み合わせがあり、人々はARM big.Little SoC、スマートフォン、スマートTV、ゲーム機、PCに苦しんでいます。これらはすべて、標準Cの領域から外れた独自の癖を持っています。特に整数表現、パディングなどに関して。

Cは、アルゴリズムを移植可能に表現できるようにする抽象化を念頭に置いて開発されたため、OSごとに異なるコードを記述する必要はありません。unsigned intこれは、4桁の16進数を読み取って値に変換する例です。

unsigned int value;
int value_is_valid = fscanf(fd, "%04x", &value) == 1;
assert(value_is_valid); // #include <assert.h>
                        /* NOTE: Actual error correction should occur in place of that
                         *       assertioon
                         */

%04X私が選んだ理由と、もっと現代的なものを選んだ理由を指摘する必要があります%08X...今日でも質問をすると、残念ながら、たとえば20年以上前の教科書やコンパイラを使用している学生がいます...彼らintは16歳です-少し技術的には、彼らのコンパイラはその点で準拠しています(ただし、実際には学界全体でgccとllvmをプッシュする必要があります)。移植性を念頭に置いて、次のようにその値を記述します。

value &= 0xFFFF;
fprintf(fd, "%04x", value);
// side-note: We often don't check the return value of `fprintf`, but it can also become   \
              very important, particularly when dealing with streams and large files...

値が2バイトを占めると仮定するとunsigned int、ビッグエンディアン表現を使用して、これらの2バイトを移植可能に読み取る方法は次のとおりです。

int hi = fgetc(fd);
int lo = fgetc(fd);
unsigned int value = 0;
assert(hi >= 0 && lo >= 0); // again, proper error detection & handling logic should be here
value += hi & 0xFF; value <<= 8;
value += lo & 0xFF;

...そして、これらの2バイトをビッグエンディアンの順序で書き込む方法は次のとおりです。

fputc((value >> 8) & 0xFF, fd);
fputc(value & 0xFF, fd);
// and you might also want to check this return value (perhaps in a finely tuned end product)

おそらく、あなたはリトルエンディアンにもっと興味があります。きちんとしたことは、コードは実際にはそれほど違いはないということです。入力は次のとおりです。

int lo = fgetc(fd);
int hi = fgetc(fd);
unsigned int value = 0;
assert(hi >= 0 && lo >= 0);
value += hi & 0xFF; value <<= 8;
value += lo & 0xFF;

...そしてここに出力があります:

fputc(value & 0xFF, fd);
fputc((value >> 8) & 0xFF, fd);

2バイトを超えるもの(つまり、along unsignedまたはlong signed)の場合fwrite((char unsigned[]){ value >> 24, value >> 16, value >> 8, value }, 1, 4, fd);、たとえば、ボイラープレートを減らすために、または何かが必要になる場合があります。それを念頭に置いて、プリプロセッサマクロを形成することは虐待的ではないようです。

#define write(fd, ...) fwrite((char unsigned){ __VA_ARGS__ }, 1, sizeof ((char unsigned) { __VA_ARGS__ }), fd)

これは、プリプロセッサの悪用または4上記のコードのマジックナンバーのどちらか良い方を選択するように見えるかもしれません。ハードコーディングwrite(fd, value >> 24, value >> 16, value >> 8, value);しなくてもできるから4です...しかし、初心者向けの言葉:副作用は頭痛の種になるので、の引数に変更、書き込み、またはグローバルな状態の変更を引き起こさないでくださいwrite

さて、それはその日のこの投稿への私の更新です...社会的に遅れたオタクの人は今のところサインアウトしています。

于 2013-03-20T19:17:39.897 に答える
0

あなたが考えているのはあなたの数を保存するのにASCII文字を利用することです、これは完全に不必要で最も非効率的です。

(複雑なアルゴリズムを使用せずに)これを行う最もスペース効率の良い方法は、数値のバイトをファイルにダンプすることです(ビット数は、保存する最大の数値に依存する必要があります。または、 8ビット、16ビットなど。

次に、ファイルを読み取ると、数値がxビット数ごとに配置されていることがわかります。そのため、1つずつ、または大きなチャンクで読み取り、チャンクをタイプの配列にするだけです。 xビット数に一致します。

于 2013-03-20T18:38:26.090 に答える