Почему определяется поведение беззнакового целочисленного переполнения, а подписанное целочисленное - нет?

Беззнаковое целочисленное переполнение хорошо определяется стандартами C и C ++. Например, стандарт C99 (§6.2.5/9) состояния

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

Однако в обоих стандартах указано, что переполнение целого числа со знаком является неопределенным поведением. Опять же из стандарта C99 (§3.4.3/1)

Примером неопределенного поведения является поведение при целочисленном переполнении.

Есть ли историческая или (даже лучше!) Техническая причина этого несоответствия?


person anthonyvd    schedule 12.08.2013    source источник
comment
Вероятно, потому что существует более одного способа представления целых чисел со знаком. Какой способ не указан в стандарте, по крайней мере, в C ++.   -  person juanchopanza    schedule 13.08.2013
comment
Полезная ссылка: en.wikipedia.org/wiki/Signed_number_presentations   -  person Robᵩ    schedule 13.08.2013
comment
То, что сказала чуанчопанза, имеет смысл. Насколько я понимаю, исходный стандарт C в значительной степени кодифицировал существующую практику. Если все реализации в то время согласились с тем, что должно делать беззнаковое переполнение, это хорошая причина для его стандартизации. Они не пришли к соглашению о том, что должно делать подписанное переполнение, поэтому это не вошло в стандарт.   -  person    schedule 13.08.2013
comment
Это может быть связано с тем, что целочисленное переполнение со знаком легко обнаружить, проверив максимальное количество sig. немного до и после. Гораздо сложнее обнаружить беззнаковое переполнение.   -  person David Elliman    schedule 13.08.2013
comment
@DavidElliman Беззнаковый перенос при добавлении также легко обнаруживается (if (a + b < a)). Переполнение при умножении затруднено как для знаковых, так и для беззнаковых типов.   -  person    schedule 13.08.2013
comment
@DavidElliman: Вопрос не только в том, сможете ли вы его обнаружить, но и в том, каков будет результат. В реализации знак + значение MAX_INT+1 == -0, в то время как в дополнении до двух это будет INT_MIN   -  person David Rodríguez - dribeas    schedule 13.08.2013


Ответы (5)


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

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

Соответствующие цитаты:

C99 6.2.6.1:3:

Значения, хранящиеся в битовых полях без знака, и объекты типа unsigned char должны быть представлены с использованием чистой двоичной нотации.

C99 6.2.6.2:2:

Если бит знака равен единице, значение должно быть изменено одним из следующих способов:

- соответствующее значение с битом знака 0 инвертируется (знак и величина);

- знаковый бит имеет значение - (2 N) (дополнение до двух);

- знаковый бит имеет значение - (2 N - 1) (до единицы).


В настоящее время все процессоры используют представление дополнения до двух, но знаковое арифметическое переполнение остается неопределенным, и производители компиляторов хотят, чтобы оно оставалось неопределенным, потому что они используют эту неопределенность для помощи в оптимизации. См., Например, эту запись в блоге Яна Лэнса Тейлора или эту жалоба Агнера Фога и ответы на его отчет об ошибке.

