Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как преобразовать дополнение 2 в его соответствующий знаковый аналог, естественный для машины?

Автор вопроса: mafsoОтветов: 2

Пусть a будет переменной целочисленного типа со знаком T, а U - соответствующим беззнаковым типом. Выражение (U)a дает значение, соответствующее представлению в дополнении до двух значения a как U. Я хочу знать, гарантирует ли стандарт C следующее, чтобы отменить это приведение. Быть u типа U и иметь значение (U)a. Be MAX максимальное значение, которое может содержать тип T. (Помните о неявных преобразованиях в типы без знака и о том факте, что каждое положительное значение переменной со знаком остается неизменным при этих преобразованиях.)

Во-первых, предположим, что T может хранить результат:

T convert_2scomplement_to_T(U n) {
    return n<=MAX ? n : -(T)(U)-n;
}

Во-вторых, допустим, функция должна обнаружить такой недопустимый аргумент; быть MIN минимальное значение T может содержать:

T convert_2scomplement_to_T_checked(U n) {
    if(n <= MAX) return n;
    if( !(n & (U)1 << sizeof(U)*CHAR_BIT-1) ) { // (*)
        // invalid argument, the value is positive and `T' cannot hold it
    }
    /* `n' represents something negative if we're here. */
    if(-n < MIN) {
        // invalid argument, the value is negative and `T' cannot hold it
    }
    return -(T)(U)-n;
}

Строка, отмеченная // (*), насколько я могу судить, не является строго соответствующей, потому что стандарт не дает никаких гарантий относительно положения бита знака.

Описанные функции работают должным образом? И можно ли избежать проверки бита знака в строго соответствующем коде?

(И помимо языкового юриста... было бы здорово, если бы кто-то, кто написал код, зная, что хотя бы один человек использовал его на платформе, не использующей дополнение до двух, мог бы оставить комментарий, что это была за машина. Википедия упоминает

величина со знаком:

дополнение:

но, похоже, в программах, написанных сегодня, об этом не стоит беспокоиться. Есть ли причина, по которой стандарт все еще касается таких машин?)

  • Вопрос кажется неясным; если вы просите что-то, что работает только на машинах с двумя комплементами? M.M 03.07.2014
  • Выражение (U)a дает значение, соответствующее представлению дополнения до двух значения a - в общем случае неверно. Если вы спрашиваете об обратной операции (U)a в целом, просто укажите, что вместо добавления 2 к 2 M.M 03.07.2014
  • @MattMcNabb: Нет, я прошу строго соответствующее решение. mafso 03.07.2014
  • Вы можете использовать союз, чтобы напечатать каламбур целого числа со знаком и без знака одного размера. C99 явно разрешает каламбур объединения. Mysticial 03.07.2014
  • @Mysticial: я не хочу каламбурить. Я хочу отменить приведение (они эквивалентны на машинах с 2-м дополнением, поэтому я не могу попробовать свой код, потому что у меня нет доступа к машине без 2-го дополнения). mafso 03.07.2014
  • @MattMcNabb: Да, в целом это правда. Стандарт описывает это как "[...] значение преобразуется путем многократного добавления или вычитания на единицу больше, чем максимальное значение, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне нового типа" (C99/C11 6.3). .1.3 p.2), что фактически является дополнением до 2. mafso 03.07.2014

clanguage-lawyerunsigned-integerunsigned

Ответы

Ответ 1 · david.pfx

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

Так что да, приведение S->U->S определенно обратимо, но U->S->U может не работать для значений с установленным старшим битом. И вы, возможно, не сможете отменить это для отрицательного нуля, потому что информация может быть потеряна.

Приведение знакового к беззнаковому сохраняет битовый шаблон и не является операцией.

Unsigned to signed имеет дело с числами, у которых установлен старший бит. Все включенные биты являются допустимыми и представляют собой отрицательный нуль, и их можно перехватывать, обрабатывать как ноль или принудительно обнулять (по крайней мере, это мое чтение, но у меня нет под рукой Univac 1100, чтобы попробовать его). Другие значения с установленным старшим битом находятся за пределами диапазона со знаком, поэтому поведение определяется реализацией. Скорее всего, это сохранит битовый рисунок, как это проще всего сделать.

Если вы ищете гарантии, вы можете их не найти. Большая часть C/C++ такова.

Ответ 2 · david.pfx

Интегральные преобразования для дополнения до двух определяются следующим образом. n3936 S4.7/2,3 [аналог n1570 s6.3.1.3]

Если целевой тип не имеет знака, результирующее значение является наименьшим целым числом без знака, сравнимым с исходным целым числом (по модулю 2n, где n - количество битов, используемых для представления беззнакового типа). [Примечание: в представлении с дополнением до двух это преобразование является концептуальным, и битовый шаблон не изменяется (если нет усечения). -конец примечания]

Конгруэнтность определяется: (Математика) отношение между двумя числами, показывающее, что числа дают одинаковый остаток при делении на некоторое заданное число.

Наименьший означает наименьший или наименьший по значению. "Некоторое заданное значение" равно 2 ^ количеству бит.

Итак, преобразование без знака оценивает (k mod 2^n), что равно (2^n - k).

  • с четырехбитным числом (со знаком)-1 => (без знака)15
  • с 16-битным числом (со знаком)-1 => (без знака)65535
  • с 32-битным числом (со знаком)-1 => (без знака)4294967295

В каждом случае это требует копирования битовой комбинации и увеличения результата.

Если целевой тип знаковый, значение не изменяется, если оно может быть представлено в целевом типе (и ширине битового поля); в противном случае значение определяется реализацией.

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

Таким образом, ответ заключается в том, что стандарт не гарантирует циклическое преобразование целых чисел со знаком в беззнаковое для реализации дополнения до двух.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы