#4 Real Вещественный тип даннных в Паскаль. Неявное приведение типа. Примеры

Вещественный тип данных

Тип Real служит для описания и хранения данных, являющихся вещественными числами.

Переменные типа Real

Переменные типа real могут быть объявлены стандартным способом (подобно integer):

var  a, b: real;

Таким переменным можно присваивать литералы вещественных чисел:

var  a, b: real;
begin 
    a := 2.5;
    b := 2.0;
end.

А также результаты любых арифметических выражений:

var  a, b: real;
begin 
    a := 2.5;
    b := a/2 + a*3*2.0; // запоминаем результат выражения
end.

Сравнение с Real с Integer

Выражения, возвращающие Integer

Если значение арифметического выражения присваивается переменной типа integer, то в него должны входить только:

  • целочисленные литералы
  • или целочисленные переменные.
  • Над указанными операндами должны выполняться операции (только эти - без операции деления):
    1. $+$ суммы (сложения)
    2. $-$ разности (вычитание)
    3. $*$ произведения (умножение)

Выражения, возвращающие Real

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

  1. $+$ суммы (сложения)
  2. $-$ разности (вычитание)
  3. $*$ произведения (умножение)
  4. $/$ деление ("отношение")

Можно сказать что тип, который возвращается выражением (тип его результата) определяется двумя моментами:

  1. типом операций (допустимые перечислены выше)
  2. типом операндов

Неявное приведение (преобразование) типа

Неявное приведение типа -- это процесс преобразования типа без каких-то особо записанных в коде инструкций, которые бы явно указывали на то, что выполняется преобразование.

Когда неявное приведение имеет место быть

Неявное приведение типа возможно в двух случаях:

  1. В ходе операции присваивания -- когда переменной типа real присваивается любое значение типа integer.
    Например:
    var  a : real; 
    begin
       a := 7; {  = 7.0  - то есть хранится будет именно вещественное число,
    хотя и с нулевой дробной частью
    }
  2. В ходе вычисления значения арифметического выражения, если хотя бы один из операндов (или результатов подвыражения, оказавшимся операндом) имеет тип real.

О втором случае поговорим подробнее.

Если в арифметическом выражении присутствуют целые числа (переменные, литералы или результаты подвыражений типа integer) и эти числа участвуют в одной операции с типом real, то:

  1. сначала целые числа будут приведены Паскалем к типу real (так как real может хранить любые данные типа integer, а обратное не верно)
  2. а затем уже будет вычислен результат арифметической операции, который тоже будет иметь тип real

Пусть у нас есть выражение:

a : real;
begin
  a =  5 + 2.0; // запоминаем результат выражения в переменную

-- этом случае вычисления будут проходить так ("под капотом" языка Паскаль):

5 + 2.0 =  5.0 + 2.0  = 7.0  // получили число 7, но типа real

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

Что к чему приводится неявно

Если в арифметических выражениях если неявное приведение типа имеет место быть, то это всегда приведения integer к real как к более широкому и универсальному классу чисел.

Рассмотрим разные выражения и прокомментируем когда происходит неявное приведение типа, а когда нет и почему:

6 + 3.3 
{ -- неявное приведения типа происходит, 
так как второй операнд имеет вещественный тип,
 а потому первый будет приведён к 6.0, а только потом вычислится сумма}

4 + 8
 { -- без неявного приведения -- оба операнда типа integer,
 сумма тоже типа integer}

10 - 3/7
 { -- неявное приведения типа происходит, 
так как второй операнд (результат подвыражения 3/7) имеет вещественный тип
 (3/7 -- это дробь примерно равная 0.4285714...),
 а потому первый будет приведён к вещественному типу и станет = 10.0,
 а только потом вычислится разность}

9.0 + 5
 {-- первый операнд вещественный, в потому второй будет приведен
 к тому же типа у станет = 5.0, затем вычислится их сумма типа real}

3 + 78 
{ -- без неявного приведения -- оба операнда типа integer,  
сумма тоже типа integer}

Присваивание несовместных типов. Что и чему можно присваивать

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

Рассмотрим примеры присваивания переменным значений с комментариями, показывающими в каких строках ошибка:

var a,b : integer;
begin
	a := 2; // справа и слева integer
	a := '2'; // ОШИБКА: справа символьный литерал, а слева integer
	b := 4; // справа и слева integer
	a := b+5; // справа и слева integer
	b := '123'; // ОШИБКА: справа строковый литерал, а слева integer
	a := b+5*2; / справа и слева integer
	a := b+5/2; { ОШИБКА: справа вещественное значение (real) так как операция деления в 
подвыражении вернёт вещественный тип а потом b будет неявно приведено к вещественному типу,
 так как второй аргумент вещественный, а слева integer}

