17

After experimenting and researching for hours, I still cannot figure out how to perform a simple equality test between two numbers.

More specifically, here, the two numbers in question are the argument to my \abc command (#1) and my \test variable.

This is what I've come up with, but it doesn't produce the expected result:

\documentclass{article}

\begin{document}
\def\test{0.5}

\newcommand{\abc}[1]{
\ifnum #1=\test
  Something % do something
\fi}

\abc{0.5} % does something
\abc{0.7} % does nothing

\end{document}

Please help me with this one.

16

\ifnum can be used to compare numbers, but only if the latter are integers. However, you can use \ifdim to compare fixed-point number. Note that you need to specify some unit (such as pt), though.

You probably want a more general command like the one I've defined below (\equalitytest), which compares the values of two arbitrary fixed-point numbers. You can always define your \abc command based on my \equalitytest command.

\documentclass{article}

\setlength{\parindent}{0pt}

\newcommand\equalitytest[2]
{%
    Is #1\ equal to #2?
    \ifdim#1pt=#2pt
        Equal.\\
    \else%
        Not equal.\\
    \fi%
}

\begin{document} 
\equalitytest{0.5}{0.5}
\equalitytest{0.7}{.8}

\def\test{0.5}
\newcommand\abc[1]
{%
    \equalitytest{#1}{\test}
}
\abc{0.9}
\end{document}

enter image description here


Edit: Direct answer to Pygmalion's post:

\documentclass{article}

\begin{document}
\def\test{0.5}

\newcommand{\abc}[1]{
\ifdim#1 pt=\test pt
  Something % do something
\fi}

\abc{0.5} % does something
\abc{0.7} % does nothing

\end{document}
  • I must commend you for your effort, but the final version of your answer just does not respond to my question, which was comparing a parameter of the function (#1) to a global value (\test). In fact, the answer to my question is as simple (\ifdim\test pt=#1 pt) as I was dumb not to find it myself. I suggest you edit your answer in a way that responds to my question (not deleting \equality test) and I'll accept it. – Pygmalion Sep 6 '13 at 13:14
  • @Pygmalion You can commend me all you want, but I accept commands from nobody :) – jub0bs Sep 6 '13 at 13:16
  • I recommend \newcommand*\equalitytest[2]{\ifnum#1pt=#2pt \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi} which can be used as \equalitytest{<f1>}{<f2>}{<true>}{<false>}. (Though, there are many packages that provide such macros.) – Qrrbrbirlbel Sep 6 '13 at 17:01
  • @Qrrbrbirlbel I like this solution. And I don't like to load the whole package of 200 lines for just two lines – Pygmalion Sep 6 '13 at 17:39
8

Jubobs answer shows, how TeX dimensions can be used to compare fixed point numbers. There are two limitations:

  • The largest TeX dimension is \maxdimen = 16383.99998pt = 16384pt - 1sp. TeX will complain with ! Dimension too large, if larger values are tried.
  • The smallest TeX dimension is 1sp = 2-16pt ≈ 0.00001525878906pt.

As jfbu pointed out in the comment, the largest unit in does not give an higher precision for the fractional part than the standard unit pt because of the rounding of the fractional part to multiples of 2-16 ≈ 0.000015258789 due to TeX's scanning of the number.

The other extreme is unit sp that ignores the fractional part. But the number can go up to 230-1 = 1073741824.

Package fp

Package fp implements macro based fixed point arithmetic. From its readme:

Fixed point arithmetic for TeX with numbers ranging from
   -999999999999999999.999999999999999999
to
   +999999999999999999.999999999999999999

The following example implements the comparison of fixed point numbers using package fp:

\documentclass{article}

\usepackage{fp-basic}
\makeatletter
% \equalnumsthenelse{<number A>}{<number B>}{<then: A=B>}{<else: A≠B>}
\newcommand*{\equalnumsthenelse}[2]{%
  \FPifeq{#1}{#2}%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\makeatother

\begin{document}
\def\test{0.5}

\newcommand*{\abc}[1]{
  \equalnumsthenelse{#1}{\test}{%
    \[#1=\test\]%
  }{%
    \[#1\ne\test\]%
  }%
}

\abc{0.5}
\abc{0.7}
\abc{0.500000000001}
\abc{1234567890}

\end{document}

Result

In opposite to a simple \ifdim, this method is not expandable because of \FPifeq.

  • It is false that using in brings the maximal precision for the fraction part. In fact the fractional part, independently of the unit, is rounded to an integer multiple of 1/65536. cf tex.stackexchange.com/a/338510/4686 – user4686 Jun 17 '17 at 21:02
6

An alternative to be considered is l3fp, included in expl3.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewExpandableDocumentCommand{\fpcompare}{ m m m }
 {
  % #1 = test to perform
  % #2 = text for the true case
  % #3 = text for the false case
  \fp_compare:nTF { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff

\newcommand\test{0.5}
\newcommand{\abc}[1]{%
  \fpcompare{#1=\test}{Something}{}%
}

\begin{document}
\verb|\abc{0.5}|: X\abc{0.5}X

\verb|\abc{0.7}|: X\abc{0.7}X

\verb|\abc{0.500000000001}|: X\abc{0.500000000001}X

\verb|\abc{1234567890}|: X\abc{1234567890}X

\edef\TEST{\fpcompare{0.5 = 0.5}{Equal}{Different}}\texttt{\meaning\TEST}\\
\TEST

\edef\TEST{\fpcompare{0.7 = .8}{Equal}{Different}}\texttt{\meaning\TEST}\\
\TEST

\fpcompare{3.141529653 = 355/113}{Equal}{Different}

\fpcompare{3.141529653 != 355/113}{Different}{Equal}

\fpcompare{2.718281828459045 = 2718.281828459045/1000}{Equal}{Different}

\end{document}

One can test for equality with <fp1> = <fp2>, strict inequality with <fp1> < <fp2> or <fp1> > <fp2>, non strict inequality with <fp1> <= <fp2> or <fp1> >= <fp2>, inequality with <fp1> != <fp2>.

In the example code, I show that the test is fully expandable. Consult interface3.pdf, part XXI for more information about the syntax of <fp> and size limitations.

enter image description here

4

To compare arbitrarily big decimal rational numbers (for example 3.141592 versus 2.1782817828) you could use package xintfrac.

Particularly since 1.09a (2013/09/24) it provides \xintifEq{A}{B}{<do this if A=B>}{<do that if A\neq B>}.

Here A and B may be (big) integers, decimal numbers (with scientific part), or fractions, or macros expanding to such things.

\documentclass{article}
\usepackage{xintfrac}

\newcommand*\equalitytest[2]{%
    \xintifEq{#1}{#2}{#1 is equal to #2}{#1 is unequal to #2}%
}%

\begin{document}

\equalitytest{3.141529653}{355/113}

\equalitytest{2.718281828459045}{2718.281828459045/1000}

\end{document}

enter image description here


original answer (before addition of \xintifEq to xintfrac)

\xintCmp{A}{B} returns -1, 0, or 1 if A<B, A=B, A>B. A and B may be decimal numbers, or fractions, or macros expanding to such things.

And \xintSgnFork{\x}{I}{II}{III} does I if \x expands to -1, II if 0, and III if 1.

\documentclass{article}
\usepackage{xintfrac}

% arguments may be decimal numbers such as 3.14
% or fractions such as 355/113

% this is an expandable command
% (its arguments may be macros expanding to the numbers or fractions)

\newcommand*\equalitytest[2]{%
    \xintSgnFork{\xintiAbs{\xintCmp{#1}{#2}}}% -1 converted into 1
    {}% -1: does not happen
    {equal}%   \xintCmp returned 0
    {unequal}% \xintCmp returned -1 or 1.
}%

\begin{document}

\equalitytest{3.141529653}{355/113} (355/113=\xintTrunc{10}{355/113}...) %unequal

\equalitytest{2.718281828459045}{2718.281828459045/1000} % equal


\end{document}

comparison

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.