Странное поведение Real

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

Странное поведение Real

Сообщение lillgrinn » 25.10.2010 20:22:46

Такая вот программа:
Код: Выделить всё
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.
lillgrinn
новенький
 
Сообщения: 17
Зарегистрирован: 12.10.2007 11:14:28

Re: Странное поведение Real

Сообщение and » 25.10.2010 20:47:24

Курим учебник: вещественные числа проверять на равенство не стОит, чревато. Можно лишь считать их близость с необходимой точностью: Abs(a-b)<epsilon
В Вашем случае я бы советовал обернуть внутренности цикла в try-except с выносом "writeln('При x=0 значение функции не существует')" в except-часть.
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Re: Странное поведение Real

Сообщение alexrayne » 25.10.2010 20:56:17

попробуйте почитать здесь. http://forum.sources.ru/index.php?showt ... try2471685
вообще это глобальная беда плавающей запятой - если вы сравниваетет константы разной точности - то обычное сравнение несработает, надо перед сравнение оба числа округлять. у вас константа "0" - типа интегер, конвертнется в дефолтовый тип плавающего числа - что для ш486 и выше - extended. тобиш вы сравниваете extended и real.
по теории есть вариант создать переменную типа реал и присвоить ей 0.0, это бы сработало еслибы дельфа и фрюха работали с числами так как надо математикам, но программеры забивают болт на достоверность вычислений и на вообще осмысленность их. моя дисуссия\просьба к Флориану Кумпфу чтобы во фрюху встроили достоверное сравнение была отметена тем что задача хорошего компилятора - ничего не потерять - а именно непотерять лишние цифры в числах. то что при этом теряется смысл сравнения почемуто разработчиков фрюхи неколышит.
FPU х86 поддерживает специальные установки см math.SetPrecisionMode - возможно в вашем случае этого может хватить
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Странное поведение Real

Сообщение lillgrinn » 26.10.2010 09:12:32

Информатика, 9 класс. Классическая задача на табулирование функции.
and писал(а):Курим учебник: вещественные числа проверять на равенство не стОит, чревато. Можно лишь считать их близость с необходимой точностью: Abs(a-b)<epsilon
В Вашем случае я бы советовал обернуть внутренности цикла в try-except с выносом "writeln('При x=0 значение функции не существует')" в except-часть.

Поскольку тема циклов достаточно "туго всасывается", то данный вариант вызовет глобальный фриз у 90% состава класса.
alexrayne писал(а):у вас константа "0" - типа интегер, конвертнется в дефолтовый тип плавающего числа - что для ш486 и выше - extended. тобиш вы сравниваете extended и real.

Т.е. выходом будет использовать вместо Real тип Extended, если имеет место сравнение дробных чисел с константами?
И что такое ш486?
alexrayne писал(а):попробуйте почитать здесь. http://forum.sources.ru/index.php?showt ... try2471685

К стати, такой результат наблюдается не только на Intel но и на AMD.
lillgrinn
новенький
 
Сообщения: 17
Зарегистрирован: 12.10.2007 11:14:28

Re: Странное поведение Real

Сообщение Mr.Smart » 26.10.2010 11:50:12

Используйте тип Double.
И что такое ш486?

i486 - линейка процессоров от Intel и клоны их от AMD (давно это было).
К стати, такой результат наблюдается не только на Intel но и на AMD.

В данном случае от процессора мало, что зависит.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Странное поведение Real

Сообщение lillgrinn » 26.10.2010 12:39:26

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 данная задача не решаема. И это не проблема ученика, а проблема, скорее, компилятора.
lillgrinn
новенький
 
Сообщения: 17
Зарегистрирован: 12.10.2007 11:14:28

Re: Странное поведение Real

Сообщение Mr.Smart » 26.10.2010 12:50:36

а если так :wink:
Код: Выделить всё
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.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Странное поведение Real

Сообщение lillgrinn » 26.10.2010 13:06:58

Прошу прощения за, возможно, глупый вопрос, но что означает эта конструкция "//=" в строке "if IsZero(x)//=0.0"?
lillgrinn
новенький
 
Сообщения: 17
Зарегистрирован: 12.10.2007 11:14:28

Re: Странное поведение Real

Сообщение Mr.Smart » 26.10.2010 13:11:40

// - комментарий. не обращайте внимания
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Странное поведение Real

Сообщение lillgrinn » 26.10.2010 13:47:23

О! *краснеет* Привык к {...}
Указание дробной части в присвоении, заголовке цикла, увеличении переменной "х" сделано с целью правильного преобразования типов?

Спасибо. Приведенный вами вариант программы работает. Наверное он единственно возможный вариант решения данной проблемы.
lillgrinn
новенький
 
Сообщения: 17
Зарегистрирован: 12.10.2007 11:14:28

Re: Странное поведение Real

Сообщение alexrayne » 26.10.2010 14:26:23

Используйте тип Double.

дабл тут тоже не покатит - говорил же родной тип для х86 - екстендед. таки пользуйте везде extended.

имхо более правильно былобы попробовать вместо сравнения с 0.0 сравнивать с eps типа того:
Код: Выделить всё
const  eps : extended = 0.0; //или заданый порог

begin
    if abs(x) <= eps
    then ....// авария


такой код имхо более математичен....
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Странное поведение Real

Сообщение and » 26.10.2010 20:10:38

2lillgrinn: Функция IsZero из модуля Math как раз и делает то, что я написАл выше: оценивает на близость к нулю. Эпсилон по умолчанию равен константе minFloat.
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Re: Странное поведение Real

Сообщение alexrayne » 26.10.2010 22:52:55

Я в курсе что такое IsZero, но в теоремах математических да и в физике я встречал только такой вариант записи условия достаточной малости. я говорил именно о матетматическом стиле.
Вдобавок такой вариант сравнения позволяет легко настраивать епс для конкретных ситуаций.
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Странное поведение Real

Сообщение Sergei I. Gorelkin » 27.10.2010 03:14:56

В IsZero тоже можно передавать эпсилон вторым параметром...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Странное поведение Real

Сообщение Max Rusov » 02.11.2010 11:50:34

alexrayne писал(а):...родной тип для х86 - екстендед. таки пользуйте везде extended...

Double такой же "родной" как и Extended. Более того, в x64 Extended вообще не поддерживается, и используется только Double. Т.ч., пока не поздно, переходите на Double :)
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

След.

Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

Рейтинг@Mail.ru