7

Can the following MWE be reduced by creating a command that can accept a formula then print and evaluate it without the need to write it twice in two different forms for both evaluating and printing as shown below?

\documentclass[border=5mm]{standalone}
\usepackage{pgf,mathtools,siunitx}

\begin{document}

\newcommand{\toprint}{\frac{-4+\sqrt{4^2-4*1*3}}{2}}
\newcommand{\toevaluate}{(-4+sqrt(4^2-4*1*3))/2}

\pgfmathparse{\toevaluate}

The first root is evaluated by $x_1 = \toprint =  \SI{\pgfmathresult}{\cm} $

\end{document}

enter image description here

9

AFAIK there is no such function available but I may be wrong. You could write your own parser that locally redefines the macros that print stuff to macros that wraps stuff in the respective functions. In the code below, I do that for \frac and \sqrt. This works in this case, also because you were kind enough to explicitly spell out multiplications and even used * for them. Clearly, this "parser" is fragile, but if you really feel it is worthwhile you may add other functions like \sin and so on.

\documentclass[border=5mm]{standalone}
\usepackage{pgf,mathtools,siunitx}

\begin{document}

\newcommand{\toprint}{\frac{-4+\sqrt{4^2-4*1*3}}{2}}
%\newcommand{\toevaluate}{(-4+sqrt(4^2-4*1*3))/2}
\newcommand{\DiaaParse}[1]{\begingroup\def\frac##1##2{((##1)/(##2))}%
\def\sqrt##1{sqrt(##1)}%
\edef\ret{#1}%
\pgfmathparse{\ret}\pgfmathprintnumber{\pgfmathresult}%
\endgroup}

%\pgfmathparse{\toevaluate}

The first root is evaluated by $x_1 = \toprint =  \DiaaParse{\toprint}$

\end{document}

enter image description here

This version does not work with \SI, also because I didn't understand where the units cm come from, but this could be changed.

If you want the parser just to parse and to store the result in \pgfmathresult, you could use

\documentclass[border=5mm]{standalone}
\usepackage{pgf,mathtools,siunitx}

\begin{document}

\newcommand{\toprint}{\frac{-4+\sqrt{4^2-4\times1\times 3}}{2}}
\newcommand{\DiaaParse}[1]{\begingroup\def\frac##1##2{((##1)/(##2))}%
\def\sqrt##1{sqrt(##1)}%
\def\cdot{*}%
\def\times{*}%
\def\exp##1{exp(##1)}%
\def\log##1{log(##1)}%
\def\ln##1{ln(##1)}%
\def\arcsin##1{asin(##1)}%
\def\cot##1{cot(##1)}%
\def\sin##1{sin(##1)}%
\def\sinh##1{sinh(##1)}%
\def\arccos##1{acos(##1)}%
\def\cot##1{cot(##1)}%
\def\cos##1{cos(##1)}%
\def\arctan##1{atan(##1)}%
\def\cot##1{cot(##1)}%
\def\tan##1{tan(##1)}%
\def\tanh##1{tanh(##1)}%
\def\arccot##1{acot(##1)}%
\def\cot##1{cot(##1)}%
\def\cot##1{cot(##1)}%
\edef\ret{#1}%
\pgfmathparse{\ret}%
\pgfmathsmuggle\pgfmathresult%
\endgroup}


The first root is evaluated by $x_1 = \toprint =\DiaaParse{\toprint}
\SI{\pgfmathresult}{\cm}$

\end{document}

enter image description here

As you see, this does work with \SI and so on, simply because it wraps the additional parsing around \pgfmathparse. This also defines the replacement rules for other commands, but I stress it is fragile. Please note that this requires a rather recent version of pgf (3.1.1 or higher, I think) which has \pgfmathsmuggle in it. For older versions, you have to use other smuggling techniques, see the answers of this question for possible ways.

Overall this does something of the sort you are suggesting, but I stress it is fragile. What if a user wants to compute, say, \log_{7} 29? Yes, one could extend the parser to deal with that as well, but this will be more effort. And then the next user wants \sqrt[3]{19}. Also possible, but more efforts. And how about \log_{10} 3\frac{1}{4}, how would the parser know that this is log(13/4)/log(7)? Of course, if you use external programs, you can avoid duplication, e.g. Mathematica has TeXForm to convert the result of some module to not-so-nice but most times working (La)TeX code.

  • Could you please suggest how to deal with the multiplication in the form of \times instead of *? – Diaa May 19 at 1:04
  • 1
    @Diaa You just have to add \def\cdot{*}%, which I added in the second example. – marmot May 19 at 2:51
  • 1
    @Diaa This works the same for times: \def\times{*}%. – marmot May 19 at 3:25
  • 3
    @Diaa I recommend tikzmarmots. It does not produce precisely the same output, but is much more entertaining. ;-) More seriously, I can see that why folks are reluctant to write such a package. It will be (almost) inevitably fragile. So you spend 10 minutes on writing the core functions and 5 month on making it more robust. It is almost trivial to add the functions of section 94.3 Syntax for Mathematical Expressions: Functions of the pgfmanual 3.1.3 to the above parser but very hard to cope with all the ways users may typeset their expressions. – marmot May 19 at 4:14
  • 1
    @Diaa If I would have to guess, then I'd think that the author/maintainer of siunitx will have the best chances of accomplishing this. siunitx does already a lot of related things and its maintainer presumably has a very good idea of what can go wrong. – marmot May 19 at 19:55
2

Some years ago, I had the same problem.

Since writing a robust parser is not a trivial exercise, I decided to not try it in TeX, but use Python (version 3.6 or later) instead.

The result was the TeXcalc module.

The input looks like this:

from texcalc import Calculation

c = Calculation()
c.add('rho_f', '1.62', 'g/cm^3', 'Fiber density')
c.add('rho_r', '1.2', 'g/cm^3', "Resin density")
c.add('v_f', '0.3', '-', 'Fiber volume fraction')
c.add('W_f', '450', 'g/m^2', "Area weight fibers", fmt=".0f")
c.add('t_f', 'W_f/(10000*rho_f)*10', 'mm')
c.add('t', 't_f/v_f', 'mm', "Laminate thickness")
c.add('t_r', 't-t_f', 'mm')
c.add('W_r', 't_f/10*(10000*rho_r)', 'g/m^2', "Area weight resin", fmt=".0f")
print(c)

It outputs an align* environment (from the amsmath package) and uses siunitx to typeset the units. After processing with LaTeX, the output looks like this. TexCalc example


Adapted to the MWE on request

The following are the contents of mwe.py

from texcalc import Calculation

c = Calculation()
c.add('b', 4)
c.add('a', 1)
c.add('c', 3)
c.add('x1', '(-b+sqrt(b**2-4*a*c))/2', 'cm', 'first root')
c.add('x2', '(-b-sqrt(b**2-4*a*c))/2', 'cm', 'second root')
print(c)

Run this as python3 mwe.py > foo.tex

This is mwe.tex:

\documentclass[preview=true]{standalone}
\usepackage{amsmath,siunitx}

\begin{document}
\input{foo.tex}
\end{document}

Run this with pdflatex mwe.tex.

This results in: MWE image

The goal of TeXcalc is to clarify complicated calculations that have multiple steps, as shown in the first example. This to make it easier for others to follow.

So it cannot exactly match your MWE, since it doesn't produce in-line math. Although in this case, you could extract the necessary data from foo.tex.

  • 1
    Your answer looks interesting. Could you please adapt it to my MWE? – Diaa May 19 at 10:18
  • 1
    @Diaa: See updated answer. – Roland Smith May 19 at 17:23

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.