14

I want to create a set of macros like this:

\addnumbers{2}{5}

\subtractnumbers{3}{5}

\multiplynumbers{2}{-2}

\dividenumbers{2}{8}

The first will display the number 7, adding #1 and #2.

The second will display -2, subtracting #2 from #1.

The third will display -4, multiplying #1 by #2.

The last will display 4, dividing #2 by #1.

I've tried searching for ways to do these calculations in ConTeXt or even Plain TeX, but since math is a common thing to display in this software, the search results just return ways to display math, not to calculate it.

How can I get these macros to do the calculations?

  • 2
    Are you ok with a Plain-LuaTeX solution, or does it have to be a Plain-pdfTeX solution? – Mico Nov 23 '19 at 14:30
  • 1
    \nexcount simply creates the count (assigns a register). Setting it is a separate step (\thisisacounter=4). BTW, LaTeX nomenclature is that a counter is a count of the form \c@name for some counter name.. – John Kormylo Nov 23 '19 at 15:56
  • 2
    The "Plain" in "PlainTeX" refers to the macros defined in the TeXbook -- collectively, a "format". The term "PlainTeX" does not specify which engine is in use: it could be pdfTeX, XeTeX, or LuaTeX. ConTeXt is a format that's built exclusively on LuaTeX; it will not work under pdfTeX. "Plain-LuaTeX", then, corresponds to the Plain format built on top of the LuaTeX engine. – Mico Nov 23 '19 at 15:56
  • 1
    Just to add to the comment by @Mico: Actually, ConTeXt is a format that can be built on pdfTeX, XeTeX, LuaTeX and LuaMetaTeX. MkII works on pdfTeX and XeTeX, MkIV is LuaTeX-only and LMTX is LuaMetaTeX-only. MkIV and LMTX support Lua interaction. – TeXnician Nov 24 '19 at 15:59
  • 1
    @Mico I have no definite number for this. But I would guess it is for at least 8 years. It has been the default in 2014 (when I made a first attempt to use it) for sure. And given the adaption rate of Hans Hagen with LuaMetaTeX (which basically replaced MkIV in large parts of his productive environment within a few weeks) I would think it has been similar with MkIV. – TeXnician Nov 27 '19 at 13:50
11

In ConTeXt you can use the lua interface:

\starttext
  The first will display the number \ctxlua{context(2+5)}
\stoptext

enter image description here

|improve this answer|||||
  • 4
    Use \luaexpr{2+5} instead of \ctxlua{context(2+5)}. See ConTeXt Lua Documents for details. – Henri Menke Nov 24 '19 at 2:51
  • @HenriMenke: I still prefer \ctxlua{context(...)} because it is possible to specify formatting specifiers: \ctxlua(context("0.3f", 5/3)}. Not sure how to do that using \luaexpr. – Aditya Nov 24 '19 at 7:25
  • 2
    @Aditya You have a \letterpercent missing. With \luaexpr you can also easily do it: \luaexpr{string.format("\letterpercent 0.3f", 5/3)}. The main point of \luaexpr is to protect the user from a situation where the expression could evaluate to a boolean in which case it is interpreted in a special way by context(...). – Henri Menke Nov 24 '19 at 7:32
  • 1
    @HenriMenke: Ah, thanks! – Aditya Nov 24 '19 at 7:41
  • @HenriMenke: Good to know 👍 – DG' Nov 24 '19 at 10:08
19

You can use the ε-TeX primitive \numexpr for expandable integer expressions. The only restriction is that it won't work in engines without ε-TeX extensions (mostly Knuth TeX nowadays), in which case you need to go with siracusa's solution.

These macros being expandable, allows you to use them anywhere TeX expects a number, like in \ifnum, \ifcase, or \ifdim (with the proper units) tests, register assignments, etc.

Here are the four interfaces you want (I swapped the order of the arguments in \dividenumbers because I think it makes more sense this way), plus a generic \inteval, which takes an integer expression, like 2+5*(3-4), as argument:

\def\addnumbers#1#2{\number\numexpr#1+#2\relax}
\def\subtractnumbers#1#2{\number\numexpr#1-#2\relax}
\def\multiplynumbers#1#2{\number\numexpr#1*#2\relax}
\def\dividenumbers#1#2{\number\numexpr#1/#2\relax}
\def\inteval#1{\number\numexpr#1\relax}

\def\test#1#2#3#4{$#2#3#4 = #1{#2}{#4}$\par}
\test\addnumbers{2}+{5}
\test\subtractnumbers{3}-{5}
\test\multiplynumbers{2}\times{-2}
\test\dividenumbers{8}\div{2}

$2+5\times(3-4) = \inteval{2+5*(3-4)}$
\bye

enter image description here

If you don't want to restrict yourself to integers, you can use expl3's FPU, which is format-independent, and also expandable. It allows you a much larger range of operations. The code below defines the four interfaces you asked, plus \fpeval for generic floating point expressions (in LaTeX the package xfp provides the same \fpeval):

