当我写出超越纳皮尔数的十进制数字时,我的学生总是很高兴埃。我只记得 30 位十进制数字,例如。我提醒所有读者,我不是这个siunitx
包的专家。但是,我知道正确处理其中的数字、单位和空格很重要。:-)
\documentclass{article}
\begin{document}
$e=2.718281828459045235360287471352\dots$
\end{document}
使用此小部件沃尔夫拉姆阿尔法的纳皮尔数我可以选择小数位数。 是否可以使用 LaTeX 实现同样的功能?
答案1
我保存了 100 位小数埃。
\documentclass{article}
\usepackage{siunitx} % also loads expl3 and xparse
\ExplSyntaxOn
\tl_const:Nn \c_sebastiano_napier_tl
{
71828182845904523536
02874713526624977572
47093699959574966967
62772407663035354759
45713821785251664274
}
\NewDocumentCommand{\napier}{m}
{
\num{ 2.\tl_range:Nnn \c_sebastiano_napier_tl { 1 } { #1 } }
}
\ExplSyntaxOff
\begin{document}
\napier{2}
\napier{18}
\end{document}
尽可能使用换行符\napier*
。
\documentclass{article}
\usepackage{amsmath}
\usepackage{siunitx} % also loads expl3 and xparse
\showthe\thinmuskip
\ExplSyntaxOn
\tl_const:Nn \c_sebastiano_napier_tl
{
71828182845904523536
02874713526624977572
47093699959574966967
62772407663035354759
45713821785251664274
}
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }
\NewDocumentCommand{\napier}{sm}
{
\IfBooleanTF { #1 }
{
\sebastiano_napier_inline:n { #2 }
}
{
\num{ 2.\tl_range:Nnn \c_sebastiano_napier_tl { 1 } { #2 } }
}
}
\cs_new_protected:Nn \sebastiano_napier_inline:n
{
\seq_set_split:Nnx \l_tmpa_seq {} { \tl_range:Nnn \c_sebastiano_napier_tl { 1 } { #1 } }
2.\seq_indexed_map_function:NN \l_tmpa_seq \__sebastiano_napier_split:nn
}
\cs_new_protected:Nn \__sebastiano_napier_split:nn
{
#2
\int_compare:nT { \int_mod:nn { #1 } { 3 } = 0 }
{
\mode_if_math:TF
{
\penalty \c_zero_int
\mspace{1\thinmuskip plus 1\thinmuskip}
}
{
\hspace{0.16667em plus 0.16667em}
}
}
}
\ExplSyntaxOff
\begin{document}
\napier{2}
\napier{18}
\napier*{99}
$\napier*{99}$
\end{document}
答案2
只是为了好玩,这里有一个使用 LuaTeX 的答案,它可以计算 Lua 中的数字e
,无需外部数据,至少可以计算约 10000 位数字。 (实际上,原则上,该算法应该可以很好地工作 (只是需要很长时间),适用于数十亿位数字甚至数百万亿位数字,具体取决于 Lua 的编译方式,但您很快就会失去耐心和/或内存。)
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
-- Takes time ~n^2 to compute n digits. Tolerable until about n=10000.
function digits_e(n)
-- Spigot algorithm by Rabinowitz and Wagon:
-- http://www.cecm.sfu.ca/~jborwein/Expbook/Manuscript/Related%20files/spigot.pdf
-- The idea: Just as we can say that
-- e = 2 + (7, 1, 8, 2, 8, ...) in base (1/10, 1/10, 1/10, 1/10, 1/10, ...)
-- the fact that e = sum(1/k!) over k≥0 gives, in the same notation,
-- e = 2 + (1, 1, 1, 1, 1, ...) in base (1/2, 1/3, 1/4, 1/5, 1/6, 1/7, ...)
-- We convert to the decimal base by repeatedly multiplying by 10.
local len = n + 2
-- After k≥0 steps, fractional part of (e-2)10^k in base (1/2, 1/3, 1/4, ...)
local a = {}; for j = 1, len do a[j] = 1 end
tex.sprint('2.')
for k = 1, n do
local carry = 0 -- We're about to multiply by 10, right to left.
for i = len, 1, -1 do
local x = carry + 10 * a[i]
a[i] = math.fmod(x, i + 1)
carry = math.modf(x / (i + 1))
end
tex.sprint(carry)
if k % 1000 == 0 then print(string.format('Done %d digits', k)) end
if k % 3 == 0 then tex.sprint([[\hskip 1.66663pt plus 0.6pt\relax]]) end
end
end
\end{luacode}
\newcommand\napier[1]{\directlua{tex.sprint(digits_e(#1))}}
\begin{document}
\napier{2}
\napier{18}
\napier{100} % Last 10 digits: ...525 166 427 4
\napier{1000} % Last 10 digits: ...957 035 035 4
\napier{10000} % Last 10 digits: ...946 553 678 8
\end{document}
我重新利用了以前使用的算法早期的 pi,尽管对于 e 来说它要简单得多。
它的复杂度为 O(n^2),因此有点慢(10000 位数字需要几秒钟)。我们可以通过乘以 10 的幂而不是乘以 10 本身来将其速度提高一个小的常数倍(例如 10)。(
block
参见此答案的第二次修订;恢复以保持代码清晰和简单。)该算法足够简单(并且仅使用小数字的算术,其大小大致与请求的数字相同),我怀疑它甚至可以用 TeX 宏和足够多的寄存器来实现。:-)
我尝试使用
\num
fromsiunitx
,但很难弄清楚如何排版长数字而不会出现框满警告等问题——似乎该包不提供这样的功能,而且它看起来很复杂。最终还是放弃了,\hskip
手动写入 Lua 代码。:-)
答案3
这是一个基于 LuaLaTeX 的解决方案。它提供了两个 LaTeX 实用宏 --\ShowNum
和\ShowGrNum
-- 以及两个执行实际工作的 Lua 函数。
一些评论:
因为 Lua 只执行双精度计算,所以你应该不是如果您打算显示超过 15 位十进制数字,请使用此方法。如果您确实打算显示超过 15 位十进制数字,则需要预先存储感兴趣的数字,直到达到所需的精度水平,如@egreg 的回答以及下面所示的附录,或者追求任意精度的方法,比如@ShreevatsaR 的回答。
LaTeX 宏
\ShowNum
接受 2 个参数:数字本身和要显示的小数位数。不进行分组。的第一个参数可以是
\ShowNum
常量,例如,,12345.6789012
或者是可以由Lua 进行有意义评估的内容,例如math.exp(1)
,,,,或。math.pi
2*math.acos(0)
2*math.asin(1)
第一个参数中可以使用四个算术符号
+-*/
;但是,不要^
在第一个参数中使用(指数),\ShowNum
因为 LaTeX 会将其解释为上标材料的开始。一般来说,要小心,以免第一个参数包含可能被 LaTeX 以某种意想不到的方式扩展的材料。当然,第一个参数
\ShowNum
包含扩展为 Lua 可以处理的内容的 LaTeX 宏是可以的。
该宏
\ShowGrNum
采用与 相同的 2 个参数\ShowNum
,外加一个确定分组类型的可选参数。可选参数应为整数(又称正整数)。可选参数的默认值为3
,即小数部分(但不是整数部分)将默认以 3 位数字的块分组。请注意,允许在每组数字后换行;这与包的宏\ShowGrNum
的属性相反。\num
siunitx
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function PrintNum ( n , m )
-- n: number to be printed
-- m: number of decimal digits to be shown
return string.format ( "%."..m.."f" , n )
end
function GroupNum ( s , g )
-- s: number whose decimal part should be grouped
-- g: number of digits in group (say, '3')
s = tostring ( s )
local m
m = s:find ( "%." ) -- find the integer part of 's'
if m then -- print integer part first
tex.sprint ( s:sub(1,m) ) -- no grouping applied
s = s:sub(m+1)
end
-- Apply visual grouping to decimal part:
while #s > g do
tex.sprint ( s:sub(1,g) .. "\\hspace{0.1666em}\\allowbreak")
s = s:sub(g+1) -- discard the first 'n' chars
end
tex.sprint ( s )
end
\end{luacode}
%% Define 2 LaTeX macros:
%% \ShowNum just prints the number
%% \ShowGrNum additionally groups the number
\newcommand\ShowNum[2]{\directlua{%
tex.sprint ( PrintNum ( #1 , #2 ) )}}
\newcommand\ShowGrNum[3][3]{\directlua{%
GroupNum ( PrintNum ( #2 , #3 ) , #1 )}}
\begin{document}
\ShowNum{math.exp(1)}{15}
$\ShowNum{math.pi}{15}$
\smallskip
\ShowGrNum{math.exp(1)}{15}
$\ShowGrNum[4]{2*math.acos(0)}{15}$
\end{document}
附录:只是为了好玩,这里有一个 LuaLaTeX 解决方案版本,它存储了纳皮尔数的前 2000 位十进制数字。通过 LaTeX 宏可以显示从 0 到 2000 的任何数字\Napier
。该宏有一个可选参数:每组中的数字位数。(默认分组数为 3。)如上面的答案所示,分组是借助 Lua 强大的功能进行的string.sub
。
% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
-- store the first 2000 decimal digits of Napier's number as a string:
local napiernum = "71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101901157383418793070215408914993488416750924476146066808226480016847741185374234544243710753907774499206955170276183860626133138458300075204493382656029760673711320070932870912744374704723069697720931014169283681902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312773617821542499922957635148220826989519366803318252886939849646510582093923982948879332036250944311730123819706841614039701983767932068328237646480429531180232878250981945581530175671736133206981125099618188159304169035159888851934580727386673858942287922849989208680582574927961048419844436346324496848756023362482704197862320900216099023530436994184914631409343173814364054625315209618369088870701676839642437814059271456354906130310720851038375051011574770417189861068739696552126715468895703503540212340784981933432106817012100562788023519303322474501585390473041995777709350366041699732972508868769664035557071622684471625607988265178713419512466520103059212366771943252786753985589448969709640975459185695638023637016211204774272283648961342251644507818244235294863637214174023889344124796357437026375529444833799801612549227850925778256209262264832627793338656648162772516401910590049164499828931505660472580277863186415519565324425869829469593080191529872117255634754639644791014590409058629849679128740687050489585867174798546677575732056812884592054133405392200011378630094556068816674001698420558040336379537645203040243225661352783695117788386387443966253224985065499588623428189970773327617178392803494650143455889707194258639877275471096295374152111513683506275260232648472870392076431005958411661205452970302364725492966693811513732275364509888903136020572481765851180630364428123149655070475102544650117272115551948668508003685322818315219600373562527944951582841882947876108526398139"
function Napier ( n , g )
-- n: number of decimal digits to be shown (0\le n \le 2000)
-- g: number of digits per group (3 by default)
if n==0 then -- no decimal part to show
tex.sprint ( "2" )
else
e = napiernum:sub ( 1 , n ) -- retain the first n digits
tex.sprint "2."
while #e>g do
tex.sprint ( e:sub ( 1 , g ) .. "\\,\\allowbreak" )
e = e:sub ( g+1 ) -- discard first g digits
end
tex.sprint ( e ) -- display remaining digits (if any)
end
end
\end{luacode}
%% LaTeX macro to show first n digits of "e", grouped:
\newcommand\Napier[2][3]{\directlua{Napier(#2,#1)}}
\begin{document}
\raggedright
\Napier{0}, \Napier{1}, \Napier{9}
\smallskip
\Napier[8]{1024} % in groups of 8
\end{document}
答案4
答案sagetex
可以稍微缩短一点,改编一下 PeterGrill 的回答格式化小数。使用numprint
包和 minipage 环境可防止 SAGE 输出溢出行。由于这对于较长的 SAGE 输出很有用,因此我在下面添加了代码。
\documentclass[]{article}
\usepackage{sagetex,numprint}
\npdecimalsign{\ensuremath{.}}%
\npthousandsep{ }%
\begin{document}
\begin{sagesilent}
output = r"\begin{minipage}{.95\linewidth}"
output += r"\numprint{%s}"%(e.n(digits=1000))
output += r"\end{minipage}"
\end{sagesilent}
$\sagestr{output}$
\end{document}
Cocalc 中的运行输出如下: