pgf add tag
JeT
I have a list of functions I define for multiple graphs along my course

```
%--------- Librairie de fonctions ---------
\tikzset{
	declare function={ 
		ZC(\x,\y)= pow(1+\x,-\y);
		binom(\k,\n,\p)=\n!/(\k!*(\n-\k)!)*\p^\k*(1-\p)^(\n-\k);
		Transfo(\a,\b,\c) = \a+\b+\c;
		Spread(\a,\b,\c,\d,\e,\f)=\a*\d+\b*\e+\c*\f ;
		normcdf(\x,\m,\SIG) = 1/(1 + exp(-0.07056*((\x-\m)/\SIG)^3 - 1.5976*(\x-\m)/\SIG));
		invgauss(\a,\b) = sqrt(-2*ln(\a))*cos(deg(2*pi*\b));
		d1(\x,\y,\KK,\RR,\SIG) = d2(\x,\y,\KK,\RR,\SIG) + (\SIG*(sqrt(\y)));
		d2(\x,\y,\KK,\RR,\SIG) = (ln(\x/\KK)+(\RR-(pow(\SIG,2)/2)*\y))/(\SIG*(sqrt(\y)));
		Nd1(\x,\y,\KK,\RR,\SIG) = normcdf(d1(\x,\y,\KK,\RR,\SIG),0,1);
		Nd2(\x,\y,\KK,\RR,\SIG) = normcdf(d2(\x,\y,\KK,\RR,\SIG),0,1);
		NPd1(\x,\y,\KK,\RR,\SIG) = Nprime(d1(\x,\y,\KK,\RR,\SIG));
		NPd2(\x,\y,\KK,\RR,\SIG) = Nprime(d2(\x,\y,\KK,\RR,\SIG));		
		%... x100 more...
}
```

Since they're already written, why use `PythonTeX` (I thought about this interesting solution for calculations but a bazooka for a simple task) while I could use [mathematical-function-in-pgf-tikz](https://tex.stackexchange.com/questions/105766/using-mathematical-function-in-pgf-tikz) ?

However, I think the use of `\pgfmathparse{int(d1(\x,\y,\KK,\RR,\SIG)/100}\pgfmathresult` is quite heavy, so I must be doing someting wrong.

I could use a `\newcommand` like 
```
\newcommand{\dOne}[5]{\pgfmathparse{int(d1(#1,#3,#2,#4,#5)*100)/100}\pgfmathresult}
``` 
but I lose the ability to name `\d1` my macro. I also believe what I do here is not elegant (d!mn French with elegance issues :))

Hence my question : 

I'd like to have a fluid way of calling the functions and get the result (for a set of parameters) in my text.

```
MWE

\documentclass[tikz]{article}

%--------- Librairie de fonctions ---------
\tikzset{
	declare function={ 
		ZC(\x,\y)= pow(1+\x,-\y);
		binom(\k,\n,\p)=\n!/(\k!*(\n-\k)!)*\p^\k*(1-\p)^(\n-\k);
		Transfo(\a,\b,\c) = \a+\b+\c; %<- not pretty
		Spread(\a,\b,\c,\d,\e,\f)=\a*\d+\b*\e+\c*\f ; %<-hum hum too
		normcdf(\x,\m,\SIG) = 1/(1 + exp(-0.07056*((\x-\m)/\SIG)^3 - 1.5976*(\x-\m)/\SIG));
		invgauss(\a,\b) = sqrt(-2*ln(\a))*cos(deg(2*pi*\b));
		d1(\x,\y,\KK,\RR,\SIG) = d2(\x,\y,\KK,\RR,\SIG) + (\SIG*(sqrt(\y)));
		d2(\x,\y,\KK,\RR,\SIG) = (ln(\x/\KK)+(\RR-(pow(\SIG,2)/2)*\y))/(\SIG*(sqrt(\y)));
		Nd1(\x,\y,\KK,\RR,\SIG) = normcdf(d1(\x,\y,\KK,\RR,\SIG),0,1);
		Nd2(\x,\y,\KK,\RR,\SIG) = normcdf(d2(\x,\y,\KK,\RR,\SIG),0,1);
		NPd1(\x,\y,\KK,\RR,\SIG) = Nprime(d1(\x,\y,\KK,\RR,\SIG));
		NPd2(\x,\y,\KK,\RR,\SIG) = Nprime(d2(\x,\y,\KK,\RR,\SIG));		
		%... x100 more...
}


\newcommand{\dOne}[5]{\pgfmathparse{int(d1(#1,#3,#2,#4,#5)*100)/100}\pgfmathresult}

\begin{document}

\dOne{100}{100}{1}{0}{0.25}  result prints ok

\dOne{100}{100}{1}{0}{0.50}  result prints ok

\dOne{100}{100}{1}{0}{0.75}  result prints ok

\dOne{100}{100}{1}{0}{1.00}  result prints ok

\end{document}
```

