25

I want to create a command that, for a given integer n, type sets a simplified square root of n. For example, the output of

\rsqrt{4}
\rsqrt{8}
\rsqrt{18}
\rsqrt{7}

would be the same as that of

2
2\sqrt{2}
3\sqrt{2}
\sqrt{7}

where \rsqrt{} is the command in question.

I know that the algorithm would look somewhat like this

i = square root of n rounded down 

while i > 0:
    if n is divisible by i²:
        simplification is i\sqrt{n/i²}
        break loop
    i = i - 1

%the simpification will always be found
%since every n is divisible by 1

where n is the given integer, i is the number before \sqrt and n/i² is the argument of \sqrt{...}.

But I have no idea how to implement this in latex?

EDIT: Clarified that the input number will always be an integer.

8
  • Please clarify what the term if not (n mod i²) denotes: what's being tested? Equality to zero? Please advise.
    – Mico
    Commented Mar 20, 2016 at 21:22
  • it denotes if (n is divisible by i²) do. And yes, equality to zero of the (n mod i²) is being tested. Commented Mar 20, 2016 at 21:27
  • Oh, no, I'm asking about the implementation of the above algorithm in LaTeX, not about the algorithm itself. Actually, I'm asking about a LaTeX implementation of any algorithm that gives the desired results, I just felt that including an existing algorithm in the question would make it easier to answer. Commented Mar 20, 2016 at 22:03
  • 2
    Easy in lualatex. Would that do?
    – JPi
    Commented Mar 20, 2016 at 23:01
  • 1
    @JPi - Please see the answer I just posted. :-)
    – Mico
    Commented Mar 20, 2016 at 23:07

5 Answers 5

27

The algorithm in the question is very inefficient: except of course if the original integer is a perfect square.

This answer (in chronological order):

  1. an approach with macros which mimics the simplest factorization algorithm,

  2. an expandable approach using the algorithm as in OP. update very embarrassingly, the author had not understood the OP's algorithm and after having found a simplifying I such as I^2 divided N, he went one recursively with N<-N/I^2 not understanding that the algorithm could stop there. (as a pale excuse, he had implemented first the "bottom-up" way, which needs recursivity, contrarily to the "top-down" (less efficient) way). The answer is thus updated, apologies to all generous trustful early up-voters.

    I am updating again (sorry) because I have now read more of xintexpr.sty's documentation, and I switched for efficiency from i=sqrt(N)..1 to i=-sqrt(N)++ (there is no -- available, hence a trick with minus sign). The former generates beforehand the whole list of floor(\sqrt{N}) numbers (sqrt means truncated square root in \xintiiexpr), the latter is an iterator which doesn't generate things beforehand. Furthermore the former syntax can only generate about 5000 values (sqrt(N)..[-1]..1 would have no such limitation, but still would generate everything beforehand).

  3. an expandable implementation of faster (high-school factorization type) algorithm as in approach 1.

To be honest 2., 3. and even 1. would probably be better written entirely using \numexpr as their pretence at handling numbers bigger than 2^31 is a bit far-stretched, it takes time with a prime number of 10 digits to do tens of thousands of divisions to conclude it was square-free ... Implementation 2. has an intrinsic limit to 2^62 because the square root must be a TeX number (due to some construct inside).

In 2. and 3., we push a bit beyond reasonable range the possibilities of \xintexpr syntax with recursive sequences. The notation is a bit cumbersome. Besides xintexpr.sty 1.2g is needed because it changed relevant syntax.

  1. finally (2017) I also add the no-package numexpr only expandable approach.

First approach (we change the algorithm)

Not to say that this is an easy problem. A bit of googling reveals that apparently mathematicians currently believe that finding the square free radical of an integer may be as hard as complete factorization: https://math.stackexchange.com/questions/171568/finding-the-radical-of-an-integer and https://math.stackexchange.com/questions/14667/square-free-integers-factorization.

Here is an approach (using macros) which mimicks simplest form of factorization algorithm.

Package xintexpr is used only in order to allow inputs such as 1e7 or even expressions. It also loads xinttools which is used in the syntax.

