Finding erf using Maclaurin series breaks down around x = 5
5 views (last 30 days)
Show older comments
Phuwanut Pataratawinun
on 3 Mar 2022
Commented: Phuwanut Pataratawinun
on 6 Mar 2022
After I got around 2.9850991e+40 instead of 1 at x=10, I thought it may be related to precision, so I tried this code:
X = [0.5, 1, 5, 10]
for i = 1:length(X)
x = X(i)
fprintf('Actual: %#.8g', erf(x))
ErrorFunctionNew(x)
end
function ErrorFunctionNew(x)
SUM = vpa(0,1000);
for n = 0:100
N(1,n+1) = vpa(sym((((-1)^n)*(x^(2*n+1)))/(factorial(n)*(2*n+1))),1000);
end
%disp(N)
SUM = vpa(sum(N,'all'),1000);
base = vpa(sym(2/sqrt(pi)),1000);
Answer = base * SUM;
fprintf('Erf: %#.8g', Answer)
end
But it did not really help, what am I doing wrong, or is it just not possible with this formula?
Here is the source:
Update: The professor sent this code back after I messaged him for help with my revised code. (Question was homework, and deadline is still weeks away, but I guess he was leniant on this one)
x = 0.5;
Erf = 0;
sign = 1;
fac = 1;
for n = 0:500
Erf = Erf + sign*(x^(2*n+1))/(fac*(2*n+1));
sign = -sign;
fac = fac*(n+1)
end
Erf = Erf*2/sqrt(pi)
2 Comments
Jan
on 5 Mar 2022
Edited: Jan
on 5 Mar 2022
The faculty, power and exp are very expensive operations. Avoiding (-1)^n by a repeated multiplication by -1 is cheap. This works for x^(2*n+1) also:
x = 0.5;
Erf = 0;
sgn = 1;
fac = 1;
xp = x;
xpm = x * x;
for n = 0:500
% Sum of: (-1)^n * x^(2*n+1) / (factorial(n) * (2*n+1))
Erf = Erf + sgn * xp / (fac * (2 * n + 1));
sgn = -sgn; % (-1)^n
xp = xp * xpm; % x^(2n+1)
fac = fac * (n + 1); % faculty(n)
end
Erf = Erf * 2 / sqrt(pi);
Erf - erf(x)
The sum until 400 is a waste of time: fac is Inf for n=170 already and the following terms of the sum are 0, so insert:
if isinf(fac), break; end
For x=7 the method fails due to overflow.
Accepted Answer
Jan
on 4 Mar 2022
Edited: Jan
on 4 Mar 2022
Your code is almost correct and working, except for: factorial(n). When n is a double, this tends to overflow soon. So calculate the factorial symbolically also:
x = sym(7);
digits(200)
for n = 0:200
sn = sym(n);
N(1,n+1) = vpa(sym((((-1)^n) * (x^(2*n+1))) / (factorial(sn) * (2*n+1))));
% ^^
end
SUM = vpa(sum(N));
base = vpa(sym(2/sqrt(pi)));
Answer = vpa(base * SUM)
double(Answer - erf(x))
Now increasing the number of digits or the length of the sum does not increase the accuracy of the output. But why? Again: sym(2 / sqrt(pi)) is calculated with doubles at first.
base = vpa(sym(2) / sqrt(sym(pi)));
Answer = vpa(base * SUM)
double(Answer - erf(x))
Now digits(1000) and for n=0:400 increase the accuracy such that the deviation is 2e-196.
1 Comment
Torsten
on 5 Mar 2022
What about the recursion
N(1,1) = x;
N(1,n+1) = N(1,n) * (-1) * x^2 * (2*n-1)/(2*n+1) * 1/n ;
?
No factorial needed.
More Answers (2)
David Hill
on 3 Mar 2022
ERF=@(x)round(2/sqrt(pi)*integral(@(t)exp(-t.^2),0,x),8);%much easier using the integral definition
3 Comments
John D'Errico
on 3 Mar 2022
Edited: John D'Errico
on 4 Mar 2022
Do you expect that all infinite series are convergent? And sometimes, even a series that is theoretically convergent for all x, do not work, because of numerical problems, which would force you in theory to work in extremely high precision.
Note the comment in there about how the erf series is famously known for poor convergence even for x greater than only 1. A problem is the denominator coefficients do not go to zero quickly enough to kill off the numerator, until the number of terms grows very large. And since the terms have alternating signs, that kills you with massive subtractive cancellation. (If you don't know what that expression means, do some reading online.)
The problem is not in your code. It is the series itself. Having said that, are there tricks one can use? Well, yes. There are other series that are not technically Taylor series, but you are asking how to deal with erf in context of the Taylor series. As I recall, you can also work with the complimentary error function for large values of x. I'm sure there are other tricks one can do, but your question is purely in terms of the Taylor series.
Sorry, but you were effectively given this assignment to learn that things can get nasty, not to actually get a good answer.
Look at the terms, even for small x.
x = sym(5);
n = (0:10)';
vpa((-1).^n.*x.^(2*n+1)./(factorial(n).*(2*n+1)))
Do you see that each term is growing in size quickly? Eventually, the x^(2*n+1) will dominate. For example....
N = [20 40 60 80 100]';
vpa(x.^(2*N+1)./(factorial(N).*(2*N+1)))
So finally, after 100 terms, they are starting to get small. But if you look at the intermediate terms, you will see that massive subtractive cancellation kills your chances. If x is larger yet, like 10, things go to hell way worse. Again, this is a normal problem, given to students purely to see them squirm when they think they got things wrong. I can think of a few others that are classically nasty. Thank your instructor.
Seriously, if you really wanted to evaluate the error function, there are better approximation forms than the series you were told to use here. I would start by loooking in say Abramowitz & Stegun, where you might find perhaps a Pade approximant that will do better. And then I would look at the classic by JF Hart, "Computer Approximations", which surely has many such approximations.
3 Comments
Torsten
on 4 Mar 2022
I think John D'Errico is right:
This is a problem you should learn from, not solve it.
Jan
on 4 Mar 2022
Edited: Jan
on 4 Mar 2022
@John D'Errico: As soon as the factorial is evaluated with a high precision also, the strange result vanishes and the sum converges:
factorial(n) --> factorial(sym(n))
See Also
Categories
Find more on Special Functions in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!