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) 第一個(水平)子級的水平距離為 3 厘米,2) 第二個子級的生長角度為 -5 度。有了這兩個條件和一些基本的三角學,我們可以先計算連續節點之間的兄弟距離,然後計算任何子節點的角度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。 (最近可以切換到幾種浮點運算模式,但我不會在這裡使用它們。)

所以我決定製作第二張圖的 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}

好吧,據我所知,它們似乎正確對齊:

在此輸入影像描述

因此,在這種情況下,似乎存在問題,不是定點算術本身存在問題,而是定點庫tikz(用於表示數字的兩個位元?)。或用三角函數的定義方式。

無論如何,如果可以切換到浮點運算tikz(也許可以使用 LuaTeX?),它將大大提高準確性。

相關內容