Infinite loop in babylonian method for square roots - loops

In some specific numbers my algorithm gets stuck. It never reaches the minimum approximation so we never get out of the while. I think I can either low my approximation requisites or use double for my numbers, but I'm trying to figure out other solutions.
I'm programming a babylonian algorithm to calculate roots. First I'm doing this in C and later I will do this in Assembly(University homework). When I try to find the root of numbers like 99999 the program iterates to infinity. I have already tried two different stop conditions, one of them I did exactly like this tutorial from geeks4geeks(the first one inside the site).
https://www.geeksforgeeks.org/square-root-of-a-perfect-square/
The second stop condition I tested was this:
while ((x*x - n) > e) {}
I tried something like this because it is more "relatable" to the method enunciation. The full code is showed below:
#include <stdio.h>
#include <math.h>
/*Returns the square root of n. Note that the function */
float squareRoot(float n)
{
/*We are using n itself as initial approximation
This can definitely be improved */
float x = n;
float y = 1;
float e = 0.000001; /* e decides the accuracy level*/
while ((x*x - n) > e) {
x = (x + y) / 2;
y = n / x;
// if(prev_err == x-y){
// printf("A aproximação por ponto flutuante alcançou o máximo possível para o caso\n");
// return x;
// }
// prev_err = x-y;
}
return x;
}
/* Driver program to test above function*/
int main()
{
int n;
printf("Insira o número cuja raiz deseja calcular\n");
scanf("%d", &n);
printf("Square root of %d is %.8f\n", n, squareRoot(n));
return 0;
}

An absolute tolerance will never work. If n is large, x.x - n can remain large and the loop will never stop. If n is tiny, x.x - n can too quickly become small and the result will be quite inaccurate.
Your test has another big flaw: if x.x - n < e, the iterations will stop immediately if the LHS is negative, whatever its value.
The cure is to take the absolute value and a relative tolerance.
A better cure is to
adapt the starting approximation to the magnitude of n (such as the nearest power of 4),
use a fixed number of iterations (with a good starting approximation, 7 iterations are enough).

float only can take 4 Size (bytes),
so If you want to calculate the square root for number greater than 4 bytes
You need to replace all float to double
like this:
#include <stdio.h>
#include <math.h>
/*Returns the square root of n. Note that the function */
double squareRoot(double n)
{
/*We are using n itself as initial approximation
This can definitely be improved */
double x = n;
double y = 1;
double e = 0.000001; /* e decides the accuracy level*/
while ((x*x - n) > e) {
x = (x + y) / 2;
y = n / x;
// if(prev_err == x-y){
// printf("A aproximação por ponto flutuante alcançou o máximo possível para o caso\n");
// return x;
// }
// prev_err = x-y;
}
return x;
}
/* Driver program to test above function*/
int main()
{
int n;
printf("Insira o número cuja raiz deseja calcular\n");
scanf("%d", &n);
printf("Square root of %d is %.8f\n", n, squareRoot(n));
return 0;
}
if u want learn more about Primitive Data Types size in c:
Primitive Data Types sizes
https://www.programiz.com/c-programming/c-data-types#:~:text=The%20size%20of%20float%20(single,data%20type)%20is%208%20bytes.

Related

Find the series in C programming

