不同的 TeX 實作(例如 MiKTeX 和 TeX Live)是否應該產生相同的 DVI 檔案?

不同的 TeX 實作(例如 MiKTeX 和 TeX Live)是否應該產生相同的 DVI 檔案?

據說 TeX 在所有系統上都應該以相同的方式運作。例如,高德納跳脫測試存在是為了確保任何程式只有在給定特定輸入執行特定操作時才可以稱為“TeX”。 TeX 程式本身採取某些措施來防止系統相關因素導致行為差異,例如尺寸,TeX 使用定點數而不是浮點數:1 sp(縮放點)的整數倍,即 1/65536 1/72.27 英吋。

Q1:但是(除了通過行程測試之外)行為相同意味著什麼?

由於 TeX 的輸出是一個包含排版指令的 DVI 檔案(選擇字體 F、向右移動 W 單位、在那裡設定字元 97 等),一種自然的解釋(在我看來)是 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 個單位的差異,在運行文本後恢復同步,並且 aw0right3指令也存在差異,這導致所有未來的指令都以不同的位元組開始。

Q2:MiKTeX 和 TeX Live 之間的這種差異是否是它們中的一個錯誤?顯然,這兩個程序一定在某個地方以不同的方式實現了舍入。他們中的一個人是否未能以“正確”的方式做到這一點(如果有的話)?

我知道差異很小。如果我沒記錯的話,DVI 檔案中 1 個單位的差異(DVI 單位?)對應於 1 sp,即大約 5 奈米的差異,小於可見光的波長。即使該單位不完全是1 sp,我也曾在某處看到過這些稱為“RSU”的單位,即“可笑的小單位”。因此,除非 DVI 檔案以某種荒謬的(物理上不可能的)解析度和/或放大倍率輸出,否則在實踐中差異並不重要,只要能夠在視覺上區分輸出即可。

然而,還是有差別的,TeX 不是應該在所有系統上產生相同的結果嗎? (請注意,我沒有使用 pdfTeX 或 eTeX,而只是使用 Knuth 的 TeX。)這種差異使得很難知道兩個 TeX 實現何時表現相同。那麼,最後幾個問題:

Q3:TeX 實現之間一定程度的捨入誤差/浮點差異是否可以接受?如果可以的話,到底多少是可以接受的?這TRIP測試文件在這個問題上本身就令人困惑,因為它說了這樣的話(強調我的):

中的膠水設置顯示TeX 框受到系統相關舍入的影響,因此允許輕微偏差。然而,這種偏差僅適用於出現在\hbox或行末尾的黏合設定值\vbox所有其他數字應該完全一致,因為它們是用整數算術計算的規定的系統獨立方式

……

產生的文件應與TRIP.TYP步驟 0 的主文件一致,除了有些值可能有點偏差由於浮點舍入差異。此外,「right」與「w」和「x」指令之間以及「down」與「y」和「z」指令之間可能存在差異;關鍵是所有的角色和規則xxx應該處於幾乎相同的位置如附錄 F 所示。

第四季:最後,鑑於 TeX 實作之間不僅位置不同,甚至命令(以及因此所有後續位元組)也可能不同,我們如何測試新的 TeX 實作是否與「真正的」TeX 表現正確/相同?的DVI 檔案?顯然,僅僅diff在 DVI 檔案上運行(在 後dvitype)是行不通的,因為它大量產生明顯微不足道的差異。是否有一些工具(例如 Knuth 提到的“你可能想編寫一個DVIcompare程式”)或其他一些測試套件?

答案1

TeX 涉及實體媒體(例如紙張)上的排版。對於Don 來說,相同的輸出意味著視覺上相同的外觀,並且任何用戶級計算都完全相同(這就是為什麼您無法了解TeX 的某些內部結構並使用它們的值,因為它們可能會因安裝而異)。這意味著換行符號和分頁符號應該完全相同。然而,他故意使用浮點來計算部分黏合處理(以一種無法更改換行符或分頁符的方式),但在寫入 dvi 檔案時,所得到的字元的精確位置可能會有一小部分偏差。

回答您的明確問題:

Q1:這確實顯示了 TRIP 測試手冊中解釋的內容(您在 Q3 中引用的部分)。

Q2:沒有bug(因為TRIP測試手冊中是這樣寫的)

Q3:不確定該聲明有什麼令人困惑的地方。請注意,「黏合設定」是指最終確定dvi 檔案中的確切位置時,當在TeX 內部使用黏合時,例如為了確定換行符,它仍然與固定點一起使用,因此不會出現此類差異。

Q4 你不能透過查看 dvi 檔案(據我所知,行程測試並不能做到這一點)。我認為您甚至不能通過查看“已發貨的完整盒子”數據而不掩蓋那裡顯示的(膠水組...)部件中可能存在的捨入錯誤。但是這種屏蔽是可能的,符號輸出顯示的所有其他部分將完全相同,這就是我們在 LaTeX 回歸測試套件中使用的內容,以比較對 LaTeX 程式碼進行更改後的輸出。

答案2

對於 web2c,我在 web2c/triptrap/README 中記錄了為什麼所有差異都被認為是可接受的,即 http://tug.org/svn/texlive/trunk/Build/source/texk/web2c/triptrap/README?view=markup

相關內容