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

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

2 Answers 2

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}}
1
  • 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, 2012 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}

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.