% Copyright 2019 by Henri Menke
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.


% Guard against reading twice
\ifx\pgfintloaded\pgfutil@undefined
  \let\pgfintloaded=\relax
\else
  \expandafter\endinput
\fi

% This module is pretty much a rip-off of the LaTeX3 l3int module for integer
% calculations.  Since PGF supports e-TeX now, we can make use of those
% extended facilities.

% In contrast to l3int we will just admit that integers are regular TeX \count
% register and will not implement an extra "integer datatype".

% Evaluate an integer expression using \numexpr
\def\pgfinteval#1{\number\numexpr#1\relax}

% Get the absolute value of an integer by stripping off a leading minus sign
\def\pgfintabs#1{\number\expandafter\pgfint@abs\number\numexpr#1\relax}
\def\pgfint@abs#1{\ifx-#1\else\expandafter#1\fi}

% Minimum and maximum
\def\pgfintmax#1#2{%
  \number\expandafter\pgfint@minmax
  \number\numexpr#1\expandafter;%
  \number\numexpr#2;%
  >
}
\def\pgfintmin#1#2{%
  \number\expandafter\pgfint@minmax
  \number\numexpr#1\expandafter;%
  \number\numexpr#2;%
  <
}
\def\pgfint@minmax#1;#2;#3{%
  \ifnum#1#3#2
    #1%
  \else
    #2%
  \fi
}

% \numexpr has the annoying property to round divisions rather than truncating
% (as you would expect for integer arithmetic).  Therefore we need a truncating
% division function.
\def\pgfintdivtruncate#1#2{%
  \number\numexpr\expandafter\pgfint@divtruncate
  \number\numexpr#1\expandafter;%
  \number\numexpr#2;%
  \relax
}
\def\pgfint@divtruncate#1#2;#3#4;{%
  \ifx0#1
    0%
  \else
    (#1#2%
      \ifx-#1 +\else-\fi
      (\ifx-#3 -\fi#3#4-1)/2%
    )%
  \fi
  /#3#4%
}

% \pgfintdivtruncate always truncates the result which leads to a rounding
% towards zero.  Donald Knuth defines in TAoCP, Vol 1, 3rd Ed, Section 1.2.4
% that the modulo operation is
%
%    x mod y = x - y * floor(x/y)
%
% In contrast to truncated division, floored division always rounds towards
% -inf, i.e. floor(1/2) = 0 and floor(-1/2) = -1.  This is also how integer
% division is done in Lua.
\def\pgfintdivfloor#1#2{%
  \number\numexpr\expandafter\pgfint@divfloor
  \number\numexpr#1\expandafter;%
  \number\numexpr#2;%
  \relax
}
\def\pgfint@divfloor#1#2;#3#4;{%
  \ifx0#1
    0%
  \else
    \ifnum
      0\ifx-#1\ifx#3-\else1\fi\fi
      0\ifx-#3\ifx#1-\else1\fi\fi
      >0
      \pgfint@@divfloor#1#2;#3#4;-+%
    \else
      \pgfint@@divfloor#1#2;#3#4;+-%
    \fi
  \fi
  /#3#4%
}
\def\pgfint@@divfloor#1#2;#3#4;#5#6{%
  (#1#2%
  \ifx-#1 #5\else#6\fi
    (\ifx-#3 -\fi#3#4#61)/2%
  )%
}

% Round
\def\pgfintdivround#1#2{\number\numexpr(#1)/(#2)\relax}

% Modulo
\def\pgfintmod#1#2{%
  \number\numexpr\expandafter\pgfint@mod%
  \number\numexpr#1\expandafter;%
  \number\numexpr#2;%
  \relax
}
\def\pgfint@mod#1;#2;{#1-(\pgfint@divfloor#1;#2;)*#2}

% Setter function so we don't always have to write \pgfinteval
\def\pgfintset#1#2{#1 \numexpr#2\relax}

\endinput