Help me to find the sum of this series x^1+x^4+x^7+.. to n terms
#include<conio.h>
#include<math.h>
int main(int argc, char const *argv[]) {
int n;
float x;
int l=1;
printf(" Enter the value of x :");
scanf("%f",&x);
for (int i = 1; i <=n; i++)
{
l = pow(x,l+3);
}
printf("x ^ %d + power %d",x,l);
return 0;
}
I think this is what you want :) i've commented the errors
#include<conio.h>
#include<math.h>
int main(int argc, char const *argv[]) {
int n;
float x;
float l=0,i=0;
// initialize n first to determine how far the sum should go
printf(" Enter the value of n :");
scanf("%d",&n);
printf(" Enter the value of x :");
scanf("%f",&x);
for (int i = 0; i <n; i++)
{ //l+= pow(x,(i*3)+1); is equivilant to l= l+ pow(x,i+3); which i assume that's what you wanted to do
// l should be a float as well not int since x is a float
l+= pow(x,(i*3)+1);
if(i!=n-1)printf(" %f^%d +",x,i*3+1);
else printf("%f^%d",x,i*3+1);
}
printf("\nResult of the sum is %f",l);
return 0;
}
There's a problem in this loop:
for (int i = 1; i <=n; i++)
{
l = pow(x,l+3);
}
You set l every time and then in the end it has the value of the last assignment, but you wanted to add them all up. Also, it should be i in the pow call, not l+3, instead you should move that step of 3 to the loop increment. Try this:
int l = 0;
for (int i = 1; i <= n; i+=3)
{
l += pow(x, i);
}
Also make sure that you initialize n, you should probably read it in using scanf, just like you do with x.
Also note that since l is int, it's going to be truncated every time. If you don't want that, you should declare it as float instead, and depending on how precise the result should be, you might even want to consider double.
#include <stdio.h>
#include <math.h>
int main()
{
double x;
unsigned n;
fprintf(stderr, "enter x and n :");
/* enter x as a double and x as an unsigned number, both on the same line, and check 2 values are enter */
if (scanf("%lg %u", &x, &n) != 2)
puts("invalid or missing values");
else {
double r = 0; /* sum initialization */
int p = 1; /* the power to apply, 1 then 4 then 7 etc */
while (n--) { /* have to sum n times */
r += pow(x, p); /* x^1+x^4+x^7+... */
p += 3; /* next power value */
}
printf("%g\n", r);
}
return 0;
}
if I well understand n terms x^y must be added rather than the last pow is x^n, I use double for x and of course the result ( r )
Executions :
enter x and n :1.2 3
6.85678
enter x and n :2 1
2
Check with bc :
% bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=6
1.2 + 1.2^4 + 1.2^7
6.856780
Multiple operations on floating point numbers tend to compound rounding errors very quickly, so if you can minimize the number of operations, always do.
Now if you recognize that your polynomial is a Geometric series (see wikipedia article) with a = x and r = x^3, then we have the following pseudo-code algorithm (note no loops!):
Case 1 (x == 0): Sum == 0 regardless of n.
Case 2 (x == 1): Sum == n.
Case 3 (x any other number): Sum == x*(1-(x^(3*n)))/(1-(x^3)).
Case 4 (n==infinity and -1<x<1): Sum == x/(1-(x^3)).
I trust you can code accordingly.

Is there a simpler way to do this? How can I get rid of one of my while loops?