person Pascal Cuoq    schedule 12.08.2013
comment
Однако здесь важно отметить, что в современном мире нет архитектур, использующих что-либо, кроме арифметики со знаком дополнения до 2. Что языковые стандарты по-прежнему допускают реализацию, например, PDP-1 - чисто исторический артефакт. - person Andy Ross; 13.08.2013
comment
@AndyRoss А, да, ты напоминаешь мне, что мне нужно добавить примечание к своему ответу. - person Pascal Cuoq; 13.08.2013
comment
Спасибо за отличный ответ, сообщение в блоге о GCC, полагающемся на то, что подписанное целочисленное переполнение является неопределенным поведением для оптимизации, было вишенкой на торте. - person anthonyvd; 13.08.2013
comment
@AndyRoss, но есть еще системы (компиляторы OS +, правда, со старой историей) со своим дополнением и новыми выпусками по состоянию на 2013 год. Пример: OS 2200. - person ouah; 13.08.2013
comment
@ Энди Росс, вы бы не рассматривали никакие архитектуры ... с использованием чего-либо, кроме двух дополнений ... сегодня включает в себя весь спектр DSP и встроенных процессоров? - person chux - Reinstate Monica; 13.08.2013
comment
@AndyRoss: Хотя «нет» архитектур, использующих что-либо, кроме двух дополнений (для некоторого определения «нет»), есть определенно архитектуры DSP, которые используют арифметику с насыщением для целых чисел со знаком. - person Stephen Canon; 13.08.2013
comment
Коснитесь насыщенности, но, кстати, ни один из этих режимов не соответствует ISO C. Вы используете инструкции по насыщению через сборку или встроенные функции. Есть ли система, которая представляет собой переменную char / short / int / long со знаком ISO C с насыщением? - person Andy Ross; 13.08.2013
comment
Насыщающая арифметика со знаком определенно соответствует стандарту. Конечно, инструкции обертывания должны использоваться для беззнаковой арифметики, но у компилятора всегда есть информация, чтобы знать, выполняется ли беззнаковая или подписанная арифметика, поэтому он, безусловно, может выбрать инструкции соответствующим образом. - person caf; 13.08.2013
comment
Между прочим, ссылка на сообщение в блоге Яна Лэнса Тейлора мертва; если вы знаете об обновленной ссылке, стоит обновить этот ответ. В любом случае, отличный ответ, +1. - person KRyan; 14.06.2015
comment
@KRyan Ссылка все еще работает для меня, но если она исчезла, следующая должна продолжать работать: https://web.archive.org/web/20141004000724/http://www.airs.com/blog/archives/120 - person Pascal Cuoq; 14.06.2015
comment
@KRyan Гораздо позже я обнаружил это руководство по оптимизации от Nvidia для CUDA (которое не является C ++, но является производным от него), которое рекомендует подписанные счетчики циклов, когда это возможно, потому что поведение undefined передает информацию компилятору (что цикл не обернуть). Этот, вероятно, когда-нибудь испортится: docs.nvidia.com/cuda/cuda-c-best-practices-guide/ - person Pascal Cuoq; 14.06.2015
comment
@PascalCuoq Правильно; теперь работает. Должно быть, это была вспышка. Тем не менее, эта статья CUDA увлекательна; полностью меняет мою интуицию по этому поводу. А знаете ли вы, верно ли то же самое в C ++? В наши дни не нужно много писать на C. Я знаю, что стандарты в этом отношении такие же, но не уверен, какого поведения можно ожидать от компиляторов. - person KRyan; 14.06.2015
comment
@PascalCuoq: Я взял на себя смелость добавить объяснение, почему целочисленное представление определяет поведение переполнения. Это, вероятно, довольно очевидно, но может быть непонятно для кого-то без опыта в C. Не стесняйтесь редактировать заново :-). - person sleske; 14.03.2016
comment
@PascalCuoq: Авторы C89 отметили в обосновании, что большинство реализаций будут (последовательно) рассматривать подписанное переполнение как обертку в случаях, когда результат приводится к беззнаковому, и я думаю, они ожидали, что это будет продолжаться. Видите ли вы какие-либо преимущества в необдуманных сценариях того, чтобы реализации для аппаратного обеспечения без вывода сообщений выполняли какие-либо действия? - person supercat; 31.10.2016
comment
Но как насчет целых чисел фиксированной ширины? Они должны использовать запись с дополнением до 2. Почему они не обернули переполнение? - person bzim; 17.02.2018
comment
@ BrunoCorrêaZimmermann Это интересный вопрос. Я готов поспорить, что это потому, что авторы компилятора хотят, чтобы оба этих типа а) могли просто typedef эти типы int, long и long long в зависимости от ситуации на современных архитектурах, где используется дополнение 2s и обычная ширина, и b) сохраните оптимизации, которые они реализовали для этих типов, и положительные результаты тестов, которые они приносят. Но это только предположения с моей стороны. - person Pascal Cuoq; 17.02.2018
comment
@ BrunoCorrêaZimmermann: Возможность заставить компилятор преобразовывать такие вещи, как x<<y>>z в x<<(y-z) или x>>(z-y), в тех случаях, когда он знает y и z, обычно безопасно и полезно. Такая оптимизация может быть осуществлена ​​без необходимости вызова UB при переполнении, если Стандарт позволяет реализациям выбирать в неуказанном режиме среди альтернативных определенных поведений, которые будут включать перенос до любого удобного размера, который по крайней мере равен целочисленному типу, но я не видел особого интереса в формализации такой вещи. - person supercat; 06.04.2018
comment
В этом есть смысл, но почему в стандарте не сказано, что это поведение не определено или определено в реализации? - person Mikhail; 23.03.2019
comment
@Mikhail: На платформах, где целочисленное переполнение вызовет сигнал, его обработка как определение реализации серьезно ограничит способность компиляторов переупорядочивать или объединять целочисленные операции, которые могут переполниться. Если, например, код внутри цикла умножает два числа, и эти числа никогда не изменяются в этом цикле, для определения реализации переполнения потребуется, чтобы вышеупомянутый сигнал не поднимался до тех пор, пока код не достигнет той части цикла, где происходит вычисление; при отсутствии этого требования компилятор может выполнить умножение один раз перед началом цикла. - person supercat; 18.03.2020
comment
@Mikhail: Если код внутри цикла вызывает функцию, которая изменяет объект типа sig_atomic_t, который исследуется в обработчике сигнала, может быть важно, чтобы переполнение произошло в нужном месте в последовательности выполнения, но в большинстве случаев это не имеет значения. Авторы компилятора должны иметь больше возможностей для оценки потребностей своих клиентов в таких вопросах, чем когда-либо мог бы Комитет. - person supercat; 18.03.2020

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

