質問

何がベスト(ブ、最も効率的な)方法を書を浸透させる。

の機能やマクロは二つの符号なし入力が必要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フィールドの書式 abeaxebx, により、 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ビットのバージョン。彼らは自動翻訳される仕組みになって一つのアーム。

リンク:

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top