我正在为那些对十进制表示有深入理解并且对加减法有足够了解的孩子准备这个关于加减公式的小教程。这个想法是使用Ximera 项目。
Ximera 是一个很棒的教育项目,它可以让那些了解 LaTeX 和一些基本编程的人创建精彩的在线(和 PDF)数学内容。
以下是我想分多个步骤完成的操作:
给定一个随机正整数(可以使用 sagetex 或 latex 的随机化包),我想将其写为十进制块的总和。(我可以部分做到这一点。)但我希望能够对随机数执行此操作,方法是首先将给定的数字转换为列表,然后可以使用
\answer{\sage{my_list[my_entry]}}
命令为每个块引入该列表。然后,当我在 Ximera 服务器中运行代码时,它变成了一个很好的在线问题,其中人们需要引入十进制块条目。基本上,不依赖于数字的数量是问题所在。$12345=\answer{10000}+\answer{2000}+\answer{300}+\answer{40}+\answer{5}$
我想在十进制加法中产生“重命名”的想法。因此,对于 d 位加法(例如 d=3、a=987、b=74),它应该看起来像这样。别忘了:我想对两个随机整数执行此操作。
\documentclass{article}
\providecommand\answer[1]{#1} % dummy definition
\begin{document}
\[
\begin{array}{ *{10}{r} }
&&&1,000s&\star& 100s&\star & 10s& \star &1s \\
\hline
&987&=&\answer{0}&+& \answer{900}&+&\answer{80}&+&\answer{7} \\
&74&=&\answer{0}&+& \answer{0}&+&\answer{70}&+&\answer{4} \\
+&&&&&&&& \\
\hline
&rename&:&&& &+&\answer{10}&& \\
&&+&\answer{0}&+& \answer{900}&+&\answer{80}&& \\
&&+&\answer{0}&+& \answer{0}&+&\answer{70}&+&\answer{1} \\
+&&&&&&&& \\
\hline
&rename&:&&+&\answer{100} &&&& \\
&&+&\answer{0}&+& \answer{900}&+&&& \\
&&+&\answer{0}&+& \answer{0}&+&\answer{60}&+&\answer{1} \\
+&&&&&&&& \\
\hline
&rename&:&\answer{1000}&& &&&& \\
&&+&\answer{0}&+& \answer{0}&+&&& \\
&&+&\answer{0}&+& \answer{0}&+&\answer{60}&+&\answer{1} \\
+&&&&&&&& \\
\hline
&&=&\answer{1000}&+& \answer{0}&+&\answer{60}&+&\answer{1} \\
+&&&&&&&& \\
\hline
&\answer{1061}&=&&&&&&&
\end{array}
\]
\end{document}
最后,我想用同样的想法来做减法!
我知道这看起来不太好!动画是我以后再考虑的事情。
答案1
我不确定我是否完全理解了您的要求。(实际上,我很确定我没有完全理解这些要求……)无论如何,这是您描述的基本设置的完全基于 LuaLaTeX 的实现,以及两个屏幕截图。第一个屏幕截图显示不需要进位运算的情况,第二个屏幕截图显示需要 3 个进位运算的情况。
这是第一个屏幕截图:
这是第二个:
关于代码:首先,将 Lua 代码存储在名为的外部文件中base10.lua
:
function base10_addition()
-- create 2 integer-valued random numbers, <1000
num1 = math.random(999)
num2 = math.random(999)
-- Get base10 elements of num1 and num2
num1_1 = num1 % 1e1
num1_10 = num1 % 1e2 - num1_1
num1_100 = num1 - num1_10 - num1_1
num1_1000 = 0
num2_1 = num2 % 1e1
num2_10 = num2 % 1e2 - num2_1
num2_100 = num2 - num2_10 - num2_1
num2_1000 = 0
-- show the two numbers and their base-10 reps
tex.sprint ( "&"..num1.."&=&"..num1_1000.."&+&"..num1_100.."&+&"..num1_10.."&+&"..num1_1.."\\\\" )
tex.sprint ( "&"..num2.."&=&"..num2_1000.."&+&"..num2_100.."&+&"..num2_10.."&+&"..num2_1.."\\\\" )
tex.sprint ( "\\cmidrule(l){9-10}" )
tex.sprint ( "+\\\\ \\addlinespace " )
-- check if overflow in 1s column
num2_1=num1_1+num2_1
if num2_1 > 9 then
num2_1 = num2_1-10
tex.sprint ( "&\\mbox{rename}&&&&&+&10\\\\" )
carry = 10
else
carry = 0
end
tex.sprint ( "&&&"..num1_1000.."&+&"..num1_100.."&+&"..num1_10.."\\\\" )
tex.sprint ( "&&&"..num2_1000.."&+&"..num2_100.."&+&"..num2_10.."&+&"..num2_1.."\\\\" )
tex.sprint ( "\\cmidrule(lr){7-8}" )
tex.sprint ( "+\\\\ \\addlinespace " )
-- check if overflow in 10s column
num2_10=num1_10+num2_10+carry
if num2_10 > 90 then
num2_10 = num2_10-100
tex.sprint ( "&\\mbox{rename}&&& + &100\\\\" )
carry=100
else
carry=0
end
tex.sprint ( "&&&"..num1_1000.."&+&"..num1_100.."\\\\" )
tex.sprint ( "&&&"..num2_1000.."&+&"..num2_100.."&+&"..num2_10.."&+&"..num2_1.."\\\\" )
tex.sprint ( "\\cmidrule(lr){5-6}" )
tex.sprint ( "+\\\\ \\addlinespace " )
-- check if overflow in 100s column
num2_100=num1_100+num2_100+carry
if num2_100 > 900 then
num2_100 = num2_100-1000
tex.sprint ( "&\\mbox{rename}&& 1000 \\\\" )
carry=1000
else
carry=0
end
if carry>0 then
tex.sprint ("&&&")
else
tex.sprint ("&&=&")
end
tex.sprint ( num2_1000.."&+&"..num2_100.."&+&"..num2_10.."&+&"..num2_1.."\\\\" )
if carry>0 then
tex.sprint ( "\\cmidrule(lr){4-4}" )
tex.sprint ( "+\\\\" )
end
tex.sprint ( "\\midrule " )
-- print the final base-10 rep
if carry>0 then
num2_1000=num2_1000+carry
tex.sprint ( "&&=&"..num2_1000.."&+&"..num2_100.."&+&"..num2_10.."&+&"..num2_1.."\\\\" )
tex.sprint ( "\\midrule" )
end
-- print the final result
tex.sprint ( "=&" .. num1+num2 )
end
这是 LaTeX 代码。
% !TEX TS-program = lualatex
\documentclass{article}
\directlua{ dofile ( "base10.lua" ) } % load the Lua code
\usepackage{array,booktabs}
\newlength\mylen
\settowidth\mylen{rename} % define width of 2nd col.
\begin{document}
\[
\begin{array}{@{} l w{r}{\mylen} *{4}{cr} @{}}
&&&1000\mbox{s}&\star& 100\mbox{s}&\star & 10\mbox{s}& \star &1\mbox{s}\\
\midrule
\directlua{base10_addition()} % the Lua function does almost all the work
\end{array}
\]
\end{document}
答案2
更新
从评论中移出:如果我理解正确,您在 TeX 方面需要的是生成表格的 LaTeX 标记的代码,其中\answer
宏包含预先计算的答案作为参数。这与我的答案或 @Mico 的当前状态截然不同,后者在 (lua|pdf)latex 编译期间“即时”评估。请指教。我们当然可以使用随机输入和预先计算的答案生成这样的数组,并将它们输出到某个文件中,然后可以从那里再次输入;没有包,这很容易达到 9 位数字(TeX 可以处理最多 10 位数字,但<2^{31}
为了避免添加溢出,最多 9 位数字)。但使用 Python 生成 LaTeX 也很容易。如果我只使用 TeX 编写它,可能只有几十个人会理解 TeX 代码(99% 的 LaTeX 用户不编程)。如果您使用 Python 编写它,每个人都会理解代码的作用。
因此,我将原始答案转换为生成乳胶片段的答案,或多或少类似于OP中提供的示例。
- 所有
\cmidrule
等等...都被删除了 - 如果数字的数量是一个输入变量,则代码对于更多数字来说就不容易扩展:因为它使用类似的变量,
num1_1000
并且自动化这样的名称很麻烦。 - 我最初的回答重点是将 Lua 代码从 @Mico 转换为 xint 代码,因此保留了变量的命名等。这个想法是,这提供了非常易读的代码。如果我要重新开始,我会使用核心 TeX 和、等
#1
东西来获取数字,当然代码将是 TeX 核心。那么就不需要包了,除了可能与引擎(或)相比,它的随机数生成器有所改进。这种核心方法将使扩展到更多数字变得更容易一些。但最多只能达到 9 位数字。#2
#3
xint
\pdfuniformdeviate
\uniformdeviate
- 我还改变了随机数生成以保证 3 位数字(
100<= x < 1000
),这使得更有可能看到进位以及如何处理它。
无论如何,在接下来的示例中,代码会生成 5 个 LaTeX 代码片段作为外部文件(然后\input
将它们用于在 PDF 输出中直观地检查它们是否工作正常)。第三个代码片段如下所示:
\begin{array}{rrrrrrrrrr}
&&&1,000s&\star & 100s&\star & 10s& \star &1s \\
\hline
&677&=&\answer{0}&+&\answer{600}&+&\answer{70}&+&\answer{7}\\
&533&=&\answer{0}&+&\answer{500}&+&\answer{30}&+&\answer{3}\\
+&&&&&&&& \\
\hline
&rename&:&&&&+&\answer{10}\\
&&+&\answer{0}&+&\answer{600}&+&\answer{70}\\
&&+&\answer{0}&+&\answer{500}&+&\answer{30}&+&\answer{0}\\
+&&&&&&&& \\
\hline
&rename&:&& + &\answer{100}\\
&&+&\answer{0}&+&\answer{600}\\
&&+&\answer{0}&+&\answer{500}&+&\answer{10}&+&\answer{0}\\
+&&&&&&&& \\
\hline
&rename&:&\answer{1000}\\
&&+&\answer{0}&+&\answer{200}&+&\answer{10}&+&\answer{0}\\
+&&&&&&&& \\
\hline
&&=&\answer{1000}&+&\answer{200}&+&\answer{10}&+&\answer{0}\\
+&&&&&&&& \\
\hline
&\answer{1210}&=&&&&&&&
\end{array}
正如上面的评论所解释的那样,我感觉问题在于生成 LaTeX 代码片段并将其转换为 HTML。然后,使用 Python 来生成 LaTeX 代码片段会更容易,因为这里似乎没有实际使用 LaTeX 来生成 PDF 的问题:这就是为什么 @Mico 答案中的所有印刷改进都被删除了。
无论如何,代码非常简单,但正如上面所说,由于变量的命名方案,代码不易扩展。此外,我还必须对各种符号的预期进行一些猜测+
,我恢复了从@Mico 的答案中删去的一些符号。
生成代码:
\documentclass{article}
\usepackage{xintexpr}[2018/05/18]% because we use randrange()
\newwrite\forximera
\newcounter{outcount}
\makeatletter
\newcommand{\BaseTenAddition}{%
\stepcounter{outcount}%
\immediate\openout\forximera=\jobname-xim\the\value{outcount}.tex
\immediate\write\forximera{%
\string\begin{array}{rrrrrrrrrr}^^J%
\@spaces&&&1,000s&\star& 100s&\star & 10s& \star &1s \string\\^^J%
\@spaces\string\hline}%
%
%% create 2 integer-valued random numbers, <1000
%% make them 100 <= x < 1000
\xintdefiivar num1 := randrange(100, 1000);%
\xintdefiivar num2 := randrange(100, 1000);%
%
%
%% Get base10 elements of num1 and num2
\xintdefiivar num1_1 := num1 /: 10;% /: is modulo operator
\xintdefiivar num1_10 := num1 /: 100 - num1_1;%
\xintdefiivar num1_100 := num1 - num1_10 - num1_1;%
\xintdefiivar num1_1000 := 0 ;%
\xintdefiivar num2_1 := num2 /: 10;%
\xintdefiivar num2_10 := num2 /: 100 - num2_1;%
\xintdefiivar num2_100 := num2 - num2_10 - num2_1;%
\xintdefiivar num2_1000 := 0 ;%
%
%
%% show the two numbers and their base-10 reps
\immediate\write\forximera{\@spaces
&\xinttheiiexpr num1\relax
&=&\string\answer{\xinttheiiexpr num1_1000\relax}%
&+&\string\answer{\xinttheiiexpr num1_100\relax}%
&+&\string\answer{\xinttheiiexpr num1_10\relax}%
&+&\string\answer{\xinttheiiexpr num1_1\relax}\string\\}%
\immediate\write\forximera{\@spaces
&\xinttheiiexpr num2\relax
&=&\string\answer{\xinttheiiexpr num2_1000\relax}%
&+&\string\answer{\xinttheiiexpr num2_100\relax}%
&+&\string\answer{\xinttheiiexpr num2_10\relax}%
&+&\string\answer{\xinttheiiexpr num2_1\relax}\string\\}%
%%
\immediate\write\forximera{\@spaces+&&&&&&&& \string\\^^J%
\@spaces\string\hline}%
%%
%% check if overflow in 1s column
\xintdefiivar num2_1:=num1_1+num2_1;%
\xintifbooliiexpr{num2_1 > 9}
{\xintdefiivar num2_1 := num2_1-10;%
\xintdefiivar carry := 10;%
\immediate\write\forximera{\@spaces&rename&:&&&&+&\string\answer{10}\string\\}%
}
{\xintdefiivar carry := 0;}%
\immediate\write\forximera{\@spaces
&&+&\string\answer{\xinttheiiexpr num1_1000\relax}%
&+&\string\answer{\xinttheiiexpr num1_100\relax}%
&+&\string\answer{\xinttheiiexpr num1_10\relax}%
\string\\}%
\immediate\write\forximera{\@spaces
&&+&\string\answer{\xinttheiiexpr num2_1000\relax}%
&+&\string\answer{\xinttheiiexpr num2_100\relax}%
&+&\string\answer{\xinttheiiexpr num2_10\relax}%
&+&\string\answer{\xinttheiiexpr num2_1\relax}%
\string\\}%
%%
\immediate\write\forximera{\@spaces+&&&&&&&& \string\\^^J%
\@spaces\string\hline}%
%
%
%% check if overflow in 10s column
\xintdefiivar num2_10:=num1_10+num2_10+carry;%
\xintifbooliiexpr{num2_10 > 90}
{\xintdefiivar num2_10 := num2_10-100;%
\xintdefiivar carry := 100;%
\immediate\write\forximera{\@spaces&rename&:&& + &\string\answer{100}\string\\}%
}
{\xintdefiivar carry := 0;}%
\immediate\write\forximera{\@spaces
&&+&\string\answer{\xinttheiiexpr num1_1000\relax}%
&+&\string\answer{\xinttheiiexpr num1_100\relax}\string\\}%
\immediate\write\forximera{\@spaces
&&+&\string\answer{\xinttheiiexpr num2_1000\relax}%
&+&\string\answer{\xinttheiiexpr num2_100\relax}%
&+&\string\answer{\xinttheiiexpr num2_10\relax}%
&+&\string\answer{\xinttheiiexpr num2_1\relax}\string\\}%
%%
\immediate\write\forximera{\@spaces+&&&&&&&& \string\\^^J%
\@spaces\string\hline}%
%
%
%% check if overflow in 100s column
\xintdefiivar num2_100:=num1_100+num2_100+carry;%
\xintifbooliiexpr{num2_100 > 900}
{\xintdefiivar num2_100 := num2_100-1000;%
\xintdefiivar carry := 1000;%
\immediate\write\forximera{\@spaces&rename&:&\string\answer{1000}\string\\}%
}
{\xintdefiivar carry := 0;}%
\immediate\write\forximera{\@spaces
\xintifbooliiexpr{carry>0}{&&+&}{&&=&}%
\string\answer{\xinttheiiexpr num2_1000\relax}%
&+&\string\answer{\xinttheiiexpr num2_100\relax}%
&+&\string\answer{\xinttheiiexpr num2_10\relax}%
&+&\string\answer{\xinttheiiexpr num2_1\relax}%
\string\\}%
%%
\immediate\write\forximera{\@spaces+&&&&&&&& \string\\^^J%
\@spaces\string\hline}%
%%
%% print the final base-10 rep
\xintifbooliiexpr{carry>0}
{\xintdefiivar num2_1000:=num2_1000+carry;%
\immediate\write\forximera{\@spaces
&&=&\string\answer{\xinttheiiexpr num2_1000\relax}%
&+&\string\answer{\xinttheiiexpr num2_100\relax}%
&+&\string\answer{\xinttheiiexpr num2_10\relax}%
&+&\string\answer{\xinttheiiexpr num2_1\relax}%
\string\\}%
%%
\immediate\write\forximera{\@spaces+&&&&&&&& \string\\^^J%
\@spaces\string\hline}%
%%
}
{}% no false branch
%% print the final result
\immediate\write\forximera{\@spaces
&\string\answer{\xinttheiiexpr num1+num2\relax}&=&&&&&&&^^J%
\string\end{array}}%
%
% close output file
\immediate\closeout\forximera
}
\usepackage{array}
\begin{document}\pagestyle{empty}\thispagestyle{empty}
\pdfsetrandomseed 12345678
\BaseTenAddition % generate external file
\BaseTenAddition % one more
\BaseTenAddition % one more
\BaseTenAddition % one more
\BaseTenAddition % one more
% testing the files, give \answer some definition.
\def\answer#1{#1}
\[
\input \jobname-xim1
\]
Again
\[
\input \jobname-xim2
\]
Again
\[
\input \jobname-xim3
\]
Again
\[
\input \jobname-xim4
\]
Again
\[
\input \jobname-xim5
\]
\end{document}
原始答案
我不确定我是否完全理解了您的要求。(实际上,我很确定我没有完全理解这些要求......)无论如何,这里有一个完全xintexpr
-基于您描述的基本设置的实现,以及两个屏幕截图。
这里再补充两句,因为作者对于原作者@Mico 的这种抄袭行为感到非常自豪:
关于代码:第一的我们用 LaTeX 代码完成所有工作。
承认错误:我已经说过我抄袭了@Mico 的代码。我从 Lua 转回了xint
。但一切都可以在没有任何包的情况下完成,只需一些\edef
和\numexpr
和\pdfuniformdeviate
。
综上所述,我们需要的最新版本因为它 才xint
具有功能。randrange()
第二:没有第二步;-)
……
\documentclass{article}
\usepackage{xintexpr}[2018/05/18]% because we use randrange()
\newcommand{\BaseTenAddition}{%
% temporarily make definitions have global scope, because
% xint creation of variable is scope obedient and is lacking
% user interface for global scope (should be added in future)
\globaldefs1
%
% no need to reset \globaldefs afterwards explicitely
% as its setting will be extinguished after first cell...
%
%% create 2 integer-valued random numbers, <1000
\xintdefiivar num1 := randrange(1000);%
\xintdefiivar num2 := randrange(1000);%
%
%
%% Get base10 elements of num1 and num2
\xintdefiivar num1_1 := num1 /: 10;% /: is modulo operator
\xintdefiivar num1_10 := num1 /: 100 - num1_1;%
\xintdefiivar num1_100 := num1 - num1_10 - num1_1;%
\xintdefiivar num1_1000 := 0 ;%
\xintdefiivar num2_1 := num2 /: 10;%
\xintdefiivar num2_10 := num2 /: 100 - num2_1;%
\xintdefiivar num2_100 := num2 - num2_10 - num2_1;%
\xintdefiivar num2_1000 := 0 ;%
%
%
%% show the two numbers and their base-10 reps
&\xinttheiiexpr num1\relax
&=&\xinttheiiexpr num1_1000\relax
&+&\xinttheiiexpr num1_100\relax
&+&\xinttheiiexpr num1_10\relax
&+&\xinttheiiexpr num1_1\relax\\
&\xinttheiiexpr num2\relax
&=&\xinttheiiexpr num2_1000\relax
&+&\xinttheiiexpr num2_100\relax
&+&\xinttheiiexpr num2_10\relax
&+&\xinttheiiexpr num2_1\relax\\
\cmidrule(l){9-10}
+\\ \addlinespace
%
%
%% check if overflow in 1s column
\globaldefs1
\xintdefiivar num2_1:=num1_1+num2_1;%
\xintifbooliiexpr{num2_1 > 9}
{\xintdefiivar num2_1 := num2_1-10;%
\xintdefiivar carry := 10;%
&\mbox{rename}&&&&&+&10\\
}
{\xintdefiivar carry := 0;}%
&&&\xinttheiiexpr num1_1000\relax
&+&\xinttheiiexpr num1_100\relax
&+&\xinttheiiexpr num1_10\relax
\\
&&&\xinttheiiexpr num2_1000\relax
&+&\xinttheiiexpr num2_100\relax
&+&\xinttheiiexpr num2_10\relax
&+&\xinttheiiexpr num2_1\relax
\\
\cmidrule(lr){7-8}
+\\ \addlinespace
%
%
%% check if overflow in 10s column
\globaldefs1
\xintdefiivar num2_10:=num1_10+num2_10+carry;%
\xintifbooliiexpr{num2_10 > 90}
{\xintdefiivar num2_10 := num2_10-100;%
\xintdefiivar carry := 100;%
&\mbox{rename}&&& + &100\\
}
{\xintdefiivar carry := 0;}%
&&&\xinttheiiexpr num1_1000\relax
&+&\xinttheiiexpr num1_100\relax\\
&&&\xinttheiiexpr num2_1000\relax
&+&\xinttheiiexpr num2_100\relax
&+&\xinttheiiexpr num2_10\relax
&+&\xinttheiiexpr num2_1\relax\\
\cmidrule(lr){5-6}
+\\ \addlinespace
%
%
%% check if overflow in 100s column
\globaldefs1
\xintdefiivar num2_100:=num1_100+num2_100+carry;%
\xintifbooliiexpr{num2_100 > 900}
{\xintdefiivar num2_100 := num2_100-1000;%
\xintdefiivar carry := 1000;%
&\mbox{rename}&& 1000 \\
}
{\xintdefiivar carry := 0;}%
\xintifbooliiexpr{carry>0}{&&&}{&&=&}%
\xinttheiiexpr num2_1000\relax
&+&\xinttheiiexpr num2_100\relax
&+&\xinttheiiexpr num2_10\relax
&+&\xinttheiiexpr num2_1\relax
\\
\xintifbooliiexpr{carry > 0}
{\cmidrule(lr){4-4}+\\}
{\midrule}%
%
%
%% print the final base-10 rep
\globaldefs1
\xintifbooliiexpr{carry>0}
{\xintdefiivar num2_1000:=num2_1000+carry;%
&&=&\xinttheiiexpr num2_1000\relax
&+&\xinttheiiexpr num2_100\relax
&+&\xinttheiiexpr num2_10\relax
&+&\xinttheiiexpr num2_1\relax
\\
\midrule}
{}% no false branch
%
%
%% print the final result
=&\xinttheiiexpr num1+num2\relax
}
\usepackage{array,booktabs}
\newlength\mylen
\settowidth\mylen{rename} % define width of 2nd col.
\begin{document}
\[
\begin{array}{@{} l w{r}{\mylen} *{4}{cr} @{}}
&&&1000\mbox{s}&\star& 100\mbox{s}&\star & 10\mbox{s}& \star &1\mbox{s}\\
\midrule
\BaseTenAddition % the xintexpr-based macro does almost all the work
\end{array}
\]
Again
\[
\begin{array}{@{} l w{r}{\mylen} *{4}{cr} @{}}
&&&1000\mbox{s}&\star& 100\mbox{s}&\star & 10\mbox{s}& \star &1\mbox{s}\\
\midrule
\BaseTenAddition % the xintexpr-based macro does almost all the work
\end{array}
\]
\thispagestyle{empty}
\end{document}