Столкнулся я тут с проблемой. Есть набор значений функции  x[n] и y[n];
Функция одной переменной и n коэффициентов. Предположим:

И мне неизвестны коэффициенты a,b,c;
Я заглянул в гугл и подумал, что эту задачу лучше всего  решать методом градиентного спуска.
Я понимаю так этот алгоритм:
  Есть x[n],y[n] и F(x,args[m]), которая, предположительно, описывает зависимость y[n] от x[n].  
Шаг 1. - устанавливаем начальные значения args[m]. Вычисляем новый Y, назовём его Ych  
Шаг 2. - вычисляем сумму квадратов невязок (Y[i]-Ych[i])^2. если она не равна 0 то вычисляем градиент и вектор градиента.   
Шаг 3.Если модуль градиента не равен нулю. Изменяем каждый аргумент на значение вектора градиента.   
Шаг 4. переходим к шагу 2 
Наваял я такое изобилие 
#include <math.h>
//#include "Solover.h"
#include <iostream>
using namespace std;
struct GARDIENT {
        double* vector;//массив вектора гардиента
        int len;// длинна вектора
        double Norm;//значение гардиента
};
double deltaX = 1e-6; //шаг для дифиринцирования 
int len = 10; // длинна массива исходных точек 
int lenargs = 3;// длинна массива аргументов
double *x = new double[len]; //ИМХО массив иксов
double *y = new double[len]; //ИМХО массив Y
double *args = new double[lenargs]; // массив аргументов
double *Ych;// массив апроксимированных значений
double Funk(double x,double* args){
        // тестовая функция
        double a = args[0];
        double b = args[1];
        double c = args[2];     
        return a+b*(1-exp(c*x));
}
                
void countYch(){        
        // функция считает Y с текущими коеффициентами
                Ych = new double[len];
                for(int i =0;i<len;i++)
                        Ych[i]=Funk(x[i],args);
}
        
double SummAbsValsResiduals(){
// вычисление суммы квадратов невязок
                double Summ = 0;
                countYch();
                for (int i =0;i<len;i++){       
                        Summ+=pow((y[i]-Ych[i]),2);
                }
                return Summ;
}
        
double Derivative(int DerivativeVar){
        //производная
                args[DerivativeVar]-=deltaX;
                double Res1 = SummAbsValsResiduals();
                args[DerivativeVar]+=2*deltaX;
                double Res2 = SummAbsValsResiduals();
                double deltaY = Res2-Res1;
                args[DerivativeVar]-=deltaX;
                return deltaY/(2*deltaX);
}
        
        
GARDIENT Gardient(){
        //гардиент
                GARDIENT result;
                result.Norm = 0;
                result.len = lenargs;
                result.vector = new double[lenargs];
                for(int i =0;i<result.len ;i++){
                        double derivative = Derivative(i);
                        result.Norm = result.Norm+derivative*derivative;
                        result.vector[i]= derivative*deltaX;
                }
                result.Norm = sqrt(result.Norm);
                return result;
}
int main(){
        double a = 1;
        double b = 2;
        double c = 2;
        // исходные коэффициенты
        args[0]=a;
        args[1]=b;
        args[2]=c;
        for(int i = 0;i<len;i++){
                x[i]=i;
                y[i] = Funk(x[i],args);
        }
        
         //коефициенты поменялись
        args[0]=1;
        args[0]=2;
        args[0]=1;
        //их надо восстановить
        countYch();
        GARDIENT gar = Gardient();
        int n = 0;
        while((gar.Norm>0.1)&&(n<1e6)){
                // пока мы не пришли к локальному минимуму функции
                n++;
                countYch();
                gar = Gardient();
                for(int i =0;i<gar.len;i++){
                        args[i]=args[i]-gar.vector[i];
                }
                cout<<"----"<<gar.Norm<<endl;
                for(int i = 0;i<gar.len;i++){
                                cout<<"---->"<<gar.vector[i]<<endl;//значение вектор гардиента для каждой переменной 
                }
                cout<<"SUMM : "<<SummAbsValsResiduals()<<endl;// сумма на текущем этапе
        }
        return 1;
}
 
  Однако, изобилие работает паршиво. Можете ли мне подсказать почему? Я подозреваю в неправильной работе функцию вычисления производной или градиента. 
Производную я вычисляю вычисляя значения функции на отрезке + dx и -dx , и делю эти (dy1+dy2)/2dx
И порой, даже когда я в локальном минимуме, этот метод всё-равно мне даёт очень не хорошие значения , которые порой, становтся критическими для работы программы
Я подозреваю примерно в таких случаях:

как с этим бороться? Как правильно минимизировать сумму квадратом невязок?