Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to plot Weierstrass function using only basic TikZ picture functionality (no gnuplot or whatnot). How do I use sum in a \draw? Do I have to make a new command? Use a loop?

An alternative (ugly) solution with manual summation:

\begin{tikzpicture}[xscale=2.2,yscale=2.7]
\draw[thick, color=lightgrey,step=0.25cm,solid] (-2,-0.75) grid (2,0.75);
\draw[<->] (-2.1,0) -- (2.1,0) node[below right] {$x$};
\draw[<->] (0,-0.9) -- (0,0.9) node[left] {$y$};
\draw[color=newblue, thick, domain=-2:2,samples=500,/pgf/fpu,/pgf/fpu/output format=fixed] plot (\x, {(1/2)*sin(2*\x r) + (1/4)*sin(4*\x r) + (1/8)*sin(8*\x r) + (1/16)*sin(16*\x r) +
(1/32)*sin(32*\x r) + (1/64)*sin(64*\x r) + (1/128)*sin(128*\x r) + (1/256)*sin(256*\x r) +
(1/512)*sin(512*\x r) + (1/1024)*sin(1024*\x r) + (1/2048)*sin(2048*\x r) +
(1/4096)*sin(4096*\x r) + (1/8192)*sin(8192*\x r) + (1/16384)*sin(16384*\x r) +
(1/32768)*sin(32768*\x r) + (1/65536)*sin(65536*\x r) + (1/131072)*sin(131072*\x r) +
(1/262144)*sin(262144*\x r) + (1/524288)*sin(524288*\x r) +
(1/1048576)*sin(1048576*\x r) }) node[right, black] {};
\end{tikzpicture}
share|improve this question
1  
Without trying, I have a feeling that you will get into problems since the function involves 'summing' to infinity. –  Svend Tveskæg Feb 1 at 14:59
1  
It can still be plotted at a certain resolution or "zoom level" without any issues. If you look at Wikipedia you can see a plot over [-2,2] at a particular scale for example. –  Puffton Feb 1 at 15:21
    
I personally vote agaisnt ask LaTeX do the calculations (at least more than once). I usually prefer to save the data to a file and then plot the data from that .txt file. –  Manuel Feb 1 at 15:24
    
@Puffton: When you say "basic TikZ picture functionality", does that also preclude PGFPlots (which also does its calculations within LaTeX)? –  Jake Feb 1 at 15:39
2  
@Puffton: Yeah, I think it's you =) –  Jake Feb 1 at 16:08

8 Answers 8

up vote 10 down vote accepted

The following method is optimized for simplicity and readability rather than compilation speed or flexibility. The code avoids using LuaTeX, PSTricks, or even commands beginning with \pgfmath. The basic idea is to build the summation from the original question as a string (except that, e.g., 32 gets written as 2*2*2*2*2*1) and then pass this string to \draw plot in the usual fashion.

\documentclass[margin=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{fpu}
\def\x{\noexpand\x}    % Prevent \x from being expanded inside an \edef
\edef\weierstrass{0}     % weierstrass = 0;
\edef\currentbn{1}        % b_n = 1;
\foreach \i in {1,...,19} {
    % \global makes these definitions last beyond the current iteration
    \global\edef\currentbn{2*\currentbn}    % b_n = 2 * b_n;
    \global\edef\weierstrass{\weierstrass + (1/(\currentbn)*cos((\currentbn*\x) r))}    % weierstrass = weierstrass + (1/b_n) cos(b_n*\x radians);
}
\begin{document}
\begin{tikzpicture}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-0.75) grid (2,1.0);
    \draw[<->] (-2.1,0) -- (2.1,0) node[below right] {$x$};
    \draw[<->] (0,-0.9) -- (0,1.1) node[left] {$y$};
    \draw[color=blue, thick, domain=-2:2, samples=501, /pgf/fpu, /pgf/fpu/output format=fixed] 
        plot (\x, {\weierstrass});
