赫塔菲vs莱加内斯比赛直播:LaTeX技巧897:LaTeX中的浮動體:浮動算法

巴萨vs赫塔菲全场录像 www.vsttod.com.cn 這是系列文章的第三篇,系列文章的前兩篇分別是基礎篇;以及處理超寬問題。此篇將討論 LaTeX 中的浮動算法。在此之后,讀者應該有能力理解 LaTeX 中浮動體各種「亂跑」的現象的由來,并且知道關于 LaTeX 中浮動體一些最佳實踐。

浮動體相關的術語

浮動體類型

每個浮動體都從屬于一種浮動體類型。默認情況下,LaTeX 定義了兩種浮動體類型,即 figuretable。文檔類和宏包的作者,可以在其中定義額外的浮動體類型(比如 listings 宏包定義了用于排版代碼清單的浮動體;algirithm 宏包定義了用于排版算法的浮動體),用戶也可以在導言區定義自己需要的浮動體類型(借助 float 宏包)。浮動體從屬的類型,在多個方面會影響浮動體的最終位置。比如說,每個浮動體類型都有默認的位置選項,如果它們沒有被浮動體本身的位置選項覆蓋的話,那么就會生效。 需要特別強調的是,同一個浮動體類型中的不同浮動體,它們的相對順序是固定的。也就是說,不管浮動體如何「亂跑」,Figure 1, Figure 2, Figure 3 這樣的順序是始終保持的。(簡稱「你大爺始終是你大爺」原則)不過,不同類型的浮動體之間,其順序則可能出現穿插。比如,如果有 Table 1,則可以出現在相對上述三個圖片的任意位置。

浮動區域

在同一欄(column)當中,LaTeX 設置了兩個浮動區域:欄的頂部和底部。對于雙欄排版來說,LaTeX 還提供了額外的區域:跨過雙欄的頂部。 此外,LaTeX 種也有所謂的「浮動欄」或者「浮動頁」的設定。顧名思義,浮動欄和浮動頁就是「只有浮動體」的欄或者頁。 最后,LaTeX 也可以將浮動體放在文本內容的中間(當然,這需要顯式指定)。

浮動體位置選項

為了指定浮動體放置的位置,手稿作者需要給浮動體環境傳入浮動體位置選項(通過環境的可選參數)。如果手稿作者沒有顯式提供位置選項,那么 LaTeX 則會使用浮動體所述類型所指定的位置選項。

\begin{figure}[!htbp]
// ...
\end{figure}

LaTeX 中默認的浮動體位置選項有五種,手稿作者可以以任意順序組合使用這些選項。它們是

  • ! 表示忽略一些嚴格的限制條件(后文詳述);

  • h 表示如有可能,則放在當前位置;

  • t 表示該浮動體允許置于欄的頂部;

  • b 表示該浮動體允許置于欄的底部;

  • p 表示該浮動體允許置于浮動欄或浮動頁。

這也就是說,如果某個字符(比如 b)沒有出現在浮動體位置選項中,則 LaTeX 在嘗試輸出該浮動體時,就不會試著將它放在欄的底部。 需要再次強調的是,浮動體位置選項的指定是一個「組合」問題,而不是「排列問題」。因此,[tb][bt] 是等效的。并不是說 [bt] 表示首先嘗試放在欄的底部。

浮動算法參數

總計,大約有 20 個參數,會最終影響到 LaTeX 的浮動體算法。根本來說,這些參數限制了

  • 某個浮動區域至多允許擺放多少個浮動體,

  • 浮動區域的大小,

  • 非浮動欄或非浮動頁中,文字區域的最小大小,

  • 一個浮動區域內連續浮動體之間的垂直距離,以及

  • 浮動區域與其前后文字區域的垂直距離。

浮動體參考點

顯而易見,浮動體在手稿源代碼中的位置,會影響最終的輸出位置。因為,浮動體在手稿源代碼中的位置,決定了 LaTeX 在何時第一次遇見這個浮動體。如果,浮動體在手稿的源代碼中,被置于一個段落的中間,那么這個浮動體的參考點是(自源代碼中觀察)浮動體之后的(自最終輸出文件觀察)下一個斷行點或者分頁點。

浮動算法

