Является ли неотрицательный диапазон целого числа С++ со знаком по крайней мере таким же большим, как отрицательный диапазон?

Требует ли стандарт C++, чтобы неотрицательный диапазон стандартного целочисленного типа со знаком был не меньше отрицательного диапазона?

РЕДАКТИРОВАТЬ: обратите внимание, что здесь я имею в виду неотрицательный диапазон, а не положительный диапазон, который, очевидно, на единицу меньше неотрицательного. > диапазон.

РЕДАКТИРОВАТЬ: Если мы предположим С++ 11, ответ будет "Да". Смотрите мои пояснения ниже. С точки зрения C++03 ответ, вероятно, "Нет".

Тот же вопрос можно задать следующим образом: гарантирует ли стандарт, что результат a - b может быть представлен в стандартном целочисленном типе со знаком T, предполагая, что и a, и b являются отрицательными значениями типа T, и что a ≥ b ?

Я знаю, что стандарт допускает представление отрицательных значений с дополнением до двух, дополнением до единицы и величиной знака (см. С++ 11, раздел 3.9.1 [basic.fundamental], параграф 7), но я не уверен, требует ли он использования одного из этих трех представлений. Возможно нет.

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

Однако, даже если мы примем одно из упомянутых представлений, этого действительно недостаточно, чтобы гарантировать что-либо относительно размера любого диапазона.

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

Любая помощь будет оценена.


Обратите внимание, что было бы достаточно чего-то вроде следующего: каждый бит в «слоте хранения» целого числа имеет одну и только одну из следующих функций:

  • Неиспользованный
  • Бит знака (исключительно или смешанный бит знака/значения)
  • Бит значения (участвующий в значении)

У меня есть смутное воспоминание, что C99 говорит что-то в этом роде. Кто-нибудь что-нибудь знает об этом?


Хорошо, C99 (с TC3) предоставляет необходимые гарантии в разделе 6.2.6.2 «Целые типы», параграф 2:

Для целочисленных типов со знаком биты представления объекта должны быть разделены на три группы: биты значения, биты заполнения и бит знака. Не должно быть битов заполнения; должен быть ровно один бит знака. Каждый бит, который является битом значения, должен иметь то же значение, что и тот же бит в объектном представлении соответствующего беззнакового типа (если имеется M битов значения в знаковом типе и N в беззнаковом типе, тогда M ≤ N ). Если знаковый бит равен нулю, это не должно влиять на результирующее значение. Если знаковый бит равен единице, значение должно быть изменено одним из следующих способов:

  • соответствующее значение со знаковым битом 0 инвертируется (знак и величина);
  • бит знака имеет значение -(2N ) (дополнение до двух);
  • бит знака имеет значение -(2N - 1) (дополнение до единиц).

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

Может ли кто-нибудь подтвердить, что эта часть C99 также является обязательной частью C++11?


Я еще раз внимательно изучил стандарты C99 и C++11, и стало ясно, что гарантии в параграфе 2 раздела 6.2.6.2 C99 обязательны и для C++11.

C89/C90 не дает таких гарантий, поэтому нам нужен C99, а значит, нам нужен C++11.

Таким образом, C++11 (и C99) предоставляет следующие гарантии:

  1. Отрицательные значения в основных типах целых чисел со знаком (стандартные + расширенные) должны быть представлены с использованием одного из следующих трех представлений: дополнение до двух, дополнение до единицы или величина знака.

  2. Размер неотрицательного диапазона на единицу больше или равен размеру отрицательного диапазона для всех основных типов целых чисел со знаком (стандартный + расширенный).

Вторую гарантию можно переформулировать следующим образом:

-1 ≤ min<T> + max<T> ≤ 0

для любых фундаментальных целых чисел со знаком введите T (стандартный + расширенный), где min<T> и max<T> являются сокращениями для std::numeric_limits<T>::min() и std::numeric_limits<T>::max() соответственно.

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


person Kristian Spangsege    schedule 05.03.2014    source источник
comment
Нет. В дополнении до 2 самое отрицательное число на единицу больше, чем самое положительное число. например 8 бит дают диапазон [-128, 127].   -  person Moberg    schedule 05.03.2014
comment
@Moberg Да, в этом случае размер неотрицательного диапазона действительно равен размеру отрицательного диапазона. Правильно?   -  person Kristian Spangsege    schedule 05.03.2014
comment
Да, я поторопился.   -  person Moberg    schedule 05.03.2014


Ответы (1)


Стандарт, похоже, не требует такой вещи, хотя я могу пропустить ключевые отрывки. Все, что мы знаем о фундаментальных целочисленных типах со знаком, находится в 3.9.1/2:

Существует пять стандартных типов целых чисел со знаком: «signed char», «short int», «int», «long int» и «long long int». В этом списке каждый тип обеспечивает как минимум столько же памяти, сколько и предшествующие ему в списке.

А в 3.9.1/7:

Типы bool, char, char16_t, char32_t, wchar_t, а также целые типы со знаком и без знака вместе называются интегральными типами.48 Синонимом целочисленного типа является целочисленный тип. Представления целочисленных типов должны определять значения с использованием чистой двоичной системы счисления.

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

person Mark B    schedule 05.03.2014
comment
Да, и, к сожалению, определение чистой двоичной системы счисления в сноске 49 слишком слабое, чтобы дать какую-либо полезную информацию по этому вопросу. - person Kristian Spangsege; 05.03.2014
comment
Что ж, я мог бы придумать множество различных двоичных представлений, которые не соответствовали бы потребностям OP: возьмите целочисленный тип без знака и определите все числа выше любого произвольного числа как отрицательные числа. Почти так же, как дополнение 2 определяет все числа после 0x7fffffff как отрицательные, просто используйте меньшую константу... Будем надеяться, что ни один производитель ЦП никогда не реализует что-то подобное. - person cmaster - reinstate monica; 05.03.2014
comment
@cmaster Верно, поэтому вопрос в том, намерен ли стандарт разрешать такие представления или нет. - person Kristian Spangsege; 05.03.2014
comment
Интересно, можно ли снять некоторые из необходимых гарантий из стандарта C. - person Kristian Spangsege; 05.03.2014