2014 dxdy logo

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

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




Начать новую тему Ответить на тему
 
 Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 17:04 


24/05/10
2
Привет! Очень нужна помощь. Необходимо написать программу, реализующую метод Ньютона для СНУ.
Программа написана, но в ней 1 ошибка, никак не могу от нее избавиться! Подскажите, пожалуйста, что не так!
Вот текст программы:
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
  1. #include "stdafx.h"
  2. #include <math.h>
  3. #include <conio.h>
  4. // Количество уравнений
  5. const int n = 2;
  6. void GaussSolve (double *A,double *b,double *x);
  7. double f1(double *x);
  8. double f2(double *x);
  9. double df1_dx(double *x);
  10. double df1_dy(double *x);
  11. double df2_dx(double *x);
  12. double df2_dy(double *x);
  13. double norm (double *x);
  14. double fun(double *x);
  15. int main(int argc, char* argv[])
  16. {
  17.         int i, iter=0;
  18.         double *xk;
  19.         printf ("%s","Reshenie SNY metodom Newton\n");
  20.         fun(xk);
  21.         printf ("%s","Vektor resheniia: [ ");
  22.         for (i=0;i<n;i++)
  23.         {
  24.                 printf ("%f ",xk[i]);
  25.         }
  26.         printf ("%s","]\n");
  27.         printf ("Reshenie nadeno za %i iterazii\n",iter);
  28.         return 0;
  29. }
  30. double f1(double *x)
  31. {
  32.         return x[0]*x[1]+x[1]*x[1]+2;
  33. }
  34. double f2(double *x)
  35. {
  36.         return x[0]*x[1]*x[1]-3;
  37. }
  38. double df1_dx(double *x)
  39. {
  40.         return x[1];
  41. }
  42. double df1_dy(double *x)
  43. {
  44.         return x[0]+2*x[1];
  45. }
  46. double df2_dx(double *x)
  47. {
  48.         return x[1]*x[1];
  49. }
  50. double df2_dy(double *x)
  51. {
  52.         return 2*x[0]*x[1];
  53. }
  54. double norm (double *x)
  55. {
  56.         double sum = 0;
  57.         for (int i=0;i<n;i++)
  58.         {
  59.                 sum+=x[i]*x[i];
  60.         }
  61.         return sqrtf(sum);
  62. }
  63. double fun(double *x)
  64. {
  65.         int i, iter=0;
  66.         // Точность
  67.         double eps;
  68.         // Матрица
  69.         double **A;
  70.         // Вектор правых частей
  71.         double *b;
  72.         // Вектор решения
  73.         double *xk,*p;
  74.         // начальное приближение
  75.         xk[0]=1;xk[1]=1;
  76.         do
  77.         {
  78.                 iter++;
  79.                 for (i=0;i<n;i++)
  80.                 {
  81.                         x[i] = xk[i];
  82.                 }
  83.                 // Заполнение матрицы A
  84.                 A[0][0]=df1_dx(x); A[0][1]=df1_dy(x);
  85.                 A[1][0]=df2_dx(x); A[1][1]=df2_dy(x);
  86.                 // Заполнение вектора правых частей
  87.                 b[0]=-f1(x); b[1]=-f2(x);
  88.                 GaussSolve (A,b,p);
  89.                 // Получаем следующее приближение,
  90.                 // складывая предыдущее и вновь полученное
  91.                 for (i=0;i<n;i++)
  92.                 {
  93.                         xk[i] = x[i] + p[i];
  94.                 }
  95.         }
  96.         while (fabs(norm (x) - norm(xk))>=eps);
  97.         return xk[i];
  98. }
  99. void GaussSolve (double **A,double *b,double *x)
  100. // Решение СЛУ методом Гаусса
  101. {
  102.         const double eps=0.0001f;
  103.         double tmpValue;
  104.         int i,j,k,z;
  105.         double dblLeadElement;
  106.         // Прямой ход
  107.         for(i=0; i<n; i++)
  108.         {
  109.                   dblLeadElement=A[i][i];
  110.                   // Находим строку, в которой элемент, стоящий под ведущим - наибольший
  111.                   double tmpMax = dblLeadElement;
  112.                   int tmpMaxNumber = i;
  113.                   for (z=i;z<n;z++)
  114.                   {
  115.                           if (A[z][i]>tmpMax){tmpMax = A[z][i];tmpMaxNumber=z;}
  116.                   }
  117.                   // Меняем местами i-ю строку и строку tmpMaxNumber
  118.                   for (z=i;z<n;z++)
  119.                   {
  120.                           tmpValue = A[i][z];
  121.                           A[i][z] = A[tmpMaxNumber][z];
  122.                           A[tmpMaxNumber][z] = tmpValue;
  123.  
  124.                   }
  125.                   tmpValue = b[i];
  126.                   b[i] = b[tmpMaxNumber];
  127.                   b[tmpMaxNumber] = tmpValue;
  128.                   dblLeadElement = tmpMax;
  129.                   for(j=i; j<n; j++)
  130.                         {
  131.                                 A[i][j]/=dblLeadElement;
  132.                         }
  133.                         b[i]/=dblLeadElement;
  134.                   for(k=i+1; k<n; k++)
  135.                         {
  136.                            double dblToDivide=A[k][i]/A[i][i];
  137.                                 for(z=i;z<n; z++)
  138.                                 {
  139.                                     A[k][z]-=A[i][z]*dblToDivide;
  140.                                 }              
  141.                        
  142.                                 b[k]-=b[i]*dblToDivide;
  143.                         }
  144.         }
  145.         // Обратный ход
  146.         x[n-1]=b[n-1];
  147.     for(k=n-2; k>=0; k--)
  148.         {
  149.           double sum=b[k];
  150.           for(j=k+1; j<n; j++)
  151.                 {
  152.                         sum-=A[k][j]*x[j];
  153.                 }
  154.       x[k]=sum;
  155.         }
  156. }