\end{tikzpicture}
\end{document}

Here's the output:

enter image description here

share|improve this answer
    
What equation is this? It doesn't seem to be the Weierstrass function describe on MathWorld, because that uses n^2, but if I understand your code correctly, you're using 2^n (and you're using cos instead of sin), and it doesn't seem to be the original Weierstrass function, because that uses a^n with 0<a<1 and b^n with b a positive odd integer. Am I misunderstanding something? –  Jake Feb 4 at 15:14
    
@Jake: I got the function from the OP. I have no idea where (s)he got it from. –  Charles Staats Feb 4 at 15:39
    
@Jake the equation is with cos(2^n*x)/2^n whereas other answers use predominantly cos(3^n*pi*x)/2^n. My own answer initially uses cos(2^n*pi*x)/2^n as general term, I will perhaps extend it to do also cos(3^n*pi*x)/2^n but first I need to understand how to use fpu for all things in plot, or perhaps proceed differently with coordinates. –  jfbu Feb 5 at 9:44
    
@Jake, I think the one with n^2 is called Riemann's function (with sin I think) and its study is much more delicate than the Weierstrass' one with a^n cos(b^n x) (or pi*x). I have forgotten now but the Riemann's one does have points of derivability (I think at specific rationals). –  jfbu Feb 5 at 9:47
    
@jfbu: Thanks for the info. Do you perhaps have a reference for the cos(2^n*pi*x)/2^n equation? –  Jake Feb 5 at 9:52

The pst-func package knows \psWeierstrass(x0,x1)[a]{a or b}. It uses the function from http://mathworld.wolfram.com/WeierstrassFunction.html or, if the optional argument is given, the original one, seen here http://en.wikipedia.org/wiki/Weierstrass_function:

\documentclass[pstricks,border=10pt]{standalone}
\usepackage{pst-func}   
\begin{document}

\psset{yunit=10,xunit=5}
\begin{pspicture}(-0.1,-0.5)(2.1,0.5)
\psaxes[Dx=0.2,Dy=0.1,ticksize=-4pt 0,labelFontSize=\scriptstyle]{->}(0,0)(0,-0.5)(2.1,0.5)
\psWeierstrass[linecolor=red](0,2){2}
\psWeierstrass[linecolor=green](0,2){3}
\psWeierstrass[linecolor=blue](0,2){4}
\end{pspicture}

\end{document}

Run the example with xelatex or latex->dvips->ps2pdf. You need the latest version of pst-funx.tex from http://texnik.dante.de/tex/generic/pst-func/ or tomorrows update of TeX Live/MiKTeX.

output

and the same with the original Weierstraß definition and a variable interation number:

\documentclass{article}
\usepackage{ifxetex} 
\ifxetex\usepackage{fontspec}\else\usepackage[utf8]{inputenc}\fi
\usepackage{pst-func}   
\begin{document}

The original Weierstraß function
\[ f(x)= \sum_{n=0}^\infty a^n \cos(b^n \pi x) \]

\psset{unit=2cm,linewidth=0.5pt,plotpoints=5000}
\begin{pspicture}(-2.1,-2.1)(2.1,2.1)
\psaxes[Dx=0.5,Dy=0.5,ticksize=-2pt 0,labelFontSize=\scriptstyle]{->}(0,0)(-2,-2)(2,2)
\psWeierstrass[linecolor=red](-2,2)[0.5]{3}
\psWeierstrass[linecolor=blue!70](-2,2)[0.5]{10}
\end{pspicture}

\end{document}

enter image description here

And now a LuaTeX version with pgf which also has a varibale number of iterations:

\documentclass[tikz,border=0.125cm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\usepackage{luacode}
\begin{luacode}
function weierstrass(x0, x1, n, a, b, epsilon)
 local dx = (x1-x0)/n 
 local x = x0
 local out=assert(io.open("tmp.data","w"))
 local y,k,dy
 while (x <= x1) do
   y = 0
   k = 0
   repeat
      dy = math.pow(a,k) * math.cos(math.pow(b,k)*math.pi*x)
      y = y + dy
      k = k + 1
   until (math.abs(dy) < epsilon)
   out:write(x, " ", y, "\string\n") 
   x = x + dx
 end
 out:close()
end
\end{luacode}

\begin{document}

\begin{tikzpicture}
\directlua{weierstrass(-2,2,5000,0.3,5,1.e-12)}%
\begin{axis}[axis lines=middle,domain=-2:2]
\addplot [thick, black, line join=round] table {tmp.data};
\end{axis}
\end{tikzpicture}

\end{document}
share|improve this answer
1  
This is not using basic TikZ picture functionality. –  Puffton Feb 1 at 17:43
4  
@Puffton: It is allowed to answer with PSTricks for other readers. –  cyanide-based food Feb 1 at 17:49
1  
dup abs 1e-8 gt { ps@WS add /ps@WS ED }{ ps@WS add exit } ifelse can also be simplified as dup ps@WS add /ps@WS ED abs 1e-8 lt {exit} if ...} loop ps@WS –  cyanide-based food Feb 1 at 18:26
1  
possible is \psWeierstrass[a]{b} or \psWeierstrass{a} –  Herbert Feb 2 at 13:53
    
@Puffton: the last example does! –  Herbert Feb 3 at 10:18

Here's a pgfmath function definition of the original Weierstrass function: weierstrass(x,a,b,i). i is the number of iterations to be used for approximating the function.

\documentclass{article}
\usepackage{pgfplots}

\makeatletter
\pgfmathdeclarefunction{weierstrass}{4}{%
    \pgfmathfloattofixed@{#4}%
    \afterassignment\pgfmath@x%
    \expandafter\c@pgfmath@counta\pgfmathresult pt\relax%
    \pgfmathfloatcreate{1}{0.0}{0}%
    \let\pgfmathfloat@loc@TMPr=\pgfmathresult
    \pgfmathfloatpi@%
    \let\pgfmathfloat@loc@TMPp=\pgfmathresult%
    \edef\pgfmathfloat@loc@TMPx{#1}%
    \edef\pgfmathfloat@loc@TMPa{#2}%
    \edef\pgfmathfloat@loc@TMPb{#3}%
    \pgfmathloop
        \ifnum\c@pgfmath@counta>-1\relax%
            \pgfmathfloatparsenumber{\the\c@pgfmath@counta}%
            \let\pgfmathfloat@loc@TMPn=\pgfmathresult%
            \pgfmathpow{\pgfmathfloat@loc@TMPa}{\pgfmathfloat@loc@TMPn}%
            \let\pgfmathfloat@loc@TMPe=\pgfmathresult%
            \pgfmathpow{\pgfmathfloat@loc@TMPb}{\pgfmathfloat@loc@TMPn}%
            \pgfmathmultiply{\pgfmathresult}{\pgfmathfloat@loc@TMPp}%
            \pgfmathmultiply{\pgfmathresult}{\pgfmathfloat@loc@TMPx}%
            \pgfmathdeg{\pgfmathresult}%
            \pgfmathcos{\pgfmathresult}%
            \pgfmathmultiply{\pgfmathresult}{\pgfmathfloat@loc@TMPe}%
            \pgfmathadd{\pgfmathresult}{\pgfmathfloat@loc@TMPr}%
            \let\pgfmathfloat@loc@TMPr=\pgfmathresult
            \advance\c@pgfmath@counta by-1\relax%
    \repeatpgfmathloop%
}

\begin{document}
\begin{tikzpicture}
\begin{axis}[axis lines=middle, axis equal image, enlarge y limits=true]
\addplot [thick, black, samples=301, line join=round, domain=-2:2] {weierstrass(x,0.5,3,10)};
\end{axis}
\end{tikzpicture}
\end{document}

And here's the version from MathWorld that's implemented in PSTricks:

\documentclass{article}
\usepackage{pgfplots}

\makeatletter
\pgfmathdeclarefunction{weierstrass}{3}{%
    \pgfmathfloattofixed@{#3}%
    \afterassignment\pgfmath@x%
    \expandafter\c@pgfmath@counta\pgfmathresult pt\relax%
    \pgfmathfloatcreate{1}{0.0}{0}%
    \let\pgfmathfloat@loc@TMPa=\pgfmathresult
    \pgfmathfloatpi@%
    \let\pgfmathfloat@loc@TMPd=\pgfmathresult%
    \edef\pgfmathfloat@loc@TMPb{#1}%
    \edef\pgfmathfloat@loc@TMPc{#2}%
    \pgfmathloop
        \ifnum\c@pgfmath@counta>0\relax%
            \pgfmathfloatparsenumber{\the\c@pgfmath@counta}%
            \pgfmathpow{\pgfmathresult}{\pgfmathfloat@loc@TMPc}%
            \pgfmathfloatmultiply@{\pgfmathresult}{\pgfmathfloat@loc@TMPd}%
            \let\pgfmathfloat@loc@TMPe=\pgfmathresult%
            \pgfmathmultiply{\pgfmathresult}{\pgfmathfloat@loc@TMPb}%
            \pgfmathdeg{\pgfmathresult}%
            \pgfmathsin{\pgfmathresult}%
            \pgfmathdivide{\pgfmathresult}{\pgfmathfloat@loc@TMPe}%
            \pgfmathadd{\pgfmathresult}{\pgfmathfloat@loc@TMPa}%
            \let\pgfmathfloat@loc@TMPa=\pgfmathresult
            \advance\c@pgfmath@counta by-1\relax%
    \repeatpgfmathloop%
}
\makeatother

\begin{document}
\begin{tikzpicture}
\begin{axis}[axis lines=middle,
    xmin=0, xmax=2,
    ymin=-0.5, ymax=0.5,
    axis equal image
]
\addplot [red, samples=300, domain=0:2] {weierstrass(x,2,15)};
\addplot [green, samples=300, domain=0:2] {weierstrass(x,3,15)};
\addplot [blue, samples=300, domain=0:2] {weierstrass(x,4,15)};
\end{axis}
\end{tikzpicture}

\end{document}
share|improve this answer
5  
15 iterations for a sum which is defined for k=1,..,\infty is a bit trickery :-). However, well done! –  Herbert Feb 2 at 12:47

Jake's method using lualatex with pgfplots. Some nonsense seems to be required to convert to and from the internal representation of numbers used by pgfplots which makes this annoying inefficient.

\documentclass[tikz,border=0.125cm]{standalone}
\usepackage{pgfplots}
\directlua{%
  function weierstrass(x, a, b, N)
    local y, n
    y = 0
    for n = 0,N do
      y = y + math.pow(a,n) * math.cos(math.pow(b, n)*math.pi*x)
    end
    return y
  end
}

\pgfmathdeclarefunction{weierstrass}{4}{%
  \begingroup%
    \pgfkeys{/pgf/number format/.cd,assume math mode,verbatim}%
    \pgfmathprintnumberto{#1}{\x}\pgfmathprintnumberto{#2}{\a}%
    \pgfmathprintnumberto{#3}{\b}\pgfmathprintnumberto{#4}{\N}%
    \edef\pgfmathresult{\directlua{tex.print("" .. weierstrass(\x,\a,\b,\N))}}%
   \expandafter\endgroup\expandafter%
    \pgfmathfloatparsenumber\expandafter{\pgfmathresult}%
}
\begin{document}

\begin{tikzpicture}
\begin{axis}[axis lines=middle, axis equal image, enlarge y limits=true]
\addplot [thick, black, samples=301, line join=round, domain=-2:2] 
  {weierstrass(x,0.5,3,100)};
\end{axis}
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer

A sagetex solution combined with the tkz-fct package for setting up the axes and running in Sagemath Cloud. The x values running up to 2.01 are because Python doesn't implement the last number, so it actually stops at 2.

\documentclass{scrartcl}
\usepackage{sagetex}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{tkz-fct}
\pagestyle{empty}

\begin{document}
\begin{sagesilent}
y=var('y')
a = .5
b = 3
n = 100
t = var('t')
def weierstrass(t,a,b,n):
    answer = 0
    for i in range(0,n):
        answer += a^i*cos(b^i*pi*t).n(digits=5)

    return answer

x_coords = [t for t in srange(-2,2.01,.01)]
y_coords = [weierstrass(t,a,b,n).n(digits=6) for t in srange(-2,2.01,.01)]

output = ""
for i in range(0,len(x_coords)-1):
    output += r"\draw[blue, thin] (%f cm ,%f cm)--(%f cm ,%f cm);"%(x_coords[i],y_coords[i],x_coords[i+1],y_coords[i+1])
\end{sagesilent}
\begin{tikzpicture}[scale=1.25]
\tkzInit[xmin=-2,xmax=2,ymin=-2,ymax=2]
\tkzAxeXY
\sagestr{output}
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer

last edit: added a method using the fpu library with pgfplots, for the general \sum_n a^n*cos(b^n x) Weierstrass function. The powers a^n and b^n are pre-computed as floating point numbers with xintfrac, which also prepares the complete partial sum. I kept only 6 digits of precision as anyhow the fpu library mantissa computations are between 4 and 7 digits of precision.

As the x axis will be in degrees, which is what cos and sin use, no need here to worry about a pi, it's all in the horizontal scale.

See bottom of answer for the result.


Taking over Charles' solution, with the difference that the powers of two are now precomputed. A partial sum expression is prepared using xint to pass to tikz's plot, with the fpu library loaded.

edit: the plots now use an odd number of sample points (101 vs 100, or 201 vs 200); hence are better looking at x=0. (only second image replaced, the one with n=20).

Note: I don't know how tikz's fpu interfaces with the plot command, and I have noticed that with a too long partial sum (say n=30) an error arises:Dimension too large (but admittedly it does not make sense to handle that many terms which will be completely negligible). Thus, it seems some computations at least are not handled by the floating point library, presumably at least the additions? if everything was handled by the fpu there would not be a Dimension too large error, right?

Besides, I use only 200 samples for n=20, else it is too slow.

\documentclass[multi=preview]{standalone}
\usepackage{tikz}
\usetikzlibrary{fpu}
\usepackage{xint}

\makeatletter
% general term will compute 1/2^n*cos(2^n pi x), or 1/2^n*sin(2^n pi x)
% (where 2^n is already evaluated)
% we need pi and r to use radians. 
% (I don't know if loading the tikz library fpu increased the precision of pi, 
%  perhaps it does not)

\def\@weierstrassgeneralterm #1#2#3{(1/#3*#2(#3*#1*pi r))}

\def\@weierstrassseries #1#2#3{% 
% #1 will be \x or \y etc... 
% #2=cos or sin 
% #3=summation will be from 0 to #3
    \xintListWithSep{+}
                    {\xintApply {\@weierstrassgeneralterm{#1}{#2}}
                                {\xintApply{\xintiPow {2}}{\xintSeq {0}{#3}}}}%
}

% \fdef is defined by xint, it expands fully the first token. Hence no need
% to protect the \x, or \y which will be passed as argument.

% (initial version used \edef, see below)

\def\SetWeierstrass #1#2{% #1=\x or \y, etc..., #2=summation from 0 to #2
    \fdef\weierstrasscos {\@weierstrassseries {#1}{cos}{#2}}%
    \fdef\weierstrasssin {\@weierstrassseries {#1}{sin}{#2}}%
}%

% earlier version:
%
%\def\SetWeierstrass #1#2{% #1=\x or \y, etc..., #2=summation from 0 to #2
%    \edef\weierstrasscos {\@weierstrassseries {#1}{cos}{#2}}%
%    \edef\weierstrasssin {\@weierstrassseries {#1}{sin}{#2}}%
%}%

% \edef in \SetWeierstrass meant we had to use \noexpand here:

%\def\@weierstrassseries #1#2#3{% 
% #1 will be \x or \y etc... \noexpand as it will then end up in an \edef 
% #2=cos or sin 
% #3=summation will be from 0 to #3
%    \xintListWithSep{+}
%                    {\xintApply {\@weierstrassgeneralterm{\noexpand#1}{#2}}
%                                {\xintApply{\xintiPow {2}}{\xintSeq {0}{#3}}}}%
%}

\makeatother

\begin{document}

% % debugging
% \SetWeierstrass \x{10}
% \show\weierstrasscos
% \show\weierstrasssin
% \stop

\begin{preview}
\begin{tikzpicture}\SetWeierstrass \x{0}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-1.5) grid (2,2);
    \draw[->] (-2.1,0) -- (2.1,0) ;
    \draw[->] (0,-1.6) -- (0,2.1) ;
    \draw[color=blue, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasscos}) ;
    \draw[color=red, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasssin}) ;
\end{tikzpicture}

\begin{tikzpicture}\SetWeierstrass \x{1}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-1.5) grid (2,2);
    \draw[->] (-2.1,0) -- (2.1,0) ;
    \draw[->] (0,-1.6) -- (0,2.1) ;
    \draw[color=blue, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasscos}) ;
    \draw[color=red, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasssin}) ;
\end{tikzpicture}

\begin{tikzpicture}\SetWeierstrass \x{2}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-1.5) grid (2,2);
    \draw[->] (-2.1,0) -- (2.1,0) ;
    \draw[->] (0,-1.6) -- (0,2.1) ;
    \draw[color=blue, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasscos}) ;
    \draw[color=red, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasssin}) ;
\end{tikzpicture}
\begin{tikzpicture}\SetWeierstrass \x{3}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-1.5) grid (2,2);
    \draw[->] (-2.1,0) -- (2.1,0) ;
    \draw[->] (0,-1.6) -- (0,2.1) ;
    \draw[color=blue, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasscos}) ;
    \draw[color=red, thick, domain=-2:2, samples=101, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasssin}) ;
\end{tikzpicture}
\end{preview}

% odd number of sample points to get it right at the origin.
\begin{preview}
\begin{tikzpicture}[scale=2]\SetWeierstrass \x{20}
    \draw[thick, color=lightgray,step=0.25cm,solid] (-2,-1.5) grid (2,2);
    \draw[->] (-2.1,0) -- (2.1,0) ;
    \draw[->] (0,-1.6) -- (0,2.1) ;
    \draw[color=blue, thick, domain=-2:2, samples=201, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasscos}) ;
    \draw[color=red, thick, domain=-2:2, samples=201, /pgf/fpu, 
          /pgf/fpu/output format=fixed] 
       plot (\x, {\weierstrasssin}) ;
\end{tikzpicture}
\end{preview}

\end{document}

weierstrass functions n=0,1,2,3

weierstrass n=20

\documentclass[multi=preview]{standalone}
\usepackage{tikz}
\usetikzlibrary{fpu}
\usepackage{pgfplots}
\usepackage{xintfrac}

\makeatletter

\def\SetWeierstrass #1#2#3#4{% 
% #1=typically 'x' for pgfplots expression, 
% #2=sum will be from n=0 to #2
% formula will be:  sum of a^n * (cos or sin) (b^n x)
% a=#3, b=#4, may be fractions, numbers in scientific notations, fixed point ...
% their powers will be computed as float with only 6 digits precision
    \def\@weierX {\noexpand #1}% in case one has some \x, rather
    \def\@weierA {#3}%           perhaps with an \@weierstrassgeneralterm
    \def\@weierB {#4}%           not using floating point numbers...
    \def\@weierN {#2}%
    \edef\weierstrasscos {\@weierstrassseries {cos}}%
    \edef\weierstrasssin {\@weierstrassseries {sin}}%
}%
\def\@weierstrassseries #1{% #1 = cos or sin
    \xintListWithSep{+}
    {\xintApply{\@weierstrassgeneralterm {#1}}{\xintSeq {0}{\@weierN}}}%
}
\def\@weierstrassgeneralterm #1#2% [6] means 6 digits of precision
  {(\xintFloatPow [6]{\@weierA}{#2}*% #1= cos or sin
                #1(\xintFloatPow [6]{\@weierB}{#2}*\@weierX))}


\makeatother


\begin{document}

% debugging
% \SetWeierstrass x{5}{1/2}{3}
% \show\weierstrasscos
% % e.g. [was with 8 digits precision]
% % (1.0000000e0*cos(1.0000000e0*x))+(5.0000000e-1*cos(3.0000000e0*x))+
% % (2.5000000e-1*cos(9.0000000e0*x))+(1.2500000e-1*cos(2.7000000e1*x))+
% % (6.2500000e-2*cos(8.1000000e1*x))+(3.1250000e-2*cos(2.4300000e2*x)).
% \show\weierstrasssin

\begin{preview}
\begin{tikzpicture}[domain=-360:360]\SetWeierstrass {x}{10}{1/2}{3}%
    \begin{axis}[xmin=-360, xmax=+360, ymin=-2, ymax=+2, width=12cm,
      height=12cm, scale only axis]% ENFIN!
    \addplot [color=blue, samples=601] {\weierstrasscos} ;
    \addplot [color=red, samples=601]  {\weierstrasssin} ;
    \end{axis}
\end{tikzpicture}
\end{preview}

\begin{preview}
\begin{tikzpicture}[domain=-360:360]\SetWeierstrass {x}{0}{1/2}{3}%
    \begin{axis}[xmin=-360, xmax=+360, ymin=-2, ymax=+2, width=2.8cm,
      height=2.8cm, scale only axis]%
    \addplot [color=blue, samples=301] {\weierstrasscos} ;
    \addplot [color=red, samples=301]  {\weierstrasssin} ;
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}[domain=-360:360]\SetWeierstrass {x}{1}{1/2}{3}%
    \begin{axis}[xmin=-360, xmax=+360, ymin=-2, ymax=+2, width=2.8cm,
      height=2.8cm, scale only axis]%
    \addplot [color=blue, samples=301] {\weierstrasscos} ;
    \addplot [color=red, samples=301]  {\weierstrasssin} ;
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}[domain=-360:360]\SetWeierstrass {x}{2}{1/2}{3}%
    \begin{axis}[xmin=-360, xmax=+360, ymin=-2, ymax=+2, width=2.8cm,
      height=2.8cm, scale only axis]%
    \addplot [color=blue, samples=301] {\weierstrasscos} ;
    \addplot [color=red, samples=301]  {\weierstrasssin} ;
    \end{axis}
\end{tikzpicture}

\begin{tikzpicture}[domain=-360:360]\SetWeierstrass {x}{3}{1/2}{3}%
    \begin{axis}[xmin=-360, xmax=+360, ymin=-2, ymax=+2, width=2.8cm,
      height=2.8cm, scale only axis]%
    \addplot [color=blue, samples=301] {\weierstrasscos} ;
    \addplot [color=red, samples=301]  {\weierstrasssin} ;
    \end{axis}
\end{tikzpicture}

\end{preview}
\end{document}

weierstrass with pgfplots A weierstrass with pgfplots B

share|improve this answer

Since many of you have proposed non-tikz solutions, I've felt free to propose one which makes use of MetaPost. It has borrowed many elements of Herbert's very clear Lua-solution.

Since the very recent implementation of floating-point arithmetic in its core, MetaPost has become able to do this kind of computations. It was quite fun to play with it and the Weierstrass function, which reminds me of my time as a math student :-)

If you want to execute the following program, assuming it has been called weierstrass.mp, run the following command line, with the Metafun format and with the numbersystem flag set to double:

mpost --mem=metafun --numbersystem="double" weierstrass.mp

For a PDF version of the graph, run mptopdf weierstrass.1.

input latexmp ;
setupLaTeXMP(options="12pt", textextlabel = enable, mode = rerun);

% The pi number as defined in the current metafun format is too inaccurate
% for the new floating-point arithmetic of MetaPost, so I redefine it more precisely
pi := 3.14159265358979323846;

% Weierstrass sum (heavily inspired by Herbert's Lua code)
vardef weierstrass_sum(expr x, a, b, epsilon) =
    save k, y, dy; 
    y = 0; k = 0;
    forever:
        dy := a**k*cos(b**k*pi*x);
        y := y + dy; k := k + 1;
        exitif abs(dy) < epsilon;
    endfor;
    y
enddef;

% Weirstrass curve (also heavily inspired by Herbert's Lua code)
vardef weierstrass_curve(expr xs, xf, n, a, b, epsilon) =
    save k, x, dx;
    dx = (xf-xs)/n;
    (xs, weierstrass_sum(xs, a, b, epsilon))
    for x= xs+dx step dx until xf:
        -- (x, weierstrass_sum(x, a, b, epsilon))
    endfor
enddef;

beginfig(1); 
    % For scaling
    u := 4cm;
    % Weierstrass curve between -2 and 2, with n = 5000, a = 0.5, b = 3 and epsilon = 1e-12
    draw weierstrass_curve(-2, 2, 5000, 0.5, 3, 1e-12) xyscaled u withcolor red;
    % Axes
    drawarrow (-2u, 0) -- (2u, 0);
    drawarrow (0, -2.25u) -- (0, 2.25u);
    % Marking and labels
    eps := 3bp;
    labeloffset:=6bp;
    for x = -2, -1, 1, 2:
        draw (x*u, -eps)--(x*u, eps); label.bot("$" & decimal(x) & "$", (x*u, 0));
        draw (-eps, x*u)--(eps, x*u); label.lft("$" & decimal(x) & "$", (0, x*u));
    endfor;
endfig;

end.

enter image description here

share|improve this answer

Simplifying Jake's solution and it was taken (or stolen) from Herbert's idea.

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-plot}
\begin{document}
\begin{pspicture}(-\psPi,-3)(\psPi,3)
    \psaxes(0,0)(-\psPi,-3)(\psPi,3)
    \psplot[linecolor=blue,plotpoints=1000]{Pi neg}{Pi}
    [userdict begin /a .5 def /b 3 def /n 15 def end]
    {userdict begin /out 0 def 0 1 n {dup a exch exp exch b exch exp Pi mul x mul RadtoDeg cos mul out add /out ED} for out end}
\end{pspicture}
\end{document}

enter image description here

share|improve this answer
    
I starting loving PostScript programming... –  cyanide-based food Feb 2 at 14:55
    
How do you compile this? I get ! Undefined control sequence. <recently read> \c@lor@to@ps? –  Jake Feb 2 at 15:00
    
@Jake: Compile with latex-dvips-ps2pdf sequence. –  cyanide-based food Feb 2 at 15:01
1  
\psplot[...]{Pi neg}{Pi}[/a .5 def /b 3 def /n 15 def]{ /out 0 def ... } then a,b,and n are defined only once. –  Herbert Feb 2 at 15:08
    
@Herbert: OK. Thanks for informing this best practice. –  cyanide-based food Feb 2 at 15:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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