关于 Precision

关于 Precision

解决 x+x^2=0 的牛顿法只需四步,因为迭代次数计算不准确。

fpu 库可以大大提高精度,但我不知道如何使用。

有人能告诉我如何创建一个向量/数组以便保留迭代以供稍后在 tikz 中绘图吗?

\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{math}
\usetikzlibrary {fpu}
\begin{document}

    \pgfmathfloatsetextprecision{3} %maximum precision
    \xdef\Nit{9}  % no of iterations
    \def\x{0.5}  % x current, initialized, determining xnew
    %\pgfmathfloattoextentedprecision{\x}  %not allowed
    %\pgfmathsetmacro\x{\pgfmathresult}
    \foreach \i in {1,...,\Nit} {

          % \pgfmathfloatadd, \pgfmathfloatdiv here instead, for each operation??
          \pgfmathsetmacro\xn{\x - (\x + \x^2)/(1 + 2*\x)}  % new x
          \pgfmathfloatparsenumber{\x}
          \pgfmathfloattomacro{\pgfmathresult}{\F}{\M}{\E} 
          Flags: \F; Mantissa \M; Exponent \E \\
          \xdef\x{\xn}  %update x
    }

\end{document}

答案1

xfp包可以在这里使用:

\documentclass{article}
\usepackage{xfp}
\usepackage{tikz}
\usepackage{pgfplots}
\def\printx#1{
  \pgfmathfloatparsenumber{\x}
  \pgfmathfloattomacro{\pgfmathresult}{\F}{\M}{\E} 
  it: #1 Flags: \F; Mantissa \M; Exponent \E \par
}
\pgfmathfloatsetextprecision{3} %maximum precision
\begin{document}
\xdef\Nit{7}  % no of iterations
\def\x{0.5}  % x current, initialized, determining xnew
\printx{0}
\foreach \i in {1,...,\Nit} {
  \def\xn{\fpeval{\x -(\x + \x^2)/(1 + 2*\x)}}
  \xdef\x{\xn}  %update x
  \printx{\i}
}
\end{document}

关于 Precision

默认数学引擎使用 TeX 固定数字。

fpu 库使用具有可变精度的浮点数(以 10 为基数,尾数在约 5 位到约 8 位之间)。

xfp 库使用具有固定精度的浮点数(尾数在十进制中约为 16 位数字)。

对于每个库,以下文档计算(10 ** i-1) - (10 ** i)增加 i 的值直到得到 0。

\documentclass{article}
\usepackage[margin=2cm]{geometry}
\pagestyle{empty}
\usepackage{tikz}
\usepackage{xfp}
\usepackage{siunitx}
\usetikzlibrary{fpu}

\begin{document}
\textbf{pfg default math engine (\TeX)}\par
\foreach \i in {1,...,4}{
  \pgfmathsetmacro\xdiff{(pow(10,\i)+1)-(pow(10,\i))}
  \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
  \i : $\num{\xdiff} = (10^{\i}+1)-(10^{\i})$ \par
  \ifnum 0 = \correct\relax
  \breakforeach
  \fi
}
5: \emph{dimension too large!}\par
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=sci}
\foreach \myprecision in {0,...,3}{
  \textbf{fpu with precision \myprecision}\par
  \pgfmathfloatsetextprecision{\myprecision}
  \foreach \i in {1,...,30}{
    \pgfmathsetmacro\xdiff{(pow(10,\i)+1)-(pow(10,\i))}
    \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
    \i : $\num{\xdiff} = (10^{\i}+1)-(10^{\i})$ \par
    \ifnum 0 = \correct\relax
    \breakforeach
    \fi
  }
}
\textbf{xfp}\par
\foreach \i in {1,...,30}{
  \edef\xdiff{\fpeval{(10**\i+1)-(10**\i)}}
  \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
  \i : $\num{\xdiff} = (10^{\i}+1)-(10^{\i})$ \par
  \ifnum 0 = \correct\relax
  \breakforeach
  \fi
}
\end{document}

在此处输入图片描述

以下代码显示的结果与(2^\i)-(2^\i-1)

\documentclass[twocolumn]{article}
\usepackage[margin=2.5cm]{geometry}
\pagestyle{empty}
\usepackage{tikz}
\usepackage{xfp}
\usepackage{siunitx}
\usetikzlibrary{fpu}


\begin{document}
\textbf{pfg default math engine (\TeX)}\par
\foreach \i in {10,...,13}{
  \pgfmathsetmacro\xdiff{(pow(2,\i)-(pow(2,\i)-1))}
  \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
  \i : $\num{\xdiff} = (2^{\i})-(2^{\i}-1)$ \par
  \ifnum 0 = \correct\relax
  \breakforeach
  \fi
}
14: \emph{! Dimension too large}\par
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=sci}
\foreach \myprecision in {0,...,3}{
  \textbf{fpu with precision \myprecision}\par
  \pgfmathfloatsetextprecision{\myprecision}
  \foreach \i in {12,...,30}{
    \pgfmathsetmacro\xdiff{(pow(2,\i))-(pow(2,\i)-1)}
    \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
    \i : $\num{\xdiff} = (2^{\i})-(2^{\i}-1)$ \par
    \ifnum 0 = \correct\relax
    \breakforeach
    \fi
  }
}
\textbf{xfp}\par
\foreach \i in {10,...,58}{
  \edef\xdiff{\fpeval{(2**\i)-(2**\i-1)}}
  \pgfmathtruncatemacro\correct{(\xdiff!=0)?1:0}
  \i : $\num{\xdiff} = (2^{\i})-(2^{\i}-1)$ \par
  \ifnum 0 = \correct\relax
  \breakforeach
  \fi
}
\end{document}

