5

I would like to know how to check properly for evenness or oddness within some macro. I have played a little with fp and pgfmath package, but it seems I am not keen enough in TeX to do it properly. Here is a sample example where I try to check evenness of 2 parameters:

\documentclass{article}
\usepackage{tikz}

\def\IfEven#1{\pgfmathparse{int(mod(#1,2))}\ifnum\pgfmathresult=0}
\newcommand{\parity}[2]{%                                                                             
  \def\x{#1}%                                                                                         
  \def\y{#2}%                                                                                         
  \IfEven{\x}%                                                                                        
    \IfEven{\y}%                                                                                        
      {\x} and {\y} are even.%                                                                            
    \else%                                                                                              
      {\x} is even and {\y} is odd.%                                                                      
    \fi%                                                                                                
  \else%                                                                                              
    \IfEven{\y}%                                                                                        
      {\x} is odd and {\y} is even.%                                                                      
    \else%                                                                                              
      {\x} and {\y} are odd.%                                                                             
    \fi%                                                                                                
  %% If I put a second \fi here I got an error 'Extra \fi.', otherwise                                
  %% it compiles and works fine but there are two warnings:                                           
  %% (\end occurred when \ifnum on line 28 was incomplete)                                            
  %% (\end occurred when \ifnum on line 26 was incomplete)                                            
}

\begin{document}
\parity{0}{7}\\
\parity{3}{3}\\
\parity{2}{6}\\
\parity{1}{4}\\
\end{document}

I do understand that I should write a second \fi (but it does not compile). Otherwise, it compiles, displays what I was expecting, but I do not feel comfortable at all with the warnings... and I guess the more I will be using this macro, the more I will have warnings.

So If you have any suggestions...

  • TeX comes with a conditional for testing oddness \ifodd, so I think it would be simpler to use that. \ifodd\y odd code\else even code\fi. – Nicola Talbot Jun 23 '16 at 13:54
  • I followed your suggestion. If I remove the {} around the tests and add the second \fi, it works fine. Thanks ! However I can't help thinking that I have not understood why the previous approach does not work. – Jacques-Olivier Lachaud Jun 23 '16 at 14:13
  • It's probably something to do with the \ifnum being hidden in the code that isn't executed. I think the problem is similar to that in Do all \if's need to be defined before a nested if? – Nicola Talbot Jun 23 '16 at 15:14
2

When conditional text is skipped over, TeX still keeps track of \if..., \else and \fi.

When you call \parity{1}{0}, the first \IfEven is expanded, leaving \ifnum in the input stream. Since the conditional returns false, the inner \IfEven is not expanded and the first \else is matched to \ifnum.

There is an old trick for this, using \if. The trick is ascribed to the Grand Wizard himself.

\documentclass{article}
\usepackage{tikz}

\def\IsEven#1{%
  TT\fi
  \pgfmathparse{int(mod(#1,2))}%
  \ifnum\pgfmathresult=0
}
\newcommand{\parity}[2]{%
  \if\IsEven{#1}%
    \if\IsEven{#2}%
      #1 and #2 are even.%
    \else%
      #1 is even and #2 is odd.%
    \fi
  \else
    \if\IsEven{#2}%
      #1 is odd and #2 is even.%
    \else
      #1 and #2 are odd.%
    \fi
  \fi
}

\begin{document}

\parity{0}{7}

\parity{3}{3}

\parity{2}{6}

\parity{1}{4}

\end{document}

This way there is always a conditional to make the correct balance. When it is in non-skipped over text, \if triggers expansion of \IsEven which will leave

\if TT\fi
<code>
\ifnum...

and the conditionals will be balanced again. The \if TT\fi part expands to nothing.

enter image description here

  • Just to clarify the \if TT\fitrick : you need two tokens and arbitrarily chose "T" ? – Christoph Frings Jun 23 '16 at 18:52
  • @ChristophFrings Yes, it's immaterial what you choose; they just need to be two unexpandable tokens. – egreg Jun 23 '16 at 19:32
2

don't do

\def\IfEven#1{\pgfmathparse{int(mod(#1,2))}\ifnum\pgfmathresult=0}

as such a syntax leaves trailing \else and \fi not matched by a tex-primitive \if.

Either use \if syntax or use argument syntax

\pgfmathparse{int(mod(#1,2))}%
\ifnum\pgfmathresult=0
yes
\else
no
\fi

or

\def\IfEven#1#2#3{\pgfmathparse{int(mod(#1,2))}\ifnum\pgfmathresult=0 %need this space!
 #2%
 \else
 #3%
 \fi}

then

\IfEven{\x}{yes}{no}

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.