Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I've been trying to modify the solution here into a LaTeX3 command that takes a variable length comma separated list of numbers and an optional argument (a unit) and prints the square root of the sum of the square of each number (along with the unit, if given).

\sumofsquares{2,3,-4}[m/s] should give

enter image description here

but \sumofsquares{3,-4}[m/s] should give

enter image description here

I've Googled for LaTeX3 examples but the ones I've found (documentation for xparse and expl3) don't contain any examples. The differences between lists and sequences mystifies me.

share|improve this question
    
A sequence is just a linear array of items. It has a first item, a second item and so on. To make one, you just take a list of things whose distinct elements are separated by some specific character, say ; and use \seq_set_split:Nnn {name}{separator}{list}. expl3 then provides functions for working with them. Think of a clist as a sequence whose separator is a comma. Functionally, I don't think there's much difference between them. sequence's are more versatile, clist's maybe shorten some syntax. –  Scott H. Nov 11 '12 at 3:33
    
A comma list is 'closer' to user syntax than a sequence: more convenient in many cases but not quite as general. As is mentioned in one of the answers, your input syntax is odd: I'd expect either \sumofsquares[m/s]{2,3,4} or \sumofsquares{2,3,4}{m/s} (with no optional argument). –  Joseph Wright Nov 11 '12 at 8:35
    
@Joesph The package I'm developing defines syntax the way one would say it. One always says units after the numerical value of a physical quantity. I can't see how or why it should be any other way. –  user19024 Nov 12 '12 at 2:26

3 Answers 3

up vote 6 down vote accepted

Here's an option using sequences, it could probably be made a little more compact as the code from the two helper macros is almost identical.

