3

I write an fp macro that calculates the distance between frets on a guitar neck:

\def\ScaleLength{25.5}
\def\ScaleFactor{0.1}

\def\FretDist#1{\FPmul\resulta{-1}{#1}%
\FPdiv\resulta{\resulta}{12}%
\FPpow\resulta{2}{\resulta}%
\FPsub\resulta{1}{\resulta}%
\FPmul\resulta{25.5}{\resulta}
\FPmul\resulta{\resulta}{\ScaleFactor}
\resulta
}

And putting things like

\FretDist{3}

In latex gives the proper floating point value.

When I try to use that value in a package like

\put(3,\FretDist{3}){\circle{3}}

I get an error "Missing number, treated as zero", yet if I do

\put(3,3){\circle{3}}

works fine

Uiy
  • 6,132
  • 1
    Please consider assembling your code snippets in a "Minimum Working Example" (MWE) of LaTeX code. – Mico Mar 15 '12 at 23:09

2 Answers2

4

You can use xfp, that works expandably and allows a neater syntax for the operations. The number of decimal digits is not the same as provided by fp, but it shouldn't matter for most applications (including this one).

\documentclass{article}
\usepackage{pict2e}

\usepackage{fp} % for the old method \usepackage{xfp} % for the new method

\newcommand\ScaleLength{25.5} \newcommand\ScaleFactor{0.1}

\newcommand\FretDist[1]{\FPmul\resulta{-1}{#1}% \FPdiv\resulta{\resulta}{12}% \FPpow\resulta{2}{\resulta}% \FPsub\resulta{1}{\resulta}% \FPmul\resulta{\ScaleLength}{\resulta} \FPmul\resulta{\resulta}{\ScaleFactor} \resulta }

\newcommand{\xFretDist}[1]{% \fpeval{ \ScaleLength\ScaleFactor(1-exp(-(#1/12)*ln(2))) } }

\begin{document}

\FretDist{9}

\xFretDist{9}

\FretDist{3} % now \resulta contains the value

\xFretDist{3}

\bigskip

\fbox{\begin{picture}(10,10) \put(3,\resulta){\circle{3}} \end{picture}}

\fbox{\begin{picture}(10,10) \put(3,\xFretDist{3}){\circle{3}} \end{picture}}

\end{document}

As you can see, the pictures are the same.

enter image description here

Old answer

You can't use \FretDist{3} as argument to \put, because this commands expects a number and not a whole set of instructions to print it. Change the definition of \FretDist as follows

\def\FretDist#1{\FPmul\resulta{-1}{#1}%
\FPdiv\resulta{\resulta}{12}%
\FPpow\resulta{2}{\resulta}%
\FPsub\resulta{1}{\resulta}%
\FPmul\resulta{25.5}{\resulta}
\FPmul\resulta{\resulta}{\ScaleFactor}
}

so that, after calling it, you'll have \resulta available for usage as a number:

\FretDist{3} % store the number in \resulta
\put(3,\resulta){\circle{3}}
egreg
  • 1,121,712
  • This works but takes more work when you are looping over a variable. Counters and dimensions cannot be used as arguments for fretdist so I had to use one of fp's registers which means I had to add code to treat it like a counter. – Uiy Mar 15 '12 at 23:23
0

With functional package, tricky argument expansion can be replaced by intuitive function composition, which is similar to other programmming languages such as Lua. The evaluation of composite functions is from inside to outside.

\documentclass{article}

\usepackage{pict2e} \usepackage{functional}

\def\ScaleLength{25.5} \def\ScaleFactor{0.1}

\PrgNewFunction \FretDist {m} {% \FpEval{(1-2^(((-1)(#1))/12))\ScaleLength*\ScaleFactor}% }

\PrgNewFunction \FunPut {mmm} {\put(#1,#2){#3}}

\begin{document}

\FretDist{3}

\begin{picture}(40,30) \put(3,0.405714141103028){\circle{3}} \end{picture}

\begin{picture}(40,30) \FunPut{3}{\FretDist{3}}{\circle{3}} \end{picture}

\end{document}

L.J.R.
  • 10,932