Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Что происходит в оперативной памяти при прибавлении 1 к максимальному значению переменной?

#математика


Есть int  с максимальным значением 2147483647. В оперативке выглядит так:
11111111111111111111111111111111

При прибавлении единицы число превращается в -2147483647 и 
01111111111111111111111111111111

Из-за чего Происходит смена именно 1ой ячейки? Как выглядит этот процесс?
p.s. буду благодарен тому, кто посоветует подходящую метку    


Ответы

Ответ 1



Никакой мистики, просто дополнительный код. У вас небольшая ошибка: число 2147483647 в дополнительном коде выглядит как 0111 1111 1111 1111 1111 1111 1111 1111 (31 единица), а -2147483648 - 1000 0000 0000 0000 0000 0000 0000 0000 (единица и 31 ноль).

Ответ 2



Никакой мистики нету, это всё определяется стандартами языков программирования. В C++, например, переполнение знакового целого является undefined behaviour, то есть, программа некорректна, и может случиться всё, что угодно, включая получение того ответа, который вы ожидали, любого другого ответа, снос операционной системы и появление привидений из дисковода. Обычно, однако же, n-разрядные целые в C++ (да и во многих других языках) ведут себя как остатки по модулю 2^n: при вычислении "переполненного" значения разряды старше n-го просто отбрасываются. Для вашего случая, 2147483647 (двоичное 0111 1111 1111 1111 1111 1111 1111 1111) превращается в -2147483648 (двоичное 1000 0000 0000 0000 0000 0000 0000 0000). Но надеяться на это не стоит: компилятор имеет право воспользоваться тем, что в случае UB он может генерировать любой код, для более мощной оптимизации. Заметьте, что переполнение беззнакового целого в C++ — определённая и допустимая вещь: при переполнении число "законно" заменяется на остаток при делении на 2^n. В C# стандарт языка диктует другое правило: в непроверяемом контексте переполнение приводит к неявному взятию остатка по модулю 2^n; в проверяемом же контексте переполнение приводит к исключению. Пример: public class Test { public static void Main() { int maxint = 2147483647; int increased1 = unchecked(maxint + 1); Console.WriteLine("increased1 = {0}", increased1); int increased2 = checked(maxint + 1); Console.WriteLine("this will never be reached"); } } Здесь работает только первое переполнение, программа выдаёт increased1 = -2147483648 после чего срабатывает исключение. В Java переполнения примитивных типов исключены стандартом, результат не отличается от C# в непроверяемом контексте.

Комментариев нет:

Отправить комментарий