0

Note: this question is very similar to this one, but differs since I am using float values instead of int.

I am auto-generating a LaTeX table with a python script which contains times in decimal hour form which are always multiples of 15 minutes, so possible values are 0.25, 0.50, 0.75, 1.00, 1.25, ...

In LaTeX, I would like to automatically calculate the sum of these values. It would be easy to calculate the sum in the script that generates the file, but it is necessary that the sum is correct even if the tex is manually edited.

The current approach which works looks like this:

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{tabularx}
\usepackage{pgf}
\usepackage{pgfplots}
\pgfkeys{/pgf/fpu}
\pgfkeys{
    /pgf/number format/precision=2,
    /pgf/number format/fixed=true,
    /pgf/number format/fixed zerofill=true,
    /pgf/number format/assume math mode=true,
    /pgf/number format/use comma=true
}
\newcommand{\minutestohours}[1]{
    \pgfmathparse{#1/60}\pgfmathprintnumber{\pgfmathresult}
}
\newcounter{totalminutes}
\newcommand{\addtime}[1]{
    \addtocounter{totalminutes}{#1}
    \minutestohours{#1}
}
\begin{document}

\begin{tabularx}{.5\textwidth}{XX} 1 & \addtime{60} \ \hline 2 & \addtime{90} \ \hline 3 & \addtime{195} \ \hline 4 & \addtime{255} \ \hline 5 & \addtime{45} \ \hline 6 & \addtime{180} \ \hline 7 & \addtime{105} \ \hline 8 & \addtime{30} \ \hline 9 & \addtime{240} \ \hline 10 & \addtime{30} \ \hline 11 & \addtime{195} \ \hline 12 & \addtime{90} \ \hline 13 & \addtime{225} \ \hline \end{tabularx}

\vspace*{5mm}

Sum: \minutestohours{\thetotalminutes}

\end{document}

This generates a document that looks like this which is the desired result:

example

Note that the sum has the correct value of 29. The problem with this is that I do not want to feed the times as minutes, but rather in the decimal hour form in which they are printed. I tried to calculate the minutes with pgfmath and store the result in the counter totalminutes, which can be found in the snippet below, but the end result will then be 0.22 (which is 13/60).

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{tabularx}
\usepackage{pgf}
\usepackage{pgfplots}
\pgfkeys{/pgf/fpu}
\pgfkeys{
    /pgf/number format/precision=2,
    /pgf/number format/fixed=true,
    /pgf/number format/fixed zerofill=true,
    /pgf/number format/assume math mode=true,
    /pgf/number format/use comma=true
}
\newcommand{\minutestohours}[1]{
    \pgfmathparse{#1/60}\pgfmathprintnumber{\pgfmathresult}
}
\newcounter{totalminutes}
\newcommand{\addtime}[1]{
    \pgfmathparse{#1}
    \pgfmathprintnumber{\pgfmathresult}
    \pgfmathparse{int(#1*60)}
    \pgfmathtruncatemacro{\minutes}{\pgfmathresult}
    \addtocounter{totalminutes}{\minutes}
}
\begin{document}

\begin{tabularx}{.5\textwidth}{XX} 1 & \addtime{1.00} \ \hline 2 & \addtime{1.50} \ \hline 3 & \addtime{3.25} \ \hline 4 & \addtime{4.25} \ \hline 5 & \addtime{0.75} \ \hline 6 & \addtime{3.00} \ \hline 7 & \addtime{1.75} \ \hline 8 & \addtime{0.50} \ \hline 9 & \addtime{4.00} \ \hline 10 & \addtime{0.50} \ \hline 11 & \addtime{3.25} \ \hline 12 & \addtime{1.50} \ \hline 13 & \addtime{3.75} \ \hline \end{tabularx}

\vspace*{5mm}

Sum: \minutestohours{\thetotalminutes}

\end{document}

I also tried to not use a counter at all, but rather store the result directly via pgfmath, which is in the snippet below, but this will yield a sum of 87 (which is 29*3).

\documentclass[12pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[ngerman]{babel}
\usepackage{tabularx}
\usepackage{pgf}
\usepackage{pgfplots}
\pgfkeys{/pgf/fpu}
\pgfkeys{
    /pgf/number format/precision=2,
    /pgf/number format/fixed=true,
    /pgf/number format/fixed zerofill=true,
    /pgf/number format/assume math mode=true,
    /pgf/number format/use comma=true
}
\newcommand{\minutestohours}[1]{
    \pgfmathparse{#1/60}\pgfmathprintnumber{\pgfmathresult}
}
\pgfmathsetmacro{\totalminutes}{0}
\newcommand{\addtime}[1]{
    \pgfmathparse{#1}
    \pgfmathprintnumber{\pgfmathresult}
    \pgfmathparse{\totalminutes+int(#1*60)}
    \pgfmathsetmacro{\totalminutes}{\pgfmathresult}
    \xdef\totalminutes{\totalminutes}
}
\begin{document}

\begin{tabularx}{.5\textwidth}{XX} 1 & \addtime{1.00} \ \hline 2 & \addtime{1.50} \ \hline 3 & \addtime{3.25} \ \hline 4 & \addtime{4.25} \ \hline 5 & \addtime{0.75} \ \hline 6 & \addtime{3.00} \ \hline 7 & \addtime{1.75} \ \hline 8 & \addtime{0.50} \ \hline 9 & \addtime{4.00} \ \hline 10 & \addtime{0.50} \ \hline 11 & \addtime{3.25} \ \hline 12 & \addtime{1.50} \ \hline 13 & \addtime{3.75} \ \hline \end{tabularx}

\vspace*{5mm}

Sum: \minutestohours{\totalminutes}

\end{document}

So, how can I define \addtime so that the end result is correct? It doesn't matter if the running sum is stored in minutes (int) or hours (float), as long as the input of \addtime is given in hours.

1 Answers1

3

The following uses a number of packages to provide an automated solution for this.

The collcell package is used to collect the numbers, xfp is used to sum them, siunitx is used to output them. And array is used to stick the pieces together.

The result is the special "column" specification \summed. It accepts an optional argument (options for the siunitx output), and two mandatory ones (the macro name in which the sum is stored, and the real column type you want to use).

\documentclass[]{article}

\usepackage{array} \usepackage{collcell} \usepackage{tabularx} \usepackage{xfp} \usepackage[output-decimal-marker={,}]{siunitx}

\makeatletter \newcolumntype\summed{} \expandafter\renewcommand\expandafter\csname NC@rewrite@\string\summed\endcsname[3][] {% \gdef#2{0}% @temptokena\expandafter {% \the@temptokena >{\collectcell{\summed@col#2{#1}}}#3<{\endcollectcell}% }% \NC@find } \newcommand\summed@col[3]{\xdef#1{\fpeval{#1+#3}}\tablenum[{#2}]{#3}} \makeatother

\begin{document} \begin{tabularx}{.5\textwidth}{X\summed[table-format=1.2]\mysum{X}} 1 & 1.00 \ \hline 2 & 1.50 \ \hline 3 & 3.25 \ \hline 4 & 4.25 \ \hline 5 & 0.75 \ \hline 6 & 3.00 \ \hline 7 & 1.75 \ \hline 8 & 0.50 \ \hline 9 & 4.00 \ \hline 10 & 0.50 \ \hline 11 & 3.25 \ \hline 12 & 1.50 \ \hline 13 & 3.75 \ \hline \end{tabularx}

\bigskip

Sum: \mysum \end{document}

enter image description here

Skillmon
  • 60,462
  • Thanks. Is it possible to adapt this solution so one can include a table header and empty rows? – lug_wrench Dec 13 '21 at 11:32
  • 1
    Sure, place \multicolumn{1}{<column>}{<stuff>} in the cells you don't want to be considered. – Skillmon Dec 13 '21 at 12:29
  • I made this process a bit more convenient by defining \newcommand{\nosum}[1]{\multicolumn{1}{c|}{#1}} and got the sum to be printed in the desired way by writing \num[round-integer-to-decimal=true,round-mode=places,round-precision=2]{\mysum} – lug_wrench Dec 13 '21 at 14:57