答案1
编辑:我添加了一个新方法,它非常适合逐位计算十进制对数。它直接受到以下启发:这张漂亮的纸。
它比接下来基于 Borchardt 算法操作实现的方法要快得多(我指的是这里在 TeX 宏级别的实现)。
(背景是我正在使用的可怜的数学引擎到目前为止懒得实现日志,所以我们必须找到解决方法)
\documentclass[letterpaper]{article}
\usepackage{geometry}
\usepackage{xintexpr}
% Computation of logarithms via a simple-minded digit by digit algorithm
% reference
% https://tidsskrift.dk/brics/issue/view/3152
% We work with a sequence of floating point numbers x_n, 1 <= x_n < 10
% algorithm for a new digit :
% x_n**10 = x_{n+1} times 10**d_{n+1}
% This means \xintFloatPow{x_n}{10} expands to x_{n+1} e d_{n+1}
% Strangely xint is lacking a macro to get exponent of a floating point
% number ? we do it by hand
\makeatletter
\def\GetOneMoreDigit {%
\expandafter\GetOneMoreDigit@\romannumeral0\xintfloatpow{\X}{10}!%
}%
\def\GetOneMoreDigit@ #1e#2!{\def\X{#1e0}\def\D{#2}}
\def\GetAndPrintFourRoundedDigits #1{\def\X{#1}%
\GetOneMoreDigit\let\Da\D
\GetOneMoreDigit\let\Db\D
\GetOneMoreDigit\let\Dc\D
\GetOneMoreDigit\let\Dd\D
\GetOneMoreDigit\let\De\D
\expandafter\@gobble\the\numexpr
1\Da\Db\Dc\Dd+\ifnum\De>4 1\else 0\fi\relax
}%
\makeatother
\usepackage{array}
\begin{document}
\begin{table}[htbp]
\centering
\caption{Table of logarithms}
% use \xintDigits:=8; ?? does not seem to increase speed a lot
\begin{tabular}{|r||*{5}{c}|*{5}{c}|}
\hline
N\xintFor* #1 in {0123456789}\do
{&\multicolumn{1}{c|}{#1}}\\\hline
%
\xintFor* #1 in {\xintSeq{10}{24}}\do {%
#1\xintFor* #2 in {0123456789}\do {%
& \GetAndPrintFourRoundedDigits{#1#2e-2}
}% fin de boucle avec #2
\ifnum#1<24 \ifnum\numexpr#1+1-((#1+1)/5)*5=0 \\[1ex]\else\\\fi\else\\\fi
}% fin de boucle avec #1
\hline
\end{tabular}
\end{table}
\end{document}
因为xintexpr仍然缺乏log
我,为了好玩,做了一个(高级)Borchardt算法的使用。
有点慢,但没有以任何方式优化......(除了将表格切割成不要太多行;-)
)。
我从这个答案
\documentclass[letterpaper]{article}
\usepackage{geometry}
\usepackage{xintexpr}
% Computation of logarithms via Borchardt's algorithm
% Just for fun, because sqrt is available, so let's try this out
\xintdeffloatfunc B(a, b):= subs((c, sqrt(c*b)), c = (a+b)/2);
% Currently, one must go via a macro-like definition when abstracting
% usage of "iter". This means the whole parsing is done again
% at time of execution. Perhaps in future, one could use here
% \xintdeffloatfunc
% \BDigits is a parameter to be set later. This is like a macro
% definition, it does no parsing nor expansion.
\xintNewFunction{log}[1]{%
iter((1+#1)/2, sqrt(#1); % initial values
(abs([@][0]-[@][1]) < 1[-\BDigits])? % stop iterating ...
{break(2*(#1-1)/([@][0]+[@][1]))} % ... and do final computation,
{B(@)}, % else iterate via "B" formulas
i=1++) % The i is not used. Only serves to generate iteration
}
% Compute log(10) with circa 8 or 9 digits of precision
\xintDigits:=10;
\def\BDigits{8}
\xintverbosetrue
\xintdeffloatvar LnTen:=log(10);
% (we will need less precision for the table itself)
\usepackage{array}
\begin{document}
\begin{table}[htbp]
\centering
\caption{Table of logarithms}
\xintDigits:=8;
\def\BDigits{5}% Precision to be achieved in Borchardts algorithm
% (do not take it too close to \xintDigits value)
\begin{tabular}{|>{\bfseries}c|*{10}{r|}}
\hline
N\xintFor* #1 in {0123456789}\do
{&\multicolumn{1}{c|}{#1}}%
\\\hline
\xintFor* #1 in {12}\do {%
\xintFor* #2 in {0123456789}\do {%
#1.#2\xintFor* #3 in {0123456789}\do {%
&\xinttheiexpr [4]
\xintfloatexpr log(#1.#2#3)/LnTen\relax
\relax
}% fin de boucle avec #3
\\\hline
}% fin de boucle avec #2
}% fin de boucle avec #1
% add last row
% 4.0\xintFor* #3 in {0123456789}\do {%
% &%\np{% in case \np macro of numprint is used
% \xinttheiexpr
% 10000*\xintfloatexpr log(4.0#3)/LnTen\relax
% \relax
% %}%
% }% fin de boucle avec #3
%\\\hline
\end{tabular}
\end{table}
\end{document}
48位对数的变体算法!
我们使用牛顿法,假设我们有一个exp
函数。但我们没有函数,exp
所以我们也必须对其进行编程……
最后有点慢...
\documentclass[]{article}
\usepackage{geometry}
\usepackage{xintexpr}
%\newcommand{\FPprecision}{48}% we will need to set \xintDigits to some higher
% value, say 52 for 4 guard digits
% anyway I will hardcode this for the moment
% again, as we use "iter" statement, there is currently
% no way to convert this into expandable macro calls
% having done already all parsing. So we use simply
% "macro encapsulations"
% We need e=exp(1) computed already,
% find first N! > 1e54
\xintverbosetrue % push to logsvariable definitions
% attention that the first ; must be hidden from \xintdefiivar :-((
% and use num(1e54) to convert to explicit digits as "ii" parser
% is for strict integers
\xintdefiivar Nmin := iter(2{;}(@>num(1e54))?{break(i-1)}{i*@}, i=3++);
% turns out to be 44
% compute the corresponding value of e. As this uses
% the float parser, value of \xintDigits must now be set (else uses 16 per default)
\xintDigits:=52;
% problem is that each addition will be done with 52 digits
% precision only. But 52 is big enough compared to 48 digits
% which is our final goal.
% attention again to first semi-colon
\xintdeffloatvar e:=`+`(rseq(1{;} @/i, i= 1..Nmin));
% If the latter use this 'e' with a lower \xintDigits,
% it will be rounded *before* actual operations, but
% we stick here with our \xintDigits set to 52
% of course we could organize that easier if we dropped expandability!
\xintNewFunction{expt}[1]{% the #1 will actually be negative > -1 in our usage
iter(1, #1; (abs([@][1]) < 1e-48) ? % check if we abort
{break([@][0]+[@][1])} % yes, precision reached (add the last one nevertheless)
{([@][0]+[@][1], [@][1]*#1/i)}% iterate
,i = 2++)% first iteration computes 1+x and x^2/2
}%
% x = num(x) + frac(x), num is truncation of x to integer (towards zero), so
% tfrac same sign as x)
\xintNewFunction{exp}[1]{e^num(#1)*expt(frac(#1))}
% Now compute (natural) logarithm by Newton's method
% y_{n+1} = y_n - (1 - x\cdot e^{-y_n}), y_0 = x - 1
\xintNewFunction{log}[1]{%
iter(#1-1;
% must use single letter (here "d" stand for "delta") for substitution variable!
% and the reason for the substitution is to avoid computing multiple times
subs((d<1e-48)?
{break(@-d)}
{@-d},
d=1-#1*exp(-@))
,i=1++)% dummy iteration index, not used but needed by iter()
}
\begin{document}
\begin{table}[htbp]
\centering
\caption{Table of high-precision natural logarithms}
\begin{tabular}{|c|r|}
\hline
$x$&$\log(x)$\\\hline
\xintFor* #1 in {123456789{10}}\do {%
#1 &\xinttheiexpr [48]
\xintfloatexpr log(#1)\relax
\relax
\\\hline
}%
\end{tabular}
\end{table}
\end{document}
答案2
类似这样,但您可能需要检查舍入逻辑(我注意到我在最后一列得到 1731,您显示 1732)但这将帮助您入门(需要 lualatex)
\documentclass{article}
\begin{document}
{\parindent0pt
\catcode`\%=12
\directlua{
for i=10,99 do
if (i%5==0) then
tex.sprint("\string\\bigskip")
end
tex.sprint(string.format("%02d: \string\\ ",i))
for j =0,9 do
tex.sprint(string.format("%04d ",10000*math.log(0.1*i+0.01*j,10)))
end
tex.sprint("\string\\par")
end
}}
\end{document}
答案3
expl3
当然,您可以使用 来完成。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\logtable}{mm}
{% #1 = start, % #2 = end ( #2 - #1 + 1 should be a multiple of 5)
% the tl will contain the table body
\tl_clear:N \l__jjgreen_logtable_tl
% cycle from #1 to #2
\int_step_inline:nnnn { #1 } { 1 } { #2 }
{
% first add the tens as first column
\tl_put_right:Nn \l__jjgreen_logtable_tl { ##1 }
% compute the common logarithm of 10*#1+(0..9)
\int_step_inline:nnnn { 0 } { 1 } { 9 }
{
\tl_put_right:Nx \l__jjgreen_logtable_tl
{
& \jjgreen_mantissa:n { \fp_eval:n { round(ln(##1*10+####1)/ln(10),4) } }
}
}
\bool_lazy_and:nnTF
{% we're at a fifth row
\int_compare_p:n { \int_mod:nn { ##1 - #1 }{5} = 4 }
}
{% but not at the last
\int_compare_p:n { ##1 != #2 }
}
{ \tl_put_right:Nn \l__jjgreen_logtable_tl { \\[1ex] } }
{ \tl_put_right:Nn \l__jjgreen_logtable_tl { \\ } }
}
\begin{tabular}{ | r || *{5}{c} | *{5}{c} | }
\hline
N & 0 & 1 & 2 & 3 & 4 & 5 & 6 &7 & 8 & 9 \\
\hline
\tl_use:N \l__jjgreen_logtable_tl
\hline
\end{tabular}
}
\tl_new:N \l__jjgreen_logtable_tl
\tl_new:N \l__jjgreen_mantissa_tl
\seq_new:N \l__jjgreen_mantissa_seq
\cs_new_protected:Nn \jjgreen_mantissa:n
{
\seq_set_split:Nnn \l__jjgreen_mantissa_seq { . } { #1 }
\tl_set:Nx \l__jjgreen_mantissa_tl
{ \seq_item:Nn \l__jjgreen_mantissa_seq { 2 } }
\tl_use:N \l__jjgreen_mantissa_tl
\prg_replicate:nn { 4 - \tl_count:N \l__jjgreen_mantissa_tl } { 0 }
}
\ExplSyntaxOff
\begin{document}
\begin{center}
\logtable{10}{24}
\end{center}
\end{document}
的常用对数X计算为 ln(x)/ln(10),因为expl3
还没有十进制对数函数。结果四舍五入到小数点后四位,并传递(扩展)到非扩展函数以仅显示尾数。它在小数点处拆分并使用小数部分,用必要数量的零填充。
答案4
如果你想用 Python 代替 Lua,这里是大卫·卡莱尔的回答。
\documentclass[varwidth,border=7mm]{standalone}
\usepackage{python}
\begin{document}
\begin{python}
from math import log
for i in range(10, 99):
if i % 5 == 0:
print('\\bigskip')
print('%02d: \\ ' % i)
for j in range(0, 10):
print('%04d ' % round(10000 * log(0.1 * i + 0.01 * j, 10)))
print('\\par')
\end{python}%
\end{document}