[Tex/LaTex] Performing basic arithmetic in custom commands

calculationsmacros

One thing annoying in sparklines is its verbosity and dependence on external arithmetics. For example, to depict a three bar graph of 16%, 53%, 31%, one has to write:

\begin{sparkline}{4}
  \sparkspike .166 .302
  \sparkspike .500 1
  \sparkspike .834 .585 
\end{sparkline}

I would prefer:

\threesparkline{0.16}{0.53}{0.31}

So my main question is can I do basic arithmetic in LaTeX, like dividing and multiplying numbers, finding the max among three parameters, etc?

Alternatively, is there a better way of using sparklines that I've missed?

UPDATE:

After the sugestion of using the calc package, I'm stuck with the following attempt which yields an error in \real and \ratio:

\newcommand{\threespike}[3]{
    \newcounter{max}\setcounter{max}{\maxof{\maxof{\real{#1}}{\real{#2}}}{\real{#3}}}
    \newcounter{a}\setcounter{a}{\ratio{\real{#1}}{max}}
    \newcounter{b}\setcounter{b}{\ratio{\real{#2}}{max}}
    \newcounter{c}\setcounter{c}{\ratio{\real{#3}}{max}}    
    \begin{sparkline}{4}
      \sparkspike .166 a
      \sparkspike .500 b
      \sparkspike .834 c 
    \end{sparkline}
}

UPDATE2:

I eventually got to make \ratio work directly like this:

\newcommand{\ratiofivespark}[7]{
    \begin{sparkline}{6}
      \sparkspike .1 \ratio{#2}{#1}
      \sparkspike .3 \ratio{#3}{#1}
      \sparkspike .5 \ratio{#4}{#1}
      \sparkspike .7 \ratio{#5}{#1}
      \sparkspike .9 \ratio{#6}{#1} 
    \end{sparkline}
}

Where the first parameter passed establishes the full height of a bar. See the accepted answer for more powerful LaTeX-Fu!

Best Answer

You can certainly do basic arithmetic in LaTeX. You have several options. You can use the standard TeX \advance, \multiply, and \divide. You can use the calc package for a more natural way of doing arithmetic (although, I find I don't use it). You can also use the e-TeX extension \numexpr ... \relax.

Edit: Okay. I think I've got a solution for you.

\documentclass{article}
\usepackage{sparklines}
\usepackage{fp}
\newcount\slnum
\makeatletter
\newcommand\dosparkline[2][4]{%
        \FPset\slmax{0}%
        \FPset\slpos{0}%
        \slnum0
        \slparse#2,\relax
        \FPadd\sladvance{1}{\the\slnum}%
        \FPdiv\sladvance{1}\sladvance
        \count@\slnum
        \loop\ifnum\count@>0
                \advance\count@-1
                \FPdiv\sltemp{\csname sl@\the\count@\endcsname}\slmax
                \expandafter\let\csname sl@\the\count@\endcsname\sltemp
        \repeat
        \begin{sparkline}{#1}
                \count@0
                \loop\ifnum\count@<\slnum
                        \FPadd\slpos\slpos\sladvance
                        % The {} are necessary
                        \sparkspike \slpos{} \csname sl@\the\count@\endcsname{}
                        \advance\count@1
                \repeat
        \end{sparkline}
}
\def\slparse#1,#2\relax{%
        \FPset\sltemp{#1}%
        \FPmax\slmax\slmax\sltemp
        \expandafter\let\csname sl@\the\slnum\endcsname\sltemp
        \advance\slnum1
        \ifx\relax#2\relax\else
                \slparse#2\relax
        \fi
}
\makeatother
\begin{document}
\dosparkline[10]{16,53,31,25,10,45}

\dosparkline{.16,.53,.31}
\begin{sparkline}{4}
  \sparkspike .166 .302
  \sparkspike .500 1
  \sparkspike .834 .585 
\end{sparkline}

\end{document}

The first \dosparkline shows the optional argument which is the width (in ex of all things!). The second one shows what you asked for which you can compare without the output of yours. You'll note I didn't match your spacing. You can play around with that by changing how \sladvance is computed.

Related Question