![TAPgfCalulations.png](/image?hash=2eb0b9671c60f7cac4b98cb0ba2429ae0f6eff69656c81f00a13f3f753e9aadf)

NB : I don't mention here the roundings of the results. I know it's a limitation.

Top Answer
marmot
This is slight variation of [Rmano's nice answer](https://topanswers.xyz/tex?q=1557#a1809), merely for fun. I was wondering whether it is possible to steer the keys of `siunitx` with pgf keys. It is possible, but unless I am missing something basic one has to be a bit careful. (There are definitely improvements possible.) The command created here is `\Formula`, which takes one mandatory argument, the function that is to be parsed. And then there are options, which simultaneously allow one to steer `siunitx` stuff and pgf options. One can add `siunitx` keys with `si+={...}`. It does support things like `\Formula[si+={round-precision=4,math-rm=\mathtt}]{binom(1,2,3)}` which contain formatting macros like `\mathtt`. This works by copying the token mechanism of pgf keys. The parsed results also get remembered because sometimes one uses random numbers at some stage, and the subsequent results depend on the value of the random number. For instance, `StoredResult(2)` yields the result of the next-to-last computation. As usual, the rationale of using pgf keys here is to make the macro upgradable without losing backward compatibility.
```
\documentclass{article}
\usepackage[fleqn]{amsmath}% just for operatorname
\usepackage{tikz}
\usetikzlibrary{fpu}
\usepackage{siunitx}
\tikzset{
	declare function={ 
		ZC(\x,\y)= pow(1+\x,-\y);
		binom(\k,\n,\p)=\n!/(\k!*(\n-\k)!)*\p^\k*(1-\p)^(\n-\k);
}}
\makeatletter
\newcounter{Formula@Stored@Results}
\pgfmathdeclarefunction*{StoredResult}{1}{%
\pgfmathifisint{#1}{\begingroup
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathtruncatemacro{\pgfutil@tempi}{\number\value{Formula@Stored@Results}}%
\pgfmathtruncatemacro{\pgfutil@tempj}{\pgfutil@tempi-#1}%
\ifnum\pgfutil@tempj<1\relax
\typeout{Sorry, you wanted to retrieve the \pgfutil@tempi-#1th result, but only positive numbers are allowed.}
\edef\pgfmathresult{0}%
\else
\edef\pgfmathresult{\csname Formula@Stored@Results@\pgfutil@tempj\endcsname}%
\fi
\pgfmathsmuggle\pgfmathresult\endgroup}{\typeout{Sorry, StoredResult only accepts integer results.}}}
\newcommand{\Formula}[2][]{%
  \begingroup
    \stepcounter{Formula@Stored@Results}%
	\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
  	\pgfkeys{/Formula/.cd,#1}%
	\pgfkeysgetvalue{/Formula/sikeys}{\pgfutil@tempb}%
	\pgfkeys@temptoks\expandafter\expandafter\expandafter{\csname pgfk@/Formula/sikeys\endcsname}%
  	\edef\pgfutil@tempa{\noexpand\sisetup{\the\pgfkeys@temptoks}}%
  	\pgfutil@tempa
    \pgfmathparse{#2}%
	\expandafter\xdef\csname Formula@Stored@Results@\number\value{Formula@Stored@Results}\endcsname{\pgfmathresult}%
	\if@Formula@has@units
	  \SI{\pgfmathresult}{\@Formula@units}%
	\else
      \num{\pgfmathresult}%
	\fi
  \endgroup	
}
\newif\if@Formula@has@units
\@Formula@has@unitsfalse
\pgfkeys{/Formula/.cd,has units/.is if=@Formula@has@units,
units/.code={\@Formula@has@unitstrue
\def\@Formula@units{#1}%
},sikeys/.initial={round-mode=figures,round-precision=2},
si+/.style={/Formula/sikeys/.append={,#1}}}
\makeatother
\begin{document}
We know that
\[\operatorname{binom}(1,2,3)=\Formula{binom(1,2,3)}\]
and that
\[Z_C= \Formula[units=\meter\squared]{ZC(3,3)}\;.\]
We can add digits, e.g.\
\[\operatorname{binom}(1,2,3)=\Formula[si+={round-precision=4,math-rm=\mathtt}]{binom(1,2,3)}\;,\]
and add other \texttt{siunitx} keys on the spot. BTW, the unitless next-to-last
result was \Formula{StoredResult(2)}.
\end{document}
```
![Screen Shot 2020-12-17 at 5.11.27 PM.png](/image?hash=782864fc748b821f2fa2d37afaa21b57d4c8125660ebd1231c229b9df00dab6c)
Answer #2
Rmano
I use the `declare function` a lot for my texts for students (especially exams, in order to easily create variants). The precision and range of the calculation is often a problem, so that I have to pre-scale units (forget about going with 46e-6 or things like that); having the same fuctionality in `l3fp` would be great). But alas, it's still very handy!

