1

次のタイプの 3 つの変数があります。

 uint64_t old_addr, new_addr;
 int delta;

そして、私はこの課題をやりたいです

 new_addr = old_addr + delta;

ただし、問題は、いつとold_addr=915256delta=-6472064なるかです。new_addr18446744069414584325

修正するには、いくつか確認する必要があります。

 if ( delta < 0 ) {
if ( old_addr < abs(delta) )
   new_addr = 0;
    else   
       new_addr = old_addr + delta;
 }

より良い効率的な方法はありますか?

4

3 に答える 3

4

これは飽和加算と呼ばれ、一部のプロセッサにはそのための特別な機械語命令があります。そのコードをインライン関数に抽出し、ターゲット実行環境に応じてマシン命令を使用できます。

あなたはすでにそれを知っているので、代わりにabs(delta)単に書くことができます。-deltadelta < 0

于 2012-03-09T08:47:58.243 に答える
2

問題は、どのような値old_addrを取り、new_addr取ることができるかです。uint64_tそして、単にではなく、なぜそうなのかint。最も単純な式は次のようになります。

new_addr = old_addr + std::min( delta, -static_cast<int>( old_addr ) );

ですが、old_addrより大きい場合INT_MAX、これは機能しません。それ以外の場合、C/C++ での符号付き/符号なし算術混合のルールは、明示的なifs を使用するのがおそらく最も安全であり、値を確認する前に混合算術を危険にさらさないようなものです。

また、ほとんどのマシンでは、が に等しいabs( delta )場合でも、 は負になる ことに注意してください。すべてのケースを正しく処理するには、次のようなものが必要です。deltaINT_MIN

if ( delta > 0 ) {
    new_addr = std::numeric_limits<uin64_t>::max() - delta > old_addr
            ?   old_addr + delta
            :   std::numeric_limits<uint64_t>::max();
} else if ( delta < 0 ) {
    new_addr = old_addr != 0 && -(delta + 1) < old_addr - 1
            ?   old_addr + delta
            :   0;
} else {
    new_addr = old_addr;
}

(私の頭のてっぺんから。そこには簡単に1つのエラーがある可能性があります。)

于 2012-03-09T09:11:51.313 に答える
0

このコードは非常に単純で、両方向のオーバーフローを処理します。

#include <assert.h>
#include <inttypes.h>
#include <stdint.h>

static uint64_t saturated_add(uint64_t a, int delta) {
  uint64_t result = a + delta;
  if (delta < 0 && result > a) {
    return 0;
  } else if (delta > 0 && result < a) {
    return -1;
  } else {
    return result;
  }
}

int main() {
  assert(saturated_add(915256, -6472064) == 0);
  assert(saturated_add(100, -99) == 1);
  assert(saturated_add(100, -100) == 0);
  assert(saturated_add(100, -101) == 0);
  assert(saturated_add(UINT64_C(0x1111222233334444), -0x33334445) == UINT64_C(0x11112221FFFFFFFF));
  assert(saturated_add(-5, 6) == UINT64_C(-1));
  assert(saturated_add(-5, 5) == UINT64_C(-1));
  assert(saturated_add(-5, 4) == UINT64_C(-1));
  assert(saturated_add(-5, 3) == UINT64_C(-2));
  return 0;
}
于 2012-03-09T14:45:13.863 に答える