我想在 LaTeX 文档中根据屏幕的对角线和纵横比计算屏幕的宽度。该公式很容易从勾股定理得出,但需要平方根。
我目前使用calc
计算平方根的包来计算巴比伦方法,但它不太优雅。在 latex 中计算平方根(和其他函数)的最佳方法是什么?
答案1
这是一个有趣的问题。首先我们需要比较和分析一些答案
1)使用 Lua:这是未来,而且非常准确,但不幸的是它使用得不够多,而且很多 TeX 用户只使用 pdf(la)TeX。
2)fp
解决方案很好,但我们需要谨慎使用,因为这可能会很慢。这是我喜欢的方法。但fp
如果您需要获得的结果,则可能会出现问题(-1.5)^(2)
。
下一个代码来自我修改的 Christian Tellechea 2009。
\documentclass{scrartcl}
\usepackage{fp}
\makeatletter
\def\FP@pow#1#2#3{%
\FP@beginmessage{POW}%
{\def\FP@beginmessage##1{}%
\def\FP@endmessage##1{}%
\FPifzero{#2}%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\FP@pow@zero{#3}}%
{\FPifint{#3}%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\FPifneg{#2}%
\FPneg\FP@tmpd{#2}%
\FPln\FP@tmpd\FP@tmpd
\FPmul\FP@tmpd\FP@tmpd{#3}%
\FPexp\FP@tmpd\FP@tmpd
\FPtrunc\FP@tmp{#3}0%
\ifodd\FP@tmp
\FPneg\FP@tmp\FP@tmpd
\else
\let\FP@tmp\FP@tmpd
\fi
\else
\FPln\FP@tmpd{#2}%
\FPmul\FP@tmpd\FP@tmpd{#3}%
\FPexp\FP@tmp\FP@tmpd
\fi
}%
{\FPln\FP@tmpd{#2}%
\FPmul\FP@tmpd\FP@tmpd{#3}%
\FPexp\FP@tmp\FP@tmpd}%
}%
\global\let\FP@tmp\FP@tmp}%
\FP@endmessage{}%
\let#1\FP@tmp}
\makeatletter
\begin{document}
\FPpow\temp{-1.5}{2}
\temp
\FPpow\temp{-2}{3}
\temp
\end{document}
3)pgfmath
。Martin 的回答描述了传统方法。对于极值,它也可能很慢,有时不准确。下图说明了有时使用 会导致不准确的结果pgfmath
。图片来自段落中的 pgfmanual投影修改器的语法。三个高度的交点在较小尺寸下没有问题,但使用大缩放我们得到以下结果:
4)有了fpu
。就可以使用fpu
里面有一个包pgf
。
\documentclass{article}
\usepackage{tikz}
\usepackage{fp}
\usetikzlibrary{fpu}
\newlength{\lengtha}
\newlength{\lengthb}
\begin{document}
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
\setlength{\lengtha}{1pt}
\setlength{\lengthb}{1pt}
\pgfmathparse{sqrt(\lengtha*\lengtha + \lengthb*\lengthb)}
\pgfmathresult
\end{document}
结果是 1.414192000000000。这很奇怪,因为pgfmath
在这种情况下给出的是 1.41421,而fp
使用相同的值则给出 1.414213562373095042。
5)\usetikzlibrary{fixedpointarithmetic}
另一种可能是fixed point arithmetic
。它又在里面pgf
\documentclass{article}
\usepackage{tikz}
\usepackage{fp}
\usetikzlibrary{fixedpointarithmetic}
\newlength{\lengtha}
\newlength{\lengthb}
\begin{document}
\setlength{\lengtha}{1pt}
\setlength{\lengthb}{1pt}
\pgfkeys{/pgf/fixed point arithmetic={scale results=10^-6}}
\pgfmathparse{sqrt(\lengtha*\lengtha + \lengthb*\lengthb)}
\pgfmathresult
\end{document}
结果与 一样fp
,正常fp
使用 !! result = 1.414213562373095042
6)\usepackage{tkz-euclide}
当需要计算两个节点之间的距离时,可以使用我在我的包中定义的宏:tkz-euclide
。它与的混合fp
。
\begin{tikzpicture}
\coordinate (A) at (3,0);
\coordinate (B) at (0,4);
\tkzCalcLength[cm](A,B)
\node {\tkzLengthResult } ;
\draw (A) circle (\tkzLengthResult cm) ;
\draw[fill=red] (A) circle (2pt) ;
\draw[fill=red] (B) circle (2pt) ;
\end{tikzpicture}
\tkzLengthResult
给出 5.00000 有一个选项可以以 pt 或 cm 为单位获取结果。
7) 最后使用最后一个解决方案TeX
。此解决方案由朋友 J_C Charpentier 编写。这很有趣。宏被命名\pythagore
,此宏使用另一个宏\SQRT
来获取整数 < 1962446671 的平方根。
\documentclass{article}
\makeatletter
\newcount\@tempcntc
\newcommand\SQRT[2]{%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% #2 = \sqrt{#1} (valeur entière) %
% #2 est une longueur %
% #1 ne doit pas dépasser 1962446671 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialisations
\@tempcnta #1\relax % Sauvegarde valeur
\@tempcntb 1 % juste pour le premier test
\@tempcntc #1\relax % Terme en cours
% simili racine pour le premier terme !!!!
\ifnum \@tempcntc > 1073741824 % 2^{30}
\divide \@tempcntc 32738
\else\ifnum \@tempcntc > 268435456 % 2^{28}
\divide \@tempcntc 16384
\else\ifnum \@tempcntc > 67108864 % 2^{26}
\divide \@tempcntc 8192
\else\ifnum \@tempcntc > 16777216 % 2^{24}
\divide \@tempcntc 4096
\else\ifnum \@tempcntc > 4194304 % 2^{22}
\divide \@tempcntc 2048
\else\ifnum \@tempcntc > 1048576 % 2^{20}
\divide \@tempcntc 1024
\else\ifnum \@tempcntc > 262144 % 2^{18}
\divide \@tempcntc 512
\else\ifnum \@tempcntc > 65536 % 2^{16}
\divide \@tempcntc 256
\else\ifnum \@tempcntc > 16384 % 2^{14}
\divide \@tempcntc 128
\else\ifnum \@tempcntc > 4096 % 2^{12}
\divide \@tempcntc 64
\else\ifnum \@tempcntc > 1024 % 2^{10}
\divide \@tempcntc 32
\else\ifnum \@tempcntc > 256 % 2^{8}
\divide \@tempcntc 16
\else\ifnum \@tempcntc > 64 % 2^{6}
\divide \@tempcntc 8
\else\ifnum \@tempcntc > 16 % 2^{4}
\divide \@tempcntc 4
\else\ifnum \@tempcntc > 4 % 2^{2}
\divide \@tempcntc 2
\else\ifnum \@tempcntc > 2 % 2^{1}
% c'est 3 ou 4, l'arrondi est toujours 2
\@tempcntc 2
\@tempcntb 0 % pas de boucle !
\else\ifnum \@tempcntc > 1
% C'est 2, l'arrondi est 1
\@tempcntc 1
\@tempcntb 0 % pas de boucle !
\else
% c'est 0 ou 1 la racine est le nombre
\@tempcntb 0 % pas de boucle !
\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi % joli !
% Boucle principale (Newton)
\loop
\ifnum\@tempcntb>0
% Calcul du terme suivant
\@tempcntb \@tempcnta
\divide \@tempcntb \@tempcntc
\advance \@tempcntc \@tempcntb
\divide \@tempcntc 2
% On regarde où on en est
% (différence entre l'itération au carré et le nombre initial)
\@tempcntb \@tempcntc
\multiply \@tempcntb \@tempcntb
\advance \@tempcntb -\@tempcnta
\repeat
% Sauvegarde du résultat
#2\the\@tempcntc sp\relax
}
\newcommand*\pythagore[3]{%
\dimen0=#1\relax
\@tempcnta \dimen0
\dimen0=#2\relax
\@tempcntb \dimen0
% Pour éviter les débordements
% on travaille en 1/32 de point
\divide \@tempcnta 2048
\divide \@tempcntb 2048
% calcul de a*a+b*b
\multiply \@tempcnta \@tempcnta
\multiply \@tempcntb \@tempcntb
\advance \@tempcnta \@tempcntb
% appel de la racine
\SQRT{\the\@tempcnta}{#3}%
% Fin des débordements !
#3 2048#3\relax
}
\makeatother
\newlength{\result}
\begin{document}
\pythagore{2pt}{2pt}{\result}
\the\result
\pythagore{3pt}{4pt}{\result}
\the\result
\pythagore{6pt}{8pt}{\result}
\the\result
\end{document}
结果为:2.8125pt;5.0 pt 和 10.0pt
答案2
我会使用fp
的幂函数来计算平方根等。借助fp
的精度,您还可以将舍入误差最小化到接近 15 位小数。
考虑 10 的平方根。你可以将其写成幂函数:
\FPpow\temp{10}{0.5}
我们得到 3.162277660168379312
您访问宏中的值\temp
(它可以是任何名称,fp
将动态定义它)。
将其转换回 2 的幂,我们得到:
\FPpow\temp{\temp}{2}
\FPround\temp{\temp}{15}
\temp
10.000000000000000
最小显示如下:
\documentclass{article}
\usepackage{fp}
\begin{document}
\FPpow\temp{10}{0.5}
\temp
\FPpow\temp{\temp}{2}
\FPround\temp{\temp}{15}
\temp
\end{document}
使用的变量\temp
会累积结果。无需扰乱命名空间。
答案3
您可以使用矢量图形包的数学功能PGF
:
\documentclass{article}
\usepackage{pgf}
\pgfmathsetmacro{\diagonal}{1280}
\pgfmathsetmacro{\aspectratio}{4/3}
\pgfmathsetmacro{\screenwidth}{(\diagonal*\aspectratio)/sqrt(\aspectratio^2+1)}
\begin{document}
\screenwidth
\end{document}
不幸的是,结果是1024.0023
,所以它不是绝对准确的。如果你只需要结果的整数部分,你可以使用\pgfmathtruncatemacro{\screenwidth}{(\diagonal*\aspectratio)/sqrt(\aspectratio^2+1)}
,它会截掉小数位。
答案4
您可以使用pgfmath
(pgf
包) 来为您提供一个sqrt
功能。但是,就像 Harlad Hanche-Olsen 在他的评论中已经提到的那样,这取决于所需的精度。这使用了 TeX 长度寄存器的精度,这有其局限性。
例如:
\documentclass{article}
\usepackage{pgf}
\newlength{\lengtha}
\newlength{\lengthb}
\begin{document}
\setlength{\lengtha}{3pt}
\setlength{\lengthb}{5pt}
\pgfmathparse{sqrt(\lengtha*\lengtha + \lengthb*\lengthb)}
\pgfmathresult
\end{document}