А вот и ошибка!
error C2664: 'GaussSolve' : cannot convert parameter 1 from 'double **' to 'double *'

Очень надеюсь на вашу помощь!!!

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 17:21 
Заслуженный участник


09/08/09
3438
С.Петербург
Бросается в глаза следующее:
1. Описание функции GaussSolve в строке 6 не соответствует её определению в строке 99 (лучше убрать все описания функций в начале программы, main поместить в самый низ, а fun -- сразу над ней).
2. Работать всё равно не будет, ибо память под массивы вообще нигде не выделяется.
(Более подробно не смотрел).

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 17:22 
Заслуженный участник


04/05/09
4587
Inna_07, у вас forward declaration функции GaussSolve:
Код:
void GaussSolve (double *A,double *b,double *x);

И определение самой функции:
Код:
void GaussSolve (double **A,double *b,double *x)
// Решение СЛУ методом Гаусса
{

не совпадают. Если это единственная ошибка, то достаточно будет исправить forward declaration (добавить звёздочку).
В следующий раз, если пишете про ошибку компиляции, то указывайте и номер строчки, где ошибка.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 18:14 


24/05/10
2
Спасибо большое!!!! :)
ошибка ушла)))
теперь все запускается! только вот все равно не работает(
а нельзя немного подробнее про выделение памяти под массивы, наверное проблема в этом теперь.
просто никогда раньше не писала матрицы и векторы через *, но преподаватель говорит так нужно и все.
до попытки исправления мной программы с использованием *, она работала.
Еще раз спасибо!)

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение25.05.2010, 04:46 
Заслуженный участник


26/07/09
1559
Алматы
2Inna_07
Цитата:
а нельзя немного подробнее про выделение памяти под массивы

См. malloc(...) или calloc(...).

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение25.05.2010, 08:05 


04/02/08
325
Буково
Советую почитать "numerical receipes": там можно найти много чего полезного (уже готовые реализации наиболее популярных алгоритмов).

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 00:16 


25/03/10
4
Inna_07 в сообщении #323507 писал(а):
а нельзя немного подробнее про выделение памяти под массивы, наверное проблема в этом теперь

С++ не поддерживает массивы как таковые, передача массивов не предусмотрена стандартами. Можно передать указатель на первый элемент, далее все определяет программист. Передать в функцию массив НЕЛЬЗЯ. Или можно, но строго определенного размера.
malloc(...), calloc(...) выделяют область памяти, что с ней делать и как работать - определяет программист.
Почитайте Страуструпа, либо задавайте более конкретные вопросы.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 11:34 


26/01/10
959
Для начала я бы посоветовал написать программу со статическими массивами (когда сразу задается размер всех массивов и матриц). Вот, например, такая инструкция

Код:
dblLeadElement=A[i][i];

непонятно что делает, когда массив A имеет тип double **. Откуда компилятор знает, что такое A[i][j], если ему непонятно, какую длину имеют массивы A[i]? Это вообще не должно было компилироваться.

Также имейте в виду, что, передавая массив в качестве параметра, передается указатель на нулевой его элемент. Содержимое массива остаётся изменённым после выхода из функции. Если хотите передавать массив как локальную переменную, надо заводить новую структуру данных, в которой будет этот массив и конструктор копирования.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 13:44 
Заслуженный участник


04/05/09
4587
Zealint в сообщении #324818 писал(а):
Код:
dblLeadElement=A[i][i];

