добавив "int" с "uint_64t" - PullRequest
       18

добавив "int" с "uint_64t"

1 голос
/ 09 марта 2012

Существуют три переменные со следующими типами

 uint64_t old_addr, new_addr;
 int delta;

, и я хочу выполнить это назначение

 new_addr = old_addr + delta;

Однако проблема заключается в том, когда old_addr=915256 и delta=-6472064,new_addr becoms 18446744069414584325

, чтобы исправить это, я должен проверить некоторые вещи:

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

Есть ли лучший и эффективный способ?

Ответы [ 3 ]

4 голосов
/ 09 марта 2012

Это называется насыщенным сложением, и некоторые процессоры имеют специальные машинные инструкции для этого.Вы можете извлечь этот код во встроенную функцию и, в зависимости от целевой среды выполнения, использовать машинную инструкцию.

Вместо abs(delta) вы можете просто написать -delta, поскольку вы уже знаете, что delta < 0.

2 голосов
/ 09 марта 2012

Вопрос в том, что могут принимать значения 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 ++ таковы, что вам, вероятно, лучше всего использовать явные if s и не рисковать любой смешанной арифметикой, прежде чем быть уверенным в значениях.

И обратите внимание, что на большинстве машин abs( delta ) все равно будет отрицательным, если delta равно INT_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;
}

(чуть выше моей головы. Там может быть одно отключение при одной ошибке).

0 голосов
/ 09 марта 2012

Этот код очень прост и заботится о переполнении в обоих направлениях.

#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;
}
...