Кастинг длинные и целые, используя только побитовое - PullRequest
0 голосов
/ 04 ноября 2019

Я пытаюсь воспроизвести вывод следующей функции, используя только побитовые операторы! ~ & ^ |+ << >>.

int test_dl2(int x, int y) { 
   long long lsum = (long long) x + y;
   return lsum == (int) lsum;
}

Все мои тесты показывают, что ответ на все вопросы - всего 1. Однако, автоматический тестер, который сообщает вам, если вопрос правильный, говорит, что возвращение одного вопроса не является правильным.

В каких ситуациях на этот ответ не 1? И если функция не реплицируется следующим образом:

int test_dl2(int x, int y) { 
   return 1;
}

Какой должна быть правильная функция / выражение (используя только указанные побитовые операторы)?

Ответы [ 3 ]

1 голос
/ 04 ноября 2019

Возможно, вы пытаетесь проверить, даст ли добавление x и y действительный результат как uint32_t. Проблема, как уже говорилось в комментариях, заключается в том, что если число слишком «большое», преобразование из uint64_t в uint32_t не определено.

В настоящее время ни C, ни C ++ не предполагают, что числа представлены как дополнение к двум иэтот вид проверки сложен. Это изменится, так как следующий стандарт C ++ обеспечит использование дополнения two к целым числам со знаком (и, вероятно, будет следовать стандарт C).

Но это не даст смыслав неправильное преобразование, и ваш код по-прежнему будет недействительным.

Некоторые тесты могут быть выполнены, если мы предположим, что числа закодированы в дополнение к двум (и это уже поведение на большинстве компьютеров).

Можно использовать несколько решений. Вот тот, который в основном опирается на побитовые операторы.

Схема метода:

  • числа сдвига влево, чтобы разделить их на два (предполагается, что сдвиги влево на знаковых являются арифметическими, что верно для большинства компьютеров, но не требуется в настоящее время стандартом)

  • добавить их. Это вычислит x / 2 + y / 2 и будет равно (x + y) / 2 , за исключением , если оба LSB равны x и y - это единицы, в этом случае существует перенос, сгенерированный с весом 2 ^ 1 в x + y .
    Мы проверяем существование этого переноса с помощью и с младшим битом x и y , и мы добавляем его к сумме.

  • результат предыдущеговычисление (x + y) / 2 всегда допустимо для 32 бит. Мы проверяем, действительно ли это на 31 бит. Если это правда, x + y будет действительным для 32 битов.
    Проверка этой действительности выполняется путем сравнения битов 31 и 30. Если они равны, результат может быть преобразован в 31Бит безопасно. В противном случае преобразование вызовет изменение знака.

int is_add32_valid(uint32_t x, uint32_t y) { 
  uint32_t z = (x>>1) + (y>>1) + (x & y & 0x1) ;
  return !( (z ^ (z <<1)) & (1 << 31) ) ;
}
1 голос
/ 04 ноября 2019

Следующий тест возвращает 0 для вашей функции:

#include <stdio.h>
#include <limits.h>

int test_dl2(int x, int y) { 
   long long lsum = (long long) x + y;
   return lsum == (int) lsum;
}

int main() {
    printf("%d", test_dl2(INT_MAX, 1));
    return 0;
}

Максимальное число int, которое я использовал, вызывает переполнение. Ваш код предназначен для тестирования переполнения в int, поэтому вам нужно проверить его со значениями, которые вызывают переполнение в + для int. Есть много тестов, чтобы показать это переполнение, и мой пример только.

Обновление:

Как уже упоминалось в комментариях, lsum == (int) lsum часть вашего кода вреализация определена в C, поэтому вы не можете передавать результаты функции вообще. Мой аргумент верен, если типы данных были без знака (unsigned int и unsigned long long). Этот код также является реализацией, определенной до C++20 в C++. После C++20 он снова определяется в C++.

0 голосов
/ 04 ноября 2019

Возвращается 0, если x + y больше tmax или меньше tmin.

В противном случае возвращается 1.

...