データの構造を利用するカスタム圧縮メカニズムを使用すると、非常に効率的になりそうです。
まず、 のshort[]
代わりに (16 ビット データ型) を使用するint[]
と、送信されるデータの量が半分 (!) になります。数値が-2^15
(-32768) と2^15-1
(32767) の間に簡単に収まるため、これを行うことができます。これは驚くほど簡単に実装できます。
第 2 に、ランレングス エンコーディングに似たスキームを使用できます。正の数はその数を文字どおりに表し、負の数は (絶対値を取った後) 多くのゼロを表します。例えば
[10, 40, 0, 0, 0, 30, 0, 100, 0, 0, 0, 0] <=> [10, 40, -3, 30, -1, 100, -4]
short
を置き換えるだけでは実装が難しくなりますint
が、最悪の場合 (1000 個の数字、100 個の非ゼロ、いずれも連続していない) では最大 80% の圧縮が提供されます。
圧縮率を計算するためにいくつかのシミュレーションを行いました。上記の方法と、Louis Wasserman と sbridges によって提案された方法をテストしました。どちらも非常にうまく機能しました。
配列の長さとゼロ以外の数値の数が両方とも境界内で均一であると仮定すると、両方の方法で平均して約 5400int
秒 (またはshort
秒) 節約でき、元のサイズの約 2.5% の圧縮サイズになります! ランレングス エンコーディング方法は、約 1 追加int
(または 0.03% 小さい平均圧縮サイズ) を節約するようです。つまり、基本的に違いはありません。したがって、実装が最も簡単なものを使用する必要があります。以下は、50000 個のランダム サンプルの圧縮率のヒストグラムです (非常によく似ています!)。
まとめ: short
s の代わりにint
s を使用し、圧縮方法の 1 つを使用すると、データを元のサイズの約 1% に圧縮できます。
シミュレーションには、次の R スクリプトを使用しました。
SIZE <- 50000
lengths <- sample(1000:10000, SIZE, replace=T)
nonzeros <- sample(1:100, SIZE, replace=T)
f.rle <- function(len, nonzero) {
indexes <- sort(c(0,sample(1:len, nonzero, F)))
steps <- diff(indexes)
sum(steps > 1) + nonzero # one short per run of zeros, and one per zero
}
f.index <- function(len, nonzero) {
nonzero * 2
}
# using the [value, -1 * number of zeros,...] method
rle.comprs <- mapply(f.rle, lengths, nonzeros)
print(mean(lengths - rle.comprs)) # average number of shorts saved
rle.ratios <- rle.comprs / lengths * 100
print(mean(rle.ratios)) # average compression ratio
# using the [(index, value),...] method
index.comprs <- mapply(f.index, lengths, nonzeros)
print(mean(lengths - index.comprs)) # average number of shorts saved
index.ratios <- index.comprs / lengths * 100
print(mean(index.ratios)) # average compression ratio
par(mfrow=c(2,1))
hist(rle.ratios, breaks=100, freq=F, xlab="Compression ratio (%)", main="Run length encoding")
hist(index.ratios, breaks=100, freq=F, xlab="Compression ratio (%)", main="Store indices")