Apart from that all operations are done with macros available from xint. As we deal in the example almost only with numbers <2^31 we could employ a variant where all operations would be done using uniquely \numexpr, naturally that would be quite faster.

The code uses \xintiiDivision which computes simultaneously quotient and remainder. This is why \xintAssign is used to store them into two macros \A and \B. The code examines if \B vanishes to detect the divisibility by a Q=P^2.

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}

\makeatletter
\def\Rsqrt@ {%
    \let\Nrad\N
    \def\Nroot {1}% 
% we will always have original N = \Nrad times \Nroot^2
% first we check powers of 2
    \def\P{2}%
    \def\Q{4}% \Q is always square of \P
    \xintloop
% try to divide \Nrad by 4. If possible, multiply \Nroot by 2
        \xintAssign\xintiiDivision{\Nrad}{\Q}\to \A\B
        \xintiiifZero{\B}
           {\let\Nrad\A
            \edef\Nroot{\xintiiMul{\Nroot}{\P}}% 
            \iftrue}
           {\iffalse}%
    \repeat
% try to divide \Nrad by 9=3^2, then by 25=5^2, etc...
% unfortunately we divide by all odd integers, but only odd prime
% integers would be really needed
    \def\P{3}%
    \xintloop
      \edef\Q{\xintiiSqr{\P}}%
      \xintiiifGt{\Q}{\Nrad}
         {\iffalse}%
         {\xintloop
             \xintAssign\xintiiDivision{\Nrad}{\Q}\to \A\B
             \xintiiifZero{\B}
                {\let\Nrad\A
                 \edef\Nroot{\xintiiMul{\P}{\Nroot}}% 
                 \iftrue}
                {\iffalse}%
          \repeat 
          \edef\P{\xintiiAdd{2}{\P}}%
          \iftrue
         }%
    \repeat
% at this stage \N = \Nrad times \Nroot^2
% and \Nrad is square-free.
    \xintiiifOne{\Nroot}{}{\Nroot}%
    \xintiiifOne{\Nrad} {}{\sqrt{\Nrad}}%
}%

