据说 TeX 应该在所有系统上以相同的方式工作。例如,克努斯的TRIP 测试存在是为了确保任何程序只有在给定特定输入的情况下执行特定操作时才能被称为“TeX”。TeX 程序本身采取了某些措施来防止系统相关因素导致行为差异,例如对于尺寸,TeX 使用定点数而不是浮点数:1 的整数倍sp
(缩放点),即 1/72.27 英寸的 1/65536。
问题 1:但是(除了通过旅行测试之外)行为相同意味着什么?
由于 TeX 的输出是包含排版指令(拾取字体 F、向右移动 W 个单位、将字符 97 设置在那里等)的 DVI 文件,因此一个自然的解释(在我看来)是 DVI 文件必须相同,当然除了构成时间戳的字节之外。同样地,如果我们dvitype
在这两个文件上运行,并且比较在过滤掉时间戳行之后,它们应该包含相同的指令(是一种解释)。
但即使是相当简单的输入文件,我也看到 MiKTeX 和 TeX Live 之间的 DVI 文件(即不仅仅是时间戳行)存在差异。具体来说,请考虑以下最小.tex
输入文件(摘自TeX 简介):
The DVI file is then read by another program (called a
device driver) that produces the output that is readable by
humans. Why the extra file? The same DVI file can be
read by different device drivers to produce output on a dot
matrix printer, a laser printer, a screen viewer, or a
phototypesetter. Once you have
\end
当我通过两个名为 TeX 的程序运行上述文件时,即:
MiKTeX-TeX 2.9.6300 (3.14159265) (MiKTeX 2.9.6600)
和
TeX 3.14159265 (TeX Live 2017)
都在同一台电脑上(macOS 10.13.3 High Sierra),TeX 的输出(DVI 文件)看视觉上相同,但大小不同(字节数不同)。当比较 DVI 文件中包含的实际指令(操作码)(通过dvitype
在每个文件上运行)时,会发现数百个细微的差异。在本例中,第一个是
10c10
< Postamble starts at byte 561.
---
> Postamble starts at byte 564.
这是由下面稍后发生的差异引起的:
< 436: w0 261236 h:=9392617+261236=9653853, hh:=611
< 437: setchar112 h:=9653853+364090=10017943, hh:=634
< 438: setchar114 h:=10017943+256683=10274626, hh:=650
< 439: setchar105 h:=10274626+182045=10456671, hh:=662
< 440: setchar110 h:=10456671+364090=10820761, hh:=685
< 441: x2 -18205 h:=10820761-18205=10802556, hh:=684
< 444: setchar116 h:=10802556+254863=11057419, hh:=700
< 445: setchar101 h:=11057419+291271=11348690, hh:=718
< 446: setchar114 h:=11348690+256683=11605373, hh:=734
< 447: setchar44 h:=11605373+182045=11787418, hh:=746
< 448: right3 271931 h:=11787418+271931=12059349, hh:=764
< 452: setchar97 h:=12059349+327681=12387030, hh:=785
---
> 436: right3 261235 h:=9392617+261235=9653852, hh:=611
> 440: setchar112 h:=9653852+364090=10017942, hh:=634
> 441: setchar114 h:=10017942+256683=10274625, hh:=650
> 442: setchar105 h:=10274625+182045=10456670, hh:=662
> 443: setchar110 h:=10456670+364090=10820760, hh:=685
> 444: x2 -18205 h:=10820760-18205=10802555, hh:=684
> 447: setchar116 h:=10802555+254863=11057418, hh:=700
> 448: setchar101 h:=11057418+291271=11348689, hh:=718
> 449: setchar114 h:=11348689+256683=11605372, hh:=734
> 450: setchar44 h:=11605372+182045=11787417, hh:=746
> 451: right3 271932 h:=11787417+271932=12059349, hh:=764
> 455: setchar97 h:=12059349+327681=12387030, hh:=785
或者如果你想要垂直并排查看:
436: w0 261236 h:=9392617+261236=9653853, hh:=611 | 436: right3 261235 h:=9392617+261235=9653852, hh:=611
437: setchar112 h:=9653853+364090=10017943, hh:=634 | 440: setchar112 h:=9653852+364090=10017942, hh:=634
438: setchar114 h:=10017943+256683=10274626, hh:=650 | 441: setchar114 h:=10017942+256683=10274625, hh:=650
439: setchar105 h:=10274626+182045=10456671, hh:=662 | 442: setchar105 h:=10274625+182045=10456670, hh:=662
440: setchar110 h:=10456671+364090=10820761, hh:=685 | 443: setchar110 h:=10456670+364090=10820760, hh:=685
441: x2 -18205 h:=10820761-18205=10802556, hh:=684 | 444: x2 -18205 h:=10820760-18205=10802555, hh:=684
444: setchar116 h:=10802556+254863=11057419, hh:=700 | 447: setchar116 h:=10802555+254863=11057418, hh:=700
445: setchar101 h:=11057419+291271=11348690, hh:=718 | 448: setchar101 h:=11057418+291271=11348689, hh:=718
446: setchar114 h:=11348690+256683=11605373, hh:=734 | 449: setchar114 h:=11348689+256683=11605372, hh:=734
447: setchar44 h:=11605373+182045=11787418, hh:=746 | 450: setchar44 h:=11605372+182045=11787417, hh:=746
448: right3 271931 h:=11787418+271931=12059349, hh:=764 | 451: right3 271932 h:=11787417+271932=12059349, hh:=764
452: setchar97 h:=12059349+327681=12387030, hh:=785 | 455: setchar97 h:=12059349+327681=12387030, hh:=785
之后,所有内容都在后一个文件(由 TeX Live 生成的文件tex
)的三个字节后发生,包括最后的后文。这些对应于部分printer, a
,我们可以看到,两种情况下使用的胶水之间存在 1 个单位的差异,在运行完这段文本后恢复同步,并且与w0
指令之间存在差异right3
,这导致所有未来指令都从不同的字节开始。
第二季度:MiKTeX 和 TeX Live 之间的这种差异是它们其中之一的缺陷吗?显然这两个程序在某个地方一定以不同的方式实现了舍入。其中一个程序是否未能以“正确”的方式执行舍入(如果有的话)?
我知道差异很小。如果我没记错的话,DVI 文件中 1 个单位的差异(DVI 单位?)相当于 1 sp
,即约 5 纳米的差异,小于可见光的波长。即使单位不完全是1 sp
,我也曾在某处看到过这些单位被称为“RSU”,即“极小单位”。因此,除非 DVI 文件以某种荒谬的(物理上不可能的)分辨率和/或放大倍数输出,否则就能够在视觉上区分输出而言,差异在实践中并不重要。
尽管如此,还是存在差异,TeX 不是应该在所有系统上产生相同的结果吗?(请注意,我没有使用 pdfTeX 或 eTeX,而只是使用 Knuth 的 TeX。)这种差异使得很难知道两个 TeX 实现何时表现相同。所以,最后几个问题是:
问题3:TeX 实现之间是否可以接受一定程度的舍入误差/浮点差异?如果可以,那么到底多少是可以接受的?TRIP 测试文档在这个问题上它本身就令人困惑,因为它说了类似这样的话(强调我的):
胶水设置显示器TeX 框会受到系统相关的舍入,因此允许轻微偏差
\hbox
。然而,这种偏差仅适用于出现在或末尾的胶合值\vbox
;所有其他数字应该完全一致因为它们是用整数算法计算的规定的独立于系统的方式。…
生成的文件应该与
TRIP.TYP
步骤 0 的主文件一致,但以下情况除外有些价值观可能有点偏差由于浮点舍入差异。此外,'right' 和 'w' 和 'x' 命令之间以及 'down' 和 'y' 和 'z' 之间可能存在差异;关键是所有字符和规则以及xxx的应该处于几乎相同的位置如附录 F 所规定。
Q4:最后,考虑到不仅位置,而且命令(以及所有后续字节)在不同的 TeX 实现之间都可能不同,我们如何测试新的 TeX 实现是否与“真实”的 TeX 行为正确/相同,即生成“基本”相同的 DVI 文件?显然,简单地diff
在 DVI 文件上运行(之后dvitype
)是行不通的,因为它会产生大量明显微不足道的差异。是否有某种工具(例如 Knuth 提到的“您可能想要编写一个DVIcompare
程序”)或其他一些测试套件?
答案1
TeX 关注的是物理介质(例如纸张)上的排版。对于 Don 来说,相同的输出意味着视觉上相同的外观,并且任何用户级计算都完全相同(这就是为什么您无法获取 TeX 的某些内部结构并使用它们的值,因为它们可能因安装而异)。这意味着换行符和分页符应该完全位于同一点。然而,他故意使用浮点来计算粘合处理的部分(这样它就不能改变换行符或分页符),但在写入 dvi 文件时,字符的最终准确位置可能会有微小的偏差。
回答您的明确问题:
Q1:这实际上展示了 TRIP 测试手册中解释的内容(您在 Q3 中引用的部分)。
Q2:没有错误(因为TRIP测试手册上有写)
Q3:不确定该声明中有什么令人困惑的地方。请注意,“粘合设置”是在最终确定 dvi 文件中的确切位置时进行的,当在 TeX 内部使用粘合时,例如确定换行符时,它仍然与固定点一起使用,因此不会出现这种差异。
Q4 您无法通过查看 dvi 文件(据我所知,trip 测试无法做到这一点)。我认为您甚至无法通过查看“已完成的箱子发货”数据而不屏蔽那里显示的(胶合组...)部分中可能出现的舍入误差。但这种屏蔽是可能的,符号输出显示的所有其他部分将完全相同,这就是我们在 LaTeX 回归测试套件中用来比较对 LaTeX 代码进行更改后的输出的方法。
答案2
对于 web2c,我在 web2c/triptrap/README 中记录了为什么所有差异都是可以接受的,即, http://tug.org/svn/texlive/trunk/Build/source/texk/web2c/triptrap/README?view=markup