2016-05-12 9 views
2

2つの大きなByteBufferの4バイトごとに以下を実行します。 (最初から2番目のアルファを引くと、アルファが0未満に行くことができない;。RGBAデータ)最小の0の減算のためのより速いバイト計算

static void subtractAlphaSecondFromFirst (ByteBuffer first, ByteBuffer second, int pixelCount) { 
    for (int i = 3; i < pixelCount * 4; i = i + 4) { 
     byte a = first.get(i); 
     byte b = second.get(i); 
     first.put(i, (byte)Math.max(0, a - b)); 
    } 
} 

私はJNIに飛び込む前に、私は(byte)Math.max(0, a - b)にいくつかの速度向上を得ることができるかどうかを確認したいのですが表現。同じことを達成するビット単位の操作がいくつかありますか?私は、確かに2バイトを整数に昇格させるより速い方法があり、その上にmax()を実行し、バイトにキャストするのがより高速な方法だと思いますが、それを思いつくのは苦労しています。

私がC言語に移植すると、私はまだ同じ方程式を保つと思います。

+0

maxファンクションと整数シャッフルを削除するには、 'first.put(i、(a> b)?a-b:0)'を実行できますか? – Serdalis

+1

あなたの数学が正しいかどうか分からないのは、「バイト」が符号付きの型だからです。 「a」の値が「0xFF」/「255」で、「b」が「0」である場合、どのような結果が期待できますか?私はalphaに '0xFF' /' 255'という結果を与えるはずですが、あなたのコードは '0'になります.Math.max(0、-1 - 0)= = 0 'となる。 – msandiford

+0

何かをする前に、ループで費やされた時間が実際には非常に単純な数学、max()とキャストであるかどうかをプロファイラで調べる必要があります。私はそれを疑います。経験からは、ByteBuffer get/put(およびそこにあるすべてのインデックスチェック)が時間がかかると推測します。しかし、私の言葉をそれに服用しないでください。測定する。 :-) – haraldK

答えて

0

はたぶん、あなただけのternary operatorこの場合

static void subtractAlphaSecondFromFirst (ByteBuffer first, ByteBuffer second, int pixelCount) { 
    for (int i = 3; i < pixelCount * 4; i = i + 4) { 
     byte a = first.get(i); 
     first.put(i, (b > a ? 0 : a-b)); 
    } 
} 

「(?B> 0:AB)」を使用して簡単に比較してsubstractionを作ることができbがより大きい場合、評価する」という意味0以外の場合は(a - b)と評価されます。

+0

答えを書かなかった主な理由は、ベンチマークできなかったからです。あなたはいくつかのベンチマークを追加することができればまともな答えになるでしょう。これは実際には高速ではないかもしれません。 – Serdalis

+1

答えを提出するまであなたのコメントが表示されませんでした。ソースを見ると、Math.max()の実装は実際には "return(a> = b)?a:b;"なので、どちらのアプローチも基本的に同じ解決方法であり、部。 –

+0

それは大丈夫です:)、型キャスティングと関数呼び出しは高価かもしれませんが、正しい答えかもしれませんがベンチマークされている必要があります。私の主な関心事は、「xがyよりも速い」質問の場合、数字が良い答えの鍵であるということです。 – Serdalis

0

飽和減算のブランチのないバージョンを使用できます。これは、潜在的に、内側ループ内のブランチ誤予測の数を減少させるであろう。このような何か:

static void subtractAlphaSecondFromFirst(ByteBuffer first, ByteBuffer second, int pixelCount) { 
    for (int i = 3; i < pixelCount * 4; i = i + 4) { 
     int a = first.get(i) & 0xFF; 
     int b = second.get(i) & 0xFF; 
     int v = a - b; 
     // Propagate sign bit into all bits and invert 
     // Mask will be 0 if v is negative, -1 otherwise 
     int mask = (v >> (Integer.SIZE - 1))^-1; 
     first.put(i, (byte)(v & mask)); 
    } 
} 

は、残念ながら、私はこれがあなたのために物事を改善したり、それらを悪化させるだろうかどうかを知るのは本当の方法がありません。私は、コメントに書かれているように、署名付き/署名なしの問題だと思っているものの修正を加えました。

+0

完全にランダムなソースデータで約8%速くベンチマークされました。私は、ソースデータがよりブロックされていれば、利益は少なくなると思います。ありがとう! – Tenfour04

0

私は、昨夜の質問を投稿したときに、私が使用したケースで重要な事実を見落としていたので、気難しそうでした。各バイトの値は、常に0またはFFです!

ので、ビット操作のバージョンは単純です:

first.put(i, (byte)((a^b)&a)); 

私はそれをベンチマークし、ランダムなソースのデータを使用している場合、それは私の元のバージョンよりも約25%高速です。

関連する問題