解决 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}