どのような符号なしを浸透させる。
-
02-07-2019 - |
質問
何がベスト(ブ、最も効率的な)方法を書を浸透させる。
の機能やマクロは二つの符号なし入力が必要16-32-bitバージョン)帰すべてのビット-ワン(0xFFFFは小さいか、0xffffffffバイト)値の合計があります。
対象はx86アームに使用さ(4.1.2)とVisual Studio(シミュレーションのみ、フォールバックの実装はOKにあります。
解決
だ携帯 C
コードすることでコンパイラをして適切なアームます。アームは条件付きの移動ができ、条件のオーバーフロー.このアルゴリズムが追加条件セットの先符号なし(-1)がオーバーフローしていました。
uint16_t add16(uint16_t a, uint16_t b)
{
uint16_t c = a + b;
if (c<a) /* Can only happen due to overflow */
c = -1;
return c;
}
との違いに留意することからその他のアルゴリズムで補正がオーバフローに頼るのではなく、別の計算を検出するオーバーフロー.
x86-64clang3.7-O3出力adds32:っているという考えその他の回答:
add edi, esi
mov eax, -1
cmovae eax, edi
ret
ARMv7: gcc 4.8 -O3 -mcpu=cortex-a15 -fverbose-asm
出力adds32:
adds r0, r0, r1 @ c, a, b
it cs
movcs r0, #-1 @ conditional-move
bx lr
16bit:ものを使用しませんの腕のunsigned-浸透させ、追加説明書(UADD16
)
add r1, r1, r0 @ tmp114, a
movw r3, #65535 @ tmp116,
uxth r1, r1 @ c, tmp114
cmp r0, r1 @ a, c
ite ls @
movls r0, r1 @,, c
movhi r0, r3 @,, tmp116
bx lr @
他のヒント
C
uint16_t sadd16(uint16_t a, uint16_t b)
{ return (a > 0xFFFF - b) ? 0xFFFF : a + b; }
uint32_t sadd32(uint32_t a, uint32_t b)
{ return (a > 0xFFFFFFFF - b) ? 0xFFFFFFFF : a + b;}
はほとんどのマクロ化および直接伝える意味があります。
にIA32な条件付きの移動:
uint32_t sadd32(uint32_t a, uint32_t b)
{
#if defined IA32
__asm
{
mov eax,a
xor edx,edx
add eax,b
setnc dl
dec edx
or eax,edx
}
#elif defined ARM
// ARM code
#else
// non-IA32/ARM way, copy from above
#endif
}
にアームが既に飽和演算ですのでお問い合わせ下さい。のARMv5DSP-拡張できる飽和レジスタへのビット長さです。また飽和アームは通常、格安できるのでexcuteも指示条件.
ARMv6も飽和し、加算、減算、その他のもの32ビットが満載。
のx86き飽和演算にはMMXはSSE.
このニーズアセンブラではんをお楽しみいただけます。
がC-技い飽和演算します。このコードは飽和した四つのバイトのdword.この理念に基づき計算32半adders並列,例.加数をオーバーフロー.
することで行います。その後の行を算出し、付加、置換マスクの場合のほうにオーバーフロー.
uint32_t SatAddUnsigned8(uint32_t x, uint32_t y)
{
uint32_t signmask = 0x80808080;
uint32_t t0 = (y ^ x) & signmask;
uint32_t t1 = (y & x) & signmask;
x &= ~signmask;
y &= ~signmask;
x += y;
t1 |= t0 & x;
t1 = (t1 << 1) - (t1 >> 7);
return (x ^ t0) | t1;
}
きの16ビット(又はそのようなビットフィールド)のsignmask一定のシフト下のようになります:
uint32_t SatAddUnsigned16(uint32_t x, uint32_t y)
{
uint32_t signmask = 0x80008000;
uint32_t t0 = (y ^ x) & signmask;
uint32_t t1 = (y & x) & signmask;
x &= ~signmask;
y &= ~signmask;
x += y;
t1 |= t0 & x;
t1 = (t1 << 1) - (t1 >> 15);
return (x ^ t0) | t1;
}
uint32_t SatAddUnsigned32 (uint32_t x, uint32_t y)
{
uint32_t signmask = 0x80000000;
uint32_t t0 = (y ^ x) & signmask;
uint32_t t1 = (y & x) & signmask;
x &= ~signmask;
y &= ~signmask;
x += y;
t1 |= t0 & x;
t1 = (t1 << 1) - (t1 >> 31);
return (x ^ t0) | t1;
}
上記のコードは同16、32ビットの値です。
必要がない場合には、機能の追加および飽和複数の値が並んマスクのビットがあります。腕につけましたが、signmask定でアームができな負荷を可能な32ビットの定数は、単一サイクルです。
編集: を並行バージョンが遅くなりに直進方法にもより速く場合は飽和し、複数の値です。
合気性能、 本当に いたいこのようなもSIMD、x86は、ネイティブ飽和演算.
この不足を浸透させ、算術演算でスカラー数学、体感することができます。る場合業務4変数全SIMDは 以上 以上により4倍以上に相当C(およびその分true8-可変幅SIMD):
sub8x8_dct8_c: 1332 clocks
sub8x8_dct8_mmx: 182 clocks
sub8x8_dct8_sse2: 127 clocks
ゼロの支店【解決
uint32_t sadd32(uint32_t a, uint32_t b)
{
uint64_t s = (uint64_t)a+b;
return -(s>>32) | (uint32_t)s;
}
良いコンパイラの最適化とともに、これまではこれを避けるだけ電源をオンにする"という実際の64ビット演算(s>>32
まずきのフラグは、 -(s>>32)
の結果 sbb %eax,%eax
).
るx86asm(AT&Tフィールドの書式 a
や b
に eax
や ebx
, により、 eax
):
add %eax,%ebx
sbb %eax,%eax
or %ebx,%eax
8-16-bitバージョンは自明である。署名した版が必要になります。
uint32_t saturate_add32(uint32_t a, uint32_t b)
{
uint32_t sum = a + b;
if ((sum < a) || (sum < b))
return ~((uint32_t)0);
else
return sum;
} /* saturate_add32 */
uint16_t saturate_add16(uint16_t a, uint16_t b)
{
uint16_t sum = a + b;
if ((sum < a) || (sum < b))
return ~((uint16_t)0);
else
return sum;
} /* saturate_add16 */
編集: ることができます掲載してお版はなんなのか鉱山はいずクリーナー/よ/り効率的な/more studly.
さんがこよりも早くSkizzのソリューション(常にプロファイル)が、こちらの代替的な支店に組み立てます。この条件付きの移動(CMOV指示するだけで使用できます。
uint32_t sadd32(uint32_t a, uint32_t b)
{
__asm
{
movl eax, a
addl eax, b
movl edx, 0xffffffff
cmovc eax, edx
}
}
現在実施してい:
#define sadd16(a, b) (uint16_t)( ((uint32_t)(a)+(uint32_t)(b)) > 0xffff ? 0xffff : ((a)+(b)))
#define sadd32(a, b) (uint32_t)( ((uint64_t)(a)+(uint64_t)(b)) > 0xffffffff ? 0xffffffff : ((a)+(b)))
最高の性能は、通常、なにインライン組立ての一部は既に述べ).
でもポータブルC、これらの機能だける一つの比較型-鋳造ることだと思い最適な):
unsigned saturate_add_uint(unsigned x, unsigned y)
{
if (y>UINT_MAX-x) return UINT_MAX;
return x+y;
}
unsigned short saturate_add_ushort(unsigned short x, unsigned short y)
{
if (y>USHRT_MAX-x) return USHRT_MAX;
return x+y;
}
としてマクロな:
SATURATE_ADD_UINT(x, y) (((y)>UINT_MAX-(x)) ? UINT_MAX : ((x)+(y)))
SATURATE_ADD_USHORT(x, y) (((y)>SHRT_MAX-(x)) ? USHRT_MAX : ((x)+(y)))
までバージョンは'unsigned long"と"符号なしlong longとして、運動のリーダー.;-)
場の人が知りたい実装なしで分岐用の2の補数32ビット整数です。
警告!このコードを未定義の動作"シフト右のよ-1"が限の物件です Intel Pentium SAL指導 へのアクセスカウントのオペランドは5ビット.
int32_t sadd(int32_t a, int32_t b){
int32_t sum = a+b;
int32_t overflow = ((a^sum)&(b^sum))>>31;
return (overflow<<31)^(sum>>overflow);
}
朝食も普通に美味しいです。実施に知っ
と思い、ニーズに合わせたサービスのx86はインラインアセンブラックオーバーフローフラグを加えた.のようなもの:
add eax, ebx
jno @@1
or eax, 0FFFFFFFFh
@@1:
.......
寒暖の差が激しいので皆様も携帯すが、まぁるものです。
代替の無料x86asm液(AT&Tフィールド書式]aとb eaxとebx、eax):
add %eax,%ebx
sbb $0,%ebx
C++で書きをより柔軟に変形 Remo.D'sソリューション:
template<typename T>
T sadd(T first, T second)
{
static_assert(std::is_integral<T>::value, "sadd is not defined for non-integral types");
return first > std::numeric_limits<T>::max() - second ? std::numeric_limits<T>::max() : first + second;
}
こ簡単に翻訳する利用の制限で定義され limits.h
.Pdf形式のファイルをご覧いただくの 固定幅の整数型 なっています。
//function-like macro to add signed vals,
//then test for overlow and clamp to max if required
#define SATURATE_ADD(a,b,val) ( {\
if( (a>=0) && (b>=0) )\
{\
val = a + b;\
if (val < 0) {val=0x7fffffff;}\
}\
else if( (a<=0) && (b<=0) )\
{\
val = a + b;\
if (val > 0) {val=-1*0x7fffffff;}\
}\
else\
{\
val = a + b;\
}\
})
かったので、迅速試験うな幅広くbashedで関する詳細を策定したものです。この作品と符号付き32ビット.op:のエディタで使用されるwebページのないよう、マクロの家な理解の非インデント書式等!
int saturating_add(int x, int y)
{
int w = sizeof(int) << 3;
int msb = 1 << (w-1);
int s = x + y;
int sign_x = msb & x;
int sign_y = msb & y;
int sign_s = msb & s;
int nflow = sign_x && sign_y && !sign_s;
int pflow = !sign_x && !sign_y && sign_s;
int nmask = (~!nflow + 1);
int pmask = (~!pflow + 1);
return (nmask & ((pmask & s) | (~pmask & ~msb))) | (~nmask & msb);
}
この実装を使用しませんの制御-フローをcampare者==
, !=
の ?:
オペレーターで使用してビット単位で事業者との論理です。
飽和度の算術演算は標準Cも多されてコンパイラintrinsics、最も効率的な方法は、ブラン.いてくれるものでなければなりませ #ifdef
ブロックの選択が必要です。MSaltersの答えでは最速のためにはx86アーキテクチャ.のためのアームを使用する必要があり __qadd16
機能(ARMコンパイラ) _arm_qadd16
(マイクロソフトVisual Studio)に16ビット版 __qadd
32ビットのバージョン。彼らは自動翻訳される仕組みになって一つのアーム。
リンク: