该命令\pgfmathparse{asin(1/\x)}
对\x
125 到 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}