\input expl3-generic.tex
\ExplSyntaxOn
\cs_new:Npn \addnumbers #1 #2
  { \fp_eval:n { #1 + #2 } }
\cs_new:Npn \subtractnumbers #1 #2
  { \fp_eval:n { #1 - #2 } }
\cs_new:Npn \multiplynumbers #1 #2
  { \fp_eval:n { #1 * #2 } }
\cs_new:Npn \dividenumbers #1 #2
  { \fp_eval:n { #1 / #2 } }
\cs_new:Npn \fpeval #1
  { \fp_eval:n { #1 } }
\ExplSyntaxOff
\def\test#1#2#3#4{$#2#3#4 = #1{#2}{#4}$\par}
%
\test\addnumbers{2}+{5}
\test\subtractnumbers{3}-{5}
\test\multiplynumbers{2}\times{-2}
\test\dividenumbers{8}\div{2}

$2^2+5\times(\cos(3)-4) = \fpeval{2^2+5*(cos(3)-4)}$
\bye

enter image description here

|improve this answer|||||
  • AFAIK expl3 is neither plain TeX nor ConTeXt – sztruks Nov 23 '19 at 16:41
  • 4
    @sztruks No. expl3 is format-independent, so you can load it in either Plain, ContTeXt, or LaTeX (try it :-). The only requirement is a recent enough TeX engine (at least pdfTeX v1.40, XeTeX v0.99992, LuaTeX v0.95, or e-(u)pTeX mid-2012). The difference is that in LaTeX there is a dedicated package expl3.sty (with all the \ProvidesPackage things), and for ConTeXt or Plain you use the generic loader expl3-generic.tex. But the bulk of the code (expl3-code.tex) is the same for all three. – Phelype Oleinik Nov 23 '19 at 16:46
  • Oh, nice to know this. Thanks. – sztruks Nov 23 '19 at 16:47
  • 4
    CAVEAT: Division in \numexpr rounds, whereas \divide truncates! – Henri Menke Nov 24 '19 at 7:43
13

As you haven't specified if the solution should be expandable, here's a non-expandable plain TeX solution.

We first define a general \docalc macro which takes a calculation command working on count registers (\advance, \multiply or \divide), and the two operands. The operation is applied on a local register which value is immediately output afterwards. Based on \docalc we then define the four macros for doing the basic arithmetic operations:

\def\docalc#1#2#3{%
    \begingroup
    \count0=#3
    #1\count0 by #2\relax
    \the\count0
    \endgroup
}

\def\addnumbers       {\docalc\advance}
\def\subtractnumbers#1{\docalc\advance{-#1}}
\def\multiplynumbers  {\docalc\multiply}
\def\dividenumbers    {\docalc\divide}

$2 + 5 = \addnumbers{2}{5}$

$5 - 3 = \subtractnumbers{3}{5}$

$2 \cdot (-2) = \multiplynumbers{2}{-2}$

$8 \div 2 = \dividenumbers{2}{8}$
\bye

enter image description here

|improve this answer|||||
  • 1
    I'd add a \relax after by #2, since what follows is expandable (+1 though :-) – Phelype Oleinik Nov 23 '19 at 16:15
  • @PhelypeOleinik This should only be an issue if \endlinechar had a weird value, no (as the space from it should make the scanner stop)? – siracusa Nov 24 '19 at 9:28
  • 2
    Sorry, I forgot the reasoning for my comment. It's just nitpicking, really. For reasonable input, that should be no problem, since the \endlinechar space stops scanning for an integer. However if the first number is an incomplete number (empty, for example), then the \the\count0 is silently taken as the number. With \relax TeX will raise an error. Of couse it requires a weirdo trying to break your code with malicious input for that to happen ;-) – Phelype Oleinik Nov 24 '19 at 14:12
10

Here's a Plain-LuaTeX solution. The arguments of \addnumbers, \subtractnumbers, etc. can be either numbers or something that evaluates to a number using simple arithmetic operations (but not exponentiation, as the meaning of ^ differs drastically between TeX and Lua). If the result of the calculations is a whole number, no decimal part is printed, courtesy of the Lua utility function myprint defined below.

enter image description here

% !TEX TS-program = luatex
\directlua{% Define a utility function:
  function myprint (u) 
    if u==math.floor (u) then 
      tex.sprint ( math.floor (u) )
    else 
      tex.sprint (u) 
    end
  end
}
\def\addnumbers#1#2{\directlua{myprint((#1)+(#2))}}
\def\subtractnumbers#1#2{\directlua{myprint((#1)-(#2))}}
\def\multiplynumbers#1#2{\directlua{myprint((#1)*(#2))}}
\def\dividenumbers#1#2{\directlua{myprint((#2)/(#1))}}

$\addnumbers{8-6}{5} \quad
 \subtractnumbers{3}{6-1} \quad
 \multiplynumbers{2}{-6+4} \quad
 \dividenumbers{3-1}{4+2+4/2}$
\bye
|improve this answer|||||

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.