支持“函数表”

支持“函数表”

在计算器出现之前,我们被“对数表”所困扰(或祝福),对数表是固定有效数字的函数表

例子

是否有 (La)TeX 支持此类表格?或者其他以 (La)TeX 格式输出此类表格的软件?

答案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}

在此处输入图片描述

相关内容