Консультация № 180529
31.10.2010, 23:02
56.55 руб.
0 17 1
Заголовок: Ряды Тейлора, С++ (Linux)

Задание:
Написать программу нахождения массива значений функции
y[i]=sin(2*PI*i/N) i=[0,N-1] с использованием ряда Тейлора.

Пользователь задаёт значения N и количество n членов ряда Тейлора.
Для расчета каждого члена ряда Тейлора запускается отдельный
процесс и его результат (член ряда) записывается в файл. Каждый
процесс выводит на экран свой id и рассчитанное значение ряда.
Головной процесс суммирует все члены ряда Тейлора, и полученное
значение y[i] записывает в файл.
Проверить работу программы для значений N,n =[64,5] и N,n =[32768,7].

Вопрос: Очень слабо с вышкой, поэтому не могу понять задание. Прошу помочь.
Ряд Тейлора не понял как на С++ реализовать.





Приложение:
Рассуждения(как я понимаю):
Пока без потоков, и вывода - там вроде понятно...

1. Сначала нужна такая функция?

Код:
 double Func1(int i, double N)
{
return 2 * PI * i/N;
};


2. Потом разложение sin в ряд Тейлора?

Код:
double sin_t(int i, int n)
{
//здесь ряд Тейлора
};


3. А потом в цикл все...

Код:
for(int i; i<n; i++)
{
sum += sin_t(i, Func1(i, N));
}


Пока пишу в VC++ 6 - здесь удобнее, а потом на Linux перенесу.
Спасибо.

Обсуждение

давно
Мастер-Эксперт
325460
1469
01.11.2010, 10:18
общий
на мой взгляд рассуждения правильные, ряд тейлора - Ряд Тейлора там есть тригонометрический функции.
Об авторе:
to live is to die
Неизвестный
01.11.2010, 11:18
общий
[$8721$] (-1)n/(2n+1)! [$215$] x2n+1
давно
Мастер-Эксперт
325460
1469
01.11.2010, 11:22
общий
да именно его и брать для n - ного члена.
Об авторе:
to live is to die
Неизвестный
01.11.2010, 11:29
общий
видел я эту формулу, но как её нормализовать для цикла и на с++ - вот в чем вопрос.
давно
Мастер-Эксперт
325460
1469
01.11.2010, 11:39
общий
#include <math.h>


long factorial (long a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}

double sin_t(int i, int n)
{
int fact=0;
fact=factorial (2i+1);
return ((pow(1, i)/fact)*pow(n, 2i+1));
};


к примеру так можно высчитать i ый член разложения в ряд.
Об авторе:
to live is to die
давно
Профессор
230118
3054
01.11.2010, 13:45
общий
Simuk:
Не получится, потому что в Linux совершенно по-другому организованы процессы. Само задание для вычисления одного числа запускать процесс - удивляет.
давно
Профессор
230118
3054
01.11.2010, 13:50
общий
Simuk:
Могу написать без процессов, чтобы каждый член ряда вычислялся рекурсивно. Тому, кто придумал задание с процессами, выдвигаю на премию Дарвина.
Неизвестный
01.11.2010, 15:31
общий
Цитата: Асмик Гаряка
Тому, кто придумал задание с процессами, выдвигаю на премию Дарвина.

Это лабораторная работа по предмету "Теория вычислительных процессов и структур",
для 3 курса БГУИР(Белорусского Государственного Университета Информатики и Радиоэлектроники) - бывший Радиотехнический. Кстати, это начальный курс изучения Linux - интересно,
зачем такая головомойка на начальном этапе изучения. :)
Неизвестный
01.11.2010, 16:00
общий
То есть получается так?
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <math.h>

#define PI 3.141592

using namespace std;

long factorial (long a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
};

double Func1(int i, double N)
{
return 2 * PI * i/N;
};

double sin_t(int i, double x)
{
int fact=0;
fact=factorial(2*i+1);
return ((pow(1, i)/fact)*pow(x, 2*i+1));
};



