2

How to get the roots automatically not in an approximate way but with square roots in Output format for text and math with macro not correct ?

(editor's update) I.e., I need a LaTeX macro \quadSol with (at least) three arguments being the coefficients a, b, c of ax^2+bx+c and which will compute the solutions exactly as rationals if possible, and if not express them with some radical for example 1+\sqrt{3} and 1-\sqrt{3}, and then also typeset some approximation. The supported coefficients a, b, c will at minimal be integers, better if also (small) decimal numbers and fractions are accepted. This is for automatic generation of school exercises, so the number of digits in coefficients will be small. (the coefficients will not themselves be irrationalities).

  • -@David Carlisle thanks for your hint. – user139826 Nov 11 '17 at 7:01
6

For this follow-up question to Output format for text and math with macro not correct, I re-visited my answer to Simplifying square roots.

The answer was updated:

  • re-factored the \ExtractRadical macro to address a remark I had made in Simplifying square roots

  • simplified \quadSol to benefit from the fact that xint 1.2p allows silmutaneous assignments.

Code

\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}

enter image description here

  • -@jfbu great work with your xint package – user139826 Nov 10 '17 at 22:54
  • @Thomas appreciation appreciated ;-) Not to complain, but perhaps you were a bit quick into accepting answer: this might discourage Luatexers or LaTeX3ers to post their own approaches... You know xint does not yet have sine or cosine etc... so you might benefit from other approaches too in the mid term. – user4686 Nov 10 '17 at 23:00
  • -@jfbu I understand what you mean and I'll remember that for the next time. Nevertheless, many thanks for your great work. – user139826 Nov 11 '17 at 6:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy