我以前没有用过Lua,所以对计算有一些疑问:
.0
如果结果是整数,如何避免追加?- 如何才能实现四舍五入后添加正确数量的零?
- 我怎样才能将小数点标记改为
.
逗号,
?
我已尝试过的(MWE):
% Plain LuaTeX
\catcode`\@=11
% From latex.ltx
\long\def\@ifnextchar#1#2#3{%
\let\reserved@d=#1%
\def\reserved@a{#2}%
\def\reserved@b{#3}%
\futurelet\@let@token\@ifnch}
\def\@ifnch{%
\ifx\@let@token\@sptoken
\let\reserved@c\@xifnch
\else
\ifx\@let@token\reserved@d
\let\reserved@c\reserved@a
\else
\let\reserved@c\reserved@b
\fi
\fi
\reserved@c}
\def\:{\let\@sptoken= } \: % this makes \@sptoken a space token
\def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch}
% seen somewhere on tex.stackexchange.com
\directlua{
function math.round_int ( x )
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
function math.round ( x , n )
return ( math.round_int ( x*10^n ) / 10^n )
end
}
% My macros
\def\c@lc[#1]#2{\directlua{tex.print(math.round(#2,#1))}}
\def\calc{\@ifnextchar[\c@lc{\c@lc[2]}} % Default is rounding to 10^-2
Let's try the macros:
$ \sqrt2 \approx \calc[4]{2^(1/2)} $ is OK.
$ \root5\of{32} = \calc{32^(1/5)} $ should be $2$ as it is an integer.
$ 1.699999 \approx \calc[3]{1.699999} $ should be $1.700$ because it is rounded to $10^{-3}$.
$ 1.9 \approx \calc[0]{1.9} $ should be $2$ as it is rounded to whole numbers.
$ 8 \approx \calc[-1]{8} $ should be $10$ as it is rounded to $10^1$.
\bye
答案1
你问,
.0
如果(舍入运算的)结果是整数,我该如何避免附加?
在 Lua 5.3 之前的版本中,只有一种数字数据类型(“浮点数”);然而,Lua 被编程来显示数字没有小数部分不带尾数.0
,即,好像它们是整数(当然,它们是整数)。Lua 5.3 版引入了一种称为“整数”的新数字数据类型;Lua 5.3 版于今年早些时候(2019 年)被纳入 LuaTeX。这一变化的一个副作用是,现在.0
只有在以下情况下才会显示整数而不带尾数类型是“整数”。(当然,Lua 5.3 提供了将数字从 类型转换float
为 类型的方法integer
。以下代码中就用到了其中一种方法。)
那么,您遇到的问题是由于 Lua 函数math.round
(由 调用\c@lc
)始终返回“浮点”类型的数字;因此后面有.0
。要显示整数而不带.0
,我建议您进行两处更改。首先,添加以下代码块
function math.myround ( x , n )
if n==0 then
return ( math.round_int ( x ) )
elseif n<0 then
return ( math.floor ( math.round ( x , n ) ) )
else
return ( math.round ( x , n ) )
end
end
到第一个调用的参数\directlua
。第二个变化
\def\c@lc[#1]#2{\directlua{tex.print(math.round(#2,#1))}}
到
\def\c@lc[#1]#2{\directlua{tex.print(math.myround(#2,#1))}}
与 有何math.myround
不同?如果 的第一个参数为 0,即,如果要执行四舍五入到最接近的整数math.round
,则函数直接math.myround
调用。此外,如果 的第一个参数为负数,它会将浮点数强制转换为整数(在调用 之后)。这样, 返回的四舍五入数字就是math.round_int
\c@lc
math.round
\c@lc
math.myround
类型 integer
如果n
为 0 或负数,即四舍五入后的数字实际上是一个整数。
你还问过,
如何才能实现四舍五入后添加正确数量的零?
如果四舍五入到小数点后的数字后x
等于(其中是整数,也就是正整数),则运行1.7
n
n
string.format ( "%."..n.."f" , x )
创建一个n
在小数点标记后有明确数字的字符串——其中一些可能是零。
笔记:%
由于的第一个参数中有一个符号string.format
,因此您无法通过 加载代码,\directlua
因为 TeX 会因该符号而严重卡住%
。您必须将 Lua 代码放入名为 的外部文件中,然后myround.lua
通过 指令加载该文件\directlua{dofile("myround.lua")}
。
你问的第三个问题是,
我怎样才能将小数点标记改为
.
逗号,
?
Lua 提供了一个非常强大的函数,称为string.gsub
。(g
ingsub
代表“全局”。)您可以更改
return ( math.round ( x , n ) )
在函数math.myround
中
return ( ( string.gsub ( math.round ( x , n ) , "%." , "{,}" ) )
请注意,.
不是改为,
而是改为{,}
;这样做是为了告知 TeX 它不应该将这些实例视为,
类型的字符math-punct
。
与上文相同:%
由于的参数中有一个符号string.gsub
,因此您不能通过 加载代码\directlua
(因为 TeX 会再次因该符号而痛苦地卡住%
)。我建议您将 Lua 代码存储在名为 的外部文件中,然后myround.lua
通过 指令加载该文件\directlua{dofile("myround.lua")}
。
以下解决方案解决了您提出的所有三个问题。它使用 LaTeX 而不是 Plain-TeX,主要是因为我不知道如何filecontents
在 Plain-TeX 设置中使用环境(这对于创建外部文件非常有用)。不过,请参阅下文以获取有关 Plain-TeX 解决方案的说明。
% !TEX TS-program = lualatex
\documentclass{article} % or some other suitable document class
% The next instruction requires LaTeX format 2019-10-01 (or more recent)
\begin{filecontents*}[overwrite]{myround.lua}
-- First two functions seen somewhere on tex.stackexchange.com.
-- (Maybe https://tex.stackexchange.com/a/468118/5001 ??)
function math.round_int ( x )
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
function math.round ( x , n )
return math.round_int ( x*10^n ) / 10^n
end
-- New:
function math.myround ( x , n )
if n==0 then
return math.round_int ( x )
elseif n<0 then
return math.floor ( math.round ( x , n ) )
else -- n>0
x = math.round ( x , n ) -- replace 'x' with rounded version
x = string.format ( "%."..n.."f" , x )
return ( x:gsub ( "%." , "{,}" , 1 ) )
end
end
\end{filecontents*}
\directlua{dofile("myround.lua")} % Load the externally-stored code
\newcommand\calc[2][0]{% default value of opt. param.: 0
\directlua{tex.sprint(math.myround(#2,#1))}}
\begin{document}
\obeylines
Let's try the macros:
$ \sqrt{2} \approx \calc[4]{2^(1/2)} $. OK.
$ \sqrt[5]{32} = \calc{32^(1/5)} $. OK.
$ 1.699999 \approx \calc[3]{1.699999} $. OK.
$ 1.699999 \approx \calc[1]{1.699999} $. Also OK.
$ 1.9 \approx \calc{1.9} $. OK.
$ 8 \approx \calc[-1]{8} $. OK.
\end{document}
附录:为了完整起见,Plain-TeX 解决方案如下所示:
首先,创建一个名为的外部文件
myround.lua
,并将上面显示的环境内容filecontents
(3 个 Lua 函数)放置在其中。\directlua
其次,删除示例代码中第一条指令的内容,因为该代码现在包含在外部文件中。三、更换
% My macros \def\c@lc[#1]#2{\directlua{tex.print(math.round(#2,#1))}} \def\calc{\@ifnextchar[\c@lc{\c@lc[2]}} % Default is rounding to 10^-2
和
\directlua{dofile("myround.lua")} % load the externally-stored code % My macros \def\c@lc[#1]#2{\directlua{tex.print(math.myround(#2,#1))}} \def\calc{\@ifnextchar[\c@lc{\c@lc[0]}} % Default rounding: to nearest integer