2

How would I go about implementing a function in TeX to add an arbitrary number of numbers? Reading through the \def notes, it seems it can only take up to nine arguments. How would I make a function that adds together an optionally arbitrarily large list of numbers?

  • 1
    Perhaps a Recursive \def like lists are implemented, within a copy to another temporary \def ( a length most probably) is needed) –  Jan 20 '15 at 07:32
  • You should be more specific in terms of the input requirements. So, mock up some example and show what you've tried. – Werner Jan 20 '15 at 07:37
  • Related (like a distant cousin): Sum of finite series – Werner Jan 20 '15 at 07:37
  • @Werner I suppose I should have asked a more basic question then, I'm still really trying to figure out how TeX works, and I was hoping seeing something like this would get me started. –  Jan 20 '15 at 07:38
  • @Anthony: Sure, but in terms of the input you have to be specific. For example, if you want to add an arbitrary number of values, just use \calc{1+2+3+4+5+6+...+1000+1001+1002+...} where \calc is from LaTeX/expl3 (\ExplSyntaxOn \cs_new_eq:NN \calc \fp_eval:n \ExplSyntaxOff). – Werner Jan 20 '15 at 07:42
  • Oh, that's nice. What does the last part of that message mean, and where can I find an implementation of \calc? –  Jan 20 '15 at 07:43
  • Perhaps I used the wrong word- I didn't want a way to use it, I wanted to know how it was defined. –  Jan 20 '15 at 07:53
  • 3
    TeX's not really set up for doing mathematics (it's good at typesetting maths!). As Werner says, you'll need to tighten up the spec of what you want to achieve. For example, are we talking integers or floating-point values, and if so how many digits? Do you need an expandable solution (one that can be used inside a context that 'expects' a number)? Can we use e-TeX/pdfTeX/LuaTeX or do you want a solution for Knuth's TeX? As indicated, a mock-up of the use case(s) and expected results would be very handy. – Joseph Wright Jan 20 '15 at 08:15
  • As a guide, implementing the FPU for expl3 uses about 5000 lines of code, is expandable and uses both e-TeX and a pdfTeX primitive. There are non-expandable maths systems in the fp package and pgfmath: again both run to 1000s of lines. All three of these cover a lot more than addition, but even that probably needs 100s of lines. Doing the same thing in LuaTeX is trivial as Lua handles the maths. – Joseph Wright Jan 20 '15 at 08:19
  • I know TeX isn't meant for this, but I know it can do it... What I had in mind is just something that can add integers. I was really hoping for some idea, any idea, of how to start this- so really I was hoping some more knowledgeable person would use their discretion to make a particularly illuminating education example. –  Jan 20 '15 at 08:28
  • You could possibly do it with lambda-lists using \Foldr and e-tex \numexpr. – morbusg Jan 20 '15 at 12:00
  • Perhaps, not what you want, but you can do it with lists in plain TeX (c.f., The Texbook, page 378): \newcount\temp \def\#1{\advance\temp by #1\relax}

    \{1}\{2}\{3}

    \showthe\temp

    – David Mitra Jan 20 '15 at 12:19

1 Answers1

5

I will answer on the assumption that the input will be of the form

\addintegers{1 + 2 + 3}

i.e. consisting of a series of integers separated by + symbols and (potentially) whitespace. I'm also going to assume the solution does not need to be expandable, that we have only the TeX3 primitives available, and that we do not have to worry about 'big' values (larger than can be held by a \count register).

To find the sum here we need to set up a loop over the input, grabbing one number at a time. As we know that + comes between each number, the way to do that is to use a macro of the form

\def\foo#1+{% Code

as this will grab everything up to the next +. We then need to make sure that there is a + after the user input and that we have some 'marker' there we can test for as 'end-of-loop'. To do the actual maths, TeX provides \count registers: I'll use a scratch on inside a group and emit the result outside of the group using \expandafter:

\catcode`\@=11 %
\def\addintegers#1{%
  \begingroup
    \count0=0\relax
    \addintegers@aux#1+\relax+\relax
}
\def\addintegers@aux#1+{%
  \ifx\relax#1\relax
    \expandafter\addintegers@end
  \else
    \advance\count0 by #1\relax
    \expandafter\addintegers@aux
  \fi
}
\def\addintegers@end#1\relax{%
  \expandafter\endgroup
  \number\count0 %
}
\catcode`\@=12 %
\addintegers{1}
\addintegers{1 + 2 + 3}
\addintegers{1 + 22 + 333}
\bye

This is of course a rather restricted solution (no coverage for example of subtraction unless there is a + sign too) but more detail would be needed in the question to go further. Full error-checking would need something a bit more complex.

If the e-TeX primitives are available the same can be achieved expandably with virtually no effort

\def\inteval#1{\number\numexpr#1\relax}
\inteval{1}
\inteval{1 + 2 + 3}
\inteval{1 + 22 + 333}
\bye

in which case the calculation can include +, -, *, /, ( and ) as supported by e-TeX (hence the different name). (e-TeX also allows whitespace in expressions.)


If you want to work expandably and to use only Knuth's TeX then it is doable if a bit tedious. Heiko Oberdiek's bigintcalc can do calculations on arbitrary integers expandably and without using e-TeX, so we could harness that (it's quite big):

\input bigintcalc.sty %
\catcode`\@=11 %
\def\addintegers#1{%
  \addintegers@auxi#1+\relax+\stop{0}%
}
\def\addintegers@auxi#1+{%
  \ifx\relax#1%
    \expandafter\addintegers@end
  \else
    \expandafter\addintegers@auxii
  \fi
    {#1}%
}
\def\addintegers@auxii#1#2\stop#3{%
  \addintegers@auxi#2\stop{\bigintcalcAdd{#1}{#3}}%
}
\def\addintegers@end#1\stop#2{#2}
\catcode`\@=12 %
\addintegers{1}
\addintegers{1 + 2 + 3}
\addintegers{1 + 22 + 333}

\bye

The detail in bigintcalc comes down to splitting the input into individual digits and doing the maths 'by hand' if \numexpr is not available.

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036