Вопрос № 43396: Здравствуйте, уважаемые эксперты!
Прошу помощи в "детском" вопросе.
Вот такая есть программка (точнее, та выжимка, которая не работает как надо в другой программе)
---
program tabul;
var
x,y: real;
Begin
x:=...
Вопрос № 43.396
Здравствуйте, уважаемые эксперты!
Прошу помощи в "детском" вопросе.
Вот такая есть программка (точнее, та выжимка, которая не работает как надо в другой программе)
---
program tabul;
var
x,y: real;
Begin
x:=-1;
repeat
if x<3 then y:=2
else
y:=4;
if x=3 then y:=5;
writeln ('x= ',x,' y= ',y);
x:=x+0.2;
until (x>5);
readln;
End.
Ребенок спрашивает, почему при шаге 0.5 и 0.25 в цикле получаются одни результаты, а при шаге 0.2 - совершенно другой? (строка x:=x+0.2;)
А я не знаю, в чем тут тонкость, ибо ошибок вроде нет, тип переменных менять пробовали... Т.е. получается, что при шаге 0.2 почему-то нет X=3 или выплывает где-то мизерная погрешность (где?!). Пробовали и разные конструкции операторов If, и цикл While - все равно вылет именно на этой точке! Так в чем же дело, никак не пойму!
(кстати, еще при шаге 0.1 тоже врет, но в другую сторону)
Спасите, пожалуйста, от вскипания мозгов (или того, что у меня вместо них)!!
Отправлен: 17.05.2006, 20:26
Вопрос задала: Shapoklak (статус: Профессор)
Всего ответов: 4 Мини-форум вопроса >>> (сообщений: 1)
Отвечает: Ерёмин Андрей
Здравствуйте, Shapoklak!
Теоретически, здесь всё правильно. Но не совсем. Всё дело в типах. В данном случае, если сравнивать 3 и 3.00000... - то это получаются две разные вещи. Поэтому, вам следует округлить real-число, либо взять его целую часть. Например, если заменить условие так: if int(x)=3 then y:=5;, то вы на выходе получите значение y = 5 в пяти строчках (3.0, 3.2, 3.4, 3.6, 3.8). Как правильно реализовать это сходство - оставляю вам на размышление :-) Надеюсь, система понятна.
--------- Нет правила без исключений. Правило без исключений - исключение из правил.
Отвечает: Устинов Сергей Евгеньевич
Здравствуйте, Shapoklak!
Проблема в том, что точность типа real 11-12 знаков, т.е. во всех знаках дальше программа может ошибаться. Именно это и происходит в Вашей программе. Для того, чтобы обойти можно воспользоваться таким методом:
if int(x*100)=300 then y:=5
(но думаю ребенку объяснить это будет не совсем просто)
Удачи!!!
--------- Ответы на все вопросы - на сайте www.ya.ru :)
Ответ отправил: Устинов Сергей Евгеньевич (статус: 9-ый класс)
Ответ отправлен: 17.05.2006, 21:25 Оценка за ответ: 5 Комментарий оценки: Спасибо.
Отвечает: Сухомлин Кирилл Владимирович
Здравствуйте, Shapoklak!
Хотел дополнить.
Все правильно, сравнивать нельзя из-за округления.
Но почему все нормально для шагов 0.5 и 0.25?
Потому, что в программе, хотя вы и оперируете числами в десятичном формате, но реальное представление в памяти (в регистрах, во всём) - двоичное. А 1/5 в двоичном представление - периодическая дробь. Аналогия: попробуйте вычислить (1/3) + (2/3) на неинженерном калькуляторе - получите 0.99999...
Или то же самое даже на компьютере:
WriteLn(1/3 + 2/3);
А (1/4) + (3/4) всегда равно 1. Если, конечно, у калькулятора не 2 разряда ;-)
Приложение:
Ответ отправил: Сухомлин Кирилл Владимирович (статус: 5-ый класс)
Ответ отправлен: 17.05.2006, 21:37 Оценка за ответ: 5 Комментарий оценки: Действительно! И правда! Да конечно с тем, что такие погрешности есть, я сталкивалась многократно, но обычно ими можно было пренебречь, а тут такая программа, что это влияет, можно сказать, катастрофическим образом! Я думаю, авторы задачника вряд ли предполагали такой результат (в ответах текст примерно как приведенный) - наверное, не проверяли конечный результат
на практике. А какая великолепная иллюстрация ко многим темам...
Отвечает: Sarymian
Здравствуйте, Shapoklak!
Измените строку
writeln ('x= ',x,' y= ',y);
на строку
writeln ('x= ',x:2:2,' y= ',y:2:2);
Увидите отличие в отображение "Реальных" чисел.
Т.к. вы обьявили тип real то числа у вас отображаются как -1,(ля-ля тополя, т.е не целая часть)E+00А если поставить Х:3:2 то у вас будут отображатся только 3 знака до запятой и 2 знака после, т.е. более приятный вид отображения числа.
Ответ отправил: Sarymian (статус: 2-ой класс)
Ответ отправлен: 18.05.2006, 06:36