12

If I have a numerical equation (i.e. no unknowns) in LaTeX, is it possible to have the equation typeset and evaluated in one go?

equation showing expanded and calculated forms

I know calculations can be done relatively easily by embedding Lua code using LuaTeX, but this requires re-writing the equation. A solution would also have to cope with very small and large numbers, so I believe this is outside the scope of normal TeX.

It just seems silly to define a formula in LaTeX and then have to write it again in a linear format in order to compute its value.

Thanks in advance.

14

As the two nice answers of @marmot and @Mico did not at all address the main query (to code only once and get both the typesetting and the value) (see the answer by @JosephWright), I feel at liberty to add one more answer not addressing the request, but doing the computation with xfp.

(but see update at bottom for a \printandeval)

\documentclass{article}
\usepackage[fleqn]{amsmath}
\usepackage{xfp}
\usepackage{siunitx}
\begin{document}
\begin{equation*}
  N = \frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}
  =\num[scientific-notation=true,
        round-mode=figures,
        round-precision=4]{\fpeval{19.32*1*10^6*6.023*10^23/197}}
\end{equation*}
\end{document}

enter image description here

I did not know how to instruct \fpeval to output in scientific notation (with a given number of places), but the options of \num came to the rescue.

I will also mention xintexpr (as I authored it) despite the fact that I still have to add math functions to it (only sqrt currently is available). Now, its syntax \xintthefloatexpr...\relax causes issues with the way the siunitx \num parses its argument. One did not get into such problem with \fpeval because \fpeval uses braces. So let's just add one user interface macro to use braces too, and this makes \num happy.

\documentclass{article}
\usepackage[fleqn]{amsmath}
\usepackage{xintexpr}
% make \num of siunitx happy, let xintexpr do the rounding to 4 digits
% of float precision (after having computed with 16 digits of
% precision, per default)
% #1 = final precision for printing, #2 = expression to evaluate
\newcommand\floatround[2]{\xintthefloatexpr [#1]#2\relax}
\usepackage{siunitx}
\begin{document}
\begin{equation*}
  N = \frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}
  =\num{\floatround{4}{19.32*1*10^6*6.023*10^23/197}}
% one can also use ** in place of ^ for powers
\end{equation*}
\end{document}

enter image description here

Finally package numprint has much to recommend to print numbers according to language of document. And its \numprint macro (or \np with package option np) will accept directly the \xintthefloatexpr with no hiding within braces contrarily to \num of siunitx.

\documentclass[english]{article}
\usepackage{babel}
\usepackage[fleqn]{amsmath}
\usepackage{xintexpr}
\usepackage[np, autolanguage]{numprint}
\begin{document}
\begin{equation*}
  N = \frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}
  =\np{\xintthefloatexpr [4] 19.32*1*10^6*6.023*10^23/197\relax}
\end{equation*}
\end{document}

enter image description here


In the simple example considered here one can do like this:

\documentclass[english]{article}
\usepackage{babel}
\usepackage[fleqn]{amsmath}
\usepackage{xintexpr}
\usepackage[np, autolanguage]{numprint}

