Math & ScienceNested macro expansion for math calculation

Information and discussion about LaTeX's math and science related features (e.g. formulas, graphs).
Post Reply
dappergreet
Posts: 2
Joined: Thu Feb 25, 2021 12:20 pm

Nested macro expansion for math calculation

Post by dappergreet »

Hello!

I am trying to learn more about macros and expansion rules in LaTeX, by writing some nested macros to do various math operations.

Here is a small code snippet:

Code: Select all

\documentclass{article}
\usepackage{xfp}

\def\getx(#1,#2,#3){#1}
\def\gety(#1,#2,#3){#2}
\def\getz(#1,#2,#3){#3}

% Vector operations
\def\vsub(#1)(#2){(\fpeval{\getx(#1)-\getx(#2)},\fpeval{\gety(#1)-\gety(#2)},\fpeval{\getz(#1)-\getz(#2)})}
\def\vdot(#1)(#2){\fpeval{\getx(#1)*\getx(#2)+\gety(#1)*\gety(#2)+\getz(#1)*\getz(#2)}}

% #1 = ray origin (point), #2 = ray dir (vect), #3 = sphere center (point), #4 = radius
\def\hitspherediscriminant(#1)(#2)(#3)#4{%
    \edef\v{\fpeval{\vsub(#1)(#3)}}%
    \edef\a{\fpeval{\vdot(#2)(#2)}}%
    \edef\b{\fpeval{2.0 * \expandafter\vdot\v(#2)}}%
    \edef\c{\fpeval{\vdot(#1)(#1) - #4*#4}}%
    \edef\discriminant{\fpeval{\b*\b - 4.0*\a*\c}}%
    \discriminant
}

\begin{document}
    % Works fine
    \def\res{\hitspherediscriminant(0,0,0)(1,0.5,0)(0,0.5,0)2}%
    \res \\
    % PROBLEM HERE during expansion
    %\edef\res{\hitspherediscriminant(0,0,0)(1,0.5,0)(0,0.5,0)2}%
    %\res \\
\end{document}
My problem is when I want to use the result of the hitspherediscriminant macro in another macro, as you can see I tried using \edef instead of \def but I am getting a (not very helpful) error message:

Code: Select all

! Undefined control sequence.
\GenericError  ...                                
                                                    #4  \errhelp \@err@     ...
l.26 ...herediscriminant(0,0,0)(1,0.5,0)(0,0.5,0)2
I understand my way to use macro in a very function-like point of view might be a bad idea. How would one work around this in LaTeX?

Thanks in advance for any tips around macros, and debugging them. ;)

Recommended reading 2024:

LaTeXguide.org • LaTeX-Cookbook.net • TikZ.org

NEW: TikZ book now 40% off at Amazon.com for a short time.

kaiserkarl13
Posts: 707
Joined: Tue Mar 25, 2008 5:02 pm

Nested macro expansion for math calculation

Post by kaiserkarl13 »

I get a slightly different error message, but the problem is the same: [cmd]\edef[/cmd] expands its argument, but it doesn't actually do anything with it, so TeX gets confused. [cmd]\def[/cmd] doesn't expand the macro [cmd]\hitspherediscriminant[/cmd] until [doc]\res[/doc] is expanded, meaning the [doc]\edef[/doc] macros inside it get expanded at that time.

You can get around this problem by using [doc]\noexpand[/doc] inside the [doc]\edef[/doc], but why would you do so is the question you should then be asking.

I think the following would also break for largely the same reasons:

Code: Select all

\edef\mytoc{\tableofcontents}
This happens because you can't execute [cmd]\tableofcontents[/cmd] at the point where the definition is made. You can, however, omit the "e" or replace [cmd]\edef[/cmd] with [cmd]\let[/cmd] and it will work just fine.
dappergreet
Posts: 2
Joined: Thu Feb 25, 2021 12:20 pm

Nested macro expansion for math calculation

Post by dappergreet »

kaiserkarl13 wrote:[cmd]\def[/cmd] doesn't expand the macro [cmd]\hitspherediscriminant[/cmd] until [doc]\res[/doc] is expanded, meaning the [doc]\edef[/doc] macros inside it get expanded at that time.
Yes I see, isn't there a way to force the expansion inside the \edef\hitspherediscriminant because it should have everything to expand all the way down to a single number?
kaiserkarl13 wrote:You can get around this problem by using [doc]\noexpand[/doc] inside the [doc]\edef[/doc], but why would you do so is the question you should then be asking.
Isn't this the same as using a \def then?

Basically, I am trying to use a \edef because I want to re-use the result later either in other macros, or for example in a \ifnum:

Code: Select all

\ifnum\res<0 negative \else positive\fi
Which outputs an error if I use the \def version of \res:

Code: Select all

! Missing number, treated as zero.
<to be read again> 
                   \edef 
l.36     \ifnum\res
                   <0 negative \else positive\fi
Thanks for your help!
Post Reply