Помощь в написании студенческих работ
Антистрессовый сервис

Переполнения при операциях с целыми

РефератПомощь в написанииУзнать стоимостьмоей работы

Зная правила двоичного кодирования отрицательных целых чисел, легко понять, как меняется значение переменной знакового типа при поразрядных операциях. Например, применяя к положительному числу операцию поразрядного инвертирования мы меняем и знак числа, и на 1 увеличиваем его абсолютное значение. При поразрядном инвертировании отрицательного числа результат равен уменьшенному на 1 его абсолютному… Читать ещё >

Переполнения при операциях с целыми (реферат, курсовая, диплом, контрольная)

Рассматривая поразрядные операции, мы ограничились операндами беззнакового типа byte, так как использование знаковых типов требует знакомства с правилами кодирования отрицательных целых чисел. Переменные и константы типа byte могут иметь значения от О до 255. Соответствующие двоичные коды — от 0 (все нули) до 11 111 111 (все единицы). В то же время для знакового типа sbyte установлены пределы от -12810 до +12710.

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

Переполнения при операциях с целыми.

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

Минимальное число типа sbyte равно -12810. Его двоичный код 10 000 000. Число -1 представлено кодом 11 111 111. Представление нуля 0, код единицы 1.

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

// 0305.cs — поразрядное инвертирование знаковых чисел!!! using System; class Program {.

static void MainQ.

{

sbyte sb = 9;

sbyte nb = 3;

Console.WriteLine («~sb = «+ ~sb);

Console.WriteLine («~sb+sb = «+ (~sb + sb));

Console.WriteLine («~nb = «+ ~nb);

Console.WriteLine («~nb+nb = «+ (~nb + nb));

} }

Результат выполнения программы:

~sb = -10 ~sb+sb = -1 ~nb = -4 ~nb+nb = -1.

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

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

byte b = 255, с = 1, d; d = (byte)(b + с);

Значением переменной d будет 0. Обоснованность такого результата иллюстрирует следующее двоичное представление.

Переполнения при операциях с целыми.

(нуль за счет отбрасывания левого разряда).

Теперь обратимся к операндам знаковых типов, например, типа sbyte.

Если просуммировать числа -1 (с поразрядным представлением 11 111 111) и 1 (с кодом 1), то получим девятиразрядное число с битовым представлением 100 000 000. Для внутреннего представления чисел типа sbyte отводится 8 разрядов. Девятиразрядное число в эти рамки не помещается, и левая (старшая) единица отбрасывается. Тем самым результатом суммирования становится код нуля 0. Все совершенно верно — выражение (-1 + 1) должно быть равно нулю! Однако так правильно завершаются вычисления не при всех значениях целочисленных операндов.

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

sbyte х = 127, у = 127, z;

z = (sbyte) (х + у);

значением переменной z будет -2. В этом легко убедиться, представив выполнение операции суммирования в двоичном виде: Переполнения при операциях с целыми.

Примечание. В операторе z = (sbyte)(х + у);

использована операция приведения типов (sbyte). При её отсутствии результат суммирования х + у автоматически приводится к типу int. Попытка присвоить значение типа int переменной z, имеющей тип sbyte, воспринимается как ошибка, и компиляция завершается аварийно.[1][2] •.

// 0306.cs — переполнение при целочисленных операндах using System; class Program {.

static void Main ().

{

int m = 1001;

Console.WriteLine («m = «+ m);

Console.WriteLine («m = «+ (m = m * m));

Console.WriteLine («m = «+ (m = m * m));

Console.WriteLine («m = «+ (m = m * m));

} }

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

Результат выполнения программы:

m = 1001 m = 1 002 001 m = -1 016 343 263 m = 554 036 801.

После первого умножения m * m значением переменной m становится 1 002 00110, после второго — результат выходит за разрядную сетку из 32 битов. Левые лишние разряды отбрасываются, однако оставшийся самый левый 32-й бит оказывается равным 1, и код воспринимается как представление отрицательного числа. После следующего умножения 32-й (крайний левый) бит оказывается равным 0, и арифметически неверный результат воспринимается как код положительного числа.

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

В рассмотренных программах с переменными типов byte и sbyte мы несколько раз применили операцию преобразования (иначе приведения) типов. Например, были использованы конструкции:

(byte)(bb&dd) z = (sbyte)(x + у);

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

Поместим в программу операторы: short dd = 15, nn = 24; dd = (dd + nn)/dd;

При компиляции программы будет выведено сообщение об ошибке:

Cannot implicitly convert type 'int' to 'short'.

(Невозможно неявное преобразование типа int в short.)

Несмотря на то, что в операторах использованы переменные только одного типа short, в сообщении компилятора указано, что появилось значение типа int! Компилятор не ошибся — при вычислении выражений с целочисленными операндами, отличными от типа long, они автоматически приводятся к типу int. Поэтому результат вычисления (dd + nn)/dd имеет тип int. Для значений типа short (см. табл. 2.1) выделяется два байта (16 разрядов), значение типа int занимает 4 байта. Попытка присвоить переменной dd с типом short значения типа int воспринимается компилятором как потенциальный источник ошибки за счет потери 16 старших разрядов числа. Именно поэтому выдано сообщение об ошибке.

Программист может «успокоить» компилятор, применив следующим образом операцию приведения типов:

dd = (short)((dd + nn)/dd);

При таком присваивании программист берет на себя ответственность за правильность вычислений.

Обратите внимание на необходимость дополнительных скобок. Если записать (short) (dd + nn)/dd, то в соответствии с рангами операций к типу short будет приведено значение (dd + пп), а результат его деления на dd получит тип int.

Контрольные вопросы и задания

  • 1. Перечислите группы (категории) операций языка С#.
  • 2. Перечислите названия групп операций в порядке возрастания их приоритетов (рангов).
  • 3. Знаки каких бинарных операций могут использоваться в составных операциях присваивания?
  • 4. В чем отличия префиксных форм операций декремента и инкремента от постфиксных.
  • 5. К каким операндам применимы операции + + и -?
  • 6. К каким операндам применима операция %?
  • 7. К каким операндам применима операция ^ ?
  • 8. В чем особенность операции деления целочисленных операндов?
  • 9. Назовите правила выполнения операций %.
  • 10. Какому действию эквивалентен сдвиг влево разрядов битового представления целого числа?
  • 11. Приведите дополнительный код отрицательного числа типа sbyte, модуль которого не превышает 127.
  • 12. Объясните механизм возникновения переполнения при вычислениях с целочисленными операндами.
  • [1] Приведенные иллюстрации переполнений разрядной сетки приарифметических операциях с восьмиразрядными целыми (типов byte, sbyte) могут быть распространены и на целые типы с большим количеством разрядов (типы с указанием разрядностей приведены в табл. 2.1). Основным типом для представления целочисленных данных в C#является тип int. Для представления целочисленных значений типа intиспользуются 32-разрядные участки памяти. Тем самым предельныезначения для значения типа int таковы: • положительные от 0 до 231 — 1;
  • [2] отрицательные от -1 до -231. В следующей программе результаты умножений переменной типаint на саму себя выходят за пределы разрядной сетки.
Показать весь текст
Заполнить форму текущей работой