непонятно что делает, когда массив A имеет тип double **. Откуда компилятор знает, что такое A[i][j], если ему непонятно, какую длину имеют массивы A[i]? Это вообще не должно было компилироваться.
Вполне легальная конструкция. A - массив указателей на массивы double. Соответственно, выделять такой массив надо в два этапа - сначала выделяем массив указателей, а потом в каждом элементе выделяем массив double. Кстати, в этим случае можно иметь строки разной длины, например - треугольную матрицу.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 16:05 


26/01/10
959
venco в сообщении #324860 писал(а):
Вполне легальная конструкция. A - массив указателей на массивы double. Соответственно, выделять такой массив надо в два этапа - сначала выделяем массив указателей, а потом в каждом элементе выделяем массив double. Кстати, в этим случае можно иметь строки разной длины, например - треугольную матрицу.


Стойте-ка. Вот в данном конкретном случае откуда компилятор знает чему равно sizeof(A[i]), чтобы правильно определить то, где в памяти находится A[i][j]? Ведь автор программы нигде память не выделяет. Если автор задаст матрицу в виде double A[100][100], то, передавая её через double **, теряется информация о том, что каждая строка имеет размер 100*sizeof(double) байт. Я об этом пишу.

А в этом случае (как Вы пишите):

Код:
A = new double * [ N ];
for ( int i = 0; i < N; i ++ )
  A [ i ] = new double [ любое число ];


все понятно, здесь каждый указатель уже знает, куда указывает. Мы уже явно присвоили всем своё значение.

Кстати, многие неправильно освобождают память в таких случаях. Надо так:

Код:
for ( int i = 0; i < N; i ++ )
  delete [ ] A [ i ];
delete [ ] A;

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 16:12 
Заслуженный участник


04/05/09
4587
Zealint в сообщении #324910 писал(а):
Стойте-ка. Вот в данном конкретном случае откуда компилятор знает чему равно sizeof(A[i]), чтобы правильно определить то, где в памяти находится A[i][j]?
sizeof(A[i]) == sizeof(double*), и компилятор про это знает.

Zealint в сообщении #324910 писал(а):
Ведь автор программы нигде память не выделяет.
Ну, это проблема приведённой программы, а не конструкции double**.

Zealint в сообщении #324910 писал(а):
Если автор задаст матрицу в виде double A[100][100], то, передавая её через double **, теряется информация о том, что каждая строка имеет размер 100*sizeof(double) байт.
Если автор задаст матрицу в виде double A[100][100], то, передать её через double ** он не сможет ввиду несовместимости типов.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 17:59 


26/01/10
959
venco в сообщении #324915 писал(а):
Если автор задаст матрицу в виде double A[100][100], то, передать её через double ** он не сможет ввиду несовместимости типов.


В общем-то, я об этом и говорю, только в другом контексте. Ошибка компиляции будет, так как типы разные, а я как раз и говорю, почему они разные, несмотря на кажущуюся одинаковость. Автору надо либо динамически массив выделять, либо передавать как double A [ ] [100]. Я просто удивился, что это может компилироваться, но теперь разобрался: автор вообще забыл выделить память.

Цитата:
sizeof(A[i]) == sizeof(double*), и компилятор про это знает.

Нет, не знает. Если double A[100][100], то sizeof(A[i]) == 100*sizeof(double). Мы сейчас друг друга запутаем, кажется : ) Короче, я за то, чтобы автор переписал все через статическую память и убрал двойные указатели. Так будет легче понять, что он сам хотел написать.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 18:27 
Заслуженный участник


04/05/09
4587
Zealint в сообщении #324951 писал(а):
Цитата:
sizeof(A[i]) == sizeof(double*), и компилятор про это знает.

Нет, не знает. Если double A[100][100], то sizeof(A[i]) == 100*sizeof(double).
Но в программе-то double** A, поэтому sizeof(A[i]) == sizeof(double*).

Zealint в сообщении #324951 писал(а):
Короче, я за то, чтобы автор переписал все через статическую память и убрал двойные указатели. Так будет легче понять, что он сам хотел написать.
Вы, кажется, пропустили вот это:
Inna_07 в сообщении #323507 писал(а):
просто никогда раньше не писала матрицы и векторы через *, но преподаватель говорит так нужно и все.
до попытки исправления мной программы с использованием *, она работала.

 Профиль  
                  
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 19:03 


26/01/10
959
venco в сообщении #324961 писал(а):
Вы, кажется, пропустили вот это:
Inna_07 в сообщении #323507 писал(а):
просто никогда раньше не писала матрицы и векторы через *, но преподаватель говорит так нужно и все.
до попытки исправления мной программы с использованием *, она работала.


Точно, прошу прощения, удаляюсь...

А автору советую узнать, что такое функция malloc или оператор new (а также free и delete). Преподаватель, видимо, хочет, чтобы программа выделяла для работы столько памяти, сколько реально требуется. Напишите правильное выделение памяти, и если после этого не заработает, тогда Вам скажут, где ещё может быть ошибка.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



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

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


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group