Any time you write use Taylor's formula to write a power series for a function, you must choose a point (of the domain) at which to evaluate the derivatives of the function. This point is called $a$. If the special choice $a=0$ is made, this yields Maclaurin's formula.
It is "gibberish" to set $a \leftarrow x$ since $a$ really is a constant for a given Taylor expansion and $x$ really is a variable. You can, however, have a Taylor series (some infinite polynomial in $x$) and then make the substitution $x \rightarrow a$ and find out the value of $f(a)$ since all the derivative terms are multiplied by powers of zero in the series.
For your coding, make a function which I here call "Taylor" and you should call something better. The simplest form of Taylor() takes the arguments $f$, $a$, $n$, $x$. Taylor() then computes the 0th through n-th derivative of $f$ at $a$, then evaluates Taylor's formula for the finite set of summation indices 1..n, returning the result. The following are improvements:
Don't supply an $x$ and get back an object which has precomputed the $n+1$ coefficients and has an operator() or "evaluate" public member function that can do the finite sum using a supplied value of $x$.
Arrange for whatever function actually does the final numerical sum to sort its arguments and sum from smaller in magnitude to larger in magnitude to control intermediate precision loss.
Don't supply an $n$ or the $x$ but do supply a precision argument. The function that does the summing now needs to have a way to estimate the residual of the Taylor series (which means your $f$ has to be able to tell you how big its next derivative can be anywhere in some interval) and then set $n$ so that the residual will be less than the precision argument when evaluated at $x$.
Construct function objects that just know their derivatives for any value of $a$. Numerically calculating the derivatives and then Taylor summing is horribly unstable.
Extend your numerical system to include "common numbers" like $\sqrt{2}$, $\sqrt{a}$ and the like. Let your system pass weighted sums of these numbers around and then only reduce them to floating point at the last possible moment. This will preserve significantly more accuracy. (I.e., a result can be of the form $0.0167889 + 45.6 \sqrt{2} + 6. \sqrt{a}$ and only reduce this to a floating point number at the last possible time.
Extend your numerical system to work with arbitrary symbolic expressions. Add a facility for simplifying these expressions so that the intermediate expression swell doesn't consume all available memory. Add a facility for computing the resulting approximations to arbitrary precision. (At this point, you've implemented quite a hunk of a computer algebra system...)