\newcommand\printandeval[1]{#1=\begingroup
    \def\frac##1##2{(##1)/(##2)}%
    \def\times{*}%
    % etc...
    \edef\x{{\xintthefloatexpr[4]#1\relax}}%
    \expandafter\endgroup\expandafter\np\x
}

% (in the above we need to re-enact standard meaning of things
%  such as \times, before \np does the typesetting of the value,
%  this is the reason for the `\expandafter` chain.

\begin{document}
\begin{equation*}
  N = \printandeval{\frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}}
\end{equation*}
\end{document}

enter image description here

I do not try here to provide a completely general one, but in pratice adding a few more redefinitions will cover many test cases, possibly enough for real life usage.

notice that braces in the input for typesetting did not have to be replaced by parentheses before evaluation (cf 10^{23})

Here is with xfp + siunitx:

\documentclass{article}
\usepackage[fleqn]{amsmath}
\usepackage{xfp}
\usepackage{siunitx}
\newcommand\printandeval[1]{#1=\begingroup
    \def\frac##1##2{(##1)/(##2)}%
    \def\times{*}%
    % etc...
    \edef\x{[scientific-notation=true,
             round-mode=figures,
             round-precision=4]{\fpeval{#1}}}%
    \expandafter\endgroup\expandafter\num\x
}

\begin{document}
\begin{equation*}
  N = \printandeval{\frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}}
\end{equation*}
\end{document}

Same output.

The code above can be slightly more efficient with

\edef\x{\endgroup\noexpand\np{\xintthefloatexpr[4]#1\relax}}% \x

in the numprint+xintexpr case and

\edef\x{\endgroup\num[scientific-notation=true, round-mode=figures, round-precision=4]{\fpeval{#1}}}% \x

in the siunitx+xfp case.

thanks to @egreg for chasing \expandafter's and pointing out \num is \protected and giving me opportunity in this edit to discover new ways to mark-up multi-line code... (I am too much active on github)

  • 1
    I know "thanks" comments are not recommended, but I had to say this is a remarkable response. Thank you and all the others on this thread for working to arrive at this. – O.MS Oct 13 '18 at 10:37
  • @O.MS thanks are welcome... my recommendation is to use xfp, you only need to add \def\sin{sin}, \def\cos{cos}. Brief testing shows that xfp will handle sin 1.57 fine with no need to use parentheses. With xintexpr even if in future it has sin, cos, log, ... parentheses will surely remain mandatory. On the other hand if you want more than 16 digits of precision or computations with big integers, xintexpr know that. – user4686 Oct 13 '18 at 10:48
  • @O.MS if I try \fpeval{sin(pi)} and \fpeval{sin(pi/1)} I get in both cases the same small non-zero value, of the order 2e-16. ( I used \num[scientific-notation=true]{\fpeval{sin(pi)}}, \num[scientific-notation=true]{\fpeval{sin(pi/1)}}). I am not sure why you get two distinct values. As per achieving sin(pi)=0 with xfp, I found in source3.pdf page 196 the comment that sin(8pi) is not quite zero. – user4686 Oct 13 '18 at 12:34
  • To fix this you probably only need to round first to fixed point, \num[scientific-notation=true, round-mode=figures, round-precision=4]{\fpeval{round(sin(pi/1),15)}} first rounds to 15 digits of fixed point precision via xfp services, and then siunitx again rounds but to 4 digits floating point. The result is 0 as expected. – user4686 Oct 13 '18 at 12:35
  • Amazing! it's working really well now, good enough for what I need. I had a quick look and Lua doesn't offer any more precision than using xfp so this is perfect. Once again thanks. – O.MS Oct 13 '18 at 13:05
11

As long as the expression is not too complex, we can use the LaTeX3 FPU to do the work here. I've gone for an approach where the input is 're-written' into the appropriate syntax: one could do that for the Lua-based answers given by others, too.

\documentclass{article}
\usepackage{siunitx,xparse}
\ExplSyntaxOn
\NewDocumentCommand { \printandcalc } { m }
  {
    #1 =
    \group_begin:
      \tl_set:Nn \l_tmpa_tl {#1}
      \cs_set:Npn \frac ##1##2 {##1/(##2)}
      \cs_set:Npn \times { * }
      \cs_set:Npx \__cs_tmp:w ##1 { \token_to_str:N ^ (##1) }
      \char_set_active_eq:NN ^ \__cs_tmp:w
      \tl_set_rescan:Nnx \l_tmpa_tl { \char_set_catcode_active:n { `\^ } }
        { \l_tmpa_tl }
      \tl_set:Nx \l_tmpa_tl { \l_tmpa_tl }
    \exp_args:NNNV \group_end:
    \tl_set:Nn \l_tmpa_tl \l_tmpa_tl
    \num [scientific-notation = true, round-mode = places]
      { \fp_eval:n { \l_tmpa_tl } }
}
\begin{document}
\[
N = \printandcalc{\frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}}
\]
\end{document}
9

Welcome to TeX.SE! There is whole discussion on doing serious computations in LaTeX. My answer is based on this answer and at best a starting point, which shows that it is indeed possible to do something along those lines.

\documentclass{article}
\usepackage[fleqn]{amsmath}
\usepackage{luacode}
% from https://tex.stackexchange.com/a/294465/121799
\def\luaprint#1{\directlua{tex.print(#1)}}
\begin{document}
\begin{equation*}
  N = \frac{6.022\cdot10^{23}}{1.2\cdot10^{19}}
  =\luaprint{(1.932*10^6)*6.022*10^(23)/(197)}
\end{equation*}
\end{document}

enter image description here

Notice also that there are various possibilities to print these numbers in LateX. Unfortunately, I do not know too much on luacode but what I do know is that section 92 of the pgfmanual lists several possibilities to do that in TikZ/pgf.

9

This answer is merely an extension of @marmot's answer. It uses (a) the luacode environment to define a Lua function in a way that allows the use of the % "magic" character and (b) the \num macro of the siunitx package, to prettify the output of the Lua calculations.

It's definitely possible to create a preprocessor-type function that captures and modifies all instances of \frac{...}{...}, \log, \sin, \pi, etc. so that the code can be parsed by Lua. (It has to be at the preprocessor stage, so that TeX will not try to act on \frac, ^, etc.) One very important consideration is that TeX's grouping characters, { and }, will have to be replaced with ( and ). Unless you need to perform lots and lots of formula evaluations in your document, it's almost certainly much quicker to perform the simplifications and adjustments "by hand".

enter image description here

\documentclass{article}
\usepackage{luacode,siunitx}
%% Lua-side code:
\begin{luacode}
function luaprint ( n )
  return tex.sprint ( string.format ( "%.3e" , n ) )
end
\end{luacode}
%% LaTeX-side code:
\def\luaprint#1{\num{\directlua{luaprint(#1)}}}

\begin{document}
\[
N = \frac{19.32\times1\times10^6\times6.023\times10^{23}}{197}
    =\luaprint{(19.32*1*10^6*6.023*10^(23))/197}
\]
\end{document}

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.