如何自动获得根,不是以近似方式,而是以平方根带有宏的文本和数学输出格式不正确?
(编辑更新)即,我需要一个 LaTeX 宏\quadSol
,它至少有三个参数,分别是a, b, c
和的系数ax^2+bx+c
,如果可能的话,它将计算出精确的有理数解,如果不能,则用一些根式(例如1+\sqrt{3}
和)来表示它们1-\sqrt{3}
,然后排版一些近似值。支持的系数a, b, c
至少是整数,如果也接受(小)小数和分数就更好了。这是为了自动生成学校练习,因此系数中的位数会很少。(系数本身不会是无理数)。
答案1
对于这个后续问题带有宏的文本和数学输出格式不正确,我重新审视了我的回答简化平方根。
答案已更新:
重新考虑了
\ExtractRadical
宏,以解决我在简化平方根简化
\quadSol
以受益于 xint1.2p
允许同时分配的事实。
代码
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{xparse}
\usepackage{siunitx}
\usepackage{geometry}
\sisetup{group-separator={\,},output-decimal-marker={,}}
\usepackage{xintexpr}
% To use \num of siunitx with \xinttheiexpr[12]...\relax kind of things
% as argument
\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}}
% Macro \ExtractRadical{N}
% ------------------------
% It outputs A,B for input N in order for
% N = A^2 * B, B square-free
% Algorithm initially from https://tex.stackexchange.com/a/300097/4686
% but now improved to have a more efficient test for breaking the loop.
% https://tex.stackexchange.com/questions/300035/simplifying-square-roots#comment726934_300097
% main variable is a quadruple P, I, J, K
% - always N = I^2 J
% - P is odd integer, except at start, P=2
% - I is divisible only by primes < P
% - K is J freed from primes < P
% initialization: 2, 1, N, N
% variables at each iteration: P, I, J, K
% Q=P^2
% is Q > K ?
% - yes: return I, J
% - no:
% does Q divide J ?
% if yes: repeat I=I*P, J=J/Q, K=K/Q until Q does not divide J
%
% then if P divides K, set K = K/P
% and continue with (P+2, I, J, K).
% Except if P=2 then we go on with P=3.
% Also works with N=0 (produces 1, 0) and with N=1 (produces 1, 1)
% This implementation uses only \numexpr and is thus limited to integers <
% 2^31.
\makeatletter
\newcommand\ExtractRadical[1]{%
\romannumeral0%
\expandafter
\ExtractRadical@two@i\expandafter1\expandafter,\the\numexpr#1.%
}%
\def\ExtractRadical@two@i #1,#2.{%
\ifnum4>#2 \expandafter\ExtractRadical@two@done\fi
\expandafter\ExtractRadical@two@ii\the\numexpr#2/4;#1,#2.%
}%
\edef\ExtractRadical@two@done #1;#2,#3.{ #2,#3}%
\def\ExtractRadical@two@ii #1;#2,#3.{%
\ifnum\numexpr#1*4=#3
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\expandafter\ExtractRadical@two@i\the\numexpr2*#2,#1.}%
{\expandafter\ExtractRadical@h
\the\numexpr\ifodd #3 #3\else#3/2\fi;#2,#3.}%
}%
\def\ExtractRadical@h {\ExtractRadical@j 9.3,}%
% P, K; I, J.
\def\ExtractRadical@i #1,{%
\expandafter\ExtractRadical@j\the\numexpr#1*#1.#1,%
}%
% P^2.P, K; I, J.
\def\ExtractRadical@j #1.#2,#3;#4,#5.%
{%
\ifnum#1>#3 \expandafter\ExtractRadical@done\fi
\expandafter
\ExtractRadical@k \the\numexpr #5/#1.#1,#2;#4,#5;#3.%
}%
\def\ExtractRadical@done #1.#2,#3;#4,#5;#6.{ #4,#5}%
% I//P^2.P^2,P;I, J;K.
\def\ExtractRadical@k #1.#2,#3;#4,#5;{%
\ifnum\numexpr#1*#2=#5
\expandafter\ExtractRadical@again
\else
\expandafter\ExtractRadical@next
\fi
#1.#2,#3;#4,#5;%
}%
\def\ExtractRadical@again #1.#2,#3;#4,#5;#6.{%
\expandafter\ExtractRadical@k
\the\numexpr#1/#2\expandafter.%
\the\numexpr#2\expandafter,%
\the\numexpr#3\expandafter;%
\the\numexpr#3*#4\expandafter,%
\the\numexpr#1\expandafter;\the\numexpr#6/#2.%
}%
\def\ExtractRadical@next #1.#2,#3;#4,#5;#6.{%
\expandafter\ExtractRadical@i
\the\numexpr2+#3\expandafter,%
\the\numexpr\ifnum\numexpr(#5/#3)*#3=#5
#6/#3\else #6\fi;#4,#5.%
}%
% An auxiliary macro
% ------------------
% we need this to separate numerator and denominator of fractions inside an
% xintexpr. There is no function for that in xintexpr syntax, so far.
\newcommand\NumAndDenom[1]{\expandafter\@NumAndDenom\romannumeral-`0#1;}
\def\@NumAndDenom #1/#2;{#1,#2}
\makeatother
% Exact Quadratic solver
% ----------------------
\newcommand\quadSol[3]{%
% REMARK: use of single letter variable with \xintdefvar is quite dangerous
% because they are also used as dummy letters in \xintexpr syntax. So if the
% code here uses an external macro itself using \xintexpr, there might
% be a clash.
%
% Currently the world is not overwhelmed
% with \xintexpr based code, but if that happens one day...
% ... better stop using single-letter names like here a, b, c, L, A, B,
% U, V, W ... this is very dangerous if using an external expandable macro
% which was written in \xintexpr syntax. As a rule, always use multi-letter
% identifiers with \xintdefvar... (do what I say, not what I do...)
%
\begingroup
% simultaneous assignments require xint 1.2p 2017/12/05 ...
\xintdefvar a, b, c := #1, #2, #3;%
\xintdefvar Delta := b*b - 4a*c;%
\xintifSgn{\xinttheexpr sgn(Delta)\relax}
{keine reellen Lösungen.\par}
{eine doppelte Lösung
% see documentation of typesetting macro \xintFrac in xint.pdf
$\xintFrac{\xinttheexpr reduce(-b/2a)\relax}$.\par
}
{zwei Lösungen
% Use \NumAndDenom macro defined above to assign numerator to A, denom to B
% simultaneous assignments require xint 1.2p 2017/12/05 ...
\xintdefiivar A, B := \NumAndDenom{\xintIrr{\xinttheexpr Delta\relax}};%
% some student exercises will be cooked up to have rational solution
% hence a discriminant being an exact square in rational numbers, so we
% first check for them even though it adds a bit of overhead to general
% case where discriminant will not be perfect square.
\xintdefiivar rA, rB := sqrt(A), sqrt(B);% truncation of exact square root
\xintifbooliiexpr{A == rA**2 && B == rB**2}
{%\perfectsquaretrue
\xintdefvar sqrtDelta := sgn(a)*rA/rB;% sgn(a) trick to get x1 < x2
\xintdefvar x1, x2:= reduce((-b-sqrtDelta)/2a),
reduce((-b+sqrtDelta)/2a);%
$x_{1}= \xintFrac{\xinttheexpr x1\relax}$
und
$x_{2}= \xintFrac{\xinttheexpr x2\relax}$.\par
}%
{%\perfectsquarefalse
% we decompose numerator and denominator as (x^2)*y with y square free
% This is done using expandable \ExtractRadical macro defined above.
\xintdefvar rA, sqfreeA := \ExtractRadical{\xinttheiiexpr A\relax};%
\xintdefvar rB, sqfreeB := \ExtractRadical{\xinttheiiexpr B\relax};%
\xintdefvar U := reduce(-b/2a);%
%
\xintdefvar V := abs(reduce(1/2a*rA/rB));% V > 0
\xintdefvar W := sqfreeA/sqfreeB;% irreducible, W > 0
\xintdefvar sqrtW := sqrt(W);% computed with \xinttheDigits digits
% The order x1, x2 is chosen so that x1 < x2 always
\xintdefvar x1, x2 := U - V*sqrtW, U + V*sqrtW;%
$x_{1} = \xintFrac{\xinttheexpr U\relax}
- \xintFrac{\xinttheexpr V\relax}\times
\sqrt{\xintFrac{\xinttheexpr W\relax}}
\approx \numx{\xinttheiexpr[12] x1\relax}$
und
$x_{2} = \xintFrac{\xinttheexpr U\relax}
+ \xintFrac{\xinttheexpr V\relax}\times
\sqrt{\xintFrac{\xinttheexpr W\relax}}
\approx\numx{\xinttheiexpr[12] x2\relax}$.\par
}%
}%
\endgroup
}
\newcommand\TestExtractRadical[1]{%
\xintdefiivar Ipart, Jpart := \ExtractRadical{#1};%
#1 -> \xinttheiiexpr Ipart, Jpart\relax\
(\xinttheiiexpr Ipart**2 * Jpart\relax =\the\numexpr#1\relax)\par
}
\begin{document}
\ttfamily
\TestExtractRadical{0}
\TestExtractRadical{1}
\TestExtractRadical{64}
\TestExtractRadical{128}
\TestExtractRadical{256}
\TestExtractRadical{1024}
\TestExtractRadical{2048}
\TestExtractRadical{72}
\TestExtractRadical{360}
\TestExtractRadical{504}
\TestExtractRadical{1690}
\TestExtractRadical{2*2*2*3*3*3*5*5*5*7*7*7*11}
\TestExtractRadical{2*2*2*3*3*3*7*7*7*19*17*17}
\bigskip
\rmfamily
\quadSol{1}{2}{-1}
\bigskip
\quadSol{39}{-34}{7}
\bigskip
\quadSol{-39}{34}{-7}
\bigskip
\quadSol{39}{-35}{7}
\bigskip
\quadSol{38}{-34}{7}
\bigskip
\quadSol{1}{-10}{1}
\bigskip
\quadSol{1}{-100}{1}
\bigskip
% \quadSol{1}{-1000}{1}
% \bigskip
% \quadSol{1}{-100000}{1}
% too big for \numexpr,
% \bigskip
\quadSol{1}{-13/5-5/13}{1}
\bigskip
\quadSol{1}{-101/99-31/16}{101/99*31/16}
\bigskip
\quadSol{1}{-2*355/113}{(355/113)**2}
\bigskip
\quadSol{1.3}{2.5}{0.9}
\thispagestyle{empty}
\end{document}