Множество действительных чисел в ТП представлено вещественными типами. За одним исключением, все они обладают определенной погрешностью при проведении арифметических операций.
Таблица свойств вещественных типов данных:
Вещественный тип |
Диапазон возможных значений |
Значащие цифры |
Размер в байтах |
Real |
|
11-12 |
6 |
Single |
|
7-8 |
4 |
Double |
|
15-16 |
8 |
Extended |
|
19-20 |
10 |
Comp |
|
19-20 |
8 |
Для типов Real, Single, Double и Extended в диапазон значений включается и отрицательная область.
Если компьютер не имеет встроенного математического сопроцессора, то удобнее всего использовать тип Real, так как разработчики ТП специально для него оптимизировали по скорости все операции. Остальные 4 типа являются специфичными для математического сопроцессора и должны использоваться с директивой компилятора {$N+}, которая указывает на его присутствии в системе, где будет исполняться программа. При отсутствии сопроцессора, с помощью директивы {$N+,E+} можно произвести его эмуляцию и применять в программе все вещественные типы.
Директива {$N+} замедляет скорость вычислений с типом Real, который является специфическим для ТП и не поддерживается сопроцессором. Таким образом, арифметические операции с типом Real предваряются переводом Real в Extended и завершаются обратным переводом.
При эмуляции математического сопроцессора по аналогичной причине замедляется обработка всех вещественных типов, кроме Real.
Тип Comp на самом деле не является вещественным. Это целочисленный тип с очень большим диапазоном значений (примерно от -1018 до 1018). Его удобно использовать в бухгалтерских расчетах, когда производятся операции над гигантскими суммами и требуется вести учет до последней копейки. Математический сопроцессор обрабатывает тип Comp методами, аналогичными для других вещественных типов.
Следующий пример отвечает на вопрос о точности вычислений для различных вещественных типов:
Задача 25. Вычислить выражение двумя способами:
1) последовательно слева направо
2) последовательно слева направо вычисляются , затем
, после чего второе значение вычитается из первого.
Определить, насколько будут отличаться результаты, полученные при первом и втором методах расчета.
Решение:
var s,s1,s2,s3:real;
i,sign:integer;
begin
{----- ПЕРВЫЙ способ -----}
s:=0;
sign:=1; {значение, с помощью которого меняется знак перед слагаемым}
for i:=1 to 100 do begin
s:=s+sign/i; {вычисляем сумму}
sign:=-sign; {меняем знак}
end;
{----- ВТОРОЙ способ -----}
s1:=0;
for i:=1 to 50 do s1:=s1+1/(i*2-1);{вычисляем сумму с нечетным знаменателем}
s2:=0;
for i:=1 to 50 do s2:=s2+1/(i*2);{вычисляем сумму с четным знаменателем}
s3:=s1-s2;{вычисляем разность между полученными значениями }
writeln(s);
writeln(s3);
writeln(s-s3);
readln;
end.
В результате выполнения программы на экране появятся 3 числа:
6.8817217931E-01
6.8817217931E-01
-9.0949470177E-12
Точность вычисления в данном случае составляет примерно 10-11.
Применим директиву компилятора {$N+, E+}, чтобы проанализировать работу программы при использовании математического сопроцессора. ($N - для подключения сопроцессора, $E - для эмуляции в случае его отсутствия):
{$N+, E+}
var s,s1,s2,s3:real;
i,sign:integer;
begin
...
Результат:
6.88172179303365E-0001
6.88172179314279E-0001
-1.09139364212751E-0011
Последовательно заменяя тип Real в программе на типы Single, Double и Extended получим следующие значения:
Для типа Single:
6.88171803951263E-0001
6.88172578811646E-0001
-7.74860382080078E-0007
Для типа Double:
6.88172179310196E-0001
6.88172179310195E-0001
3.33066907387547E-0016
Для типа Extended:
6.88172179310195E-0001
6.88172179310195E-0001
6.50521303491303E-0019
Как можно заметить, во всех случаях погрешность вычислений примерно соответствует заявленной в таблице. В то же время, результаты выполнения данной программы могут несколько различаться на компьютерах с различными видами сопроцессоров.
Вещественный тип можно преобразовать в порядковый (а конкретно - в целочисленный) с помощью двух функций:
function Round(X: Real): Longint;
function Trunc(X: Real): Longint;
Функция Round производит округление переданного ей вещественного значения до ближайшего целого.
Например:
Begin
Write(round(1.3),' ', round(2.7),' ', round(-7.3),' ', round(-15.5));
End.
В результате выполнения этой программы на экране появится строка, состоящая из 4 чисел: 1 3 -7 -16
Функция Trunc производит отбрасывание дробной части у переданного ей вещественного значения.
Например:
Begin
Write(trunc(1.3),' ', trunc(2.7),' ', trunc(-7.3),' ', trunc(-15.5));
End.
В результате выполнения этой программы на экране появится строка, состоящая из 4 чисел: 1 2 -7 -15
Отвечая на вопрос, какие вещественные типы целесообразнее использовать в различных ситуациях, мы можем посоветовать следующее:
Для простых, с небольшим объемом вещественных расчетов используйте тип Real.
Если у Вас в программе выполняются сложные математические расчеты, при этом очень важна точность, и достаточно как оперативной памяти, так и времени, используйте тип Extended.
Если объем памяти ограничен или требуется обработка больших вещественных массивов, и при этом точность вычислений не играет особой роли, используйте тип Single.
В ситуации, промежуточной между первыми двумя, используйте тип Double.
Если Вы выполняете расчеты с очень большими целыми числами, используете тип Comp.
Если у Вас отсутствует математический сопроцессор, а скорость выполнения программы играет решающую роль, используйте тип Real.