Помощь - Поиск - Пользователи - Календарь
Полная версия: Как преобразовать Integer в Real
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Xelix
Код
Program LR10;
Uses CRT,graph;
Procedure GrOnScr;
Var
  y,x:real;
  expo:real;
  i,i2:integer;
  yscr:integer;
  dr,rm:integer;
Begin
   dr:=detect;
   InitGraph(dr,rm,'D:\TP7\BIN');
   MoveTo(0,240);
   LineTo(640,240);
   Moveto(320,0);
   LineTo(320,480);
   MoveTo(0,240);
   SetLineStyle(0,Solidln,1);
   yscr:=0;
   i:=1;
   Repeat
      [b]yscr:=Round((7*sqr(i)*(exp(-5*i)))*480/640+240);[/b]
         If i<=640 Then
            LineTo(i,yscr);
         PutPixel(Random(640),Random(480),Random(5));
         Delay(500);
         PutPixel(Random(640),Random(480),Random(5));
         i:=i+1;
   Until keypressed;
End;
Begin
   GrOnScr;
   ReadKey;
End.


В выделенной строке компилятор выдаёт ошибку floating point overflow. Что делать?
polic
какая из них выделенная?
Xelix
yscr:=Round((7*sqr(i)*(exp(-5*i)))*480/640+240);
мисс_граффити
дело не в переводе.
у меня вылетает при i=18...
причем пишет про overflow - то есть переполнение. почему оно возникает: exp(-90)=1/exp(90)
exp(90)=1.22*10^39
многовато....
Xelix
Так как исправить положение? Когда отключаю комментами функцию экспоненты всё работает. Работает и когда из экспоненты убираю i
мисс_граффити
у функции exp и аргумент, и возвращаемое значение - real
либо делай проверку и при больших х заменяй в формуле эту эксопоненту на 0, либо пиши свою функцию с более емким типом.
Гость
НО тут же подэкспоненциальное выражение максимум выходит -3200! О каком переполнении reala может идти речь? Может можно как-то заменить именно эту функуцию через логарифм например? Лично мне кажется, что тут всё же паскаль ругается из-за того, что i-переменная типа интеджер. Так как же её перевести в real?
volvo
Integer -> Real переводится автоматически, проблема не в этом... Попробуй поменять тип с Real на Double и первой строкой программы сделать {$N+}
мисс_граффити
Цитата(Гость @ 23.12.2006 21:53) *

Лично мне кажется, что тут всё же паскаль ругается из-за того, что i-переменная типа интеджер. Так как же её перевести в real?

Угу. Именно так и есть, конечно.
Маленьких интеджеров (до 18) паскаль не боится, а потом пугается и решает в real не переводить - мало ли что.

А то, что вылетает на примерно 10^39, а граница диапазона real'а - 1.7*10^38 - совпадение!

Как ты думаешь, если процедура получает и возвращает результат типа real, внутри нее вычисления на каком типе ведутся?

Цитата
Попробуй поменять тип с Real на Double

Тип чего?
Xelix
А если же в этой строке убрать минус перед 5, то ошибка другая:
"Invalid floating poit operation"
volvo
Цитата
НО тут же подэкспоненциальное выражение максимум выходит -3200!
Правда? А если подумать? И сделать вот так, например:

Program LR10;
Uses CRT,graph;
Procedure GrOnScr;
Var
y,x:real;
expo:real;
i,i2:integer;
yscr:integer;
Begin
yscr:=0;
i:=1;
Repeat
writeln('i = ', i);
yscr:=Round((7*sqr(i)*(exp(-5*i)))*480/640+240);
If i<=640 Then
writeln('lineto', i, ' ', yscr);
i:=i+1;
Until keypressed;
End;
Begin
GrOnScr;
ReadKey;
End.
, то при каком значении i программа вылетит? У меня получилось 2272!!! А значит, под экспонентой не -3200, а -11360... А теперь - небольшой эксперимент:

writeln(exp(-5 * 2271));
и смотрим на результат:
Цитата(Console)
3.85618613316889E-4932
Это при граничном значении, равном 3.4e-4932 для типа Extended!!! И что произойдет, если я еще чуть-чуть увеличу выражение под экспонентой? То, что и произошло у тебя, FP Overflow... Возражения?

Цитата
А если же в этой строке убрать минус перед 5
То значение, которое должно получиться в результате - не поместится в отводимое под тип место, и ... Результат ты видел ...
Xelix
Хорошо, проблема ясна - мы легко переполняем тип. А теперь извечный русский вопрос - что делать?
мисс_граффити
Цитата
У меня получилось 2272!!!

а у меня опять 18 (TP 7.0)

Гость, ты мои сообщения игнорируешь? Что ж, твое право.
volvo
Цитата
а у меня опять 18 (TP 7.0)
У меня тоже TP70, только поддержка сопроцессора у меня подключена в опциях компилера, поэтому у меня программа использует гораздо более емкий тип Extended (даже если в программе и фигурирует Real), а у тебя - именно Real, что влияет на результат...

FPC, кстати, вообще не сбоит - даже при i > 20000 blum.gif

Цитата
что делать?
Перейти на Extended и сделать так:

   Repeat
yscr:=Round((7*sqr(i)*(exp(-5*i)))*480/640+240);
If i<=640 Then LineTo(i,yscr)
Else Break; { <--- !!! }
PutPixel(Random(640),Random(480),Random(5));
Delay(500);
PutPixel(Random(640),Random(480),Random(5));
i:=i+1;
Until keypressed;
Xelix
Я ничьи сообщения не игнорирую, а наоборот, читаю все советы. В любом случае, нашёл кое-какой выход из положения, чтобы график качественно расовался как надо.
мисс_граффити
Цитата
FPC, кстати, вообще не сбоит - даже при i > 20000

делфи тоже...
Для
y:=round(exp(-i));
(y: integer) прекрасно работает, а вот для
y:=round(exp(i));
вылетает при i=44.
По-разному реализовано вычисление отрицательных степеней?
volvo
Цитата
По-разному реализовано вычисление отрицательных степеней?
Не путай исчезающе малое число и очень большое... Если в первом случае FPC/Delphi просто поступают логично, заменяя число с порядком почти -5000 обыкновенным нулем, то в случае с порядком +5000 - каким бы "умным" не был компилятор - ему просто некуда засунуть полученное число, и программа вылетит с переполнением типа...
мисс_граффити
это понятно.
я о другом...
про 44 написала просто для того, чтобы показать сопоставимость степеней, на которых происходит переполнение.

ну, грубо говоря, чтобы посчитать 5^-2 можно либо сначала посчитать 5^2 (вот здесь риск получить переполнение), а потом разделить на это единицу . А можно единицу 2 раза разделить на 5 (никакого переполнения).
Получается, в разных компиляторах одно и то же реализовано по-разному...
или в более "умных" вариантах просто вставлено условие типа если степень меньше скольки-то, то не заморачиваться с подсчетами и выдать 0?
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.