I'm not an expert so take my advice with a grain of salt but I would just stick with using sequences. They require an extra line of code here and there, but the additional options that they provide are well worth it.

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn
\NewDocumentCommand{\sumofsquares}{ m o }
    {
        \IfNoValueTF {#2}
            % if optional is missing call this
            {\sum_of_squares:n {#1}}
            % if not, then call this
            {\sum_of_squares:nn {#1}{#2}}
    }

\cs_new_protected:Npn \sum_of_squares:n #1
    {
        % does what the name suggests, set a sequence from the clist
        \seq_set_from_clist:Nn \l_tmpa_seq {#1}
        % applies final arg to each element of second seq and stores result in first seq
        \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq {(##1)^2}
        % \seq_use puts the items from the seq back in the input with "+" as a separator
        \sqrt{\seq_use:Nnnn \l_tmpb_seq {+}{+}{+}}
    }
\cs_new_protected:Npn \sum_of_squares:nn #1 #2
    {
        % same as above, but with the addition of units
        \seq_set_from_clist:Nn \l_tmpa_seq {#1}
        \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq {(\SI{##1}{#2})^2}
        \sqrt{\seq_use:Nnnn \l_tmpb_seq {+}{+}{+}}
    }


\ExplSyntaxOff
\begin{document}

$\sumofsquares{2,3,-4}$\par\medskip
$\sumofsquares{2,3,-4}[m/s]$

\end{document}

Here's a slightly shorter (and less clear) example using clists. The same method could have been used to shorten the code above.

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn

\NewDocumentCommand{\sumofsquares}{ m O{} }
    {
        \sum_of_squares:nn {#1}{#2}
    }

\cs_new_protected:Npn \sum_of_squares:nn #1 #2
    {
        \tl_if_empty:nTF {#2}
            {
                \clist_set:Nn \l_tmpa_clist {#1}
                \sqrt{(\clist_use:Nnnn \l_tmpa_clist {)^2+(} {)^2+(} {)^2+(} )^2 }
            }
            {
                \clist_set:Nn \l_tmpa_clist {#1}
                \sqrt{(\clist_use:Nnnn \l_tmpa_clist {\,\si{#2})^2+(} {\,\si{#2})^2+(} {\,\si{#2})^2+(} \,\si{#2})^2}
            }
    }

\ExplSyntaxOff
\begin{document}

$\sumofsquares{2,3,-4}$\par\medskip
$\sumofsquares{2,3,-4}[m/s]$

\end{document}
share|improve this answer
    
I think I'm taking LaTeX "programming" too literally. I have to remember that it's still a macro expansion markup. BTW, does the shorter solution allow for an arbitrary number of numerical arguments like the first solution? –  user19024 Nov 12 '12 at 2:57
    
Hi Joe: the second version also allows for an arbitrary number of arguments. They work the same, but because clists don't offer the equivalent of set_map, I used a workaround that happened to be a bit shorter. –  Scott H. Nov 12 '12 at 3:25
    
Why couldn't/shouldn't \sum_of_squares:nn be put within the braces of the \NewDocumentCommand code? Why is it needed as an intermediary in the first place? Programmatically, it looks like it shouldn't work as written. Obviously it does, but it still looks nonintuitive to me. –  user19024 Nov 12 '12 at 16:12
    
One more thing. Both version worked perfectly except when I used the first one with SIunits instead of siunitx. I kept getting "TeX capacity exceeded" errors when using any command defined in SIunits. I could define them myself locally and then they sometimes worked. The second example doesn't have this problem. –  user19024 Nov 12 '12 at 16:17
    
Re first comment: the code of \sum_of_squares:nn could be put in the body of \NewDocumentCommand. I have come to understand that doing so is stylistically undesirable. It has been pointed out that \NewDocumentCommand should be used only as a wrapper that passes off control to the relevant expl3 macros. In this case \sumofsquares simply grabs the two arguments at the document level, and passes them to \sum_of_squares:nn. In the first version, I did that "properly" with the branching in the document command, and in the second I didn't. –  Scott H. Nov 12 '12 at 18:12

Well, you can do this just with xparse, so

$\sumofsquares{2,3,-4}[m/s]$
$\sumofsquares{2,3,-4,4,7}$

yields:

enter image description here

References:

Code:

\documentclass{article}
\usepackage{siunitx}
\usepackage{xparse}
\usepackage{pgffor}

\newcommand{\SequenceOfSquares}{}
\newcommand*{\TermSeparator}{}%
\NewDocumentCommand{\sumofsquares}{m O{}}{%
    \gdef\TermSeparator{}% clear up from last use (if any)
    \def\Sequence{#1}
    \foreach \x in  \Sequence {%
        \xdef\SequenceOfSquares{\SequenceOfSquares \TermSeparator (\SI{\x}{#2})^2}%
        \gdef\TermSeparator{+}%
    }
    \sqrt{\SequenceOfSquares}%
    \gdef\SequenceOfSquares{}%
}

\begin{document}
$\sumofsquares{2,3,-4}[m/s]$

\medskip
$\sumofsquares{2,3,-4,4,7}$
\end{document}
share|improve this answer

Here is another solution. No need for xparse in this solution:

\documentclass{article}
\usepackage{siunitx}
\makeatletter
\newcommand\sumofsquares[2][]{%
  \def\tempa{}%
  \@for\reserved:=#2\do{%
    \edef\tempa{\tempa\ifx\tempa\empty\else+\fi(\SI{\reserved}{#1})^2}%
  }
  \sqrt{\tempa}%
}
\makeatother
\begin{document}
$\sumofsquares[m/s]{2,3,-4}$
\par\medskip
$\sumofsquares{2,3,-4,4,7}$
\end{document}

Putting the optional argument at the end

That is the OP's choice; I don't recommend it.

\documentclass{article}
\usepackage{siunitx}
\makeatletter
\newcommand*\sumofsquares[1]{\@testopt{\@sumofsquares{#1}}{}}
\def\@sumofsquares#1[#2]{%
  \begingroup
  \def\tempa{}%
  \@for\reserved:=#1\do{%
    \edef\tempa{\tempa\ifx\tempa\empty\else+\fi(\SI{\reserved}{#2})^2}%
  }
  \expandafter\endgroup\expandafter\sqrt\expandafter{\tempa}%
}
\makeatother
\begin{document}
$\sumofsquares{2,3,-4}[m/s]$
\par\medskip
$\sumofsquares{2,3,-4,4,7}$
\end{document}
share|improve this answer
    
Ok, but the OP had requested that the optional parameter be the second parameter, not the first. Not saying that I think that that is a good idea. –  Peter Grill Nov 11 '12 at 6:02
    
That is easy to address. See the updated solution. –  Ahmed Musa Nov 12 '12 at 18:40
    
As I said in a previous comment, one always says/writes the unit after the numerical value, never the other way around. My target audience is students and instructors of physics and I want to encourage a "write what you think" model. It's far more intuitive. –  user19024 Nov 12 '12 at 22:07

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.