TF1 GetParameter : accuracy is limited

Hello!

I have one problem with GetParameter method.
The accuracy is only 6 digits.
I try to fit my data without noise and I can’t give initial value.
For example, if the initial value is 100000.3, the fit value is 100000.
But if the the initial value is 99999.3, the fit value right and equal 99999.3.
It is really strange, because double or Double_t have range from 1.7E-308 to 1.7E+308.
This simple example reproduce my problem:

#include <iostream>
#include <vector>

#include "TRandom.h"
#include "TMath.h"
#include "TGraphErrors.h"
#include  "TF1.h"

//#include "MinimizerOptions.h"
#include "Math/MinimizerOptions.h"

using namespace std;

Double_t fitFunction(Double_t *x, Double_t *par)
{
	return pow((x[0] - par[2])*par[0], 2.0) + par[1];
}

int main()
{
	double noise_amp = 0;

	vector<double> xv;
	vector<double> yv;

	vector<double> xverr;
	vector<double> yverr;

	double a = 5;
	double y_0 = 3;
	//double x_0 = 100000.3; //error!
	double x_0 = 99999.3; // work well

	//fill vectors ...
	for (int i = -20 + x_0; i < x_0 + 20; i++)
	{
		xv.push_back(i);
		yv.push_back((pow((i - x_0) * a, 2.0) + y_0) + noise_amp*gRandom->Uniform(-1, 1));

		xverr.push_back(0);
		yverr.push_back(noise_amp);
	}

	TCanvas *c1 = new TCanvas("c1","A Simple Graph Example",200,10,700,500);
	c1->SetGrid();
	
	TGraphErrors * gr = new TGraphErrors(xv.size(), &xv[0], &yv[0], &xverr[0], &yverr[0]);
	TF1 *fitFcn = new TF1("fitFcn", fitFunction, -20 + x_0, x_0 + 20, 3);

	gr->SetMarkerColor(4);
	gr->SetMarkerStyle(kFullCircle);

	fitFcn->SetParameter(0, 1);
	fitFcn->SetParLimits(0, 0, 10);

	fitFcn->SetParameter(1, 1);
	fitFcn->SetParLimits(1, -100, 100);

	fitFcn->SetParameter(2, x_0);
	fitFcn->SetParLimits(2, -20 + x_0, 20 + x_0);

	
	ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit", "Simplex"); // change minimizer method
	gr->Fit("fitFcn", "R");
	gr->Draw("AP");
	
	cout << "Parameter(2) is " << fitFcn->GetParameter(2) << endl;

	return 0;
}

Hi,

here you are mixing two concepts: the precision with which you can represent a real number with a double precision floating point number and the stability of the fit.
Around 10^5 the density of double precision floating point numbers is still very high: I tend to exclude a precision issue.
Parameters’ values after a fit should not be depend on their initial values: if this happens, this is usually due to instabilities in the fit.
Said that, I wonder if the difference you see is really relevant in your setup.

Danilo

Hi,
I see you are using Simplex. Simplex is not using any function gradient information and it does not converge to the minimum as well as Migrad.
It could be useful only in some case for functions which have discontinuities in the derivatives or when Migrad fails to find a minimum. But I would always try to run Migrad after Simplex to find a better minimum value.

Best Regards

Lorenzo

Hello!

I think, you are not undestand me.
I draw points from this equation: y(x) = [a * (x - x_0) ] ^2 + y_0.
I have three initial parameters: a = 5, x_0 = 100000.3, y_0 = 3.
So my equation is y(x) = [5 * (x - 100000.3) ] ^2 + 3.
My xv array is {-20 + 100000, -19 +100000, …, 19 +100000}
and yv array is {y(-20 + 100000), y(-19 +100000), …, y(19 +100000)}.

Then I create TGraphErrors using xv and yv (xverr and yverr are filled with zero values) and fit
if by y(x) = [a * (x - x_0) ] ^2 + y_0.
So my graph is prntscr.com/8j5d8a

I check x_0 parameter from fit and my initial parameter x_0 = 100000.3.
They are not equal! This is error, because there is no reason to be different.

I see strange peaks in the spectrum (in my another programm) on integer numbers.
So I can’t make fit properly.
Small part of my data:
98620.2
98733.6
98799.2
98878.6
99465
100229
100373
100545
100676
100744
100825

I know this. When I use Simplex or Migrad with initial parameter x_0 = 99999.3 my fit parameter = 99999.3.
But when I use Simplex or Migrad with initial parameter x_0 = 100000.3 my fit parameter = 100000.

[code]// …
#include
#include
// …
std::cout << std::setprecision(17)
<< "Parameter(2) is " << fitFcn->GetParameter(2)
<< std::endl;

std::cout << std::setprecision(7)
<< "Parameter(2) is " << fitFcn->GetParameter(2)
<< std::endl;
// …[/code]

It works :smiley:
Thanks for helping me out with this project.
I owe you big time.