int main(int argc, char* argv[])
{
system("cls");

int N = 0; // значение пользователя
int n = 0; //кол-во рядов
double sum = 0; // сумма ряда

cout << "vvod n = "; //ввод кол-ва рядов
cin >> n; cout << endl;

cout << "vvod N = "; // число пользователя
cin >> N; cout<< endl << endl;
N -= 1; // по условию i=[0,N-1] или здесь путаю с 'n'

for(int i = 0; i < n; i++)
{
cout << "sin_t = " << sin_t(i, Func1(i, N)) << endl; // вывод ряда
sum += sin_t(i, Func1(i, N)); // суммируем
}

cout << endl << sum << endl; // вывод суммы

system("pause");
return 0;
}
давно
Профессор
230118
3054
01.11.2010, 16:10
общий
Simuk:
Процесс Linux запускается командой fork, который возвращает pid, который надо записать в файл. Причем если запустить много процессов, нет гарантии, что они будут работать по очереди. Но так как от перестановки слагаемых сумма не меняется, это не страшно, но один процесс будет пытаться открыть файл, когда он занят другим(и неизвестно каким), поэтому надо будет организовать цикл ожидания.
Неизвестный
01.11.2010, 20:04
общий
Цитата: Асмик Гаряка
но один процесс будет пытаться открыть файл, когда он занят другим(и неизвестно каким), поэтому надо будет организовать цикл ожидания.

Зачем? А если заранее открыть - в каждый процесс ссылку на файл, и пусть пишут? Под win32 запись в файл несколькими потоками была нормально, но под Linux еще не знаю...
давно
Профессор
230118
3054
01.11.2010, 22:41
общий
Simuk:
Посмотрела - этого даже делать не надо, все файлы для всех процессов общие.
Неизвестный
02.11.2010, 21:16
общий
Simuk:
Написать эту бредовую задачу я написал. Но вот беда. Проблемы с инетом. Пишу со смарта. Выложу как отремонтируют.
Неизвестный
04.11.2010, 18:33
общий
это ответ
Здравствуйте, Simuk!
Программа:
Код:

/*
* File: main.cpp
* Author: Micren
*
* Created on 2 Ноябрь 2010 г., 18:07
*/

#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <limits>
#include <iostream>
#include <stdexcept>
#include <cerrno>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <fstream>
#include <string>
#include <iomanip>
#include <locale>

using namespace std;

/*
*
*/

// Имя временного файла для частичных сумм
const char* const TMP_FILE = "tmpfile";
// Имя файла для результатов
const char* const RESULT_FILE = "result";
// Точность выводимых данных
const streamsize PRECISION = 8;

// 2*PI
const double M_PIx2 = 2.0 * M_PI;

// Файл для результатов
wofstream fout(RESULT_FILE);

// Класс - файл
// Будем использовать низкоуровневый ввод/вывод и обернем это в класс

template<class T>
class file
{
static const size_t data_len = sizeof (T);
public:
// Конструктор
file(const char* const name, int flags);
// Деструктор
virtual ~file();
// Запись значений в файл
void put(T value);
// Читает из файла. Возвращет false если конец файла
bool get(T& result);
private:
int fd;
file(const file&);
file & operator=(const file&);
};

// Для ввода целых чисел
int input(const char* const msg);
// Вычисляет i-й член ряда для аргумента х
double elem(double x, int i);
// Вычисляет значение sin(2*PI*i/N) используя n членов ряда
double msin(double arg, int n) throw (runtime_error);

// Тут, думаю, все понятно

