2014 dxdy logo

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

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




 
 Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 17:04 
Привет! Очень нужна помощь. Необходимо написать программу, реализующую метод Ньютона для СНУ.
Программа написана, но в ней 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 
Бросается в глаза следующее:
1. Описание функции GaussSolve в строке 6 не соответствует её определению в строке 99 (лучше убрать все описания функций в начале программы, main поместить в самый низ, а fun -- сразу над ней).
2. Работать всё равно не будет, ибо память под массивы вообще нигде не выделяется.
(Более подробно не смотрел).

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение24.05.2010, 17:22 
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 
Спасибо большое!!!! :)
ошибка ушла)))
теперь все запускается! только вот все равно не работает(
а нельзя немного подробнее про выделение памяти под массивы, наверное проблема в этом теперь.
просто никогда раньше не писала матрицы и векторы через *, но преподаватель говорит так нужно и все.
до попытки исправления мной программы с использованием *, она работала.
Еще раз спасибо!)

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение25.05.2010, 04:46 
2Inna_07
Цитата:
а нельзя немного подробнее про выделение памяти под массивы

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

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение25.05.2010, 08:05 
Советую почитать "numerical receipes": там можно найти много чего полезного (уже готовые реализации наиболее популярных алгоритмов).

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 00:16 
Inna_07 в сообщении #323507 писал(а):
а нельзя немного подробнее про выделение памяти под массивы, наверное проблема в этом теперь

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

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 11:34 
Для начала я бы посоветовал написать программу со статическими массивами (когда сразу задается размер всех массивов и матриц). Вот, например, такая инструкция

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

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

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

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 13:44 
Zealint в сообщении #324818 писал(а):
Код:
dblLeadElement=A[i][i];

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

 
 
 
 Re: Метод Ньютона для СНУ на Visual C++
Сообщение28.05.2010, 16:05 
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 
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 
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 
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 
venco в сообщении #324961 писал(а):
Вы, кажется, пропустили вот это:
Inna_07 в сообщении #323507 писал(а):
просто никогда раньше не писала матрицы и векторы через *, но преподаватель говорит так нужно и все.
до попытки исправления мной программы с использованием *, она работала.


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

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

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


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