2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 Решения ряда. При больших порядках программа выдает ошибку
Сообщение26.09.2010, 20:35 
Задание заключается в следующем: нужно вычислить значение функционального ряда $arcsin(x)$ до N-го порядка малости.

Ряд задан формулой: $arcsin(x)=x+\frac 1 {2*3}x^3+\frac {1*3}{2*4*5}x^5+\frac{1*3*5}{2*4*6*7}x^7+...$
Сразу задался вопросом, какой будет общий член у этого ряда. Свёл к следующему:
$\sum_{i=1}^n \frac{(-1)^2...(2(i-1)-1)^2}{(2i-1)!}x^{2i-1}$

Теперь нужно было реализовать программу, вот она:
код: [ скачать ] [ спрятать ]
Используется синтаксис Pascal
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Math;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Edit2: TEdit;
    Label3: TLabel;
    Label4: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
function proizv(n:integer):integer;
begin
if n>0 then
proizv:=sqr(2*n-1)*proizv(n-1)
else
proizv:=1;
end;
function factorial(p:integer):integer;
begin
if p>1 then
factorial:=p*factorial(p-1)
else
factorial:=1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var summ,x:real; n,i,p:integer;
begin
x:=strtofloat(edit1.Text);
n:=strtoint(edit2.Text);
i:=1;
summ:=0;
repeat
p:=2*i-1;
summ:=summ+(proizv(i-1)/factorial(p))*power(x,p);
i:=i+1;
until (i>n);
label1.caption:=floattostrf(summ,fffixed,6,3);

end;

end.


А теперь о проблеме.. Программа считает только малые порядки, у меня на n=15 программа ещё работает нормально, но при n=20 вылазиет ошибка:
Цитата:
project Project1.exe raised exception class EZeroDivide with message 'Floating point division by zero' Process stopped. Use Step or Run to continue
Не знаю как с этим бороться, может кто подскажет что я не так сделал? :roll:

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение26.09.2010, 22:00 
Elarium в сообщении #356489 писал(а):
Не знаю как с этим бороться, может кто подскажет что я не так сделал? :roll:
Как там ясно написано, вы делите на ноль.

P. S. Объявление function factorial(...) ужасно. Переделайте по-нормальному.

-- Пн сен 27, 2010 01:02:06 --

P. P. S. Остальной код не смотрел.

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение26.09.2010, 22:46 
arseniiv в сообщении #356516 писал(а):
Elarium в сообщении #356489 писал(а):
Не знаю как с этим бороться, может кто подскажет что я не так сделал? :roll:
Как там ясно написано, вы делите на ноль.

P. S. Объявление function factorial(...) ужасно. Переделайте по-нормальному.

-- Пн сен 27, 2010 01:02:06 --

P. P. S. Остальной код не смотрел.


Ну я попробую, но страно то, что для N<18 счет идет нормальный и на ноль ничего не делиться. :twisted:

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение26.09.2010, 22:51 
Elarium писал(а):
что я не так сделал?

Все не так сделали.

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 05:45 
У Вас переполнение integer при вычислении факториала, да и proizv() тоже.
До некоторого n вычисляемое значение факториала просто неправильное, а далее, когда в факториале наберётся достаточное количество делителей двоек, Ваша функция factorial() вообще будет возвращать ноль, отсюда и ошибка.
Простейшее исправление - изменить тип функций factorial() и proizv() на real.
Других ошибок не искал.

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 08:18 
venco

Надо начать с изменения алгоритма: так ряды не суммируют.

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 08:33 
y_nikolaenko в сообщении #356588 писал(а):
venco

Надо начать с изменения алгоритма: так ряды не суммируют.

Ну и как же их суммируют, если не секрет? :mrgreen:

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 09:14 
venco в сообщении #356571 писал(а):
До некоторого n вычисляемое значение факториала просто неправильное, а далее, когда в факториале наберётся достаточное количество делителей двоек, Ваша функция factorial() вообще будет возвращать ноль,

Так и есть. Тип integer (в дельфях) -- четырёхбайтовый, и как раз $33!=(2\cdot17-1)!$ нуля ещё не даёт (хотя даёт, конечно, чёрт-те что вместо истинного факториала, последнее правильное значение получается для $12!$), а $34!$, тем более $35!=(2\cdot18-1)!$ -- уже возвращает ноль.

Но главная проблема, конечно, в нелепости алгоритма. Во-первых, как уже было сказано y_nikolaenko, степенные ряды надо суммировать так:

Код:
y:=x;
S:=y;
for i:=1 to n do begin
    y:=y * <соответственно> * sqr(x);
    S:=S + y;
end;
(и, кстати, исходный вид разложения арксинуса гораздо приятнее для программирования, чем выражение с факториалами).

А во-вторых, нормальные люди не смешивают вычислительные и интерфейсные фрагменты в одну кучу. Какой ещё Button-то?... При чём тут вообще Button?... Выделите вычислительную часть в отдельную процедуру -- и ссылайтесь на неё по мере необходимости.

Ну и, конечно, выводить текст программы без отступов -- неприлично. Пользуйтесь тегом [ code].

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 14:33 