int main(int argc, char** argv)
{
int N = input("N="), n = input("n=");

// Выведем заголовок таблицы в файл результатов
// Для этого рассчитаем ширину столбцов
size_t w_i = log10(N) + 2;
size_t w_arg = log10(M_PIx2) + PRECISION + 3;
size_t w_res = PRECISION + 4;
wstring line(w_i + w_arg + 2 * w_res + 5, L'-');

fout.imbue(locale(""));
fout << L"Результаты вычисления ф-ии y=sin(2i/N) i=[0.." << N - 1 << L"].\nБерется членов в ряду Тейлора: " << n << L'.' << endl;
fout << line << endl;
fout << L'|' << setw(w_i) << L'i' << L'|' << setw(w_arg) << L'x' << L'|' << setw(w_res) << L"msin(x)" << L'|' << setw(w_res) << L"sin(x)" << L'|' << endl;
fout << line << endl;
fout.setf(ios_base::fixed);
fout.precision(PRECISION);

try
{
for (int i = 0; i < N; ++i)
{
double arg = M_PIx2 * i / N;
double result = msin(arg, n);
double etalon = sin(arg);

// Выводим результат
cout << "y[" << i << "]=" << result << "(" << etalon << ")" << endl;
fout << L'|' << setw(w_i) << i << L'|' << setw(w_arg) << arg << L'|' << setw(w_res) << result << L'|' << setw(w_res) << etalon << L'|' << endl;
fout << line << endl;
}
}
catch (exception& ex)
{
cerr << ex.what() << endl;
return EXIT_FAILURE;
}
catch (...)
{
cerr << "Черт! Неизвестное исключение" << endl;
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

int input(const char* const msg)
{
int res = 0;
while (true)
{
cout << msg;
cin >> res;
if (cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Ошибка ввода. Ожидается int." << endl;
}
else if (res <= 0)
{
cout << "Ожидается положительное число." << endl;
}
else
{
return res;
}
}
}

template<class T>
file<T>::file(const char* const name, int flags)
: fd(-1)
{
if ((fd = open(name, flags, S_IRUSR | S_IWUSR)) == -1)
{
throw runtime_error(strerror(errno));
};
}

template<class T>
file<T>::~file()
{
if (fd != -1 && close(fd) == -1)
{
throw runtime_error(strerror(errno));
}
}

template<class T>
void file<T>::put(T value)
{
if (fd == -1)
{
throw runtime_error("Файл не открыт");
}

char* buf = reinterpret_cast<char*> (&value);
size_t len = data_len;
ssize_t ret;
// Вообще то для обычных файлов такие ухищрения не нужны
// write() гарантированно записывает данные, если только не происходит какой-либо
// серьезной ошибки
while (len && (ret = write(fd, buf, len)))
{
if (ret == -1)
{
if (errno != EINTR)
{
throw runtime_error(strerror(errno));
}
continue;
}
buf += ret;
len -= ret;
}
}

template<class T>
bool file<T>::get(T& result)
{
if (fd == -1)
{
throw runtime_error("Файл не открыт");
}

T value;
char* buf = reinterpret_cast<char*> (&value);
size_t len = data_len;
ssize_t ret;


while (len && (ret = read(fd, buf, data_len)))
{
if (ret == -1)
{
if (errno != EINTR)
{
throw runtime_error(strerror(errno));
}
continue;
}
len -= ret;
buf += ret;
}
if (ret == 0)
{
return false;
}
result = value;
return true;
}

double elem(double x, int i)
{
double res = (i & 1) ? -1.0 : 1.0;
long p = 2l * i + 1;
while (p)
{
res *= x / p--;
}
return res;
}

double msin(double arg, int n) throw (runtime_error)
{
typedef file<double> dfile;

// Приведем к диапазону 0..2*PI, чтоб увеличить точность.
// Хотя оно и так лежит в этом диапазоне согласно условия, но в общем случае это надо
arg -= floor(arg / M_PIx2) * M_PIx2;
// Вообще то, для уменьшения погрешности, надо приводить к -PI/2..PI/2
// В условии этого нет. Так что можете удалить, если не надо.
// Соответственно, погрешность для больших углов будет больше.
if (arg > M_PI * 3 / 2)
{
arg -= M_PIx2;
}
else if (arg > M_PI_2)
{
arg = M_PI - arg;
}

// Откроем файл
dfile out(TMP_FILE, O_APPEND | O_CREAT | O_TRUNC | O_WRONLY);
// Считаем члены ряда
for (int j = 0; j < n; ++j)
{
// Создаем процесс
pid_t pid = fork();
// Для дочернего процесса
if (pid == 0)
{
try
{
// Считаем член
double val = elem(arg, j);
// Выводим чего надо по условию
cout << getpid() << " --> " << val << endl;
// И записываем в файл член ряда
out.put(val);
// Не забываем завершиться
exit(EXIT_SUCCESS);
}
catch (...)
{
exit(EXIT_FAILURE);
}
}
else if (pid == -1)
{
throw runtime_error(strerror(errno));
}
}
// Ждем пока есть потомки
errno = 0;
while (errno != ECHILD)
{
wait(0);
}
// Открываем файл для чтения
dfile in(TMP_FILE, O_RDONLY);
// Сразу удалим его.
// В Linux так можно делать. На самом деле дисковое пространство не будет освобождено
// пока все дескрипторы, ссылающиеся на файл, не будут закрыты
// Не верите - проверьте сами:)
if (unlink(TMP_FILE) == -1)
{
throw runtime_error(strerror(errno));
}
// Сумма членов
double sum = 0;
double val;
// Читаем и суммируем пока не конец
while (in.get(val))
{
sum += val;
}
return sum;
}


Пример работы.
Консоль:
Код:

N=20
n=5
21382 --> 0
21383 --> -0
21384 --> 0
21385 --> -0
21386 --> 0
y[0]=0(0)
21387 --> 0.314159
21388 --> -0.00516771
21389 --> 2.55016e-05
21390 --> -5.99265e-08
21391 --> 8.21459e-11
y[1]=0.309017(0.309017)
21392 --> 0.628319
21393 --> -0.0413417
21394 --> 0.000816052
21395 --> -7.67059e-06
21396 --> 4.20587e-08
y[2]=0.587785(0.587785)
21397 --> 0.942478
21398 --> -0.139528
21399 --> 0.0061969
21400 --> -0.000131059
21401 --> 1.61688e-06
y[3]=0.809017(0.809017)
21402 --> 1.25664
21403 --> -0.330734
21404 --> 0.0261137
21405 --> -0.000981835
21406 --> 2.15341e-05
y[4]=0.951057(0.951057)
21407 --> 1.5708
21408 --> -0.645964
21409 --> 0.0796926
21410 --> -0.00468175
21411 --> 0.000160441
y[5]=1(1)
21412 --> 1.25664
21413 --> -0.330734
21414 --> 0.0261137
21415 --> -0.000981835
21416 --> 2.15341e-05
y[6]=0.951057(0.951057)
21417 --> 0.942478
21418 --> -0.139528
21419 --> 0.0061969
21420 --> -0.000131059
21421 --> 1.61688e-06
y[7]=0.809017(0.809017)
21422 --> 0.628319
21423 --> -0.0413417
21424 --> 0.000816052
21425 --> -7.67059e-06
21426 --> 4.20587e-08
y[8]=0.587785(0.587785)
21427 --> 0.314159
21428 --> -0.00516771
21429 --> 2.55016e-05
21430 --> -5.99265e-08
21431 --> 8.21459e-11
y[9]=0.309017(0.309017)
21432 --> 0
21433 --> -0
21434 --> 0
21435 --> -0
21436 --> 0
y[10]=0(1.22465e-16)
21437 --> -0.314159
21438 --> 0.00516771
21439 --> -2.55016e-05
21440 --> 5.99265e-08
21441 --> -8.21459e-11
y[11]=-0.309017(-0.309017)
21442 --> -0.628319
21443 --> 0.0413417
21444 --> -0.000816052
21445 --> 7.67059e-06
21446 --> -4.20587e-08
y[12]=-0.587785(-0.587785)
21447 --> -0.942478
21448 --> 0.139528
21449 --> -0.0061969
21450 --> 0.000131059
21451 --> -1.61688e-06
y[13]=-0.809017(-0.809017)
21452 --> -1.25664
21453 --> 0.330734
21454 --> -0.0261137
21455 --> 0.000981835
21456 --> -2.15341e-05
y[14]=-0.951057(-0.951057)
21457 --> -1.5708
21458 --> 0.645964
21459 --> -0.0796926
21460 --> 0.00468175
21461 --> -0.000160441
y[15]=-1(-1)
21462 --> -1.25664
21463 --> 0.330734
21464 --> -0.0261137
21465 --> 0.000981835
21466 --> -2.15341e-05
y[16]=-0.951057(-0.951057)
21467 --> -0.942478
21468 --> 0.139528
21469 --> -0.0061969
21470 --> 0.000131059
21471 --> -1.61688e-06
y[17]=-0.809017(-0.809017)
21472 --> -0.628319
21473 --> 0.0413417
21474 --> -0.000816052
21475 --> 7.67059e-06
21476 --> -4.20587e-08
y[18]=-0.587785(-0.587785)
21477 --> -0.314159
21478 --> 0.00516771
21479 --> -2.55016e-05
21480 --> 5.99265e-08
21481 --> -8.21459e-11
y[19]=-0.309017(-0.309017)


Полученный файл результатов:
Код:

Результаты вычисления ф-ии y=sin(2i/N) i=[0..19].
Берется членов в ряду Тейлора: 5.
-------------------------------------------
| i| x| msin(x)| sin(x)|
-------------------------------------------
| 0| 0,00000000| 0,00000000| 0,00000000|
-------------------------------------------
| 1| 0,31415927| 0,30901699| 0,30901699|
-------------------------------------------
| 2| 0,62831853| 0,58778525| 0,58778525|
-------------------------------------------
| 3| 0,94247780| 0,80901701| 0,80901699|
-------------------------------------------
| 4| 1,25663706| 0,95105682| 0,95105652|
-------------------------------------------
| 5| 1,57079633| 1,00000354| 1,00000000|
-------------------------------------------
| 6| 1,88495559| 0,95105682| 0,95105652|
-------------------------------------------
| 7| 2,19911486| 0,80901701| 0,80901699|
-------------------------------------------
| 8| 2,51327412| 0,58778525| 0,58778525|
-------------------------------------------
| 9| 2,82743339| 0,30901699| 0,30901699|
-------------------------------------------
| 10| 3,14159265| 0,00000000| 0,00000000|
-------------------------------------------
| 11| 3,45575192| -0,30901699| -0,30901699|
-------------------------------------------
| 12| 3,76991118| -0,58778525| -0,58778525|
-------------------------------------------
| 13| 4,08407045| -0,80901701| -0,80901699|
-------------------------------------------
| 14| 4,39822972| -0,95105682| -0,95105652|
-------------------------------------------
| 15| 4,71238898| -1,00000354| -1,00000000|
-------------------------------------------
| 16| 5,02654825| -0,95105682| -0,95105652|
-------------------------------------------
| 17| 5,34070751| -0,80901701| -0,80901699|
-------------------------------------------
| 18| 5,65486678| -0,58778525| -0,58778525|
-------------------------------------------
| 19| 5,96902604| -0,30901699| -0,30901699|
-------------------------------------------
5
Неизвестный
04.11.2010, 23:38
общий
Цитата: 256539
Написать эту бредовую задачу я написал

Спасибо за задачу еще раз... только теперь придется к февралю "грызть" Linux, в с++ изучить наконец-то шаблоны,
перегрузку операторов, обработку исключений и т.д. - как-то надо соответствовать написанной программе:):)
Неизвестный
06.11.2010, 19:36
общий
В программе была допущена неточность. Исправил.
Неизвестный
07.11.2010, 14:09
общий
Цитата: 256539
В программе была допущена неточность. Исправил.


Скобку перенес. Спасибо.
Форма ответа