How to add, subtract, multiply, and divide in plain TeX?

You can do arithmetic (with +, -, *, /, but no ^ for powers) using \numexpr expressions.

The \numexpr expressions are among the e-TeX extensions to the Knuth's TeX.

(e-TeX extensions: on modern installations they are activated by default, except if you use the executable named tex on the command line)

However you can't use truly fractional numbers inside \numexpr...\relax (for example doing 1/7+1/3). And / does therein a (rounded) division to the nearest integer. Integers must be between -2147483647 and +2147483647: this is the same limitation as for the integers one can store in a TeX \count or in a LaTeX counter; and a \count can be used directly inside a \numexpr expression, for a LaTeX counter one has \value{mycountername}.

I wrote package xintexpr which can be used either in Plain TeX (\input xintexpr.sty) or in LaTeX (\usepackage{xintexpr}).

  1. if you want the final result rounded to an integer use \xintiexpr, for example \xintiexpr 123456789987654321/(2^32+3^20)\relax. Else \xintexpr will compute a fraction.

  2. if you want the fraction in irreducible form, use the reduce function: \xintexpr reduce (1/1+1/2+1/3+1/4+1/5+1/6+1/7+1/8+1/9+1/10)\relax.

  3. contrarily to \numexpr which can be used directly in places where TeX expect a (whole) number, for example in an \ifnum test, an \xintiexpr needs to be prefixed by \xintthe: \xintthe\xintiexpr (or \xinttheiexpr). But naturally, the produced number should be less than the 2^31 limit.

  4. an \xintthe\xintexpr (or, shorter \xinttheexpr) can not be used in an \ifnum test, as TeX does not understand fractions. The package provides tests of its own to compare numbers incl. fractions.

  5. an \xintexpr expression must be terminated by a \relax whereas a \numexpr will terminate legally on any token (like a dot .) not expected by its syntax.

  6. \numexpr -(1+2)\relax does not work! but \xintexpr -(1+2)\relax does...

  7. \xintexpr is completely expandable.

Hence things such as:

\message{\xinttheexpr reduce (1/1+1/2+1/3+1/4+1/5+1/6+1/7+1/8+1/9+1/10)\relax}
\message {\xinttheiexpr 123456789987654321/(2^32+3^20)\relax}

are possible.

Code for the OP use case:

\input xintexpr.sty\relax % compile with etex or pdftex

% macro to use \xinttheiexpr which will round to the nearest whole number.
\def\roundandprint #1{\xinttheiexpr #1\relax }

\def\weeks{20}          % term is twenty weeks
\def\lessonsperweek{3}  % meets three times per week
\def\lessonduration{60} % meets for sixty minutes

\def\percentlectures{.5}    % half the time is spent in lectures
\def\percentdiscussions{.2} % 20 percent of the time is spent in disucssions

% remaining percent of time left to lab work:
\def\percentlab{\xintexpr 1 - \percentdiscussions - \percentlectures\relax} 

% minutes spent in lessons:
\def\totalduration{\xintexpr \lessonduration * \lessonsperweek * \weeks\relax} 

% total duration in hours:
\def\totaldurationhours{\xintexpr \totalduration / 60 \relax}

% minutes spent in the lab:
\def\labduration{\xintexpr \totalduration * \percentlab \relax} 

Total time in lab: \roundandprint{\labduration} minutes.

Total minutes in class: \roundandprint{\totalduration} minutes.

Total hours in class: \roundandprint{\totaldurationhours} hours.

\def\weeks{19} % these two values are changed later in the document
\def\lessonsperweek{2}

Total minutes in class: \roundandprint{\totalduration} minutes. % this value
                                % would be different because of the chagnes to
                                % \weeks and \lessonsperweek

\bye

add-subtract-multiply

Remark: the various \xintexpr ... \relax in \percentlab etc... are a bit optional; they could have been replaced by parentheses, but using such \xintexpr ... \relax sub-expressions provides the maximal flexibility. For example, one can embed them in an \edef, naturally if everything involved in the computation is defined at that time.

As mentioned in a prior example the ^ for powers is accepted: but the exponent must be an integer (3^(10/2) is ok for \xintexpr, which will correctly compute 3^5). There is a sqrt function, which computes the square-root with, by default, 16 digits of precision. A second optional argument allows more precision:

\xinttheexpr sqrt(2,60)\relax

gives 60 digits of precision. To get the result in scientific notation, there is:

\xintthefloatexpr sqrt(2,60)\relax

plain tex (uniquely) is usually used with the classic Tex engine (or at least with pdf and e-tex extensions disabled) so there is no infix arithmetic

\newcount\zzz
\zzz=5
\multiply\zzz by 3
\advance\zzz by 2

sets \zzz to 17. If you use the plain format with e-tex you can use e-tex infix arithmentic

\newcount\zzz
\zzz=\numexpr 5*5 + 2\relax

You can use PGFmath.

For \pgfmathprintnumber from (pgfmathfloat.code.tex) it is necessary to define \pgf@texdist@protect for reasons unknown to me (this seems to be some protection mechanism).
Simply \inputting pgf.tex works, too.

Code

\expandafter\def\csname pgf@texdist@protect\endcsname{}%
\input pgfmath.tex
\def\weeks{20}          % term is twenty weeks
\def\lessonsperweek{3}  % meets three times per week
\def\lessonduration{60} % meets for sixty minutes

\def\percentlectures{.5}    % half the time is spent in lectures
\def\percentdiscussions{.2} % 20 percent of the time is spent in disucssions
                            % remaining percent of time left to lab work
\def\percentlab{1 - \percentdiscussions - \percentlectures}
                            % minutes spent in lessons
\def\totalduration{\lessonduration * \lessonsperweek * \weeks}
\def\totaldurationhours{(\totalduration) / 60}
\def\labduration{(\totalduration) * (\percentlab)} % minutes spent in the lab

\pgfset{
  number format/.cd,
  min exponent for 1000 sep=4,
  int detect,
}
Total time in lab: \pgfmathprint{\labduration} (\pgfmathprintnumber[fixed,precision=0]{\pgfmathresult}) minutes.

Total minutes in class: \pgfmathprint{\totalduration}
                 (\pgfmathprintnumber{\pgfmathresult}) minutes.

Total hours in class: \pgfmathprint{\totaldurationhours} 
               (\pgfmathprintnumber{\pgfmathresult}) hours.

\def\weeks{19}         % these two values are changed later in the document
\def\lessonsperweek{2}
                       % minutes spent in lessons

% this value would be different because of the chagnes to \weeks and \lessonsperweek
Total minutes in class: \pgfmathprint{\totalduration}
                 (\pgfmathprintnumber{\pgfmathresult}) minutes.
\bye

Output

enter image description here