Также стоит отметить, что «неопределенное поведение» не означает «не работает». Это означает, что реализации разрешено делать все, что угодно в этой ситуации. Это включает в себя «правильные поступки», «вызов полиции» или «крушение». Большинство компиляторов, когда это возможно, будут выбирать «делать правильные вещи», предполагая, что это относительно легко определить (в данном случае это так). Однако, если у вас возникают переполнения в расчетах, важно понимать, к чему это на самом деле приводит, и что компилятор МОЖЕТ делать что-то иное, чем вы ожидаете (и что это может сильно зависеть от версии компилятора, настроек оптимизации и т. Д.) .

person Mats Petersson    schedule 12.08.2013
comment
Однако компиляторы не хотят, чтобы вы полагались на их правильные действия, и большинство из них покажет вам это, как только вы скомпилируете int f(int x) { return x+1>x; } с оптимизацией. GCC и ICC с параметрами по умолчанию оптимизируют вышеуказанное до return 1;. - person Pascal Cuoq; 13.08.2013
comment
Пример программы, которая дает разные результаты при int переполнении в зависимости от уровней оптимизации, см. На странице ideone.com/cki8nM. Думаю, это свидетельствует о том, что ваш ответ дает плохой совет. - person Magnus Hoff; 13.08.2013
comment
Я немного изменил эту часть. - person Mats Petersson; 13.08.2013
comment
Если C должен был предоставить средства для объявления обертывающего целого числа с дополнением до двух со знаком, ни одна платформа, которая может запускать C вообще, не должна иметь больших проблем с его поддержкой хотя бы умеренно эффективно. Дополнительных накладных расходов было бы достаточно, чтобы код не использовал такой тип, когда поведение упаковки не требуется, но большинство операций с целыми числами дополнения до двух идентичны операциям с целыми числами без знака, за исключением сравнений и рекламных акций. - person supercat; 11.02.2014
comment
@supercat: вы предполагаете, что система использует дополнение до двух. Как насчет дополнения, или знакового бита и обычного числа (например, в 8-битном: 1 = 00000001, -1 = 10000001, 63 = 00111111, -63 = 10111111 - именно так хранятся числа с плавающей запятой, так что это не выходит за рамки область возможности иметь это тоже в целочисленной форме). - person Mats Petersson; 11.02.2014
comment
@MatsPetersson: если тип был указан как 16-разрядное целое число с дополнением до двух на оборудовании без такой поддержки, компилятор должен выделить 16-разрядное целое число без знака. x < y следует заменить на (x^0x8000) < (y^0x8000), (uint32)x следует заменить на x-((uint32_t)(x&0x8000)<<1); и т. Д. Не имеет значения, использует ли оборудование дополнение до единицы или знак + величина для знаковой арифметики, потому что оборудование не будет выполнять никаких знаковых арифметических действий . Для кода, который не заботится о точной семантике двух дополнений ... - person supercat; 11.02.2014
comment
... скорее всего, будет быстрее использовать собственный подписанный формат оборудования. Однако для кода, который требует поведения с дополнением до двух, возможность указать его будет намного чище, чем необходимость имитировать его в программном обеспечении, и даст гораздо лучшую производительность на платформах, которые изначально используют дополнение до двух. - person supercat; 11.02.2014
comment
Да, я говорю об использовании оборудования, которое имеет другой целочисленный формат, чем два дополнения. Я точно знаю, что есть оборудование, у которого есть свои дополнения (нет, это не очень распространено, но оно существует в реальном мире). Я не уверен, есть ли какое-либо оборудование только со знаковым битом. - person Mats Petersson; 12.02.2014
comment
@MatsPetersson: Существуют компиляторы C для процессоров без концепции знаковой арифметики; насколько я могу, такие компиляторы неизменно используют математику с дополнением до двух. Я не знаю ничего, что могло бы помешать компилятору C для любой платформы, имеющей беззнаковые арифметические инструкции, вести себя так, как если бы платформа не имела никаких подписанных арифметических инструкций и использовала только беззнаковые для всей математики, включая подписанную арифметику; такой код может быть не таким быстрым, как код, использующий собственные подписанные арифметические инструкции, но если семантически требуется перенос арифметики с дополнением до двух ... - person supercat; 02.05.2015
comment
@MatsPetersson: ... иметь средства для указания этого в коде и инструктировать компиляторы делать то, что необходимо для достижения этого, было бы чище, чем требовать, чтобы этот код, желающий сравнить два 16-битных целых числа с двумя дополнениями i и j, был записан i+0x8000u < j+0x8000u . Я бы подумал, что, учитывая swrap16_t i,j, было бы проще иметь i<j, чтобы компиляторы использовали сравнение с двумя дополнениями на процессорах, у которых есть один, и последовательность добавления-беззнакового-и-сравнения на тех, у которых его нет, вместо того, чтобы требовать этот код используйте беззнаковую математическую последовательность и надейтесь, что компиляторы для процессоров с двумя-comp. сравнивать... - person supercat; 02.05.2015
comment
... инструкции распознают, что целью кода является выполнение сравнения с дополнением до двух и избегает дополнительных инструкций "добавить". - person supercat; 02.05.2015
comment
Отрицательные значения должны существовать и работать для правильной работы компилятора.Конечно, вполне возможно обойти отсутствие знаковых значений в процессоре и использовать значения без знака, либо в качестве дополнения до единицы, либо в качестве дополнения до двух, в зависимости от того, что имеет наибольший смысл на основе о том, что такое набор инструкций. Обычно это делать значительно медленнее, чем при аппаратной поддержке, но это не отличается от процессоров, которые не поддерживают аппаратно с плавающей запятой, или аналогичных - просто добавляет много дополнительного кода. - person Mats Petersson; 04.05.2015
comment
@MatsPetersson: Единственные причины, по которым я вижу, что реализация использует что-либо, кроме двух дополнительных представлений, это (1) совместимость с загадочными реализациями, (2) какая-то другая форма знаковой математики быстрее, чем беззнаковая математика, или (3) использование какая-то другая форма может разрешить INT_MAX ›UINT_MAX / 2. Если не выполняется одно из этих условий, использование беззнаковых типов для имитации знаковой математики с дополнением до двух было бы тривиальным. - person supercat; 24.05.2017
comment
@supercat: Или оборудование на самом деле древнее само по себе и использует эту математику ... Я не спорю, что кто-то действительно ИСПОЛЬЗУЕТ это, просто тот факт, что это действительно существует в каком-то HW (или, по крайней мере, существовало), и поэтому там есть UB в спецификации для этого конкретного сценария. - person Mats Petersson; 24.05.2017
comment
@MatsPetersson: если оборудование может поддерживать математику без знака во всю ширину так же быстро, как и любой подписанный формат, который он использует, то оно будет поддерживать большинство операций в математике с дополнением до двух так же эффективно, как и любой формат, который он использовал бы (поскольку большинство операций с математикой без знака и молчанием -wraparound два-дополнение одинаковы на уровне битов). Насколько мне известно, общее количество реализаций C99 и C11, которые используют что-то другое, кроме двух дополнительных представлений для значений со знаком, равно нулю. Я знаю реализацию C89 с композицией одного человека, которая сохранялась до 21 века, но ... - person supercat; 24.05.2017
comment
... его самый длинный беззнаковый тип составляет 36 бит, поэтому он не соответствует C99. У меня также есть скрытое подозрение, что его 71-битный знаковый тип на самом деле не использует двоичное представление. Если набор инструкций выполняет беззнаковую математику, которая обертывает mod 2 ^ 36 медленнее, чем математика, которая обертывает mod 2 ^ 36-1 (документация для реализации предполагает, что режим принудительного соответствия неподписанного поведения заставляет вещи работать медленнее), я бы ожидал, что Самый эффективный способ поддержки большого типа со знаком - это представление числовой базы (2 ^ 36-1). - person supercat; 24.05.2017

