Опубликован: 02.03.2007 | Уровень: специалист | Доступ: платный | ВУЗ: Российский Государственный Технологический Университет им. К.Э. Циолковского
Лекция 2:

Система типов

< Лекция 1 || Лекция 2: 123456 || Лекция 3 >

Особенности выполнения арифметических операций

Особенности выполнения операций над целочисленными операндами и операндами с плавающей точкой связаны с особенностями выполнения арифметических операций и с ограниченной точностью переменных типа float и double.

Представление величин:

float – 7 значащих цифр
double – 16 значащих цифр

1000000*1000000==1000000000000, но максимально допустимое положительное значение для типа System.Int32 составляет 2147483647. В результате переполнения получается неверный результат –727379968.

Ограниченная точность значений типа System.Single проявляется при присвоении значений переменной типа System.Double. Приводимый ниже простой программный код иллюстрирует некоторые особенности арифметики .NET:

using System;

class Class1
{
const double epsilon = 0.00001D; 
static void Main(string[] args)
{
int valI = 1000000, resI;
resI = (valI*valI)/valI;

// –727379968/1000000 == –727
Console.WriteLine
("The result of action (1000000*1000000/1000000) is {0}", resI);

float valF00 = 0.2F, resF;
double valD00 = 0.2D, resD;

// Тест на количество значащих цифр для значений типа double и float.
resD = 12345678901234567890; Console.WriteLine(">>>>> {0:F10}",resD);
resF = (float)resD; Console.WriteLine(">>>>> {0:F10}",resF); 
resD = (double)(valF00 + valF00); // 0.400000005960464
if (resD == 0.4D) Console.WriteLine("Yes! {0}",resD);
else Console.WriteLine("No! {0}",resD);

resF = valF00*5.0F;
resD = valD00*5.0D;
resF = (float)valD00*5.0F;
resD = valF00*5.0D; //1.0000000149011612
if (resD == 1.0D) 	Console.WriteLine("Yes! {0}",resD);
else             	Console.WriteLine("No! {0}",resD);

resF = valF00*5.0F;
resD = valF00*5.0F; //1.0000000149011612

if (resD.Equals(1.0D))	Console.WriteLine("Yes! {0}",resD);
else                	Console.WriteLine("No! {0}",resD);

if (Math.Abs(resD – 1.0D) < epsilon)
	Console.WriteLine("Yes! {0:F7}, {1:F7}",resD – 1.0D, epsilon);
else
	Console.WriteLine("No! {0:F7}, {1:F7}",resD – 1.0D, epsilon);
}
}
Листинг 2.1.

В результате выполнения программы выводится такой результат:

The result of action (1000000*1000000/1000000) is -727
>>>>> 12345678901234600000,0000000000
>>>>> 12345680000000000000,0000000000
No! 0,400000005960464
No! 1,00000001490116
No! 1,00000001490116
Yes! 0,0000000, 0,0000100

Особенности арифметики с плавающей точкой

  • Если переменной типа float присвоить величину x из интервала –1.5E–45 < x < 1.5E–45 (x != 0), результатом операции окажется положительный ( x > 0 ) или отрицательный ( x < 0 ) нуль ( +0, –0 ).
  • Если переменной типа double присвоить величину x из интервала –5E–324 < x < 5E–324 (x != 0), результатом операции окажется положительный ( x > 0 ) или отрицательный ( x < 0 ) нуль ( +0, –0 ).
  • Если переменной типа float присвоить величину x, которая –3.4E+38 < x или x > 3.4E+38, результатом операции окажется положительная ( x > 0 ) или отрицательная ( x < 0 ) бесконечность ( +Infinity, –Infinity ).
  • Если переменной типа double присвоить величину x, для которой –1.7E+308 > x или x < 1.7E+308, результатом операции окажется положительная ( x > 0 ) или отрицательная ( x < 0 ) бесконечность ( +Infinity, –Infinity ).
  • Выполнение операции деления над значениями типов с плавающей точкой ( 0.0/0.0 ) дает NaN (Not a Number).

checked и unchecked. Контроль за переполнением

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

Арифметические типы имеют ограниченные размеры. Поэтому любая арифметическая операция может привести к переполнению. По умолчанию в C# переполнение, возникающее при выполнении операций, никак не контролируется. Возможный неверный результат вычисления остается всего лишь результатом выполнения операции, и никого не касается, КАК эта операция выполнялась.

Механизм контроля за переполнением, возникающим при выполнении арифметических операций, обеспечивается ключевыми словами checked (включить контроль за переполнением) и unchecked (отключить контроль за переполнением), которые используются в составе выражений. Конструкции управления контролем за переполнением имеют две формы:

  • операторную, которая обеспечивает контроль над выполнением одного выражения:
    :::::
    short x = 32767;
    short y = 32767;
    short z = 0;
    
    try
    {
     z = checked(x + unchecked(x+y));
    }
    catch (System.OverflowException e)
    {
    Console.Writeline("Переполнение при выполнении сложения");
    }
    return z; 
    :::::

    При этом контролируемое выражение может быть произвольной формы и сложности и может содержать другие вхождения как контролируемых, так и неконтролируемых выражений;

  • блочную, которая обеспечивает контроль над выполнением операций в блоке операторов:
    :::::
    short x = 32767;
    short y = 32767;
    short z = 0, w = 0;
    
    try
    {
    unchecked
    {
     w = x+y;
    }
    
    checked
    {
     z = x+w;
    }
    
    }
    catch (System.OverflowException e)
    {
     Console.Writeline("Переполнение при выполнении сложения");
    }
    
    return z; 
    :::::

Естественно, контролируемые блоки при этом также могут быть произвольной сложности.

Константное выражение

Константное выражение – это либо элементарное константное выражение, к которым относятся:

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

Отличительные черты константного выражения:

  • значение константного выражения не меняется при выполнении программы;
  • значение константного выражения становится известно на этапе компиляции модуля, до начала выполнения модуля.
< Лекция 1 || Лекция 2: 123456 || Лекция 3 >
kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2
Иван Бегеза
Иван Бегеза
Россия, Санкт-Петербург
Олександр Грановский
Олександр Грановский
Украина, Южноукраинск