Nested FPifeq : Extra \fi error
You don't need fp
for that. TeX can do integer comparison with \ifnum
. This:
\documentclass{article}
\newcommand\Unit[1]{%
\ifnum#1=1
% nothing
\else
\ifnum#1=-1
-%
\else
#1%
\fi
\fi}
\begin{document}
\Unit{2}x \Unit{1}x \Unit{-1}x
\end{document}
produces 2x x -x
.
If you want to use fp
, then you need to hide the second test in another macro. Apparently fp
doesn't like nested conditionals:
\newcommand\Unit[1]{%
\FPifeq{#1}{1}%
% nothing
\else
\UnitInner{#1}%
\fi}
\newcommand\UnitInner[1]{%
\FPifeq{#1}{-1}%
-%
\else
#1%
\fi}
However, I recommend you use expl3
and it's own FPU. It's much more flexible and allows you to easily compose nested conditionals:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand \Unit { m }
{
\fp_compare:nF { #1 == 1 }
{
\fp_compare:nTF { #1 == -1 }
{ - }
{ #1 }
}
}
\ExplSyntaxOff
\begin{document}
\Unit{2}x \Unit{1}x \Unit{-1}x
\end{document}
The macro \FPifeq
doesn't like to be nested in a conditional, because it is not a conditional. Its structure is basically
- do some comparisons that eventually help to decide whether to execute
\FP@testtrue
or\FP@testfalse
, which make\ifFP@test
equal to either\iftrue
or\iffalse
; - set
\ifFPtest
equal to\ifFP@test
; - release
\ifFPtest
in the input stream.
However, TeX does not recognize \FPifeq
as a conditional, so with your macro
\FPifeq#1{1}{}\else\FPifeq#1{-1}{-}\else#1\fi\fi
the following happens
when
#1
is1
, then\ifFPtest
is\iftrue
, and we end up with\iftrue{}\else\FPifeq#1{-1}{-}\else#1\fi\fi
Now
{}
will be left in the input stream and the\else
will remove everything up to the matching\fi
. Oh, no! Another\fi
remains!when
#1
is not1
, then\ifFPtest
is\iffalse
, and we end up with\iffalse{}\else\FPifeq#1{-1}{-}\else#1\fi\fi
Now everything up to
\else
is removed and we remain with\FPifeq#1{-1}{-}\else#1\fi\fi
but TeX remembers it has removed an
\else
. Then everything will work well, because at the end of the job of\FPifeq
either\iftrue
or\iffalse
will result. The trailing\fi
corresponds to the\else
removed in advance, so it doesn't harm.
There are a few glitches in your code: it should be {#1}
throughout, otherwise a value such as 12
would take 1
as the first argument to \FPifeq
and 2
as the second argument.
You could fix the nesting problem by doing
\newcommand{\FPeq}{TT\fi\FPifeq}
\newcommand\Unit[1]{%
\if\FPeq{#1}{1}%
% do nothing
\else
\if\FPeq{#1}{-1}%
-%
\else
#1%
\fi
\fi
}
This is an old trick that uses \if
to make the problem above vanish; if \if
is expanded, it sees TT\fi
, which results in a true test and \FPifeq
will be executed; if it is in skipped text, it will correctly match a corresponding \else
or \fi
.
However, the usage of \FPifeq
has bad consequences on the final output. Let's see an example:
\documentclass{article}
\usepackage[nomessages]{fp}
\newcommand{\FPeq}{TT\fi\FPifeq}
\newcommand\Unit[1]{%
\if\FPeq{#1}{1}%
% do nothing
\else
\if\FPeq{#1}{-1}%
-%
\else
#1%
\fi
\fi
}
\begin{document}
$\Unit{2}x$ $\Unit{1}x$ $\Unit{-1}x$
$2x$ $x$ $-x$
\end{document}
Can you see the problem? The working of \FPifeq
creates an empty math atom, so the minus sign is treated as a binary operator rather than a unary, if leading the polynomial.
The problem does not show with Phelype Oleinik's code using expl3
.