Genauigkeit der Berechnungen in TikZ mit Festkommaarithmetik

Genauigkeit der Berechnungen in TikZ mit Festkommaarithmetik

Ich möchte einen Baum erstellen, der Folgendes erfüllt:

  1. Es wächst nach rechts.
  2. Das erste Kind wächst im 0-Grad-Winkel (die nachfolgenden Kinder wachsen im Uhrzeigersinn).
  3. Alle untergeordneten Knoten liegen in derselben Vertikalen und der Abstand zwischen aufeinanderfolgenden Knoten ist immer derselbe.

Alles in allem möchte ich Folgendes erreichen:

Bildbeschreibung hier eingeben

Tatsächlich ist eine einfache Möglichkeit, dies zu codieren, durch

\documentclass{article}
\usepackage{tikz}
\tikzset{bcir/.style={circle,fill=black,
 minimum size=4pt,inner sep=0},every node/.style={bcir}}
\begin{document}
\begin{tikzpicture}[x=3cm,y=2mm]
\node (A) {};
\foreach \i in {0,...,8} \node at (1,-\i) {} edge (A);
\end{tikzpicture}
\end{document}

Ich habe jedoch einen alternativen Ansatz ausprobiert und erwartete, dass dieser zu denselben Ergebnissen führen würde:

\documentclass{article}
\usepackage{tikz}
\usepackage{fp}
\usetikzlibrary{fixedpointarithmetic}
\tikzset{bcir/.style={circle,fill=black,
minimum size=4pt,inner sep=0},every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[fixed point arithmetic]  
\node {}
  child[grow=\g,level distance=\l cm] 
  foreach \i [evaluate={
     \k=tan(5)*\i;
     \g=-atan(\k);
     \l=3/cos(\g);
  }] in {0,...,13} {node {}};
\end{tikzpicture}  
\end{document}

Beachten Sie, dass ich im obigen Code davon ausgegangen bin, dass 1) der Höhenabstand des ersten (horizontalen) untergeordneten Knotens 3 cm beträgt und 2) das zweite untergeordnete Knoten um -5 Grad wächst. Mit diesen beiden Bedingungen und etwas grundlegender Trigonometrie kann man zunächst den Geschwisterabstand zwischen aufeinanderfolgenden Knoten und dann den Winkel- gund Höhenabstand lfür jeden untergeordneten Knoten berechnen.

Ich glaube, meine Parametrisierung ist korrekt; einige Winkel/Ebenenabstände zwischen Geschwistern sind jedoch leicht abweichend.

Bildbeschreibung hier eingeben

obwohl ich (nach anderen Antworten) die Festkomma-Arithmetik-Engine verwendet habe, um die Genauigkeit zu verbessern. Selbst wenn ich die trigonometrischen Funktionen durch die ersten Terme ihrer Taylor-Reihe ersetze,

\begin{tikzpicture}[fixed point arithmetic]  
\node {}
  child[grow=\g,level distance=\l cm] 
  foreach \i [evaluate={
     \k=tan(5)*\i;
     \grad=\k-\k^3/3+\k^5/5-\k^7/7+\k^9/9;
     \g=-deg(\grad);
     \l=3/(1-\grad^2/2!+\grad^4/4!-\grad^6/6!);
  }] in {0,...,8} {node {}};
\end{tikzpicture}

Es treten dieselben Probleme auf (beachten Sie, dass die Anzahl der Knoten hier so gewählt wurde, dass sichergestellt ist, dass die Reihe für atankonvergiert):

Bildbeschreibung hier eingeben

Kann ich etwas tun, um diese Ungenauigkeitsprobleme zu beheben, oder handelt es sich um ein inhärentes TikZ-Problem, das nicht vermieden werden kann? (Vorausgesetzt, mein Ansatz weist keine Fehler auf, was meiner Meinung nach der Fall ist).

Antwort1

Ich weiß nicht genau, warum die Berechnung in diesem Fall fehlschlägt (obwohl ich es vermutlich wissen sollte), aber es scheint kein Problem mit der Art und Weise zu sein, wie TikZ/PGF rechnet, sondern es hat etwas mit der Art und Weise zu tun, wie Bäume konstruiert werden.

Leider konnte ich nicht genau herausfinden, wo das Problem liegt, aber die Tatsache, dass das ProblemnichtDie Genauigkeit mathematischer Berechnungen an sich kann demonstriert werden, indem man dieselben Berechnungen außerhalb eines Baumes verwendet:

