4
\$\begingroup\$

Taylor series are a very useful tool in calculating values of analytic functions that cannot be expressed in terms of elementary functions, using only information about that function at a single point.

In this challenge, you won't be actually doing any math with them, but merely making string representations of taylor series of functions with periodic derivatives.

Specs

You will takes a input three things:

  1. A cycle of the derivatives of the function, including the original function as a list of strings, e.g. ["sin(x)", "cos(x)", "-sin(x)", "-cos(x)"].
  2. A number a, the point around which to center the approximation.
  3. A positive integer n, the number of terms of the series to output.

The general form for the nth term of a taylor series is:

f^(n)(a)/n!*(x-a)^n

where f^(n) is the nth derivative of f. Here is the taylor series of f in a better formatted image from wikipedia:

.

The above example with sin(x), and a of 1, and n of 6, would have an output of:

sin(1) + cos(1)*(x-1) - sin(1)/2*(x-1)^2 - cos(1)/6*(x-1)^3 + sin(1)/24*(x-1)^4 + cos(1)/120*(x-1)^5

You can do the whitespace want. However, you have to replace + - and - - with - and + respectively. Also, if the series is a maclaurin series, and a is 0, you cannot have (x-0). (x) and just x is fine, but not (x-0). Niether can you have ^0 nor ^1 nor /1 . Additionally, you must expand out the factorials in the denominators. Multiplication by juxtaposition is not allowed.

Test cases

["e^x"], 0, 4  ->  e^0 + e^0*x + e^0*x^2/2 + e^0*x^3/6
["sin(x)", "cos(x)", "-sin(x)", "-cos(x)"], 1, 6 -> sin(1) + cos(1)*(x-1) - sin(1)/2*(x-1)^2 - cos(1)/6*(x-1)^3 + sin(1)/24*(x-1)^4 + cos(1)/120*(x-1)^5
["e^(i*x)", "i * e^(i*x)", "-e^(i*x)", "-i*e^(i*x)"], 0, 7 -> e^(i*0) + i*e^(i*0)*x - e^(i*0)*x^2/2 - i*e^(i*0)*x^3/6 + e^(i*0)*x^4/24 + i*e^(i*0)*x^5/120 - e^(i*0)*x^6/720

This is , so shortest code in bytes wins!

\$\endgroup\$
15
  • \$\begingroup\$ Are built ins allowed? \$\endgroup\$
    – user45941
    Commented Apr 25, 2016 at 3:41
  • \$\begingroup\$ @Mego sure, if you can find one that doesn't evaluate the function and only does string manipulation. \$\endgroup\$
    – Maltysen
    Commented Apr 25, 2016 at 4:16
  • \$\begingroup\$ What about something like this? \$\endgroup\$
    – user45941
    Commented Apr 25, 2016 at 4:50
  • \$\begingroup\$ Additionally, can ** be used in place of ^? \$\endgroup\$
    – user45941
    Commented Apr 25, 2016 at 5:25
  • \$\begingroup\$ May we assume that the derivatives only start with nothing or a single minus sign if they're negative? \$\endgroup\$
    – orlp
    Commented Apr 25, 2016 at 10:51

3 Answers 3

1
\$\begingroup\$

JavaScript (ES6), 183 bytes

(c,a,n)=>[...Array(n)].map((_,i)=>(s=c[i%c.length].replace(/x/g,a),i?s=s.replace(/^-?/,c=>c?` - `:` + `)+(a>0?`*(x-${a})`:a<0?`*(x+${-a})`:`*x`):s,i>1?s+`^${i}/${f*=i}`:s),f=1).join``

Lots of tedious string manipulation. Explanation:

(c,a,n)=>                               Parameters
 [...Array(n)].map((_,i)=>(             Loop i from 0 to n-1
  s=c[i%c.length]                       Get the right element from the cycle
   .replace(/x/g,a),                    Substitute a in for x
  i?                                    If i > 0
   s=s.replace(/^-?/,c=>c?` - `:` + `)  Turn the sign into an operator
    +(a>0?`*(x-${a})`                   If a > 0 then * (x - a)
     :a<0?`*(x+${-a})`                  If a < 0 then * (x + -a)
     :`*x`)                             If a == 0 then * x
   :s,                                  No change if i < 1
  i>1?                                  If i > 1
   s+`^${i}/${f*=i}`                    Append ^ i / i!
   :s),                                 No change if i < 2
  f=1                                   0! == 1
 ).join``                               Join all the results together

170 bytes if you remove all the whitespace:

(c,a,n)=>[...Array(n)].map((_,i)=>(s=c[i%c.length].replace(/x/g,a),i?s=(s[0]=='-'?'':'+')+s+(a>0?`*(x-${a})`:a<0?`*(x+${-a})`:`*x`):s,i>1?s+`^${i}/${f*=i}`:s),f=1).join``
\$\endgroup\$
0
\$\begingroup\$

Python 2, 181 bytes

