PGF 数学引擎不精确?

PGF 数学引擎不精确?

该命令\pgfmathparse{asin(1/\x)}\x125 到 142 范围内的每个值都产生相同的值,而\pgfmathparse{1/\x}对每个值都产生更精确的值\x。PGF 的 ArcSin 函数是否不精确?我该怎么做才能获得更精确的结果?

梅威瑟:

\documentclass[11pt]{minimal}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
    \foreach \x in {120,121,...,150}
    {
        \pgfmathparse{1/\x}\let\fraction\pgfmathresult
        \pgfmathparse{asin(\fraction)}\let\angle\pgfmathresult
        \node at (0, \x/2-60) {\x, \fraction, \angle}; 
    }
\end{tikzpicture}
\end{document}

答案1

有不同的数学引擎可与 pgf/TikZ 一起使用。

图书馆fixedpointarithmetic

\documentclass[11pt]{minimal}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{fp}
\usetikzlibrary{fixedpointarithmetic}
\begin{document}
\begin{tikzpicture}[fixed point arithmetic]
    \foreach \x in {120,121,...,150}
    {
        \pgfmathparse{1/\x}\let\fraction\pgfmathresult
        \pgfmathparse{asin(\fraction)}\let\angle\pgfmathresult
        \node at (0, \x/2-60) {\x, \fraction, \angle};
    }
\end{tikzpicture}
\end{document}

定点运算

答案2

是的,它不精确(除非你使用fpu库),而且引擎不会逐个计算值,而是使用查找表。但除此之外,TeX 数学能力无论如何都是有限的。所以你也可以自己伪造一个近似值。

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
    \foreach \x[count=\xi] in {120,...,150}
    {
        \pgfmathsetmacro\myfraction{1/\x}
        \pgfmathsetmacro\myangle{asin(\myfraction)}
        \pgfmathsetmacro\modifiedangle{deg(\myfraction + 1/6*(\myfraction)^3 + 3/40*(\myfraction)^5)}
        \node[text width=3cm,align=left] (a-\xi) at (0,0.4*\xi) {\texttt{\myangle,\modifiedangle}};
    }
\end{tikzpicture}
\end{document}

asin与近似值asin

在此处输入图片描述

答案3

我最近发现,反正切似乎可以通过区间 [-1,1] 上的连分数很好地近似(其余实数线使用 简化为该值arctan(1/x)=pi/2-arctan(x))。这是使用 的反正切的快速而粗糙的实现l3fp。它似乎至少有 15 位精度,但可能存在错误。

\documentclass{article}
\usepackage{expl3, xparse}
\ExplSyntaxOn

%%%%% Defining the function atan2, such that atan2(y,x) is the angle of x+iy.
\int_const:Nn \c__atan_steps_int { 30 } % must be even
\fp_new:N \l__atan_x_fp
\fp_new:N \l__atan_y_fp
\fp_new:N \l__atan_offset_fp
\fp_new:N \l__atan_tmp_fp
\fp_new:N \l__atan_result_fp
\cs_new_protected:Npn \atan:nnN #1#2#3
  {
    \fp_set:Nn \l__atan_y_fp {#1}
    \fp_set:Nn \l__atan_x_fp {#2}
    \fp_zero:N \l__atan_offset_fp
    \fp_compare:nT { \l__atan_y_fp < - \l__atan_x_fp }
      {
        \fp_set:Nn \l__atan_x_fp { - \l__atan_x_fp }
        \fp_set:Nn \l__atan_y_fp { - \l__atan_y_fp }
        \fp_set_eq:NN \l__atan_offset_fp \c_pi_fp
      }
    \fp_compare:nT { \l__atan_y_fp > \l__atan_x_fp }
      {
        \fp_set_eq:NN \l__atan_tmp_fp \l__atan_x_fp
        \fp_set_eq:NN \l__atan_x_fp \l__atan_y_fp
        \fp_set:Nn \l__atan_y_fp { - \l__atan_tmp_fp }
        \fp_add:Nn \l__atan_offset_fp { pi / 2 }
      }
    % Now X >= 0 and -X <= Y <= X.
    \fp_compare:nTF { \l__atan_y_fp < 0 }
      {
        \fp_set:Nn \l__atan_y_fp { - \l__atan_y_fp }
        \__atan_compute:
        \fp_set:Nn #3 { \l__atan_offset_fp - \l__atan_result_fp }
      }
      {
        \__atan_compute:
        \fp_set:Nn #3 { \l__atan_offset_fp + \l__atan_result_fp }
      }
  }
\cs_new_protected_nopar:Npn \__atan_compute:
  {
    % atan(y/x)
    % = (y/x)(1-y^2/(3x^2+9y^2/(5+4y^2/(7x^2+25y^2/(9+16y^2/(11x^2+...))))))
    %
    \fp_set:Nn \l__atan_x_square_fp { \l__atan_x_fp * \l__atan_x_fp }
    \fp_set:Nn \l__atan_y_square_fp { \l__atan_y_fp * \l__atan_y_fp }
    \fp_set:Nn \l__atan_result_fp
      { ( 2 * \c__atan_steps_int + 3 ) * \l__atan_x_square_fp }
    \int_step_inline:nnnn \c__atan_steps_int { -2 } { 2 }
      {
        \fp_set:Nn \l__atan_result_fp
          {
            (2 * ##1 - 1) * \l__atan_x_square_fp
            + (##1 + 1)**2 * \l__atan_y_square_fp
              / ( 2 * ##1 + 1
                  + ##1 * ##1 * \l__atan_y_square_fp / \l__atan_result_fp )
          }
      }
    \fp_set:Nn \l__atan_result_fp
      {
        \l__atan_y_fp / \l__atan_x_fp
        * ( 1 - \l__atan_y_square_fp / \l__atan_result_fp )
      }
  }
%%%%% End of atan2.
\fp_new:N \l__asin_x_fp
\cs_new_protected:Npn \asin:nN #1#2
  {
    \fp_set:Nn \l__asin_x_fp {#1}
    \atan:nnN
      { \l__asin_x_fp }
      { 1 + (1 - \l__asin_x_fp ** 2) ** .5 }
      \l__asin_x_fp
    \fp_set:Nn #2 { 2 * \l__asin_x_fp }
  }
%%%%%
\fp_new:N \X
\NewDocumentCommand{\showasin}{m}
  {
    \fp_gset:Nn \X {#1}
    \fp_to_tl:N \X
    &
    \asin:nN { \X } \X
    \fp_to_tl:N \X
    \\
  }
\ExplSyntaxOff
\begin{document}

\begin{tabular}{cc}
  \showasin { 1 }
  \showasin { 1 - 1e-16 }
  \showasin { 1 - 1e-12 }
  \showasin { 1 - 1e-8 }
  \showasin { 1 - 1e-4 }
  \showasin { .9 }
  \showasin { .1 }
  \showasin { 1e-4 }
  \showasin { 1e-8 }
  \showasin { 1e-12 }
  \showasin { 1e-20 }
  \showasin { 1e-40 }
  \showasin { -1e-40 }
  \showasin { -.123 }
  \showasin { -1 }
\end{tabular}

\end{document}

相关内容