(Об отступах)

Ну, если заменить в том отрывке [quote] на [code] или даже [syntax=Pascal], отступы там сами не появятся. :-)

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 14:52 
Аватара пользователя
Выражение для общего члена ряда, при всей формально-математической правильности, для расчёта непригодно. Вычисления на ЭВМ всегда проводятся в конечной арифметике (ну... можно придумать тип данных, который позволил бы хранить произвольно большие числа... Но это спортивное достижение, а не прикладное; И, во всяком случае, если Вы ограничиваетесь стандартными типами языка, а не придумываете свои, нужно помнить их ограничения). Использование чисел, "не влезающих" в ячейку, отведенную под число, приводит к ошибке, причём может быть включена проверка выхода за границы диапазона (и тогда у Вас будет ясное сообщение, где вылетели), или отключена (и тогда в Вас в месте, где образуется ошибка, всё пройдёт, а вылетит совсем в другом месте).
В данном случае у Вас считается факториал, чрезвычайно быстро растущая функция ("продолжай далее - ты получишь числа, которые язык отказывается произнести, а рука записать" - а ведь автор "Книги Зогар" довёл таблицу факториалов лишь до 7!) и 20!=2432902008176640000 заведомо не влезет в разрядную сетку (максимальное число, представимое 4-мя байтами со знаком, есть 2147483647) и, скорее всего, бред пошёл, начиная с 12!. Разряды, не вмещавшиеся в 4 байта, просто обрубались, и к желаемым вычислениям отношения не имели.
Однако в Вашем случае нет надобности изобретать способ представления сверхдлинных чисел.
Достаточно сравнить два последовательных члена ряда. Отношение второго к первому будет весьма простым выражением (не забывайте про знак!), так что следующий член получается умножением уже имеющегося предыдущего на это выражение. Числа, которые там фигурируют, невелики и не вызовут переполнения.
Да, и чтоб два раза не вставать. Вычисление факториала рекурсией, при всей формальной правильности, решение не очень умное. Вызов функций достаточно накладная процедура, и работать будет крайне медленно. Если же ещё есть ограничения на глубину вложения вызовов (зависит от реализации компилятора), то у Вас вообще может не работать.

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 14:52 
Аватара пользователя

(Об отступах)

arseniiv в сообщении #356640 писал(а):
Ну, если заменить в том отрывке
Цитата:
на [code] или даже [syntax=Pascal], отступы там сами не появятся. :-)
Если их изначально не было, то, конечно, не появятся. А если были, то теги [code] или [syntax] их покажут (в отличие от [quote] или простого текста).

(Вставил syntax в исходное сообщение).

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 15:27 

(Оффтоп)

Евгений Машеров в сообщении #356645 писал(а):
и, скорее всего, бред пошёл, начиная с 12!.

Нет, на 12-ти всё ещё верно, бред -- с 13-ти.

Евгений Машеров в сообщении #356645 писал(а):
Выражение для общего члена ряда, при всей формально-математической правильности, для расчёта непригодно.

Вполне пригодно, если использовать, как уже было предложено, вещественные типы (там ограничения на порядок довольно слабые). Просто нерационально по времени.

Евгений Машеров в сообщении #356645 писал(а):
Вызов функций достаточно накладная процедура, и работать будет крайне медленно.

Наверное, медленно, но вовсе не крайне. В конце концов, вызов функции -- всего лишь две команды типа перехода, пусть и дальнего. Плюс загон операнда в стек, но это вообще тьфу.

Евгений Машеров в сообщении #356645 писал(а):
Если же ещё есть ограничения на глубину вложения вызовов (зависит от реализации компилятора), то у Вас вообще может не работать.

Практически это малосущественно: уж несколько-то десятков уровней в распоряжении будет, а больше для степенного ряда и не нужно (если не вблизи границы области сходимости, но тогда применение такого ряда просто не адекватно).

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 18:03 
Аватара пользователя
Ну, не знаю, ряд, где менее сотни членов ещё очень далеко от решения, как-то не вполне невозможен...

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение27.09.2010, 23:01 

(Оффтоп)

Евгений Машеров в сообщении #356695 писал(а):
Ну, не знаю, ряд, где менее сотни членов ещё очень далеко от решения, как-то не вполне невозможен...

Нет, не невозможен, конечно. Но что неразумен -- то точно. В типичных ситуациях, и при разумных подходах к способу аппроксимации -- количество членов имеет примерно тот же порядок, что и количество получаемых при этом значащих цифр.

Конкретно для арксинуса, в качестве примера. Если аргумент не превышает половинки, скажем, то шибко много членов и не понадобится. Но если он, наоборот, приближается к единичке -- то использование конкретно этого ряда становится явно неадекватным. Ну и кто ж виноват, коли приспичивает его использование в неподходящей ситуации?...

 
 
 
 Re: Решения ряда. При больших порядках программа выдает ошибку
Сообщение28.09.2010, 18:30 
Аватара пользователя
С арксинусом ситуация приятная. Там есть очевидные приведения к "хорошим" значениям аргумента. Увы, не всегда везёт.

 
 
 [ Сообщений: 15 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group