\newcommand* \Rsqrt[1]{%
   \begingroup
     \edef\N{\xinttheiexpr #1\relax}%
     \xintiiifSgn \N
        {\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
        {0}
        {\xintiiifOne \N{1}{\Rsqrt@}}
   \endgroup
}

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing
% \begin{multicols}{4}
% \xintFor* #1 in {\xintSeq {10000}{10100}}\do
%        {$\sqrt{#1}=\Rsqrt{#1}$\par}
% \end{multicols}

% $\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}, \Rsqrt{1e21}$

\pdfsetrandomseed 123456789

\begin{multicols}{3}
\xintiloop [1+1]
    \edef\Z {\xinttheiiexpr 
             (\pdfuniformdeviate 1000)^2
             *\pdfuniformdeviate 1000\relax }%
    $\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<50
\repeat
\end{multicols}
    
\end{document}

enter image description here


Second approach (same algorithm as in OP, expandable implementation)

With the original algorithm. Here we define \ExtractRadical which expandably returns A,B with N=A^2 B. A non-expandable wrapper re-cycles \Rsqrt from faster approach above to produce A\sqrt{B}, distinguishing cases of negative N or N=0, 1.

I have added code comments to explain implementation. An earlier version was very lame (see top of answer) and additionally required xintexpr 1.2g which is not the case anymore.

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}

% Aim: given N find largest I such as I^2 divides N.
% Then compute J=N/I^2 and print I\sqrt{J}.

% Algorithm: compute first truncated square root Imax of N.
% With I = Imax try to divide N by I^2, if it does not work
% repeat with I replaced by I-1 and so on. 
% As soon as it works the seeked-for I has been found.

% **** Notice: embarrassingly the author of this answer initially continued
% **** the algorithm recursively with N<-N/I^2, which was very stupid, but
% **** explainable from the fact that he had implemented first another (much
% **** faster) algorithm which divided not from the top down, but from the
% **** bottom up.

% The code is far simpler now. And it does not require xintexpr 1.2g anymore,
% earlier versions of xintexpr.sty work, too.

% The iteration over i used Imax..1 syntax which requires Imax 
% to be <2^31. Else we could use Imax..[-1]..1, but we don't
% really consider realistic to iterate over 2^31 or more values !

% After an update we use (-Imax)++ syntax; this also requires Imax<2^31.

\def\ExtractRadical #1{%
  \xinttheiiexpr 
  subs(
  % we return I, #1//I^2 where I is biggest integer such as I^2 divides #1.
     (I, #1//I^2), 
  % The I is computed via the "seq" here. Theoretically this "seq" 
  % evaluates as many values as the last list indicates.
  % But here we omit all i's such that i^2 does not divide #1
  % and as soon as we have found one, we stop here and now by 
  % "break". We work topdown, at the worst I=1.
% The i=A..B syntax pre-generates all values, which is wasteful
% and limited to about at most 5000 values.
%       I=seq((#1/:i^2)?{omit}{break(i)}, i=sqrt(#1)..1)
% On the contrary the N++ syntax does not pre-generate anything.
       I=seq((#1/:i^2)?{omit}{break(-i)}, i=-sqrt(#1)++)
% There is currently no "n--" only "n++", thus we tricked with a minus sign.
      )
  \relax
}

\makeatletter

\def\Rsqrt@ {\expandafter\Rsqrt@@\romannumeral-`0\ExtractRadical\N,}

% The #2#3 trick is to get rid of a space after the comma
% because \ExtractRadical does \xinttheiiexpr which in case
% of comma separated values on output always inserts such a space.
% Naturally as the typesetting is in math mode the space is
% not a real problem (it is not a problem either in \xintiiifOne 
% as here its argument is already expanded anyhow).
\def\Rsqrt@@ #1,#2#3,{\xintiiifOne{#1}{}{#1}\xintiiifOne{#2#3}{}{\sqrt{#2#3}}}

\newcommand* \Rsqrt[1]{%
   \begingroup
     \edef\N{\xinttheiexpr #1\relax}%
     \xintiiifSgn \N
        {\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
        {0}
        {\xintiiifOne \N{1}{\Rsqrt@}}
   \endgroup
 }

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing

\begin{multicols}{4}
\xintFor* #1 in {\xintSeq {10000}{10099}}\do
       {$\sqrt{#1}=\Rsqrt{#1}$\par}
\end{multicols}

% $\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}$%, 

% this one does not work because 10^10.5 > 2^31 causes an arithmetic
% overflow in the "sqrt(J)..1" part. 
% It would not overflow with "sqrt(J)..[-1]..1"
% but then we can wait long time ... 
% from 31622776601 downto
%      10000000000 that's a lot of iterations !
%$\Rsqrt{1e21}$
% The update uses n++ syntax, but this also requires abs(n) to be <2^31
% hence the same remark applies: a "Number too big" error is generated.
% Better actually than to wait the completion of 21622776601 iterations ;-)


% \stop

\pdfsetrandomseed 123456789

% we try with smaller numbers... 1000 replaced by 100...
\begin{multicols}{3}
\xintiloop [1+1]
    \edef\Z {\xinttheiiexpr 
             (\pdfuniformdeviate 100)^2
             *\pdfuniformdeviate 100\relax }%
    $\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<51
\repeat
\end{multicols}

\end{document}

enter image description here


Third approach: again the faster algorithm, but expandably.

It would be more reasonable to code this à la \numexpr but well. Details in the code comment. The example has now 51 random examples, and funny enough the missing one (from first approach) turned out to be a random square (with the random seed to pdftex random number generator set at 123456789).

\documentclass[a4paper]{article}

\usepackage{geometry}

\usepackage{xintexpr}[2016/03/19]%
% needs xintexpr 1.2g due to 
%  - changed meaning of iter
%  - shift by 1 in [L][n] syntax


% syntax \ExtractRadical {N or <integer expression>} expands to "A, B" with
% N=A^2 B, B square-free
% Algorithm:
% main variable a triple (P, I, J) where
%  - always N = I^2 J
%  - J's prime factors < P have multiplicity one.
% START: (2, 1, N)
% ITER:  (P, I, J)
         % Q=P^2
         % is Q > J ?
         %   - yes: STOP(I, J)
         %   - no:
         %         does Q divide J ?
         %         - yes: I<-I*P, J<-J/Q and repeat until Q does not divide J
         %         - no; continue with (P+2, I, J). 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)
%

\newcommand*\ExtractRadical [1]{%
  \xinttheiiexpr 
  iter (2, 1, #1; % starting triple P=2, I=1, J=N
  subs(subs(subs(subs(
  % apart from Q=P^2, these substitutions are mainly because [@][n] syntax
  % is cumbersome; and inefficient as it allows n to be itself a complicated
  % expression, hence does some rather unneeded parsing here of n= 0, 1, 2.
  % We really need some better syntax like iter(P=2, I=1, J=#1;...) and then
  % work with P, I, J standing for the last values.
  % Or at least something like subs(..., (Q, P, I, J)=(...)).
  % (not yet with xintexpr 1.2g). 
  (Q>J)?
      {break(I, J)}
      {(J/:Q)?
          {(n)?{P+2}{3}, I, J}
      % must use parentheses here: ([@][1]). Else ]/: will confuse parser.
      % I could have used again subs, but well. 
          {iter(P*I,J//Q;(([@][1])/:Q)?{break((n)?{P+2}{3},@)}
                                       {(P*[@][0],([@][1])//Q)},e=1++)
          }
      }
  , Q=P^2), P=[@][0]), I=[@][1]), J=[@][2]), n=0++)
    \relax
}             
                  
\makeatletter
\def\Rsqrt@ {\expandafter\Rsqrt@@\romannumeral-`0\ExtractRadical\N,}

\def\Rsqrt@@ #1,#2,{\xintiiifOne{#1}{}{#1}\xintiiifOne{#2}{}{\sqrt{#2}}}

\newcommand* \Rsqrt[1]{%
   \begingroup
     \edef\N{\xinttheiexpr #1\relax}%
     \xintiiifSgn \N
        {\pm\edef\N{\xintiiAbs{\N}}\xintiiifOne\N{}{\Rsqrt@}i}
        {0}
        {\xintiiifOne \N{1}{\Rsqrt@}}
   \endgroup
 }

\makeatother
\usepackage{multicol}

\begin{document}

\parindent0pt\def\columnseprule{.4pt}%

% testing

% \xintFor* #1 in {\xintSeq {0}{50}}\do 
% {\ExtractRadical {#1}\par}

% \ExtractRadical {128}

% \ExtractRadical {1024}
% \stop

% $\Rsqrt{5000}$

% \stop

% \begin{multicols}{4}
% \xintFor* #1 in {\xintSeq {10000}{10099}}\do
%        {$\sqrt{#1}=\Rsqrt{#1}$\par}
% \end{multicols}

$\Rsqrt{-10}, \Rsqrt{-1}, \Rsqrt{-16}$

$\Rsqrt {1e6}, \Rsqrt {1e7}, \Rsqrt {1e21}$%, 

\pdfsetrandomseed 123456789

\begin{multicols}{3}
\xintiloop [1+1]
    \edef\Z {\xinttheiiexpr 
             (\pdfuniformdeviate 1000)^2
             *\pdfuniformdeviate 1000\relax }%
    $\sqrt{\Z}=\Rsqrt{\Z}$\par
\ifnum\xintiloopindex<51
\repeat
\end{multicols}

\end{document}

enter image description here


Update (2017).

Here is no-package expandable macro, if needed. It expands to I,J where original N is I**2 times J and J is square-free. Uses only \numexpr. Limited to <2**31 integers. Works from low to big, same as elementary factorization method. Stopping criteria should be improved, the comment below applies here too.

\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.%
    {\space#2,#3}% (not sole #2 for readability)
\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.}%
   {\ExtractRadical@i 3;#2,#3.}%
}%
\def\ExtractRadical@i #1;{%
    \expandafter\ExtractRadical@ii\the\numexpr#1*#1.#1;%
}%
\def\ExtractRadical@ii #1.#2;#3,#4.{%
    \ifnum#1>#4 \expandafter\ExtractRadical@done\fi
    \expandafter\ExtractRadical@iii\the\numexpr#4/#1.#1;#4.#2;#3.%
}%
\def\ExtractRadical@iii #1.#2;#3.{%
    \ifnum\numexpr#1*#2=#3
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
    \ExtractRadical@update
    \ExtractRadical@next
    #1.#2;#3.%
}%
\def\ExtractRadical@update #1.#2;#3.#4;#5.{%
    \expandafter\ExtractRadical@ii
    \the\numexpr#2\expandafter.%
    \the\numexpr#4\expandafter;%
    \the\numexpr#4*#5,#1.%
}%
\def\ExtractRadical@next #1.#2;#3.#4;#5.{%
    \expandafter\ExtractRadical@i\the\numexpr2+#4;#5,#3.%
}%
\edef\ExtractRadical@done #1;#2.#3;#4.{\space#4,#2}%

\makeatother
6
  • I presented the above algorithm because i need the implementation for a single document, so the speed is not really an issue. However, if one was to write the command to redistribute it through a package, a more efficient algorithm would naturally be needed. Anyway, great answer! Commented Mar 21, 2016 at 13:23
  • 2
    @user414064 it is possible to implement the original algorithm using a syntax a bit alike the one in Mico's answer, but using traditional pdftex engine. I didn't do it because I have changed the relevant xintexpr.sty syntax very recently. But will add it.
    – user4686
    Commented Mar 21, 2016 at 13:26
  • Although all the answers are great, i ended up using this approach, since i'm already using the package xintexpr in my document. Commented Mar 21, 2016 at 17:34
  • In 1. and 3., criterion Q^2>J is sub-optimal, we possibly should test Q^2>K where K would be J freed from all prime divisors P found on the way. In the current implementation, J keeps a copy of each P with an odd exponent in original N.
    – user4686
    Commented Mar 21, 2016 at 20:47
  • 1
    @user414064 thanks for the tick and apologies because in my implementation of the algorithm from your question, I initially did some completely un-needed recursion. I feel like hitting my head fifty times against the wall to reset my brain ;-) Updated code in "approach 2" is now much much simpler.
    – user4686
    Commented Mar 22, 2016 at 9:15
30

Here's a LuaLaTeX-based solution. The code sets up a LaTeX macro named \rsqrt, which invokes a Lua function named rsqrt. The latter implements the simplification algorithm you've proposed -- with the following refinements:

  • For n=0 or n=1, the code simply returns n (without a square root symbol); and

  • Care is taken to omit the \sqrt{n/i²} term if it's equal to 1, i.e., if n is a "square number" (4, 9, 16, etc) or a product of smaller square numbers. E.g, if n=36, \rsqrt{36} shows 6 since 36 = 6^2 = 2^2*3^2.

No input sanity checking is performed, i.e., the user is responsible for providing an argument to \rsqrt that is either a non-negative whole number or evaluates to a non-negative whole number. Thus, it's ok to write \rsqrt{1e6} and \rsqrt{3.6e7}: the macro will return 1000 and 6000, respectively.

Observe that the macro \rsqrt must be used in math mode as it may output \sqrt directives.

enter image description here

% !TEX TS-program = lualatex  
%% Note: Code updated 2019/10/26 to work with LaTeX 2019-10-01 

%% Create an external file to contain the Lua code
\begin{filecontents*}[overwrite]{rsqrt.lua}
function rsqrt ( n )
  -- n : a non-negative whole number (or something
  --     that evaluates to a non-neg. whole number)
  if n == 0 or n == 1 then   -- Nothing to do
    return ( n )
  else
    i = math.floor ( math.sqrt ( n ) )
    while i > 1 do
      if ( n % i^2 == 0 ) then     -- n is divisible by i^2
        k = math.floor ( n / i^2 ) -- 'math.floor' makes k an explicit integer
        if k == 1 then  -- n is a "square" number (or a product of square numbers)
          return ( i )
        else
          return ( i .. "\\sqrt{" .. k .. "}" )
        end
      end
      i = i-1
    end
    -- No simplification possible:
    return ( "\\sqrt{" .. n .. "}" )
  end
end
-- Define a vector (in form of a Lua table) of whole numbers
nvec = {0,1,2,3,4,5,7,12,16,18,27,32}

-- Lua function to print 3-column array:
function PrintArray()
  for i=1,#nvec do
    u = nvec[i]
    tex.sprint ( math.floor(u) .. 
                "& \\sqrt{" .. math.floor(u) .. 
                "}&" .. rsqrt(u) .. "\\\\" )
  end
end
\end{filecontents*}

\documentclass{article}

%% Load Lua code from external file:
\directlua{dofile("rsqrt.lua")}

%% TeX-side code: "wrapper" macro that invokes the Lua function:
\newcommand\rsqrt[1]{\directlua{tex.sprint(rsqrt(#1))}}

\begin{document}
\[
\renewcommand\arraystretch{1.25}
\begin{array}{@{} rcc @{}}
  \verb+n+ & \verb+\sqrt+ & \verb+\rsqrt+ \\ % print header row
  \directlua{PrintArray()}    % create and print body of 'array'
\end{array}
\]
\end{document} 
6
  • I think this will output 2\sqrt{8} for \sqrt{32} instead of 4\sqrt{2}. Commented Mar 21, 2016 at 5:35
  • 1
    Nope, just reading the code, and missed that it counts down rather than up. Sorry. Commented Mar 21, 2016 at 6:01
  • 1
    @MichaelAnderson - Glad this is all sorted out. :-)
    – Mico
    Commented Mar 21, 2016 at 6:04
  • 4
    Aside: The seventh upvote on this answer pushed my rep point count above the 150K mark. Many thanks to all up-voters!!
    – Mico
    Commented Mar 21, 2016 at 8:17
  • 2
    Congrats Mico :)
    – cmhughes
    Commented Mar 21, 2016 at 13:04
18

In expl3:

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\rsqrt}{m}
 {
  \manual_rsqrt:n { #1 }
 }

\int_new:N \l_manual_rsqrt_int

\cs_new_protected:Nn \manual_rsqrt:n
 {
  \int_set:Nn \l_manual_rsqrt_int { \fp_to_decimal:n { trunc(sqrt(#1),0) } }
  \bool_until_do:nn
   {
    \int_compare_p:n { \int_mod:nn { #1 } { \l_manual_rsqrt_int * \l_manual_rsqrt_int } == 0 }
   }
   {
    \int_decr:N \l_manual_rsqrt_int
   }
  \int_compare:nTF { \l_manual_rsqrt_int == 1 }
   {
    \sqrt{#1}
   }
   {
    \int_to_arabic:n { \l_manual_rsqrt_int }
    \int_compare:nF { #1 == \l_manual_rsqrt_int*\l_manual_rsqrt_int }
     {
      \sqrt{ \int_to_arabic:n { #1/(\l_manual_rsqrt_int*\l_manual_rsqrt_int) } }
     }
   }
 }
\ExplSyntaxOff

\begin{document}

$\rsqrt{4}$

$\rsqrt{8}$

$\rsqrt{18}$

$\rsqrt{12}$

$\rsqrt{7}$

\end{document}

enter image description here

If you want to deal with arguments 0 and 1 and also with negative arguments, you can change the main definition into

\NewDocumentCommand{\rsqrt}{m}
 {
  \int_compare:nTF { #1 < 0 }
   {
    \int_compare:nTF { #1 = -1 } { i } { \manual_rsqrt:n { -#1 } i }
   }
   {
    \int_compare:nTF { #1 < 2 } { #1 } { \manual_rsqrt:n { #1 } }
   }
 }

Now the input

$\rsqrt{0}$ and $\rsqrt{1}$

$\rsqrt{-1}$ and $\rsqrt{-4}$ and $\rsqrt{-32}$

would output

enter image description here

5
  • For n=1 and n=0, the code produces \sqrt{1} (somewhat ugly; nicer: 1) and an Arithmetic overflow warning message, respectively. OK, so maybe 0 isn't a true integer... :-)
    – Mico
    Commented Mar 21, 2016 at 6:04
  • 3
    @Mico Dealing with these two cases is left as an exercise 😉
    – egreg
    Commented Mar 21, 2016 at 8:59
  • it should be better to write 2i\sqrt{2} for readability reasons.
    – Tarass
    Commented Mar 21, 2016 at 12:08
  • 3
    @Tarass Another exercise for the reader.
    – egreg
    Commented Mar 21, 2016 at 12:48
  • @egreg by the way,\sqrt{-4} has no sens as it has to be a positive value, 2i isn't, nor -2i.
    – Tarass
    Commented Mar 21, 2016 at 18:37
16

And here is an example how to do this using only classical TeX:

\newcount\numA \newcount\numB  \newcount\numC  \newcount\numD

\def\rsqrt#1{\numA=2 \numC=#1 \rsqrtA}
\def\rsqrtA{%
   \numB=\numA \multiply\numB by\numA
   \ifnum\numB>\numC \sqrt{\the\numC}\else
      \divisibleCbyB\iftrue \the\numA
         \divide\numC by\numB
         \ifnum\numC>1 \cdot \rsqrtA \fi
      \else
      \advance\numA by1
      \expandafter\expandafter\expandafter\rsqrtA
   \fi\fi
}
\def\divisibleCbyB#1{\numD=\numC \divide\numD by\numB \multiply\numD by\numB
   \ifnum\numD=\numC
}

$\sqrt{32} = \rsqrt{32}, \quad  \sqrt{79755174} = \rsqrt{79755174}$

\bye
1
  • +1. :-) I don't think, though, that the OP was asking for the square numbers being factored out of the square root expression to be decomposed further into products of primes.
    – Mico
    Commented Mar 21, 2016 at 12:56
10

If you're not averse to jumping outside of LaTeX, here's a solution using the pythontex package. I called it sroot for simple root. Obviously, you can call it anything you want. This version requires a

pdflatex *filename*.tex, pythontex filename*.tex, pdflatex *filename*.tex execution sequence for your document.

\documentclass{article}
\usepackage{pythontex}
\begin{document}
\newcommand{\sroot}[1]{\ensuremath{\py{simpleroot(#1)}}}
\begin{pycode}
from math import *
def simpleroot(n):
    if n==0:
        return(str(0))
    j=int(sqrt(n))
    flag_continue=True
    while flag_continue:
        b=n*1./(j*j)
        if b==int(b):
            mystring=str(j)+'\\sqrt{'+str(int(b)) +'}'
            flag_continue=False
        else:
            j-=1

        if int(b)==1:
            mystring=str(j)
        if int(b)==n and b>1:
            mystring='\\sqrt{'+str(int(b)) +'}'

    return(mystring)
\end{pycode}

This is a test.

The $\sqrt{1}$ is \sroot{1}.

The $\sqrt{4}$ is \sroot{4}.

The $\sqrt{7}$ is \sroot{7}.

The $\sqrt{8}$ is \sroot{8}.

The $\sqrt{18}$ is \sroot{18}.

The $\sqrt{23}$ is \sroot{23}.

The $\sqrt{27}$ is \sroot{27}.

The $\sqrt{32}$ is \sroot{32}.

The $\sqrt{64}$ is \sroot{64}.

The $\sqrt{80}$ is \sroot{80}.

The $\sqrt{1000}$ is \sroot{1000}.

The $\sqrt{3000033}$ is \sroot{3000033}.

Goodbye.
\end{document}
4
  • I didn't know about pythontex. Coming from a python background that's good to hear. Thanks Commented Mar 22, 2016 at 9:42
  • 1
    Alas... xintexpr will lose about its sole user ;-) !
    – user4686
    Commented Mar 22, 2016 at 21:45
  • Does pythontex work with MiKTeX for someone who's not very good with Windows command line? Commented Mar 23, 2016 at 1:28
  • pythontex should be a package in MiKTeX (I haven't tried it--using TeXLive, but it should be in MiKTeX, too). I use the TeXstudio editor and have set up a user command which runs pythontex %.tex. That executes a script which compiles and executes the python items. I let TeXstudio compile, then execute the user command, then recompile and view the pdf. The MiKTeX installation should set the path for LaTeX, and your Python installation should have it set for running the script.
    – Bill N
    Commented Mar 23, 2016 at 1:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .