Страница 1 из 2
Странное поведение Real
Добавлено: 25.10.2010 20:22:46
lillgrinn
Такая вот программа:
Код: Выделить всё
var
x,y: Real;
begin
x:=-2;
while x<=2 do
begin
if x=0
then writeln('При x=0 значение функции не существует')
else
begin
y:=1/x;
writeln('x=',x,' y=',y)
end;
x:=x+0.2;
end;
end.
Ветка "writeln('При x=0 значение функции не существует')" не выполняется ни разу. Однако, если заменить тип переменных на Extended то все работает нормально. С чем это может быть связано?
P.S.: Система: XUbuntu 10.04, Geany+FPC-compiler.
Re: Странное поведение Real
Добавлено: 25.10.2010 20:47:24
and
Курим учебник: вещественные числа проверять на равенство не стОит, чревато. Можно лишь считать их близость с необходимой точностью: Abs(a-b)<epsilon
В Вашем случае я бы советовал обернуть внутренности цикла в try-except с выносом "writeln('При x=0 значение функции не существует')" в except-часть.
Re: Странное поведение Real
Добавлено: 25.10.2010 20:56:17
alexrayne
попробуйте почитать здесь.
http://forum.sources.ru/index.php?showt ... try2471685вообще это глобальная беда плавающей запятой - если вы сравниваетет константы разной точности - то обычное сравнение несработает, надо перед сравнение оба числа округлять. у вас константа "0" - типа интегер, конвертнется в дефолтовый тип плавающего числа - что для ш486 и выше - extended. тобиш вы сравниваете extended и real.
по теории есть вариант создать переменную типа реал и присвоить ей 0.0, это бы сработало еслибы дельфа и фрюха работали с числами так как надо математикам, но программеры забивают болт на достоверность вычислений и на вообще осмысленность их. моя дисуссия\просьба к Флориану Кумпфу чтобы во фрюху встроили достоверное сравнение была отметена тем что задача хорошего компилятора - ничего не потерять - а именно непотерять лишние цифры в числах. то что при этом теряется смысл сравнения почемуто разработчиков фрюхи неколышит.
FPU х86 поддерживает специальные установки см math.SetPrecisionMode - возможно в вашем случае этого может хватить
Re: Странное поведение Real
Добавлено: 26.10.2010 09:12:32
lillgrinn
Информатика, 9 класс. Классическая задача на табулирование функции.
and писал(а):Курим учебник: вещественные числа проверять на равенство не стОит, чревато. Можно лишь считать их близость с необходимой точностью: Abs(a-b)<epsilon
В Вашем случае я бы советовал обернуть внутренности цикла в try-except с выносом "writeln('При x=0 значение функции не существует')" в except-часть.
Поскольку тема циклов достаточно "туго всасывается", то данный вариант вызовет глобальный фриз у 90% состава класса.
alexrayne писал(а):у вас константа "0" - типа интегер, конвертнется в дефолтовый тип плавающего числа - что для ш486 и выше - extended. тобиш вы сравниваете extended и real.
Т.е. выходом будет использовать вместо Real тип Extended, если имеет место сравнение дробных чисел с константами?
И что такое ш486?
К стати, такой результат наблюдается не только на Intel но и на AMD.
Re: Странное поведение Real
Добавлено: 26.10.2010 11:50:12
Mr.Smart
Используйте тип Double.
И что такое ш486?
i486 - линейка процессоров от Intel и клоны их от AMD (давно это было).
К стати, такой результат наблюдается не только на Intel но и на AMD.
В данном случае от процессора мало, что зависит.
Re: Странное поведение Real
Добавлено: 26.10.2010 12:39:26
lillgrinn
Mr.Smart писал(а):Используйте тип Double.
Не помогает.
Вот что выдаст на экран программа. Обратите внимание на значение близкое к нулю и на последнее значение. По логике, там должно быть 2.
Код: Выделить всё
x=-2.0000000000000000E+0000 y=-5.0000000000000000E-0001
x=-1.8000000000000000E+0000 y=-5.5555555555555556E-0001
x=-1.6000000000000000E+0000 y=-6.2500000000000000E-0001
x=-1.4000000000000000E+0000 y=-7.1428571428571429E-0001
x=-1.2000000000000000E+0000 y=-8.3333333333333333E-0001
x=-1.0000000000000000E+0000 y=-1.0000000000000000E+0000
x=-8.0000000000000000E-0001 y=-1.2500000000000000E+0000
x=-6.0000000000000000E-0001 y=-1.6666666666666667E+0000
x=-4.0000000000000000E-0001 y=-2.5000000000000000E+0000
x=-2.0000000000000000E-0001 y=-5.0000000000000000E+0000
x= 1.3552527156068805E-0019 y= 7.3786976294838206E+0018
x= 2.0000000000000000E-0001 y= 5.000000000000000E+0000
x= 4.0000000000000000E-0001 y= 2.5000000000000000E+0000
x= 6.0000000000000000E-0001 y= 1.6666666666666667E+0000
x= 8.0000000000000000E-0001 y= 1.2500000000000000E+0000
x= 1.0000000000000000E+0000 y= 1.0000000000000000E+0000
x= 1.2000000000000000E+0000 y= 8.3333333333333333E-0001
x= 1.4000000000000000E+0000 y= 7.1428571428571429E-0001
x= 1.6000000000000000E+0000 y= 6.2500000000000000E-0001
x= 1.8000000000000000E+0000 y= 5.5555555555555556E-0001
Mr.Smart писал(а):i486 - линейка процессоров от Intel и клоны их от AMD (давно это было).
Ну не так уж и давно. Моя первая программа на Pascal создавалась на ДВК-2.
У меня сложилось впечатление, что на уровне знаний ученика 9 класса, средствами Free Pascal данная задача не решаема. И это не проблема ученика, а проблема, скорее, компилятора.
Re: Странное поведение Real
Добавлено: 26.10.2010 12:50:36
Mr.Smart
а если так
Код: Выделить всё
uses math;
var
x,y: Double;
begin
x:=-2.0;
while x<=2.0 do
begin
if IsZero(x)//=0.0
then writeln('При x=0 значение функции не существует')
else
begin
y:=1.0/x;
writeln('x=',x,' y=',y)
end;
x:=x+0.2;
end;
ReadLn;
end.
Re: Странное поведение Real
Добавлено: 26.10.2010 13:06:58
lillgrinn
Прошу прощения за, возможно, глупый вопрос, но что означает эта конструкция "//=" в строке "if IsZero(x)//=0.0"?
Re: Странное поведение Real
Добавлено: 26.10.2010 13:11:40
Mr.Smart
// - комментарий. не обращайте внимания
Re: Странное поведение Real
Добавлено: 26.10.2010 13:47:23
lillgrinn
О! *краснеет* Привык к {...}
Указание дробной части в присвоении, заголовке цикла, увеличении переменной "х" сделано с целью правильного преобразования типов?
Спасибо. Приведенный вами вариант программы работает. Наверное он единственно возможный вариант решения данной проблемы.
Re: Странное поведение Real
Добавлено: 26.10.2010 14:26:23
alexrayne
Используйте тип Double.
дабл тут тоже не покатит - говорил же родной тип для х86 - екстендед. таки пользуйте везде extended.
имхо более правильно былобы попробовать вместо сравнения с 0.0 сравнивать с eps типа того:
Код: Выделить всё
const eps : extended = 0.0; //или заданый порог
begin
if abs(x) <= eps
then ....// авария
такой код имхо более математичен....
Re: Странное поведение Real
Добавлено: 26.10.2010 20:10:38
and
2lillgrinn: Функция IsZero из модуля Math как раз и делает то, что я написАл выше: оценивает на близость к нулю. Эпсилон по умолчанию равен константе minFloat.
Re: Странное поведение Real
Добавлено: 26.10.2010 22:52:55
alexrayne
Я в курсе что такое IsZero, но в теоремах математических да и в физике я встречал только такой вариант записи условия достаточной малости. я говорил именно о матетматическом стиле.
Вдобавок такой вариант сравнения позволяет легко настраивать епс для конкретных ситуаций.
Re: Странное поведение Real
Добавлено: 27.10.2010 03:14:56
Sergei I. Gorelkin
В IsZero тоже можно передавать эпсилон вторым параметром...
Re: Странное поведение Real
Добавлено: 02.11.2010 10:50:34
Max Rusov
alexrayne писал(а):...родной тип для х86 - екстендед. таки пользуйте везде extended...
Double такой же "родной" как и Extended. Более того, в x64 Extended вообще не поддерживается, и используется только Double. Т.ч., пока не поздно, переходите на Double
