![带有宏的文本和数学输出格式不正确](https://linux22.com/image/365129/%E5%B8%A6%E6%9C%89%E5%AE%8F%E7%9A%84%E6%96%87%E6%9C%AC%E5%92%8C%E6%95%B0%E5%AD%A6%E8%BE%93%E5%87%BA%E6%A0%BC%E5%BC%8F%E4%B8%8D%E6%AD%A3%E7%A1%AE.png)
数学或文本格式的正确语法是什么?
感谢您的帮助
\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn
\NewDocumentCommand{\quadSol}{mmm}
{% #1 = a, #2 = b, #3 = c in ax^2 + bx + c
\group_begin:
{ \thomas_quadSol_step:nnn { #1 } { #2 } { #3 } }
\group_end:
}
\cs_new_protected:Nn \thomas_quadSol_step:nnn
{
\ifnum \fp_eval:n{#2*#2-4*#1*#3} <0 {\quad Die Gleichung hat keine reellen Lösungen }
\else
$x_{1}=$
\num{ \fp_eval:n { round( (-#2+sqrt((#2)^2-4*#1*#3))/(2*#1), 2 ) } }
\quad
$x_{2}=$
\num{ \fp_eval:n { round( (-#2-sqrt((#2)^2-4*#1*#3))/(2*#1), 2 ) } }
\fi
}
\ExplSyntaxOff
\begin{document}
\quadSol{1}{2}{5}
\quadSol{1}{2}{-5}
\end{document}
答案1
问题是 是_
中的字母\ExplSyntaxOn
。请使用\sb
代替。空格也会被忽略,您必须使用 来转义它们expl3
。\
此外,要获得正确的间距,请不要使用x\sb{1}=
来括$
起整个行。您还应该用\ifnum\fp_eval:n
替换\fp_compare:nNnTF
。
\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn
\NewDocumentCommand{\quadSol}{mmm}
{% #1 = a, #2 = b, #3 = c in ax^2 + bx + c
\group_begin:
{ \thomas_quadSol_step:nnn { #1 } { #2 } { #3 } }
\group_end:
}
\cs_new_protected:Nn \thomas_quadSol_step:nnn
{
\fp_compare:nNnTF { #2*#2-4*#1*#3 } < { 0 }
{\quad Die\ Gleichung\ hat\ keine\ reellen\ Lösungen }
{
$x\sb{1}=
\num{ \fp_eval:n { round( (-#2+sqrt((#2)^2-4*#1*#3))/(2*#1), 2 ) } }
\quad\lor\quad
x\sb{2}=
\num{ \fp_eval:n { round( (-#2-sqrt((#2)^2-4*#1*#3))/(2*#1), 2 ) } }$
}
}
\ExplSyntaxOff
\begin{document}
\quadSol{1}{2}{5}
\quadSol{1}{2}{-5}
\end{document}
但请注意,您使用的算法不是数值稳定的,因此您的解决方案可能是错误的。
该算法的数值稳定性略高一些的版本(在我看来,这会花费更多时间,而且对于大多数示例来说似乎不值得)将是:
\cs_new_protected:Nn \thomas_quadSol_stable:nnn
{
\fp_compare:nNnTF { #2 * #2 } < { 4 * #1 * #3 }
{\quad Die\ Gleichung\ hat\ keine\ reellen\ Lösungen }
{
\fp_set:Nn \l_tmpa_fp { #2 / (2*#1) } % p in pq-formel
\fp_set:Nn \l_tmpb_fp { #3 / #1 } % q in pq-formel
\fp_compare:nNnTF { \l_tmpa_fp } < { 0 }
{
\fp_set:Nn \l_tmpa_fp
{ sqrt( \l_tmpa_fp*\l_tmpa_fp - \l_tmpb_fp ) - \l_tmpa_fp }
}{
\fp_set:Nn \l_tmpa_fp
{ - sqrt( \l_tmpa_fp*\l_tmpa_fp - \l_tmpb_fp ) - \l_tmpa_fp }
}
\fp_set:Nn \l_tmpb_fp { \l_tmpb_fp / \l_tmpa_fp }
$x\sb{1}=
\num{ \fp_eval:n { round( \l_tmpb_fp , 2 ) } }
\quad\lor\quad
x\sb{2}=
\num{ \fp_eval:n { round( \l_tmpa_fp , 2 ) } }$
}
}
答案2
我知道我的回答有点离题。然而,在主要答案的评论中有一些关于数值稳定性的讨论。使用 xint 可以精确计算代数,您不必担心某些减法是否会导致数字丢失;当然,平方根必须是近似的,但一旦完成,所有其他计算都是精确的,不需要关于如何最好地进行代数运算的技巧。
第二点是,在扩展其参数之前对 进行解析存在困难siunitx
。\num
例如,我在使用包\numprint
中的宏时没有遇到这样的问题numprint
。因此,答案的第二点是解释如何使用通过 xint 计算评估的参数siunitx
。\num
\documentclass[ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{siunitx}
\usepackage{xintexpr}
% workaround problem with siunitx \num parsing before expanding
% workaround done in a way allowing \num's optional parameters
\newcommand\numx[2][]{\begingroup\if\relax\detokenize{#1}\relax
\def\x{\endgroup\num}\else
\def\x{\endgroup\num[#1]}\fi
\expandafter\x\expandafter{\romannumeral-`0#2}}
% for example something like
% \numx[scientific-notation=true]{\xinttheiexpr[#1] x2\relax}
% in code below would work.
% when using numprint's \np I encountered no problem like the \num's ones
% no workaround as in the above appeared necessary then
% \usepackage[autolanguage, np]{numprint}
% \let\numx\np
\newcommand\quadSol[4][2]{%
% #1 = user specified fixed point precision for rounding the output
% #2 = a, #3 = b, #4 = c in ax^2 + bx + c
% IT IS ASSUMED a IS NOT ZERO
Die Gleichung mit $a=#2$, $b=#3$, $c=#4$ hat
\begingroup
%
% \xintdefvar does computations exactly with rational numbers
% the sqrt(x) function computes with the prevailing float
% precision set by \xintDigits. Default: 16 decimal digits.
% one can also do sqrt(x, P) for using another precision.
%
% \xinttheiexpr[N] does exact computation like \xintdefvar
% or \xinttheexpr, but it rounds final result to N decimal digits
% after decimal mark. There is no removal of trailing
% zeroes (this should be job of formatting macro).
%
\xintdefvar a := #2;%
\xintdefvar b := #3;%
\xintdefvar c := #4;%
\xintdefvar Delta := b*b - 4a*c;%
\xintifSgn{\xinttheexpr sgn(Delta)\relax}
{keine reellen Lösungen.}
{eine doppelte Lösung
${}\approx\numx{\xinttheiexpr[#1] -b/2a\relax}$.}
{zwei Lösungen
% We don't have to worry about numerical unstability because
% \xintdefvar (contrarily to \xintdeffloatvar) computes exactly!
% All the "loss" is in the square-root...
% By the way, let's compute it once only
% (use sqrt(Delta, P) for other precision P).
\xintdefvar sqrtDelta := sqrt(Delta);%
% The order x1, x2 is chosen to get x1 < x2 if a>0
\xintdefvar x1 := (-b-sqrtDelta)/2a;%
\xintdefvar x2 := (-b+sqrtDelta)/2a;%
%
% if we had been worried about numerical stability, we would have first
% defined x1 (if b>0) then get x2 by c/a/x1 formula.
%
% but we are not worried because we compute exactly...
% once the square root is approximated as a floating point number (by default
% with 16 digits of precision).
%
% Raw output from \xinttheexpr can not be fed to \num as it is in A/B[X]
% format. So we use \xinttheiexpr[N] (fixed-point) or \xintthefloatexpr[N]
% (floating-point, uses scientific notation only if exponent is out of
% -5,..,5 range as in Maple output).
%
$x_{1}\approx \numx{\xinttheiexpr[#1] x1\relax}$
and
$x_{2}\approx \numx{\xinttheiexpr[#1] x2\relax}$.
%\par
% Their sum is
% $x_1 + x_2 \approx \numx{\xinttheiexpr[#1] x1 + x2\relax}$, and their product
% ix $x_1 x_2 \approx \numx{\xinttheiexpr[#1] x1*x2\relax}$.
}%
\endgroup\par\medskip
}
\begin{document}
\quadSol{1}{2}{5}
\quadSol{1}{2}{-5}
\quadSol{1}{200}{1}
\quadSol[12]{1}{200}{1}
\quadSol{1}{10000}{1}
\quadSol[12]{1}{10000}{1}
% \quadSol{1}{-\xinttheiexpr[2] 1.73+3.27\relax}{\xinttheiexpr[4] 1.73*3.27\relax}
\end{document}