Прежде всего, обратите внимание, что C11 3.4.3, как и все примеры и сноски, не является нормативным текстом и поэтому не имеет отношения к цитированию!

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

C11 6.5 / 5

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

Разъяснение относительно поведения целочисленных типов без знака, в частности, можно найти здесь:

C11 6.2.5 / 9

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

Это делает беззнаковые целочисленные типы особым случаем.

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

C11 6.3.1.3

6.3.1.3 Целые числа со знаком и без знака

Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.

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

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

person Lundin    schedule 22.12.2016

В дополнение к другим упомянутым проблемам, беззнаковый математический перенос заставляет беззнаковые целочисленные типы вести себя как абстрактные алгебраические группы (это означает, что, среди прочего, для любой пары значений X и Y будет существовать какое-то другое значение Z, такое, что X+Z будет , при правильном произнесении, равное Y и Y-Z, при правильном произнесении будет равно X). Если беззнаковые значения были просто типами места хранения, а не типами промежуточных выражений (например, если не было беззнакового эквивалента наибольшего целочисленного типа, а арифметические операции с беззнаковыми типами вели себя так, как если бы они сначала были преобразованы в более крупные подписанные типы, тогда не было бы такой необходимости в определенном поведении обертывания, но трудно выполнять вычисления в типе, который не имеет, например, аддитивного обратного.

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

person supercat    schedule 26.08.2013
comment
Я не совсем понимаю - почему помогает добавочная инверсия? Я не могу придумать ни одной ситуации, в которой поведение переполнения действительно полезно ... - person sleske; 14.03.2016
comment
@sleske: Использование десятичной дроби для удобства восприятия человеком, если счетчик энергии показывает 0003, а предыдущее показание было 9995, означает ли это, что было использовано -9992 единиц энергии или что было использовано 0008 единиц энергии? Имея 0003-9995 yield 0008, можно легко вычислить последний результат. Если он даст -9992, это сделает его немного более неудобным. Однако отсутствие возможности сделать это потребовало бы сравнения 0003 с 9995, заметив, что оно меньше, произвести обратное вычитание, вычесть полученный результат из 9999 и прибавить 1. - person supercat; 14.03.2016
comment
@sleske: как для людей, так и для компиляторов очень полезно иметь возможность применять ассоциативные, распределительные и коммутативные законы арифметики для переписывания выражений и их упрощения; например, если выражение a+b-c вычисляется внутри цикла, но b и c в этом цикле постоянны, может быть полезно переместить вычисление (b-c) за пределы цикла, но для этого, помимо прочего, потребуется, чтобы (b-c) давало значение, которое при добавлении к a даст a+b-c, что, в свою очередь, требует, чтобы c имел аддитивную инверсию. - person supercat; 14.03.2016
comment
: Спасибо за пояснения. Если я правильно понимаю, все ваши примеры предполагают, что вы действительно хотите справиться с переполнением. В большинстве случаев, с которыми я сталкивался, переполнение нежелательно, и вы хотите предотвратить его, потому что результат вычисления с переполнением бесполезен. Например, для счетчика энергии вы, вероятно, захотите использовать такой тип, чтобы никогда не происходило переполнение. - person sleske; 14.03.2016
comment
@sleske: для таких вещей, как порядковые номера TCP, наиболее полезно иметь тип, который обертывается так же, как в примере счетчика энергии, поэтому код не должен обрабатывать случай, когда порядковый номер идет от 0xFFFFFFFC к 0x00000007 иначе, чем случай, когда он идет от 0x00000002 до 0x0000000D. Что касается примера с a, b и c, даже если никто не заботится о каких-либо случаях, когда a+b или (a+b)-c будут вне диапазона используемого типа, очень часто можно заботиться о случаях, когда (b-c) находится за пределами диапазон этого типа. Однако если тип подчиняется законам арифметики ... - person supercat; 14.03.2016
comment
... таким образом, что (a+b)-c равно a+(b-c) независимо от того, представимо ли арифметическое значение b-c в типе, подстановка будет действительна независимо от возможного диапазона значений для (b-c). - person supercat; 14.03.2016
comment
Спасибо за объяснения. Я пробовал отредактировать его в вашем ответе - не стесняйтесь поправлять. - person sleske; 15.03.2016

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

Цитата OP относится к этому факту, но также подчеркивает тот факт, что существует только один, однозначный, логический способ представления целых чисел без знака в двоичном формате. Напротив, числа со знаком чаще всего представляются с использованием дополнения до двух, но возможны и другие варианты, как описано в стандарте (раздел 6.2.6.2).

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

person yth    schedule 04.10.2017
comment
Чтобы структура была полем, каждый элемент структуры, кроме аддитивной идентичности, должен иметь мультипликативную инверсию. Структура целых чисел, совпадающих по модулю N, будет полем только тогда, когда N равно единице или простому [вырожденное поле, когда N == 1]. Вы считаете, что я что-то упустил в своем ответе? - person supercat; 05.10.2017
comment
Ты прав. Меня смущали основные модули мощности. Исходный ответ отредактирован. - person yth; 06.10.2017
comment
Дополнительную путаницу здесь вызывает то, что существует поле порядка 2 ^ n, оно просто не изоморфно по кольцу целым числам по модулю 2 ^ n. - person Kevin Ventullo; 19.06.2018
comment
И 2 ^ 31-1 - это простое число Мерсенна (но 2 ^ 63-1 не является простым). Таким образом, моя первоначальная идея была разрушена. Кроме того, целочисленные размеры были другими в те времена. Так что моя идея была в лучшем случае ревизионистской. - person yth; 22.06.2018
comment
Тот факт, что целые числа без знака образуют кольцо (а не поле), взятие младшей части также дает кольцо и выполнение операций над всем значением, а затем усечение будет вести себя эквивалентно выполнению операций только с нижней частью, было ИМХО почти наверняка соображения. - person supercat; 18.03.2020