至此,我們可以開始探討 LaTeX 浮動算法的行為了。 在理解浮動算法之前,我們有必要強調一下,這個算法是在 1980 年代設計出來的。其時,計算機的算力相對現在是非常有限的。因此,浮動算法的設計中有非常多的「妥協」。 基于這一原因,LaTeX 中所有的排版算法,都在盡力避免「回溯」。這也就是說,LaTeX 讀入源代碼之后,會試著盡可能快地將之排版出來。這樣一來,算法的復雜度就可以盡量的低——當然,它依然很復雜,并因此可以盡快輸出排版結果。 對于浮動體來說,這就意味著確定浮動體位置的浮動算法必須是一個貪心算法。在 LaTeX 遇見浮動體時,它就會盡可能地嘗試輸出它。如果 LaTeX 確定輸出了一個浮動體,那么不論之后遇到什么內容,它的位置都不會發生改變。這種貪心實際上是對運行效率的妥協。因為,顯而易見地,如此貪心的位置選擇,可能在讀入之后的數據以后,可以發現是不那么完美的。 比如說,假設一個圖片允許放在欄的頂部或者底部。而后 LaTeX 可能會將其放在某一欄的頂部區域。現在假設,在這個圖片之后,假設有兩個表格,允許放在欄的頂部,那么這兩個表格就沒地方可防了——必須放在下一頁。而實際上,最好的選擇是,將這兩個表格放在頂部,而圖片放在底部。(在這個假設中,最佳的放置辦法,LaTeX 是不會去嘗試的)

基本流程

浮動算法的基本流程,可以大致描述如下。

  • 當 LaTeX 遇到一個浮動體,它會根據浮動算法的規則(后文詳述)盡可能快地輸出該浮動體。

    • 若成功,則該浮動體被輸出,并且 LaTeX 再也不會改變它的位置。

    • 若失敗,則該浮動體被 LaTeX 放在一個等待隊列中暫存,而后在下一頁開始的時候嘗試輸出隊列中的浮動體。

  • 當一欄或者一頁組裝完畢,LaTeX 會檢查等待隊列中的浮動體,并嘗試構建一個浮動欄或浮動頁,輸出盡可能多的浮動體。如果等待隊列中的各個類型的浮動體,都不允許輸出在浮動欄或浮動頁中,則 LaTeX 會開始嘗試將剩下的浮動體放在欄的頂部或者底部。如果當前頁已無法容納更多浮動體,則余下的浮動體又被加入等待隊列,待輸出下一頁時再做嘗試。

  • 之后,LaTeX 開始處理當前頁的文本信息。當然,在這個過程中,LaTeX 可能會遇到新的浮動體。

  • 當 LaTeX 遇到 \clearpage/FloatBarrier 或者文檔末尾時,LaTeX 會新建一個頁面,而后將等待列表中的所有浮動體,都輸出在浮動欄或浮動頁中(而不論這些浮動體的位置選項是否指定了 p)。

浮動算法的規則

不論何時,當 LaTeX 讀入一個浮動體時,它都會先檢查等待隊列中是否有與該浮動體同屬一個浮動體類型的浮動體尚未輸出。若等待隊列中存在這樣的浮動體,則該浮動體會被直接加入等待隊列,而不會嘗試輸出。 若等待隊列中,沒有當前類型的浮動體,則 LaTeX 會檢查該浮動體的位置選項。

  • 如果位置選項中包含 !,則在處理該浮動體時,LaTeX 會忽略一些嚴格的限制(當前浮動區域允許放置浮動體的最大數量、當前浮動區域的最大面積)。否則,這些限制條件就會執行,以期獲得更加美觀的效果。

  • 下一步,LaTeX 會檢查是否存在 h 選項。

    • 如果存在,則 LaTeX 會嘗試將浮動體放在當前位置。如果當前位置尚有足夠的空間供放置該浮動體,則浮動體輸出成功;否則,該浮動體會被加入等待隊列。

    • 如果不存在,則 LaTeX 會檢查是否存在 t 選項。如果存在,并且上述限制條件沒能限制該浮動體,則該浮動體會被放在欄的頂部,而后終止當前的浮動體處理。

    • 最后,LaTeX 會檢查是否存在 b 選項。同樣的,如果沒有限制條件約束該浮動體,則它會被放在欄的底部。

  • 運行至此,說明當前 LaTeX 找不到適合該浮動體的位置,則它會被加入等待隊列。

注意,p 選項在此是不起作用的;它僅于分頁時起作用。

分頁時,嘗試清空等待隊列

當 LaTeX 分頁時,會首先檢查浮動體等待隊列,并盡可能地清空它。為此,LaTeX 會嘗試構建浮動欄或浮動頁。 需要注意的是,在這個步驟中,必須有 p 指定的浮動體,才會被放在浮動欄或浮動頁中;否則,它就會被留在等待隊列里面。需要注意的是,如果一個浮動類型尚未輸出的第一個浮動體不允許放在浮動欄或浮動頁中,那么,該類型所有的浮動體,都只能待在等待列表中,以等待下一個處理步驟。 如果此時有浮動體可以輸出,那么 LaTeX 會構建浮動欄或者浮動頁,并盡可能多地輸出這樣的浮動體——直到當前浮動欄或浮動頁已經「滿了」,或者觸發了某些限制條件為止。 生成浮動欄或浮動頁的步驟,一直持續到等待列表中再無可用的浮動體(在每個類型的頭部,再無指定了 p 選項的浮動體)。此時,LaTeX 會嘗試將剩余的浮動體,放在下一頁(或者欄)的欄的頂部或者底部。這一步驟和上一小節中介紹的基本相同,但有以下一些區別

  • h 選項再無作用了;

  • 此處輸出的浮動體,不再來自 LaTeX 剛從源代碼中讀取到的,而是從等待隊列中依次讀取。

