4

2つの64ビット符号なし整数を受け取り、それらの差を符号付き64ビット整数で返す関数をC++で作成しようとしています。オーバーフローの状況のた​​め、少し複雑に見えます-入力は2つの符号なし正の整数であるため、これら2つの絶対差が最大符号付き値(INT64_MAX)より大きい場合、差は符号付き整数を介して送信できません。そこで、次の実装を作成しました。まず、これが機能的に正しいかどうか、次に、より単純な実装があるかどうか疑問に思いました。任意の提案をいただければ幸いです。ありがとう!(アサーションを例外に置き換えます。今のところあります!)

int64_t GetDifference(uint64_t first, uint64_t second) {
  uint64_t abs_diff = (first > second) ? (first - second): (second - first);    
  uint64_t msb_abs_diff = (abs_diff >> (sizeof(abs_diff)*8 - 1)) & 1;
  assert(msb_abs_diff == 0);
  int64_t diff = first - second;
  return diff;
}
4

4 に答える 4

6

私には、これはより単純で読みやすい実装のように思えます。

int64_t GetDifference(uint64_t first, uint64_t second) {
    uint64_t abs_diff = (first > second) ? (first - second): (second - first);
    assert(abs_diff<=INT64_MAX);
    return (first > second) ? (int64_t)abs_diff : -(int64_t)abs_diff;
}
于 2012-01-16T20:55:53.217 に答える
4

3つの落とし穴:

  • sizeof(abs_diff)*8 - 1移植性を失うことなくリテラルに置き換えることができます63(実際、 aが8ビット幅ではないプラットフォームのため、より移植性が高くなります)char
  • & 1シフトの結果は常に1ビットであるため、必要ありません。
  • 減算を繰り返さずにdiffから導出できます。abs_diff

そうでなければ、これは私には完全に正しいようです。

于 2012-01-16T20:49:03.053 に答える
4

これはより短く、おそらくより高速です。

int64_t GetDifference(uint64_t first, uint64_t second)
{
  int64_t diff = first - second;
  bool overflowed = (diff < 0) ^ (first < second);
  assert(!overflowed);
  return diff;
}

diff < 0優れた最適化コンパイラは、それが負のフラグでありfirst < second、前の式からのキャリーフラグであることに気付くはずです。これらの2つのフラグを比較することは、オーバーフローの古典的なテストです。

それを検出しなくても、必要な操作は少なくなります。

しかし、私がこれを好む最大の理由は、マジックナンバーがないことです

于 2012-01-16T20:56:29.537 に答える
2

これはどう:

int64_t GetDifference(uint64_t first, uint64_t second) {
    int64_t diff = (int64_t)(first - second);
    assert first >= second && diff >= 0 || first < second && diff < 0;
    return diff;
}
于 2012-01-16T21:03:19.040 に答える