固定小数点演算によるTikZの計算精度

固定小数点演算によるTikZの計算精度

次の条件を満たすツリーを構築したいと思います。

  1. 右に成長します。
  2. 最初の子は 0 度で成長します (後続の子は時計回りに成長します)。
  3. すべての子ノードは同じ垂直方向にあり、連続するノード間の距離は常に同じです。

全体として、私が達成したいのは次のことです。

ここに画像の説明を入力してください

実際、それをコーディングする簡単な方法は

\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}

しかし、私は別のアプローチを試してみましたが、同じ結果が得られるだろうと予想していました。

\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}

上記のコードでは、1) 最初の (水平) 子のレベル距離が 3cm であり、2) 2 番目の子が -5 度で成長すると想定していることに注意してください。これらの 2 つの条件と基本的な三角法を使用すると、最初に連続するノード間の兄弟距離を計算し、次に任意の子ノードの角度gとレベル距離を計算できます。l

私のパラメータ化は正しいと思いますが、兄弟の角度やレベル距離が若干ずれています。

ここに画像の説明を入力してください

他の回答に従って、固定小数点演算エンジンを使用して精度を向上させようとしましたが、三角関数をテイラー級数の最初の項に置き換えても、

\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}

同じ問題が存在します(ここでのノードの数は、級数がatan収束することを保証するように選択されていることに注意してください)。

ここに画像の説明を入力してください

これらの不正確さの問題を克服するために何かできることはありますか、それともこれは避けられない本質的な TikZ の問題でしょうか? (私のアプローチに欠陥がないと仮定した場合、そうだと思います)。

答え1

この場合、なぜ数学が失敗するように見えるのかはよくわかりません (おそらくわかるはずですが)。ただし、TikZ/PGF の数学処理方法の問題ではなく、ツリーの構築方法に関係しているようです。

残念ながら、私は問題が何なのか正確には理解できていませんが、問題がない数学的計算自体の正確さは、ツリー外で同じ計算を行うことで実証できます。

\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}

ここに画像の説明を入力してください

だから、何か他のことが起こっているに違いない。

いずれにせよ、あなたはできることを無駄にしていると思います多くのカスタム成長関数を使用するとより簡単に。

grow via three points以下は、ライブラリの成長関数の例を示していますtrees

\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}

ここに画像の説明を入力してください

答え2

PSTricks のソリューション:

\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}

出力

\NoDotsパラメータの値 ( 、\Hori、 )を変更するだけで\Vert、それに応じて図面が調整されます。

答え3

あなたの問題に興味をそそられました。MetaPost もデフォルトで固定小数点演算を使用します。つまり、「数値」は より小さくも 2^(-16)より大きくもなりません2^12が、MetaPost は内部的には までの値を処理できます2^15。(ごく最近になって、いくつかの浮動小数点演算モードに切り替えることが可能になりましたが、ここでは使用しません。)

そこで、同じ機能を使用して 2 番目のグラフの MetaPost バージョンを作成し、配置を観察することにしました。(LuaLaTeX で処理します。)

\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}

まあ、私が見る限り、それらは正しく整列しているようです:

ここに画像の説明を入力してください

したがって、この場合、固定小数点演算自体に問題があるのではなく、固定小数点ライブラリ (数値を表すために使用される 2 つのビット) に問題があるようですtikz。または、三角関数の定義方法に問題があるようです。

いずれにせよ、浮動小数点演算に切り替えることができればtikz(おそらく LuaTeX を使用)、精度が大幅に向上するでしょう。

関連情報