Вывод вещественных чисел на экран

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

В некоторых реализациях Паскаля, при выводе на экран может использоваться экспаненциальная форма записи числа, то есть дробное число записывается (две особенности):

  1. в виде некоторого числа (обычно с одной цифрой в целой части), умноженного на $10$ в какой-то степени (вещественное число всегда подразумевается обладающим дробной частью, просто иногда она равна нулю, тогда число называют целым).
  2. вместо множителя $10$ используют букву $E$.

Примеры экспаненциальной записи чисел

  • Так, например число $125.35$:
    $$125.35 = 1.2535 * 100 = 1.2535 * 10^{2}$$
    в экспаненциальной форме может выглядеть так:
    1.2535E2
  • А число, скажем, $0.005567$:
    $$0.005567 = 5.567 / 1000 = 5.567 / 10^3 = 5.567 * 10^{-3} $$
    в экспаненциальной форме может быть записано как:
    5.567E-3

Разбор задач

Пример №1

Пусть есть задача:

Выведите на экран произведение чисел $5$ и $7.3$

Самое простое решение:

begin
   writeln(5*7.3); // выводим произведение литералов
end.

Хотя по хорошему лучше всегда выводить данные с пояснениями, например используя в качестве первого аргумента литерал:

begin
   writeln('5*7.3 = ', 5*7.3); // выводим произведение литералов
end.

Если же требуется вывести сумму переменных, то:

var  a: integer; // используем целый тип, так как 5 целое
 b: real; // 7.3 -- вещественное число, а потому объявляем её тип как real
begin
   a := 5;
   b := 7.3;
   writeln('otvet =', a*b); // выводим произведение переменных
end.

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

var  a: integer; // используем целый тип, так как 5 целое
   b: real; { мы  будем записывать сюда  7.3 -- вещественное число,
                      а потому объявляем её  тип как real }
   c: real; // для результата
begin
   a := 5;
   b := 7.3;
   c := a*b; // сравниваем значения переменных и записываем результат в  переменную с
   writeln('otvet =', c); // выводим значение переменной на экран
end.

Пример №2

Пусть есть задача:

Присвойте трем переменных значения $34$, $36.7$ и $7.3$, в четвертую переменную запишите разность между произведением первой и второй переменной и суммой второй и третей и выведете её значение на экран.

Решение:

var
 a :integer; // для 34 достаточно типа integer
 b, c : real; // вторая и третья (дробные числа)
 d : real; // сюда запишем результат
begin
 //для начала выполним присваивания по  условию задачи
 a := 34;
 b := 36.7;
 c := 7.3;
 
 d :=  a * b - (b + c); //  "разность между произведением первой и второй переменной  и суммой  второй и третей"

  writeln(d);  // "и выведете её значение на экран"
  writeln('otvet: ', d); // то же самое, но  c пояснением
end.

Для переменной $d$ нам пришлось использовать тип real, так как выражении:

a * b - (b + c)

две переменные были вещественного типа, а значит переменная $a$ тоже была бы неявно приведена к вещественному типу (а её значение 34 к 34.0) и результат выражения имел вещественный тип, а присваивать результат вещественного типа переменной целого типа нельзя (об этому говорилось в этом уроке выше и в предыдущем уроке), как как в этом случае неявное преобразование для присваивания не сработает (см. выше первый случай когда имеет место быть неявное преобразование типов).

Вопросы & Задачи

Теоретические вопросы:

  1. Что такое операнд? Приведите примеры операндов и операций.
  2. Для чего нужен тип real?
  3. Что такое неявное приведение типа и когда оно работает?
  4. Происходит ли приведение типа в выражениях (по каждому ответьте отдельно):
    5 + 2.3
    5 + 2/4
    4 + 2
    8.0 + 3
    8 + 3

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

  5. Что такое экспаненциальная форма записи числа? Запишите в такой форме числа:
    • 0.00045
    • 154567.34
    • 2.345
  6. Задачи:

  7. Выведите на экран сумму чисел $5$ и $7.3$
  8. Выведите на экран сумму значений двух переменных, со значениями $8$ и $71.3$ (предварительно объявите эти переменные и присвойте им указанные значения).
  9. Выведите на экран сумму чисел $9$ и $4.3$, записав результат в переменную и используя для вывода уже значение переменной.
  10. Присвойте трем переменных значения $34$, $36.7$ и $7.3$, в четвертую переменную запишите разность между произведением и суммой первых трёх переменных и выведете значение на экран.