下面的结果表明xfp使用 53 位尾数(+1 为符号)。

在此处输入图片描述

任意精度

对于任意精度,您可以尝试该xintexpr包......

答案2

我希望这能证明我的评论

\documentclass{article}
\usepackage{tikz,pgfplots}
    \usetikzlibrary{fpu}
    \pgfplotsset{compat=1.16}
\begin{document}

    \def\cs#1/{\texttt{\string#1}}

    Turn on fpu so \cs\pgfmathsetmacro/ and \cs\pgfmathparse/
    automatically convert the numbers to fpu notation.
    \tikzset{fpu=true}

    Maximum precision, three more decimal digits, or ten more binary digits.
    \pgfmathfloatsetextprecision{3}

    \xdef\Nit{9} Number of iterations = \Nit

    \def\x{0.5} Initial \cs\x/ = \x

    It is not necessary to turn \cs\x/ into fpu notation.
    But we can do it anyway.
    \pgfmathsetmacro\x{\x}
    New \cs\x/ = \x.

    Define a useful \cs\pgfkeys/ handler
    \def\pgfkeysgloballet#1#2{\global\expandafter\let\csname pgfk@#1\endcsname#2}
    \pgfkeys{/handlers/.let/.code=\pgfkeysgloballet{\pgfkeyscurrentpath}{#1}}

\subsection{Iteration}

    Start the iteration

    \foreach \i in {1,...,\Nit} {
        \pgfmathsetmacro\xi{\x - (\x + \x^4)/(1 + 4*\x^3)}  % new x
        \pgfmathfloattomacro{\xi}{\F}{\M}{\E} 
        \i th iteration: Flags: \F; Mantissa \M; Exponent \E.
        \xdef\x{\xi} % update \xi
        Put \cs\x/ in array.
        \tikzset{/bluesky/Newton result/\i/.let=\xi}

    }

    PS. \cs\tikzset/ allows almost arbitrary string as path name.
    By using numbers in the path, you are creating an array.

\subsection{Using array}

    Now check the array
    \tikzset{/Newton result/3/.get=\thirdvalue}
    Third value is \thirdvalue.
    Good.

    Now try to recall the whole array

    \foreach \i in {1,...,\Nit} {
        \tikzset{/bluesky/Newton result/\i/.get=\xi}
        \i th iteration: \cs\xi/ = \xi.

    }


    Close the fpu engine because \texttt{tikzpicture} dislikes it.
    \tikzset{fpu=false}

    Now a tikz picture to illustrate how they cooperate.

    \begin{tikzpicture}[yscale=.5]
        \draw[->](0,0)--(10,0);
        \draw[->](0,0)--(0,10);
        \foreach\i in{1,...,\Nit}{
            % we want to extract the number
            \tikzset{/bluesky/Newton result/\i/.get=\xi}
            \draw(\i,\i)node{\xi};
            % \xi is an fpu number, take log
            \draw(\i,10-\i-.5)node{\pgfmathfloatlogten{\xi}\pgfmathresult};
        }
    \end{tikzpicture}

    Now the real picture

    \begin{tikzpicture}[yscale=.5]
        \draw[->](0,0)--(10,0);
        \draw[->](0,0)--(0,10);
        \foreach\i in{1,...,\Nit}{
            % we want to extract the number
            \tikzset{/bluesky/Newton result/\i/.get=\xi}
            \pgfmathfloatlogten{\xi}
            \let\logtenxi=\pgfmathresult
            \pgfmathfloattofixed{\logtenxi}
            \let\logtenxi=\pgfmathresult
            % check if nan
            \def\textnan{nan}
            \ifx\logtenxi\textnan
                % wow, nan, cannot plot
                \draw(\i,3)node{failed};
            \else
                \draw(\i,-\logtenxi)node{good};
            \fi
        }
    \end{tikzpicture}

    See the documentation of \cs\pgfmathfloatifflags/
    to know how to test nan properly.

\subsection{Alternative}

    You can also turn on and off fpu before \texttt{tikzpicture}
    so that you can do log of floating number with \cs\pgfmathparse/.

    The following is the equivalent of python's map

    \tikzset{fpu=true}
    \foreach \i in {1,...,\Nit} {
        \tikzset{/bluesky/Newton result/\i/.get=\xi}
        \pgfmathsetmacro\mlogxi{-log10(\xi)}
        \tikzset{/bluesky/Newton result/logged/\i/.let=\mlogxi}
    }
    \tikzset{fpu=false}

    \begin{tikzpicture}[yscale=.5]
        \draw[->](0,0)--(10,0);
        \draw[->](0,0)--(0,10);
        \draw(0,0)node(prev point){};
        \foreach\i in{1,...,\Nit}{
            % extract the number
            \tikzset{/bluesky/Newton result/logged/\i/.get=\mlogxi}
            \pgfmathfloatifflags\mlogxi{+}{
                % is positive
                \def\GorB{good}
                \pgfmathfloattofixed{\mlogxi}
                \let\yvalue=\pgfmathresult
            }{
                % is probably nan
                \def\GorB{bad}
                \def\yvalue{4}
            }
            \draw(\i,\yvalue)node(this point){\GorB};
            \draw[>->](prev point)--(this point);
            \pgfnodealias{prev point}{this point}
        }
    \end{tikzpicture}

\end{document}

相关内容