What I use normally is to get help by the `siunitx` package for formatting and printing. I have in my preamble:

```latex
\newcommand{\formula}[1]{%
    \pgfmathsetmacro{\rpval}{#1}%
    \num[round-mode=figures, round-precision=4]{\rpval}
}
\newcommand{\SIformula}[2]{%
    \pgfmathsetmacro{\rpval}{#1}%
    \SI[round-mode=figures, round-precision=4]{\rpval}{#2}%
}
```

and then in my text I can use 

```latex
blah blah glub is \formula{binom(1,2,3)} and 
quack \SIformula{ZC(3,3)}{\meter\squared} quack!
````

obviously you can pass additional parameters to control formats for printing, if needed. These macro are not expandable, but well --- they do work in most cases.

Answer #3
Diaa
If you don't mind externalization using a powerful computational engine, you might go with [SageMath](https://www.sagemath.org) using [sagetext](https://doc.sagemath.org/html/en/tutorial/sagetex.html).

![image.png](/image?hash=812130bac0f97c009edcfe8803c749a1ecd74906badc7f9b3c15eb525a1c6ce6)

```
% https://tex.stackexchange.com/a/578648/2288
\documentclass{article}
\usepackage{sagetex,siunitx,mathtools}
\parindent0pt
\begin{document}
	\begin{sagesilent}
		from sage.calculus.calculus import at
		f(x) = exp(x)*sin(2*x)
		out = r"%f"%(n(diff(f(x),x,2).subs(x=2)))
		out1 = r"%4.2f"%(n(diff(f(x),x,2).subs(x=2))) 
		out2 = r"%f"%(n(diff(f(x),x,2).subs(x=2),digits=5))
		dfx2 = r"\SI[round-mode=places, round-precision=3]{%f}{\kilo\metre}"%(n(diff(f(x),x,2).subs(x=2)))
	\end{sagesilent}
	
	The second derivative of $f$ is
	\[
	\frac{\mathrm{d}^{2}}{\mathrm{d}x^{2}} \sage{f(x)} =
	\sage{diff(f, x, 2)(x)}.
	\]
	Here's a plot of $f$ from $-1$ to $1$:
    
	\begin{center}
		\sageplot[width=0.7\linewidth]{plot(f, -1, 1)}
	\end{center}
    
	Evaluating the derivatives at $x=2$ can be done in different ways
	
	\begin{align}
		&\frac{d}{dx}\sage{f(x)} = \sage{diff(f(x), x)}\\
		&\sage{diff(f(x), x)} \text{ at } (x=1) \\
		&= \sage{diff(f(x),x).subs(x=2)} = \sagestr{dfx2}\\
		&\text{or}\\
		&\sage{at(diff(f(x),x),x=2).n(digits=3)}
	\end{align}
	\sagestr{out}\\
	\sagestr{out1}\\ 
	\sagestr{out2}
\end{document}
```
---
# sagetex with arara

For automating the build process, you better use the following arara rule (if you are working on Windows) posted in this answer https://tex.stackexchange.com/a/521688/2288 after making `sagetex.sty` of SageMath [known to your latex distribution](https://doc.sagemath.org/html/en/tutorial/sagetex.html#sec-sagetex-install).

```
!config
# SageTeX-Rule for arara.
#
# Dear Windows-users, please check the paths
# pathToBashExecutive    and    pathToSageStartfile
# due to your Sage-installation!
identifier: sagetex
name: SageTeX
authors:
- TeXnician (Author)
- cis (Idea)
arguments: []
commands:
- name: A SageTeX Rule for arara
  command: >
    @{
        pathToBashExecutive = "C:\\Program Files\\SageMath 9.2\\runtime\\bin\\bash";
        pathToSageStartfile = "C:/Program Files/SageMath 9.2/runtime/opt/sagemath-9.2/sage";
        pathOfCurrentWorkingFolder = currentFile().getParent();
        theWindowsCommand = getCommand(pathToBashExecutive, "-l", pathToSageStartfile, "-c", "os.chdir(r'" + pathOfCurrentWorkingFolder + "'); load('" + getBasename(currentFile()) + ".sagetex.sage')");
        return isWindows(theWindowsCommand, getCommand("sage", getBasename(reference) + ".sagetex.sage"));
       }
```

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.