6

My document is structured as follows:

* Bla bla bla

  Quantity | Item     | Price per item | Total price
  ---------+----------+----------------+------------
         5 | Sandwich |           5.00 |       25.00


* More bla bla bla

  Quantity | Item     | Price per item | Total price
  ---------+----------+----------------+------------
         3 | Coke     |           1.00 |        3.00

Grand total: 28.00

In the past, I have created a similar document with Word 2007 where I had all calculations done automatically. Is that also possible with LaTeX?

I am aware of spreadtab, which I frequently use for invoices. It works great if all the values are in one table. However, this is not the case here.

1
10

enter image description here

\documentclass{article}
\usepackage{array}

\def\q#1{\gdef\thisq{#1}#1}
\def\p#1{\gdef\thisp{#1}#1}
\def\total{0}
\makeatletter
\def\itemcost{%
  \strip@pt\dimexpr\thisp\p@*\thisq\relax
  \xdef\total{\strip@pt\dimexpr\total\p@+\thisp\p@*\thisq\relax}}
\makeatother
\begin{document}

 Bla bla bla

\begin{tabular}{rcrr}
  Quantity & Item     & Price per item & Total price\\
\hline
       \q{5} & Sandwich &           \p{5.00} &  \itemcost
\end{tabular}


 More bla bla bla

\begin{tabular}{rcrr}
  Quantity & Item     & Price per item & Total price\\
\hline
         \q{3} & Coke     &           \p{1.00} &     \itemcost
\end{tabular}

Grand total: \total

\end{document}

If you are using tabularx you need to only do the arithmetic on the final run, not when it is doing trial runs to calculate the widths.

\def\q#1{\gdef\thisq{#1}#1}
\def\p#1{\gdef\thisp{#1}#1}
\def\total{0}
\makeatletter
\let\normalwrite\write
\def\itemcost{%
  \strip@pt\dimexpr\thisp\p@*\thisq\relax
  \ifx\write\normalwrite\xdef\total{\strip@pt\dimexpr\total\p@+\thisp\p@*\thisq\relax}\fi}
\makeatother
\usepackage{tabularx}
5
  • This looks great, only I get an "Arithmetic overflow." error if the amount of sandwiches is increased from 5 to 5000. Is there any way to make it work with large numbers?
    – feklee
    Oct 18 '13 at 8:28
  • 1
    It uses dimen arithmetic so maximum value 16384, Your examples used .00 if you only ever need integer values you could use \numexpr instead and remove the \p@ or you could use a floating point package (fp or l3fp) Oct 18 '13 at 8:33
  • With the fp package, it works fine, except that if I use tabularx, then \total is off by a factor of three (see related question). So, while your reply answers my question to the point, I am now having a closer look at the suggestion by @Corto.
    – feklee
    Oct 18 '13 at 14:17
  • 1
    @feklee it could be more than three, depending how many trials tx does: see update Oct 18 '13 at 14:32
  • That does the trick!
    – feklee
    Oct 18 '13 at 14:57
6

Here's a solution the takes advantage of some tricks available through pgfmath

\documentclass{article}
\usepackage{pgfmath}
\pgfkeys{/pgf/number format/precision=2,
         /pgf/number format/fixed zerofill=true}
\def\grandtotal{0}
\def\getgrandtotal{\pgfmathroundtozerofill{\grandtotal}\$\pgfmathresult}
%% #1=quantity
%% #2=description
%% #3=price per item
\def\receipt#1#2#3{%%
  \par
  \vspace{1.25\baselineskip}
  \begin{tabular}{cp{1.5in}rr}
  Quantity & Item & Price per item & Total price \\\hline
  #1       & #2   & \$#3             & 
  \pgfmathparse{#1*#3}\pgfmathroundtozerofill{\pgfmathresult}\$\pgfmathresult
  \pgfmathsetmacro{\grandtotal}{\pgfmathresult+\grandtotal}%%
  \xdef\grandtotal{\grandtotal}%%      
  \end{tabular}
  \vspace{1.25\baselineskip}
  \par
}

\usepackage{lipsum}
\pagestyle{empty}
\begin{document}

Some random text.

\receipt{5}{Sandwich}{5.00}

Some more random text.

\receipt{3}{Coke}{1.00}

Grand total: \getgrandtotal

\end{document}

enter image description here

UPDATE

After seeing your comments about Arithmetic overflow, here's a variation on the above pgfmath approach which uses the fp package together with siunitx to make the numbers more readable:

\documentclass{article}
\usepackage{fp}
\usepackage{siunitx}
\def\grandtotal{0}
\def\currentAmount{}
\def\dollars#1{\SI[per-mode=symbol,group-separator={,}]{#1}[\$]{}}
\def\getgrandtotal{\dollars{\grandtotal}}
%% #1=quantity
%% #2=description
%% #3=price per item
\def\receipt#1#2#3{%%
  \par
  \vspace{1.25\baselineskip}
  \begin{tabular}{cp{1.5in}rr}
  Quantity & Item & Price per item & Total price \\\hline
  #1       & #2   & \dollars{#3}   & 
    \FPmul\currentAmount{#1}{#3}%%
    \FPround\currentAmount{\currentAmount}{2}%%
    \dollars{\currentAmount}%%
    \FPadd\grandtotal{\currentAmount}{\grandtotal}%%
    \FPround\grandtotal{\grandtotal}{2}%%
    %% make the `\grandtotal` available outside of environment.
    \xdef\grandtotal{\grandtotal}%%      
  \end{tabular}
  \vspace{1.25\baselineskip}
  \par
}

\begin{document}

Some random text.

\receipt{5}{Sandwich}{5.00}

Some more random text.

\receipt{3}{Coke}{1.00}

Some more random text.

\receipt{300}{Something expensive}{16179.52}

Grand total: \getgrandtotal

\end{document}

enter image description here

4

You can use the \STsavecell macro of the spreadtab package. This macro permit to use the numerical value of a cell outside of the table.

Update

After seeing the comment of @cgnieder, I add an example based on the provided MWE

\documentclass{article}
\usepackage{spreadtab}

\begin{document}

 Bla bla bla


\begin{spreadtab}[%
  \STsavecell\TotFood{d2}]{{tabular}{cccc}}
  @Quantity & @Item     & @Price per item & @Total price\\
\hline
       5 & @Sandwich &           5 & a2*c2
\end{spreadtab}


 More bla bla bla

\begin{spreadtab}[%
  \STsavecell\TotBevreage{d2}]{{tabular}{cccc}}
  @Quantity & @Item     & @Price per item & @Total price\\
\hline
       3 & @Coke &           1 &  a2*c2
\end{spreadtab}

\FPadd{\foo}{\TotFood}{\TotBevreage}
\FPclip{\result}{\foo}
Grand total: \FPprint{\result}
\end{document}

enter image description here

1
  • Good idea. Would you mind adding an example based on the MWE provided in the question?
    – cgnieder
    Oct 18 '13 at 14:42
3

If you need to have some kind of automation, the easiest way is to achieve this outside of TeX or LaTeX. You typically store your tabular data in some external file that you process with an ad-hoc program which writes your dynamical data to one or more auxilary files that you \input in your document.

If you are working on a *NIX system and have some programming skill (even rudimentary), this is very easy to achieve, mostly because TeX input files are plain text files. With AWK or any of your favourite languages, you can do most of the work in a few minutes, so you can decently ask somebody to help you if you cannot do it yourself.

If you are working on another system, the same approach is probably possible, but you may first need to install an interpreter or a compiler for your favourite language.

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.