xoma писал(а):вот и результаты с обычным решение совпадают(как вы говорили при х = 1,4, 2 и -2)
Сходил на сайт Embarcadero в музей, скачал Turbo Pascal 5.5, рассказываю...
Модифицируем программку так, чтобы явно выводилась выбранная ветка вычислений, например:
- Код: Выделить всё
const
a = 1.65;
b = 1.4;
var
x: real;
begin
write('x = '); readln(x);
if x < b then
writeln('x < ', b:0:1, ', Q(', x:0, ') = ', pi * sqr(x) - 7 / sqr(x):0:4)
else if x = b then
writeln('x = ', b:0:1, ', Q(', x:0, ') = ', a * sqr(x) * x + 7 * sqrt(x):0:4)
else
writeln('x > ', b:0:1, ', Q(', x:0, ') = ', ln(x + 7 * sqrt(abs(x + a))) / ln(10):0:4);
end.
Прогон 1:
- Код: Выделить всё
x = 1.4
x = 1.4, Q( 1.4E+00) = 12.8101
А теперь несколько изменим настройки компиляции, в настройках среды включим использование математического сопроцессора или передадим соответствующий параметр компилятору (а можно добавить в начале программы директиву {$N+}, делающую то же самое).
Прогон 2:
- Код: Выделить всё
x = 1.4
x < 1.4, Q( 1.4E+0000) = 2.5861
Одна и та же программа повела себя по-разному. Во втором случае введённое с клавиатуры 1.4 меньше 1.4, использованного внутри программы
При b=1.6 было бы больше, а при b=1.5 работоспособность сохранилась бы, поскольку 1.5 имеет точное представление в формате IEEE-754.
В чём же дело? Во времена процессоров 8080, 8086, 80286, 80386 математический сопроцессор был штукой относительно редкой, поэтому в состав Turbo/Borland Pascal включена библиотека, программно реализующая работу с вещественной арифметикой средствами центрального процессора, естественно, существенно медленнее аппаратного решения. Её разработчики учли неминуемые погрешности при вычислении. Начиная с 486 ситуация стала противоположной, математический сопроцессор встроили в CPU (да, продавались 486sx, но это всего лишь брак -- годный CPU с нерабочим сопроцессором). А вот мат.сопроцессоры ещё со времён 8087 считают как показано во втором прогоне.
Если правильно путаю, в Free Pascal получить результаты как в прогоне 1 не удастся, поскольку возможность действительной арифметики без использования сопроцессора отсутствует. Поэтому, если работу вашей программы будут проверять при помощи FPC, верного результата не получится. Изменения, как уже говорил, минимальны:
- Код: Выделить всё
const
eps = 1e-7;
a = 1.65;
b = 1.4;
var
x: real;
begin
write('x = '); readln(x);
if abs(x - b) < eps then
writeln('x = ', b:0:1, ', Q(', x:0, ') = ', a * sqr(x) * x + 7 * sqrt(x):0:4)
else if x < b then
writeln('x < ', b:0:1, ', Q(', x:0, ') = ', pi * sqr(x) - 7 / sqr(x):0:4)
else
writeln('x > ', b:0:1, ', Q(', x:0, ') = ', ln(x + 7 * sqrt(abs(x + a))) / ln(10):0:4);
end.
Обратите внимание на перенос условия проверки на равенство в начало -- это делать обязательно, иначе стоящее ранее условие x < 1.4 сработает (помните прогон 2, введённое 1.4 было меньше) и до проверки на равенство дело не дойдёт.
Формат вывода :0:4 заставит использовать 4 знака под дробную часть, а под целую часть: 1 позиция на знак числа плюс столько позиций, сколько нужно для правильного отображения целой части. Это число тоже можно вынести в константы для гибкого управления выводом, например,
- Код: Выделить всё
const
eps = 1e-7; prec = 3;
a = 1.65; b = 1.4;
var
x: real;
begin
write('x = '); readln(x);
if abs(x - b) < eps then
writeln('x = ', b:0:1, ', Q(', x:0, ') = ', a * sqr(x) * x + 7 * sqrt(x):0:prec)
else if x < b then
writeln('x < ', b:0:1, ', Q(', x:0, ') = ', pi * sqr(x) - 7 / sqr(x):0:prec)
else
writeln('x > ', b:0:1, ', Q(', x:0, ') = ', ln(x + 7 * sqrt(abs(x + a))) / ln(10):0:prec);
end.