Сижу, ковыряю отчет (который, кстати, теоретически должен был делать не я…).
И вот, пришла мне в голову мысль: а почему бы не включить кое-какие простые расчеты прямо сразу в этот отчетец? Ведь есть же пакет fp, позволяющий производить простые операции с плавающими числами (и даже решать уравнения). Правда, время компиляции документа при этом несколько увеличивается, но зато не нужно будет 100500 раз проверять свой документ после изменения одного-двух параметров.
До этого я уже сделал небольшую заготовку - команду \Ins, которая принимает либо 1 параметр, либо не принимает их вообще. Параметр (или пустое место, если параметра нет) обводится красной рамочкой и на полях рисуется красный квадратик - мол, обрати внимание!
Теперь я решил сделать так, чтобы эта команда \Ins принимала от нуля до двух параметров, а также имела два режима: "черновик" и "чистовик". В режиме "черновик" \Ins с 0 или 1 параметром ведет себя, как и прежде, а вот с двумя параметрами - как \Ins{#2}, но при этом еще и присваивает первому параметру значение второго. В режиме "чистовик", который пока определяется командой \def\TextOut{} (а вообще, если все это оформить отдельным пакетом, можно сделать опцию пакета draft), красные рамочки рисуются лишь в случае, когда у \Ins нет параметров (т.е. мы что-то явно забыли или забили).
Итак, код:
\makeatletter
\ifx\TextOut\undefined
\def\InsTxt@#1{\red{\fbox{#1}}\marginpar{\red{\Square}}}
\else
\def\InsTxt@#1{#1}
\fi
\def\InsWFP#1#2{\expandafter\FPset\csname#1\endcsname{#2}\InsTxt@{#2}}
\def\Ins{\futurelet\next\Ins@i}
\def\Ins@i{\ifx\next\bgroup\expandafter\Ins@ii\else\expandafter\Ins@end\fi}
\def\Ins@ii#1{\def\temp@rg{#1}\futurelet\next\Ins@iii}
\def\Ins@iii{\ifx\next\bgroup\expandafter\Ins@two@rgs%
\else\expandafter\Ins@one@rg\fi}
\def\Ins@two@rgs#1{\InsWFP{\temp@rg}{#1}} % Two args
\def\Ins@one@rg{\InsTxt@{\temp@rg}} %One arg
\def\Ins@end{\red{\fbox{\phantom{text}}}\xspace\marginpar{\red{\Square}}}
\def\FPrint#1{\@@print@@#1}
\def\@@print@@#1:#2{\FPeval{\res@lt}{round(#1:2)}\res@lt}
\makeatother
Поясню, что делается в коде выше. Команда \Ins перенаправляет латех, не "проглатывая" аргументов, на команду \Ins@i. Та проверяет, идет ли после нее символ \bgroup (открывающаяся фигурная скобка). Если идет - значит, у нашей команды есть как минимум 1 аргумент - переходим к команде \Ins@ii, иначе (аргументов нет) - переходим к команде \Ins@end.
Команда \Ins@ii уже имеет один аргумент (мы его "проглотили" в предыдущей команде), поэтому его мы помещаем во временную переменную \temp@rg и опять проверяем - есть ли аргументы дальше, переходя к команде \def\Ins@iii. Там мы выполняем либо \Ins@two@rgs (если аргументов два), либо \Ins@one@rg (если он один).
Команда \Ins@two@rgs выполняет \InsWFP, которая, в свою очередь, присваивает первому аргументу (он, кстати, является обычным текстом, а не командой - для того, чтобы из него сделать команду, как того требует пакет fp, мы и используем \csname) второй аргумент, а затем выводит при помощи \InsTxt@ второй аргумент в итоговый документ.
Команда \Ins@one@rg просто выводит свой аргумент в документ.
Команда вывода \InsTxt@ зависит от нашего флага "черновика": если он установлен, мы выбрасываем текст в рамке и делаем пометку на полях, иначе - текст без рамки.
Команда \Ins@end выводит пустую рамку в любом режиме (т.к. явно если она не имеет аргумента в режиме "чистовика", это значит, что мы этот аргумент вставить забыли).
Еще я добавил команду \FPrint, позволяющую проводить вычисления в тексте и сразу же выдавать ответ в документ. Аргумент этой команды имеет вид вычисления:точность, где "вычисления" - какие-то операции, а "точность" - количество знаков после запятой (все результаты надо округлять, иначе получите огромное количество нулей после запятой даже в целом числе).
В результате из вот такого
Пусть гипотенузы треугольника равны a=\Ins{a}{2.5}, b=\Ins{b}{3}, тогда
катет будет равен $c=\sqrt{a^2+b^2}=\FPrint{root(2, (a^2 + b^2)):2}$
мы получаем:
Upd:
Сделал покрасивше и удобней (счетчик завел):
\makeatletter
\newcounter{InsC@unt@r}
\def\Ind@x{\stepcounter{InsC@unt@r}%
\hbox to 0pt{\raisebox{1ex}{\tiny\red{\arabic{InsC@unt@r}}}}}
\def\Insm@rgimp@r#1{\marginpar{\red{\tiny\arabic{InsC@unt@r}:#1}}}
\ifx\TextOut\undefined
\def\InsTxt@#1#2{#1\Ind@x\Insm@rgimp@r{#2}}
\else
\def\InsTxt@#1{#1}
\fi
\def\InsWFP#1#2{\expandafter\FPset\csname#1\endcsname{#2}\InsTxt@{#2}{#1}}
\def\Ins{\futurelet\next\Ins@i}
\def\Ins@i{\ifx\next\bgroup\expandafter\Ins@ii\else\expandafter\Ins@end\fi}
\def\Ins@ii#1{\def\temp@rg{#1}\futurelet\next\Ins@iii}
\def\Ins@iii{\ifx\next\bgroup\expandafter\Ins@two@rgs%
\else\expandafter\Ins@one@rg\fi}
\def\Ins@two@rgs#1{\InsWFP{\temp@rg}{#1}} % Two args
\def\Ins@one@rg{\InsTxt@{\temp@rg}{}} %One arg
\def\Ins@end{\red{\Square\Ind@x}\Insm@rgimp@r{?}\xspace}
\def\FPrint#1{\@@print@@#1}
\def\@@print@@#1:#2{\FPeval{\res@lt}{round(#1:2)}\res@lt}
\makeatother