浮動體算法的參數與限制條件

四個計數器

  • totalnumber(默認為 3),在非浮動頁上浮動體的最大數量。

  • topnumber(默認為 2),在一個欄的頂部浮動體的最大數量。

  • bottomnumber(默認為 1),在一個欄的底部浮動體的最大數量。

  • dbltopnumber (默認為 2),在雙欄排版中,橫跨雙欄的頂部浮動體的最大數量。

五個區域比例

  • \topfraction(默認為 0.7),欄的頂部區域占據當前欄的最大比例。

  • \bottomfraction(默認為 0.3),欄的底部區域占據當前欄的最大比例。

  • \dbltopfraction(默認為 0.7),在雙欄排版中,橫跨雙欄的頂部區域占據當前頁的最大比例。

  • \textfraction(默認為 0.2),在非浮動欄或浮動頁中,文字區域占據的最小比例。

  • \floatpagefraction(默認為 0.5),在浮動欄或浮動頁中,浮動體至少應當占據的最小比例。

五個垂直距離,它們的默認值取決于文檔類默認字號。

  • \floatsep,欄的頂部或底部區域中,連續浮動體之間的垂直距離。

  • \dblfloatsep,雙欄排版中,橫跨雙欄的浮動區域中,浮動體之間的垂直距離。

  • \textfloatsep,欄的頂部或底部的浮動區域與文字區域之間的垂直距離。

  • \dbltextfloatsep,雙欄排版中,橫跨雙欄的浮動區域與文字區域之間的垂直距離。

  • \intextsep,對于 h 生效的浮動體,與前后文字之間的垂直距離。

浮動算法導致的一些現象及其解釋

浮動體可能出現在源代碼相對位置之前

浮動體在源代碼中的位置,決定了它在最終輸出的文檔中可能出現的最早的位置。這一最早位置是「當前欄的頂部區域」。如果你有認真閱讀前面的部分,你就會發現,當等待列表中沒有當前類型的浮動體,并且當前浮動體沒有被 h 選項確定位置時,浮動體是允許放在當前欄的頂部的。因此,浮動體可能出現在源代碼相對位置之前。

雙欄排版中,跨欄浮動體總是被放入等待列表

對于雙欄排版,跨欄浮動體總是被 LaTeX 立即放入等待列表當中;也因此,跨欄浮動體最在也要輸出在下一頁的頂部。 產生這一效果的原因在于,如果期待跨欄浮動體放在當前頁的頂部區域,則若假設 LaTeX 遇到該浮動體時,第一欄已經排版完成(正在排版第二欄),那么 LaTeX 必須回溯,破壞已經排版好的第一欄。這在效率上是得不償失的。

雙欄排版中,跨欄浮動體不可以被放在底部區域

在 LaTeX 的雙欄排版中,沒有為跨欄浮動體設置底部區域。因此,如果你使用 \begin{figure*}[b],那么因為它不允許放在頂部區域,所以它直到遇見 \clearpage/\FloatBarrier 或者文檔末尾時,才會被輸出。

h 真的只表示「如果可能的話,放在這里」

如前所述,h 選項僅在一種情況下可能生效:等待列表中沒有該類型的浮動體,并且當前頁有足夠的空間供其擺放。 如果用戶希望表達「我一定要放在這里」,那么需要使用 float 宏包提供的 H 選項。

浮動體選項的順序沒有意義

如前所述,浮動體選項只有組合的意義,沒有排序的意義。

浮動體算法的文檔

參見 source2e.pdf,ltoutput.dtx 部分。 選自:https://liam0205.me/2017/04/30/floats-in-LaTeX-the-positioning-algorithm/

分享到:
未經允許不得轉載:LaTeX技巧897:LaTeX中的浮動體:浮動算法
已有 條意見

    最新文章

    加載中...
      本站提供專業LaTeX排版、咨詢、定制服務,請點擊下圖咨詢詳情


      全國首個精品的LaTeX視頻教程,大牛帶著你入門,讓LaTeX學習不再糾結,請點擊下圖咨詢詳情

      熱門評論

        聯系我們

        交流QQ群:91940767
        本站QQ號:343083553
        郵箱聯系[email protected]
        淘寶店鋪latexstudio.taobao.com 提供排版,模板定制,培訓,圖片處理,視頻教程等LaTeX服務。


        如果您投稿或者希望加入我們團隊,請發送您的簡歷到[email protected]。

        科技藝術的完美融合,專業精致的排版體驗

        聯系我們聯系我們