Globalne deklarowanie sumy

Nov 03 2020

Rozważmy następujący MWE:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
 {
  \azetina_shcpoint:n { #1 }
 }

\NewDocumentCommand{\printtotal}{ }
 {
  \int_to_arabic:n { \g_azetina_totalpoints_int }
 }

\int_new:N \g_azetina_totalpoints_int
\box_new:N \l_azetina_points_box
\cs_new_protected:Npn \azetina_shcpoint:n #1
 {
  \int_gadd:Nn \g_azetina_totalpoints_int { #1 }
  \hbox_set:Nn \l_azetina_points_box { (0 ~ \textit{points}) }
  \makebox[\box_wd:N \l_azetina_points_box][l]
   {
    (\textit{#1 ~ point\int_compare:nT { #1 > 1 } { s }})
   }
  \quad
}
\ExplSyntaxOff

\begin{document}
Total points: \printtotal

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}

W powyższym przykładzie suma punktów jest obliczana poprawnie na końcu, ale jeśli spróbuję wywołać polecenie przed deklaracją punktów, wypisuje zero.

Jaki jest najlepszy sposób na przedefiniowanie tego, aby suma była dostępna w dowolnym miejscu dokumentu?

Zauważ, że rozwiązanie zostało dostarczone przez @egreg w https://tex.stackexchange.com/a/160089/10898

Odpowiedzi

2 LaTeXer Nov 03 2020 at 06:10

Musisz zapisać sumę do .auxpliku (więc naturalnie musisz uruchomić dokument co najmniej dwa razy, aby uzyskać właściwą sumę). Dodałem nowy licznik, więc masz jeden do wydrukowania sumy, który będzie nieprawidłowy, gdy dodasz / usuniesz punkty do czasu ponownego uruchomienia dokumentu, i inny, który będzie śledzić punkty podczas pracy dokumentu. Pod koniec cyklu są one porównywane i pojawia się ostrzeżenie, więc wiesz, że musisz ponownie uruchomić LaTeX.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
 {
  \azetina_shcpoint:n { #1 }
 }

\NewDocumentCommand{\printtotal}{ }
 {
  \int_to_arabic:n { \g_azetina_totalpoints_int }
 }

\NewDocumentCommand{\shcsettotal}{ m }
 {
  \int_gset:Nn \g_azetina_totalpoints_int {#1}
 }

\int_new:N \g_azetina_totalpoints_int
\int_new:N \g__azetina_counttotal_int
\box_new:N \l_azetina_points_box
\cs_new_protected:Npn \azetina_shcpoint:n #1
 {
  \int_gadd:Nn \g__azetina_counttotal_int { #1 }
  \hbox_set:Nn \l_azetina_points_box { (0 ~ \textit{points}) }
  \makebox[\box_wd:N \l_azetina_points_box][l]
   {
    (\textit{#1 ~ point\int_compare:nT { #1 > 1 } { s }})
   }
  \quad
}

\makeatletter
\AtEndDocument
  {
    \iow_now:Nx \@auxout
      {
        \shcsettotal { \int_use:N \g__azetina_counttotal_int }
      }
    \int_compare:nNnF \g__azetina_counttotal_int = \g_azetina_totalpoints_int
      {
        \msg_warning:nn { azetina } { rerun-points }
      }
  }
\msg_new:nnn { azetina } { rerun-points }
  {
    Point~count~differs.~Rerun~LaTeX~to~get~it~right.
  }
\makeatother
\ExplSyntaxOff

\begin{document}
Total points: \printtotal

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}

Po pierwszym biegu masz

oraz ostrzeżenie w .log:

Package azetina Warning: Point count differs. Rerun LaTeX to get it right.

a po drugim biegu bez ostrzeżenia i