For my CS assignment we were asked to create a program to approximate pi using Viete's Formula. I have done that, however, I don't exactly like my code and was wondering if there was a way I could do it without using two while loops.
(My professor is asking us to use a while loop, so I want to keep at least one!)
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main()
{
double n, x, out, c, t, count, approx;
printf("enter the number of iterations to approximate pi\n");
scanf("%lf", &n);
c = 1;
out = 1;
t = 0;
count = 1;
x = sqrt(2);
while (count<=n)
{
t=t+1;
while (c<t)
{
x=sqrt(2+x);
c=c+1;
}
out=out*(x/2);
count=count+1;
}
approx=2/out;
printf("%lf is the approximation of pi\n", approx);
}
I just feel like my code could somehow be simpler, but I'm not sure how to simplify it.
Consider how many times the inner loop runs in each iteration of the outer loop
on the first iteration, it does not run at all (c == t == 1)
on each subsequent iteration, it runs exactly once (as t has been incremented once since the last iteration of the outer loop).
So you could replace this inner while with an if:
if (count > 1) {
once you do that, t and c are completely unnecessary and can be eliminated.
If you change the initial value of x (before the loop), you could have the first iteration calculate it here, thus getting rid of the if too. That leaves a minimal loop:
out = 1;
count = 1;
x = 0;
while (count<=n) {
x=sqrt(2+x);
out=out*(x/2);
count=count+1;
}
I just feel like my code could somehow be simpler, but I'm not sure how to simplify it.
I don't like the fact that I am using two while loops. I was wondering if there was a way to code this program using only one, rather than the two I am currently using
Seems simply enough to use a single loop.
OP's code, the while (c < t) loop, could be replaced with if (c < t) and achieve the same outcome. The loop is only executed 1 or 0 times. With an adjustment of initial c or t, the loop/block could executed exactly once each time. Thus negating the test completely.
A few additional adjustments are in Viete().
#include <stdio.h>
#include <math.h>
double Viete(unsigned n) {
const char *pi = "pi 3.141592653589793238462643383...";
puts(pi);
printf("m_pi=%.17f\n", acos(-1));
double term = sqrt(2.0);
double v = 1.0;
while (n-- > 0) {
v = v * term / 2;
printf("v_pi=%.17f %u\n", 2 / v, n);
term = sqrt(2 + term);
}
puts(pi);
return 2 / v;
}
int op_pi(unsigned n) {
unsigned c = 1;
unsigned t = 0;
unsigned count = 1;
double out = 1;
double x = sqrt(2);
while (count <= n) {
t = t + 1;
// while (c < t) {
// or
if (c < t) {
x = sqrt(2 + x);
c = c + 1;
}
out = out * (x / 2);
count = count + 1;
printf("%lf is the approximation of pi %u\n", 2 / out, count);
}
double approx = 2 / out;
printf("%lf is the approximation of pi\n", approx);
}
int main(void) {
op_pi(5);
Viete(5);
}
Output
2.828427 is the approximation of pi 2
3.061467 is the approximation of pi 3
3.121445 is the approximation of pi 4
3.136548 is the approximation of pi 5
3.140331 is the approximation of pi 6
3.140331 is the approximation of pi
pi 3.141592653589793238462643383...
m_pi=3.14159265358979312
v_pi=2.82842712474618985 4
v_pi=3.06146745892071825 3
v_pi=3.12144515225805197 2
v_pi=3.13654849054593887 1
v_pi=3.14033115695475251 0
pi 3.141592653589793238462643383...
Additional minor simplifications possible.

C program for calculating the value of e

I was assigned a Hw that required me to calculate the value of e via using the series:
1 + 1/1! + 1/2! + ...1/n!
The value of e must be calculated until the value of n (entered by the user) is reached. Also, the value of 1/n! must be calculated until it's value is smaller than epsilon (also entered by the user).
I wrote the code, but there are some errors that compiler is telling me errors such as relational comparisons, use of ';' etc. Could anyone please help me fix the error. Thank you in advance.
Below is my code:
#include<stdio.h>
int factorial (int i)
{
if (i==0)
return 1;
else
return i*factorial(i-1);
}
int main(void) {
int i,n;
float e,ep;
printf("what is the value of epsilon: ");
scanf("%f",&ep);
printf("what is the value of n: ");
scanf("%d",&n);
for (i=1; i<=n, i++)
e= 1+1/factorial(i);
for(1/fatorial(i)<=ep)
printf("The value of e for the entered value of epsilon and n:%f",e);
return 0;
}
For more precision I would use double instead of float.
for (i=1; i<=n, i++)
e= 1+1/factorial(i);
This is wrong, you are not adding to e, you are assigning always the last
value of the series, which is always 0 (except for i = 1). So your e will
always be 1.
factorial is a function that returns an int. A int divided by an int is
an int and in C anything 1/x (for x > 1, x integer) is 0. You you to use
1.0 or cast at least one of the arguments to double (or float if you are
using floats):
double e = 1; // initializing e
for(i = 1; i <= n; ++i)
e += 1.0/factorial(i);
Also, the value of 1/n! must be calculated until it's value is smaller than epsilon, also entered by the user.
I don't understand what that means, if n is a fixed value given by the user,
what do you keep calculating? Is this really what the exercise says?
My interpretation would be: if by n steps |e_real - e_calculated| > epsilon,
keep incrementing n, otherwise stop. That would be
#include <stdio.h>
#include <math.h>
#include <stdint.h>
uint64_t factorial (uint64_t i)
{
if (i==0)
return 1;
else
return i*factorial(i-1);
}
int main(void)
{
int n;
double e = 1;
double epsilon;
printf("what is the value of epsilon: ");
scanf("%lf", &epsilon);
printf("what is the value of n: ");
scanf("%d",&n);
int i = 1;
while(1)
{
e += 1.0/factorial(i++);
if(i >= n && (fabs(e - M_E) < epsilon))
break;
}
printf("e: %.20lf, calculated e: %.20lf, error: %.20lf, steps: %d\n", M_E, e, fabs(e-M_E), i);
return 0;
}
Note: if you are using GCC, you have to compile it with the -lm option:
$ gcc e.c -oe -lm
You're not summing the series but actually set e to 1.
Because you set it to e + 1/factorial(n) but your factorial() returns an int which is very likely to be above 1, so the division is integral, and 1 divided by any greater number will give 0.
The last loop is very strange. Did you mean while rather than for? Note that factorial is mistyped. Moreover, no work is done in the loop's body other than printing the same message over and over.

Approximating Sine(x) with a Taylor series in C and having a lot of problems

I'm trying to approximate sine(x) in C using a Taylor series and Stirling's approximation for factorials but I'm getting really weird answers for n<5 and -0 for any n=>5. I literally just started learning yesterday so i'd appreciate it if some more experienced programmers could take a look at it and tell me what's wrong
Taylor Series of Sine
Stirling's approximation of factorials
#include <stdio.h>
#include <math.h>
int main(){
float x,n,s,i,e,p,f,r;
f=M_PI;
e=2.7182818;
s=0;
printf("What value of sine do you want to apporximate?");
scanf("%f", &x);
printf("With what level of precision do you want to calculate it?");
scanf("%f", &n);
for(i=0;i<=n; ++i);{
r=((2*i)+1);
p=(sqrt(2*r*f)*(pow((r/e),r)));
s=s+(((pow((-1),i))*(pow(x,((2*i)+1))))/p);
}
printf("the value of sine at %f is %f",x,s);
}
Check your factorial function: it returns a double, but you will see that factorial of numbers like 8 or 10 are beyond the range of a double variable. Use long as returning type...
This line
for(i = 0; i <= n; ++i);{
has an extra semicolon. You're executing an empty loop.
BAsed on your formulat this is the correct code but it generate wrong output so you need to check again your formulat:
#include <stdio.h>
#include <math.h>
int main(){
double x,n,s,i,e,p,f;
f=M_PI;
e=2.7182818;
s=0;
int sign=0;// Adding this type to toggle the sign
printf("What value of sine do you want to apporximate?");
scanf("%lf", &x);// conversion specifier must be %lf for floating number
printf("With what level of precision do you want to calculate it?");
scanf("%lf", &n);
for(i=1;i<=n; i=i+2){ // Correcting the for loop
p=sqrt(2*i*f)*pow((i/e),i);
s=s+(pow(-1,sign++)*pow(x,i))/p;
}
printf("the value of sine at %f is %f",x,s);
}
this is easier bro
#include <iostream>
#include <cmath>
using namespace std;
double factorial(int X)
{
double factorial = 1;
for(int i=1; i<=X; i++)
{
factorial = factorial *i;
}
return factorial;
}
double Mysin(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow((-1),i)*pow(x,((2*i)+1))/factorial((2*i)+1);
}
return result;
}
double Mycos(double x,double result)
{
for(int i = 0;i<20;i++)
{
result+=pow(-1,i)*pow(x,2*i)/factorial(2*i);
}
return result;
}
double Mytan(double sine,double cosine)
{
return sine/cosine;
}
double deg_to_rad(double x)
{
double const pi = 3.14159265359;
return x*pi/180;
}
int main()
{
double x,result=0;
cin>>x;
cout<<"My sin: "<<Mysin(deg_to_rad(x),result)<<endl;
cout<<"My cosin: "<<Mycos(deg_to_rad(x),result)<<endl;
cout<<"My tan: "<<Mytan(Mysin(deg_to_rad(x),result),Mycos(deg_to_rad(x),result))<<endl;
return 0;
}
As the sin() is a periodic function, I should never go further than one period to calculate it. This simplifies too much mathematics, as you never need to calculate great factorial numbers. Indeed you even don't need to calculate the factorial for each term in the series, as the coefficients can be derived one from the last, by just dividing the previous coefficient by (n-1) and n. if your input is bounded to one period (well, you don't need to use a fixed period of M_PI, you can go let's say to a maximum value of 3.5 and reduce your answers for values greater by just reducing by the modulus of the division by M_PI.
Once said this, we can bind your maximum error, as for the greatest input of 3.5 we will have 3.5^n/n! as the last term of our approximation, with is bounded for some n to be less than some maximum error which fixes the number of terms we'll need to calculate.
Instead of trying to be precise with the number of terms needed to calculate, I'll try to do some guesses, from deriving an algorithm and showing actual values (for example, for the maximum input value of 3.2)
These are the values of the term at position n for input of 3.2 and
n | term at position n for input `3.2`
======+=================
8 | 0.27269634
12 | 0.00240693
16 | 0.00000578
18 | 0.00000019
20 | 0.00000001
21 | 7.9E-10
So we can stop on calculating just 20 terms of the series. This is true for the exp() function which has all terms added and is a simple function. For the sin() or cos() you can guess that a better error estimate if you consider that both have the same terms of the exp() function, (well the first has only the odd terms, the second has only the even terms)
(x^n)/(n!) - (x^(n+2))/((n+2)!) = (n!*x^n*(1 - x^2/((n+1)*(n+2))))/n!
that for n > 3.2 means each term is
< x^n/n!
so we can apply the same criterion as for the exponential.
This to say that we can stop at some point... if we continue our table we'll see that at, for example n > 30 the overall accumulated term is less than 5.3E-18 so we can stop there (for a double number, at least).
#include <stdio.h>
#include <math.h> /* for the system sin() function */
double MySin(double x) /* x must be in the range [0..3.2] */
{
int i;
const int n = 30;
double t = x, acum = x; /* first term, x/1! */
x *= x; /* square the argument so we get x^2 in variable x */
for (i = 3; i < n; i += 2) {
t = -t * x / i / (i-1); /* mutiply by -1, x^2 and divide by i and (i-1) */
acum += t; /* and add it to the accum */
}
return acum;
}
int main()
{
double arg;
for(;;) {
if (scanf("%lg", &arg) != 1)
break;
printf("MySin(%lg) = %lg; sin(%lg) = %lg\n",
arg, MySin(arg), arg, sin(arg));
}
}
If you take advantage from the symmetries that the sin function has, you can reduce your domain to M_PI/4 which is less than one, and you can stop even at term of power 18 to get around 17 significative digits (for a double) which makes your sin faster.
Finally, we can get a valid for all real domain sin2() function by:
double sin2(double x)
{
bool neg = false;
int ip = x / 2.0 / M_PI;
x -= 2.0 * M_PI * ip; /* reduce to first period [-2PI..2PI] */
if (x < 0.0) x += 2.0*M_PI; /* reduce to first period [0..2PI] */
if (x > M_PI) { x -= M_PI; neg = true; } /* ... first period negative [ 0..PI ] */
if (x > M_PI/2.0) x = M_PI - x; /* reflection [0..PI/2] */
return neg ? MySin(-x) : MySin(x);
}

Calculate sum of 1+(1/2!)+…+(1/n!) n number in C language

Like the title say, how I calculate the sum of n number of the form: 1+(1/2!)+⋯(1/n!)? I already got the code for the harmonic series:
#include <stdio.h>
int main( void )
{
int v=0,i,ch;
double x=0.;
printf("Introduce un número paracalcular la suma: ");
while(scanf("%d",&v)==0 || v<=0)
{
printf("Favor de introducir numeros reales positivos: ");
while((ch=getchar())!='\n')
if(ch==EOF)
return 1;
}
for (i=v; i>=1; i--)
x+=1./i;
printf("EL valor de la serie es %f\n", x);
getch();
return 0;
}
The question here is.. I already got the sum as the fraction, but how make the variable "i" factorial?
Note: I´m programming in language C, with DEV -C++ 4.9.9.2
You got a slightly more accurate answer for the harmonic summing 1./i + 1./(i-1) ... 1./1. Suggest you stay with that order.
[edit] Rewrite: Thanks to #pablo197 for pointing out the error of my ways.
To calculate harmonic and 1+(1/2!)+…+(1/n!), continue summing the least significant terms together first as that helps to minimize precision loss. Starting with the least significant term 1/n as sum, sum of that and the n-1 term is : sum = (1 + sum)/(n-1) and so on. (See below)
double x = 0.0;
double one_over_factorial_series = 0.0;
for (i = v; i >= 1; i--) {
x += 1.0/i;
one_over_factorial_series = (one_over_factorial_series + 1)/i;
}
printf("harmonic:%le\n", x);
// 2.828968e+00
printf("one_over_factorial:%.10le\n", one_over_factorial_series);
// 1.7182815256e+00
Add 1.0 or 1/0! to one_over_factorial_series, the result about e = 2.7182818284...
[Edit] Detail showing how direct n! calculation is avoided.
1 + (1/2!) + … + (1/n!) =
1/n! + 1/((n-1)!) + 1/((n-2)!) + 1/((n-3)!) + ... + 1 =
(1/n + 1)/((n-1)!) + 1/((n-2)!) + 1/((n-3)!) + ... + 1 =
((1/n + 1)/(n-1) + 1)/((n-2)!) + 1/((n-3)!) + ... + 1 =
...
((((1/n + 1)/(n-1) + 1)/(n-2) + 1)/(n-3) + 1)/(n-4) + ... =
If you're just looking for computing the first n factorials, I would suggest just computing them recursively, e.g.
factorial[0] = 1;
for (i = 1; i < n; i++) factorial[i] = factorial[i-1] * i;
However, unless you store them as floating point numbers, the large factorials are going to overflow really quickly.
Calculating factorial in this case is bad thing to do because it can cause overflow for small values of N . Use following pseudo code to get it in O(N) without overflow.
double sum = 0.0;
double acc = 1;
double error = 0.0000001;
for(i=1;i<=n;i++) {
acc = acc/i;
if(acc<error)
break;
sum = sum + acc;
}
print(sum);
More acurrate way of doing it though i feel it is unnecessary in case of factorials : -
double sum = 0.0;
double acc = 1;
for(i=n;i>=1;i--) {
sum = (sum + 1)/i;
}
print(sum);
Note:- Because the above method is built in reverse it more accurate but unfortunately more time consuming because it is O(N) even for higher values whereas the gain in accuracy is negligible as factorial function grows very fast hence error keeps on decreasing quickly.
The number n! is equal to the product of n and the preceding factorial, that is, (n - 1)!.
If you calculate n! in an iteration, you are doing n products.
In the next step, say n+1, you repeat again these n products followed by the multiplication by n+1.
This means that you are repeating the same operations again and again.
It is a better strategy to hold the previous factorial that was calculated in the step n, and then, in the step n+1, just to multiply the n! by n+1. This reduces the number of products to 1 in each iteration.
Thus, you can calculate the series in the following way:
int max_n = 20; /* This value can come from another point of the program */
int n; /* Initial value of the index */
double factorial_n = 1; /* It has to be initialized to 1, since the factorial of 0 is 1 */
double sum = 0.0; /* It has to be initialized to 0, in order to calculate the series */
for (n = 0; n <= max_n; )
{
sum += 1.0/factorial_n;
n++;
factorial_n *= n;
}
printf("Series result: %.20f\n", sum);
There are some numerical issues with this approach, but this go beyond the scope of your question.
About overflow: It is necessary to be carefull about the overflow of factorials after several iterations. However, I will not write code to handle overflow.
EDIT
I think that you have not to follow the suggestions of those people that advice to use a factorial function. This approach is very unefficient, since a lot of products are done in every iteration.
IN comparisson with that approach, the mine is better.
However, if you have plans to calculate these series very often, then my approach is not efficient anymore. Then, the right technique is that pointed out in the Bli0042's answer, that is: to hold the factorials in an array, and then just use them every time you need, without need to calculate them again and again in the future.
The resulting program would be this:
#include <stdio.h>
#define MAX_N 100
double factorial[MAX_N+1];
void build_factorials(double *factorial, int max)
{
factorial[0] = 1.0;
for (int j = 0; j <= max; )
{
j++;
factorial[j] = factorial[j-1] * j;
}
}
double exp_series(int n)
{
int j;
double sum;
if (n > MAX_N) /* Error */
return 0.0;
sum = 0.0;
for (j = n; j >= 0; j--)
sum += 1.0/factorial[j];
return sum;
}
int main(void)
{
int n;
double sum;
build_factorials(factorial, MAX_N);
printf("Series (up to n == 11): %.20f\n", exp_series(11));
printf("Series (up to n == 17): %.20f\n", exp_series(17));
printf("Series (up to n == 9): %.20f\n", exp_series(9));
getchar();
}
The iteration is done in reverse order inside the function exp_series() in order to improve the numerical issues (that is, to amortiguate the loss of precision when summing small terms).
The last code has side effects, because an external array is invoked inside the function exp_series().
However, I think that handling this would become my explanation more obscure.
Just, take it in account.

Resources