Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

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

4 Answers 4

up vote 9 down vote accepted

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

share|improve this answer
    
+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

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.

share|improve this answer

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}
\def\CtoK#1{\FPadd\result{#1}{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}%
\FPadd\resultc{\resultb}{32}%
\FPround\resultc{\resultc}{3}%
 \num{\resultc}%
\sisetup{%
fixed-exponent = 0,
scientific-notation = false}
}

%% Convert Fahreneit to Centigrade
\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
\def\KtoRa#1{\FPadd\result{#1}{459.67}%
\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}
share|improve this answer

I would use the math engine of pgf for it.

It would be much simpler if you would use macro names instead, e.g. \T instead of T. Then \bind could be defined as \newcommand\bind[2]{\expandafter\def\csname#1\endcsname{#2}#1} and \use would be \newcommand\use[1]{\pgfmathparse{#1}\pgfmathresult}. You would need to write \use{100*round((\V-\F)/\T,2)} then.

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.

share|improve this answer
1  
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
1  
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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