D,a,N=input()
D=["+"*(d[0]!="-")+d.replace("x",`a`)for d in D]
x=a and"*(x-%s)"%a or"*x"
r=D[0][1:]+(D[1]+x)*(N>1)
n=f=2
while n<N:r+=D[n%len(D)]+"/"+`f`+x+"^"+`n`;n+=1;f*=n
print r
\$\endgroup\$
7
  • \$\begingroup\$ Maybe a short explanation on how this works? \$\endgroup\$
    – R. Kap
    Commented Apr 27, 2016 at 23:38
  • \$\begingroup\$ @R.Kap There's nothing to explain, really. It's just a bunch of string concatenation. Each line reasonably speaks for itself. \$\endgroup\$
    – orlp
    Commented Apr 27, 2016 at 23:39
  • \$\begingroup\$ I mean, what's going on in x? What are the and and or doing there? \$\endgroup\$
    – R. Kap
    Commented Apr 27, 2016 at 23:39
  • \$\begingroup\$ @R.Kap x is simply "*(x-a)" or just "*x" if a is 0. \$\endgroup\$
    – orlp
    Commented Apr 27, 2016 at 23:40
  • \$\begingroup\$ I would presume that you would have to use ternary if statements for that, but this I did not know was even possible. \$\endgroup\$
    – R. Kap
    Commented Apr 27, 2016 at 23:41
0
\$\begingroup\$

Python 3.5, 308 299 bytes:

def g(f,a,n,L=len,S=str):import math,re;A=S(a);print('+'.join(t.replace('x',A)+re.sub('(\W\(x-\d+\)\^0|/1|\*1|\^1|\*0)(?!\d+)','',g)for t,g in zip(f*(n//L(f))+f[:n%L(f)],['*'+A+'/'+S(math.factorial(n))+'*'+'(x-'+A+')^'+S(n)for n in range(n)])).replace('+-','-').replace('--','+').replace('x-0','x'))

This always outputs in the order according to the equation f^(n)(a)/n!*(x-a)^n. For instance, if the expected output for one of the terms is e^0*x^2/2, it instead outputs e^0/2*x^2. However, they are both basically the same answer, so I hope this is okay. Confirmed by OP that this is okay. This works perfectly as I have had no issues with it. I will shorten this over time wherever I can.

Note: In the output, all (x-0) are replaced with (x).

Try it online! (Ideone) (Accepts input on 3 lines, where the first line is the input list, f, the second line is a, and the third line is n)

Explanation

For the purposes of this explanation, assume the function is executed with the values "e^(i*x)", "i*e^(i*x)", "-e^(i*x)", "-i*e^(i*x)"],0,7. That being said, basically, what's going on in the main part, step-by-step, is:

  1. '+'.join(t.replace('x',A)+re.sub('(\W\(x-\d+\)\^0|/1|\*1|\^1|\*0)(?!\d+)','',g)for t,g in zip(f*(n//L(f))+f[:n%L(f)],['*'+A+'/'+S(math.factorial(n))+'*'+'(x-'+A+')^'+S(n)for n in range(n)]))

    A list is created from each item pair in a zip object containing the input list, f, with n number of items, and another list which contains each term in the sequence except the items in f. In this second list, *+a is added, followed by a /+ n! for each value, n, in the range n, and finally, a lone * followed by (x-a)^n. After all this is done, for each item pair in this zip object, t corresponding to each object in f and g corresponding to each value in the second list, each 'x' in t is replaced with a, and every g goes through a regular expression substitution, namely (\W\(x-\d+\)\^0|/1|\*1|\^1|\*0)(?!\d+), in which every (x-a)^0, /1,*1,^1, and *0 is matched and replaced with '' as long as each of those are not followed by any more integers. After all this substitution is done, each t and g are concatenated together, and each term created using this method is joined with +s and returned. For this particular case in which "e^(i*x)", "i*e^(i*x)", "-e^(i*x)", "-i*e^(i*x)"],0,7 is the input, this part would return:

    e^(i*0)+i*e^(i*0)*(x-0)+-e^(i*0)/2*(x-0)^2+-i*e^(i*0)/6*(x-0)^3+e^(i*0)/24*(x-0)^4+i*e^(i*0)/120*(x-0)^5+-e^(i*0)/720*(x-0)^6
    

    As you can see, those +-s, --s, and (x-0)s exist. However, these will all be replaced with -,+,and (x) respectively in the next part.

  2. '+'.join(t.replace('x',A)+re.sub('(\W\(x-\d+\)\^0|/1|\*1|\^1|\*0)(?!\d+)','',g)for t,g in zip(f*(n//L(f))+f[:n%L(f)],['*'+A+'/'+S(math.factorial(n))+'*'+'(x-'+A+')^'+S(n)for n in range(n)])).replace('+-','-').replace('--','+').replace('x-0','x')

    Here is where those substrings such as +-,++,and (x-0) in the now joined string are replaced with their correct substitutes using Python's built-in sub-string replacement function. After all the replacing has been done, this finally returns the finished product, which in this case would be:

    e^(i*0)+i*e^(i*0)*(x)-e^(i*0)/2*(x)^2-i*e^(i*0)/6*(x)^3+e^(i*0)/24*(x)^4+i*e^(i*0)/120*(x)^5-e^(i*0)/720*(x)^6
    
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.