# Floating point calculations in LaTeX?

I am looking for a method to do minimal floating point / integer calculations in LaTeX, not for the purpose of package writing, but for the production of actual text.

Here is an example to illustrate. Given the following input text

 The experiment included running a battery of \bind{T}{21} tests
on \bind{S}{13} subjects, for a total of \bind{V}{T*S} expected values.
However, since \bind{F}{37} values were defective, our successful
measurement rate per subject was \use{100*round((V-F)/T,2)}\%


it would be nice if was converted to:

 The experiment included running a battery of $21$ tests
on $13$ subjects, for a total of $273$ expected values.
However, since $37$ values were defective, our successful
measurement rate per subject was $86$\%.


Where \bind{C}{expression} defines a new constant C whose value is expression, and returns C, while \use{C} simply returns the value of C. Any tips?

I am aware of the spreadtab package and this question: this question, but I am looking for something more.

-
I smell a singleton pattern... –  Matthew Leingang Apr 11 '11 at 11:40
Maybe the answers to this very related question can help you. –  diabonas Apr 11 '11 at 12:00

If you don't mind using luatex, then you could just let lua do the calculations. I use ConTeXt, but I believe that the luacode package in LaTeX provides similar functionality.

\startusercode
round = global.math.round
\stopusercode

\def\bind#1#2%
{\usercode{#1 = #2}\use{#1}}

\def\use#1%
{\usercode{global.context(#1)}}

\starttext
The experiment included running a battery of \bind{T}{21.0} tests
on \bind{S}{13} subjects, for a total of \bind{V}{T*S} expected values.
However, since \bind{F}{37} values were defective, our successful
measurement rate per subject was \use{100*round((V-F)/T,2)}\%
\stoptext


I am using usercode rather luacode so that my definitions (T=21 etc) do not pollute the global namespace.

EDIT: If you want the result to be in math mode, change global.context(...) to global.context.math(...) in the definition of \use

-
+1 for usercode. –  Khaled Hosny Apr 11 '11 at 13:15
Thumbs up for sticking to the simple, non backslash syntax. –  Yossi Gil Apr 12 '11 at 4:33

I have been extensively using the fp for this type of work. Here is a minimal for some functions, that can convert temperature units from one system to another. There are a lot of examples on this site that use the fp package. The code uses the siunitx package for formatting as well.

For example to translate degrees F to C you type \Ftoc{32.999}. Here is a minimal example.

\documentclass{article}
\usepackage{fp}
\usepackage{siunitx}
\gdef\numdec{3}

\begin{document}
%\SetConversion{C}{K}{273.15}
\FPround\result{\result}{2}%
\sisetup{%
fixed-exponent = 2,
scientific-notation = false}
\num{\result}}

%% Convert Centigrate to Fahreneit
\def\CtoF#1{\FPdiv\resulta{9}{5}%
\FPmul\resultb{\resulta}{#1}%
\FPround\resultc{\resultc}{3}%
\num{\resultc}%
\sisetup{%
fixed-exponent = 0,
scientific-notation = false}
}

\def\FtoC#1{\FPdiv\resulta{5}{9}%
\FPsub\resultb{#1}{32}%
\FPmul\resultc{\resultb}{\resulta}%
\FPround\resultc{\resultc}{\numdec}%
\sisetup{%
fixed-exponent = 0,
scientific-notation = false}
\num{\resultc}%
}

%% Convert Fahreneit to Rankine
\def\FtoRa#1{\FPmul\result{#1}{9}%
\FPdiv\result{\result}{5}%
\FPround\result{\result}{\numdec}%
\result%
}

%% Convert Kelvin to Rankine
\FPround\result{\result}{\numdec}\result}

%% Convert Rankine to Celcius
\def\RtoC#1{\FPsub\result{#1}{459.67}% to fahreneit
\FtoC{\result}}

\FtoC{32.999}

\end{document}

-

Another package to do floating point computations is l3fp. This package does not (yet) allow users to define new variables (but it supports pi, for instance, so in principle it shouldn't be too hard to extend it to support user-defined variables). A workaround is to go through the expression and replace all variables T, V, etc. by an internal variable \l__my_T_fp, \l__my_V_fp, etc., which holds the corresponding value.

This is done by the looping macro \__my_use:N, which reads one character at a time. If it is the end-marker \q_recursion_tail, then we reached the end of the expression, so exit the loop by skipping to \q_recursion_stop (done by \quark_if_recursion_tail_stop:n). If the variable \l__my_#1_fp is defined, then use it, otherwise leave the character itself for the l3fp functions to receive. Then recurse by calling \__my_use:N again.

The \my_set:nn function makes sure that \l__my_#1_fp is defined thanks to \fp_zero_new:c, then it sets its value.

\documentclass{article}
\usepackage{expl3, xparse}
\ExplSyntaxOn
\cs_new:Npn \__my_use:N #1
{
\quark_if_recursion_tail_stop:n {#1}
\cs_if_exist_use:cF { l__my_#1_fp } {#1}
\__my_use:N
}
\cs_new:Npn \my_use:n #1
{ \fp_eval:n { \__my_use:N #1 \q_recursion_tail \q_recursion_stop } }
\cs_new_protected:Npn \my_set:nn #1#2
{
\fp_zero_new:c { l__my_#1_fp }
\fp_set:cn { l__my_#1_fp } { \my_use:n {#2} }
}
\NewDocumentCommand {\bind} { m m } { \my_set:nn {#1} {#2} \my_use:n {#1} }
\NewDocumentCommand {\use} { m } { \my_use:n {#1} }
\ExplSyntaxOff
\begin{document}
The experiment included running a battery of \bind{T}{21} tests
on \bind{S}{13} subjects, for a total of \bind{V}{T*S} expected values.
However, since \bind{F}{37} values were defective, our successful
measurement rate per subject was \use{100*round((V-F)/V,2)}\%
\end{document}


I also fixed the last formula, which read (V-F)/T.

-

I would use the math engine of pgf for it.


IMHO using characters only should be possible, but would requires the definition of the characters as PGF constants/functions. I not fully sure if this will work with your original syntax.

-
This will only work in the current scope, right? Perhaps that's a good thing. But I'm worried about cluttering the namespace with all those one-character control sequences. –  Matthew Leingang Apr 11 '11 at 12:46
In particular, you redefine \S in this example. –  Aditya Apr 11 '11 at 13:16
Yes, you need to be careful with the macro names. Added a prefix would be much saver. I just wanted to show the principle. –  Martin Scharrer Apr 11 '11 at 13:22
@Matthew: Yes, this will only be working the current scope. Except if you use \gdef instead of \def. –  Martin Scharrer Apr 11 '11 at 13:23