\documentclass[tikz, border=5]{standalone}
\tikzset{bcir/.style={circle,fill=black,
  minimum size=4pt,inner sep=0}, every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[every node/.style={bcir, anchor=center}]
\node {} child [grow=\g, level distance=\l cm] foreach \i [evaluate={%
  \k=tan(5)*\i; \g=-atan(\k); \l=3/cos(\g);}]
  in {0,...,13} { node {} };

\foreach \i [evaluate={%
  \k=tan(5)*\i; \g=-atan(\k); \l=3/cos(\g);}]
  in {0,...,13} { \draw [red] (0,0) -- (\g:\l) node [bcir,fill=red]{}; }
\end{tikzpicture}  
\end{document}

Bildbeschreibung hier eingeben

Da muss also noch etwas anderes vor sich gehen.

Auf jeden Fall finde ich, dass Sie aus etwas, das getan werden könnte, eine Menge Arbeit machen.vieleinfacher mit einer benutzerdefinierten Wachstumsfunktion.

Nachfolgend sehen Sie ein Beispiel der grow via three pointsWachstumsfunktion aus der treesBibliothek.

\documentclass[tikz, border=5]{standalone}
\usetikzlibrary{trees}
\tikzset{bcir/.style={circle,fill=black,
  minimum size=4pt,inner sep=0}, every node/.style={bcir}}

\begin{document}
\begin{tikzpicture}[grow via three points={%
  one child at (3,0) and two children at (3,0) and (3,-1/4)
}]
\node {} child foreach \i in {0,...,13} { node {} };
\end{tikzpicture}  
\end{document}

Bildbeschreibung hier eingeben

Antwort2

Eine PSTricks-Lösung:

\documentclass{article}

\usepackage{multido}
\usepackage{pstricks}
\usepackage{xfp}

% parameters
\def\NoDots{9}
\def\Hori{4}
\def\Vert{3}

\begin{document}

\begin{pspicture}(\Hori,\Vert)
  \psdot(0,\Vert)
  \multido{\r = \Vert+-\fpeval{\Vert/(\NoDots-1)}}{\NoDots}{%
    \psline(0,\Vert)(\Hori,\r)
    \psdot(\Hori,\r)}
\end{pspicture}

\end{document}

Ausgabe

Sie müssen lediglich die Werte der Parameter ( \NoDots, \Hori, und \Vert) ändern und die Zeichnung wird entsprechend angepasst.

Antwort3

Ihr Problem hat mich neugierig gemacht. MetaPost verwendet standardmäßig auch Festkommaarithmetik: eine „numerische Zahl“ kann weder kleiner 2^(-16)noch größer als sein 2^12, obwohl MetaPost intern Werte bis zu verarbeiten kann 2^15. (Seit kurzem ist es möglich, zwischen mehreren Gleitkommaarithmetikmodi zu wechseln, aber ich werde sie hier nicht verwenden.)

Daher habe ich beschlossen, eine MetaPost-Version Ihres zweiten Diagramms mit denselben Funktionen zu erstellen und die Ausrichtung zu beobachten. (Soll mit LuaLaTeX verarbeitet werden.)

\documentclass[border=2mm]{standalone}
\usepackage{luamplib}
  \mplibsetformat{metafun}  
\begin{document}
  \begin{mplibcode}
    u := cm;
    def dot(expr c) = drawdot c withpen pencircle scaled 3bp enddef;
    beginfig(1);
      dot(origin); 
      for i = 0 upto 13:
        k := i*tand5; % or i*sind5/cosd5 with Plain MetaPost
        g := -atan k ; % or -angle(1, k) with Plain MetaPost; 
        l := 3u/cosd g;
        draw origin -- l*dir g;
        dot(l*dir g);
      endfor
    endfig;
  \end{mplibcode}
\end{document}

Nun, soweit ich sehen kann, scheinen sie richtig ausgerichtet zu sein:

Bildbeschreibung hier eingeben

In diesem Fall scheint es also ein Problem zu geben, nicht mit der Festkommaarithmetik an sich, sondern mit der Festkommabibliothek tikz(zwei wenige Bits, die zur Darstellung der Zahlen verwendet werden?). Oder mit der Art und Weise, wie die trigonometrischen Funktionen definiert sind.

Wenn es jedenfalls möglich wäre, auf Gleitkommaarithmetik umzustellen tikz(vielleicht mit LuaTeX?), würde das die Genauigkeit drastisch verbessern.

verwandte Informationen