% \iffalse meta-comment
%
% File: siunitx-complex.dtx Copyright (C) 2021-2026 Joseph Wright
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "siunitx bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% The released version of this bundle is available from CTAN.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/josephwright/siunitx
%
% for those people who are interested.
%
% -----------------------------------------------------------------------
%
%<*driver>
\documentclass{l3doc}
% Additional commands needed in this source
\ProvideDocumentCommand\email{m}{\href{mailto:#1}{\nolinkurl{#1}}}
\ProvideDocumentCommand\foreign{m}{\textit{#1}}
% The next line is needed so that \GetFileInfo will be able to pick up
% version data
\usepackage{siunitx}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{siunitx.sty}
%
% \title{^^A
%   \pkg{siunitx-complex} -- Complex numbers^^A
%   \thanks{This file describes \fileversion,
%     last revised \filedate.}^^A
% }
%
% \author{^^A
%  Joseph Wright^^A
%  \thanks{^^A
%    E-mail:
%    \email{joseph@texdev.net}^^A
%   }^^A
% }
%
% \date{Released \filedate}
%
% \maketitle
%
% \begin{documentation}
%
% \section{Formatting complex values}
%
% This submodule is concerned with formatting complex numbers. It augments the
% standard functions \cs{siunitx_number_format:nN} and \cs{siunitx_quantity:nn}
% by allowing parsing of numbers with a complex part. There are no additional
% assumptions concerning \LaTeXe{} commands in the submodule beyond those in the
% core number and unit submodules.
%
% \begin{function}{\siunitx_complex_number:n, \siunitx_complex_number:e}
%   \begin{syntax}
%     \cs{siunitx_complex_number:n} \Arg{number}
%   \end{syntax}
%   Parses the \meta{number} and splits into real and complex parts, which are
%   then formatted as described for \cs{siunitx_number_format:nN}. The results
%   are combined and printed using the standard functions in the module. If
%   the setting |complex-mode| is set to \meta{polar}, the input is
%   parsed, converted to polar form and then passed to
%   \cs{siunitx_complex_number:nn}. This parsing requires that the complex root
%   is given as \texttt{i} at the \emph{end} of the value.
% \end{function}
%
% \begin{function}{\siunitx_complex_number:nn}
%   \begin{syntax}
%     \cs{siunitx_complex_number:nn} \Arg{magnitude} \Arg{angle}
%   \end{syntax}
%   Parses the \meta{magnitude} and \meta{angle} and then formats each as
%   described for \cs{siunitx_number_format:nN}. The two are separated by the
%   angle symbol, which is treated as a numerical part. If
%   |complex-angle-unit| is set to |degrees| then the unit symbol is
%   added: this is printed as a unit in the usual way. If
%   the setting |complex-mode| is set to \meta{cartesian}, the input is
%   parsed, converted to Cartesian form and then passed to
%   \cs{siunitx_complex_number:n}.
% \end{function}
%
% \begin{function}
%   {
%     \siunitx_complex_quantity:nn  ,
%     \siunitx_complex_quantity:en  ,
%     \siunitx_complex_quantity:nnn
%   }
%   \begin{syntax}
%     \cs{siunitx_complex_quantity:nn} \Arg{number} \Arg{units}
%     \cs{siunitx_complex_quantity:nnn} \Arg{magnitude} \Arg{angle} \Arg{units}
%   \end{syntax}
%   These functions treat their numerical argument(s) as described
%   for the corresponding \texttt{number} functions. They then typeset the
%   entire numerical part and the unit as described for
%   \cs{siunitx_quantity:nn}.
% \end{function}
%
% \begin{function}{complex-angle-unit}
%   \begin{syntax}
%     |complex-angle-unit| = |degrees|\verb"|"|radians|
%   \end{syntax}
%   Sets how the unit for polar complex numbers is treated. This setting
%   is used to determine how polar \emph{input} is interpreted, how
%   conversion to polar form works and how output in polar form is typeset.
%   The standard setting is |degrees|.
% \end{function}
%
% \begin{function}{complex-mode}
%   \begin{syntax}
%     |complex-mode| = |cartesian|\verb"|"|input|\verb"|"|polar|
%   \end{syntax}
%   Selects how complex values are formatted: a choice from the options
%   |cartesian|, |input| and |polar|. The option |cartesian| means that
%   complex values will always be typeset in cartesian ($x + y\mathrm{i}$)
%   format, whilst |polar| means that complex are typeset as a magnitude
%   and angle. Finally, |input| setting means that the input format
%   (\foreign{i.e.}~difference between \cs{siunitx_complex_number:n} and
%   \cs{siunitx_complex_number:nn}) is maintained. The standard setting is
%   |input|.
% \end{function}
%
% \begin{function}{complex-phase-command}
%   \begin{syntax}
%     |complex-phase-command| = \meta{cmd}
%   \end{syntax}
%   Sets the command used during output of the phase of a complex number in
%   polar form. The standard setting is |\angle|.
% \end{function}
%
% \begin{function}{complex-root-position}
%   \begin{syntax}
%     |complex-root-position| = |after-number|\verb"|"|before-number|
%   \end{syntax}
%   Choice which determines where the complex root symbol is printed relative
%   to the numbers. The standard setting is |after-number|.
% \end{function}
%
% \begin{function}{complex-symbol-degree}
%   \begin{syntax}
%     |complex-symbol-degree| = \meta{symbol}
%   \end{syntax}
%   Sets the symbol used for polar degrees.
% \end{function}
%
% \begin{function}{input-complex-root}
%   \begin{syntax}
%     |input-complex-root| = \meta{tokens}
%   \end{syntax}
%   The token(s) considered as complexes roots for number parsing.
%   The standard setting is |ij|.
% \end{function}
%
% \begin{function}{output-complex-root}
%   \begin{syntax}
%     |output-complex-root| = \meta{tokens}
%   \end{syntax}
%   The token(s) used to show the complex root in output. The standard setting
%   is |\mathrm{i}|.
% \end{function}
%
% \begin{function}{print-complex-unity}
%   \begin{syntax}
%     |print-complex-unity| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch to determine if the number \num{1} is printed for a complex
%   part which is exactly unity.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% Start the \pkg{DocStrip} guards.
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% \section{\pkg{siunitx-complex} implementation}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_complex>
%    \end{macrocode}
%
% \subsection{General setup}
%
% \begin{variable}{\l_@@_tmp_fp, \l_@@_tmp_tl}
%    \begin{macrocode}
\fp_new:N \l_@@_tmp_fp
\tl_new:N \l_@@_tmp_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_input_tl}
%   The numerical input exactly as given by the user.
%    \begin{macrocode}
\tl_new:N \l_@@_input_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_comparator_tl}
%   A comparator, if found, is held here.
%    \begin{macrocode}
\tl_new:N \l_@@_comparator_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_exp_tl}
%   The exponent part of a parsed number.
%    \begin{macrocode}
\tl_new:N \l_@@_exp_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_real_tl, \l_@@_img_tl}
%   The real and imaginary parts of cartesian form, respectively.
%    \begin{macrocode}
\tl_new:N \l_@@_real_tl
\tl_new:N \l_@@_img_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_mag_tl, \l_@@_angle_tl}
%   The magnitude and angle of polar form, respectively.
%    \begin{macrocode}
\tl_new:N \l_@@_mag_tl
\tl_new:N \l_@@_angle_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_join_tl, \l_@@_sign_tl}
%   Staging posts for a joining and leading sign, respectively.
%    \begin{macrocode}
\tl_new:N \l_@@_join_tl
\tl_new:N \l_@@_sign_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_suppress_negative:, \@@_suppress_non_polar:}
%   Pre-compilation of keys to suppress special treatment of negative values
%   and input not suitable for polar form.
%    \begin{macrocode}
\keys_precompile:nnN
  { siunitx }
  {
    bracket-negative-numbers = false ,
    negative-color           =
  }
  \l_@@_tmp_tl
\cs_new_protected:Npe \@@_suppress_negative:
  { \exp_not:V \l_@@_tmp_tl }
\keys_precompile:nnN
  { siunitx }
  {
    input-comparators       = ,
    input-exponent-markers  = ,
    input-open-uncertainty  = ,
    input-close-uncertainty =
  }
  \l_@@_tmp_tl
\cs_new_protected:Npe \@@_suppress_non_polar:
  { \exp_not:V \l_@@_tmp_tl }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}
%   {
%     \l_@@_root_after_bool      ,
%     \l_@@_force_cartesian_bool ,
%     \l_@@_force_polar_bool     ,
%     \l_@@_phase_tl             ,
%     \l_@@_polar_degree_bool    ,
%     \l_@@_symbol_degree_tl     ,
%     \l_@@_input_root_tl        ,
%     \l_@@_output_root_tl
%   }
%    \begin{macrocode}
\bool_new:N \l_@@_root_after_bool
\bool_new:N \l_@@_force_cartesian_bool
\bool_new:N \l_@@_force_polar_bool
\bool_new:N \l_@@_polar_degree_bool
\keys_define:nn { siunitx }
  {
    complex-mode .choice: ,
    complex-mode / cartesian .code:n =
      {
        \bool_set_true:N \l_@@_force_cartesian_bool
        \bool_set_false:N \l_@@_force_polar_bool
      } ,
    complex-mode / polar .code:n =
      {
        \bool_set_false:N \l_@@_force_cartesian_bool
        \bool_set_true:N \l_@@_force_polar_bool
      } ,
    complex-mode / input .code:n =
      {
        \bool_set_false:N \l_@@_force_cartesian_bool
        \bool_set_false:N \l_@@_force_polar_bool
      } ,
    complex-angle-unit .choice: ,
    complex-angle-unit / degrees .code:n =
      { \bool_set_true:N \l_@@_polar_degree_bool } ,
    complex-angle-unit / radians .code:n =
      { \bool_set_false:N \l_@@_polar_degree_bool } ,
    complex-phase-command .tl_set:N =
      \l_@@_phase_tl ,
    complex-root-position .choice: ,
    complex-root-position / after-number .code:n =
      { \bool_set_true:N \l_@@_root_after_bool } ,
    complex-root-position / before-number .code:n =
      { \bool_set_false:N \l_@@_root_after_bool } ,
    complex-symbol-degree .tl_set:N =
      \l_@@_symbol_degree_tl ,
    input-complex-root .tl_set:N =
      \l_@@_input_root_tl ,
    output-complex-root .tl_set:N =
      \l_@@_output_root_tl ,
    print-complex-unity .bool_set:N =
      \l_@@_print_unity_bool
  }
%    \end{macrocode}
% \end{variable}
%
% \subsection{Parsing}
%
% \begin{macro}{\@@_expand:nN}
%   A small auxiliary to expand input and replace symbols: we need to do this
%   quite early so it is separated out. The storage is hard-coded as this is
%   low-level stuff.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_expand:n #1
  {
    \protected@edef \l_@@_arg_tl {#1}
    \tl_set_eq:NN \l_@@_input_tl \l_@@_arg_tl
    \siunitx_number_normalize_symbols:N \l_@@_arg_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse:n, \@@_parse:V}
% \begin{macro}{\@@_parse_clear:}
%   Parsing for complex numbers needs some of the same approaches as the
%   general parser. However, as the aim here is to do only enough to split
%   the real and imaginary parts before handing off the usual code,
%   it's not a full repeat. Instead, we shortcut where we can. The |clear|
%   function here is not only there to make this function shorter: it
%   also allows a single way to zap any stored data if a parse error occurs.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse:n #1  
  {
    \@@_parse_clear:
    \tl_if_empty:NF \l_@@_arg_tl
      { \@@_parse_comparator: }
    \@@_parse_check:
  }
\cs_generate_variant:Nn \@@_parse:n { V }
\cs_new_protected:Npn \@@_parse_clear:
  {
    \tl_clear:N \l_@@_real_tl
    \tl_clear:N \l_@@_img_tl
    \tl_clear:N \l_@@_exp_tl
    \tl_clear:N \l_@@_sign_tl
    \tl_clear:N \l_@@_join_tl
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_check:}
% \begin{macro}{\@@_parse_check:N}
%   Now we tidy up and do the main work: passing to the standard formatter for
%   final parsing.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_check:
  {
    \tl_if_empty:NTF \l_@@_img_tl
      { \@@_parse_check:N \l_@@_real_tl }
      {
        \tl_if_empty:NTF \l_@@_real_tl
          { \@@_parse_check:N \l_@@_img_tl }
          {
            \@@_parse_check:N \l_@@_real_tl
            \tl_set_eq:NN \l_@@_sign_tl \l_@@_join_tl
            \@@_parse_check:N \l_@@_img_tl
          }
      }
  }
\cs_new_protected:Npn \@@_parse_check:N #1
  {
    \tl_set:Ne #1
      {
        \exp_not:V \l_@@_comparator_tl
        \exp_not:V \l_@@_sign_tl
        \exp_not:V #1
        \exp_not:V \l_@@_exp_tl
      }
    \tl_clear:N \l_@@_comparator_tl
    \tl_clear:N \l_@@_sign_tl
    \siunitx_number_parse:VN #1 #1
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_comparator:}
% \begin{macro}{\@@_parse_comparator_aux:Nw}
%   The first step is to extract any comparator: this is the same as
%   for a full number parse.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_comparator:
  {
    \exp_after:wN \@@_parse_comparator_aux:Nw
      \l_@@_arg_tl \q_stop
  }
\cs_new_protected:Npn \@@_parse_comparator_aux:Nw #1#2 \q_stop
  {
    \tl_if_in:NnTF \l_siunitx_number_input_comparator_tl {#1}
      {
        \tl_set:Nn \l_@@_comparator_tl {#1}
        \tl_set:Nn \l_@@_arg_tl {#2}
      }
      { \tl_clear:N \l_@@_comparator_tl }
    \tl_if_empty:NF \l_@@_arg_tl
      { \@@_parse_sign: }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_exponent:}
% \begin{macro}{\@@_parse_exponent_auxi:w}
% \begin{macro}{\@@_parse_exponent_auxii:nn}
%   An exponent part of a number has to come at the end and can only occur
%   once. Thus it is relatively easy to parse. The code here is a simplified
%   version of that in \pkg{siunitx-number}: we only need to find \emph{some}
%   exponent, not check on the detail. Notice that we need to retain the
%   exponent marker here: that is done using the short-lived temporary
%   variable.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_exponent:
  {
    \tl_if_empty:NTF \l_siunitx_number_input_exponent_tl
      { \@@_parse_root: }
      {
        \tl_set:Ne \l_@@_tmp_tl
          { \tl_head:V \l_siunitx_number_input_exponent_tl }
        \tl_map_inline:Nn \l_siunitx_number_input_exponent_tl
          {
            \tl_replace_all:NnV \l_@@_arg_tl
              {##1} \l_@@_tmp_tl
          }
        \use:e
          {
            \cs_set_protected:Npn
              \exp_not:N \@@_parse_exponent_auxi:w
              ##1 \exp_not:V \l_@@_tmp_tl
              ##2 \exp_not:V \l_@@_tmp_tl
              ##3 \exp_not:N \q_stop
          }
            { \@@_parse_exponent_auxii:nn {##1} {##2} }
        \use:e
          {
            \@@_parse_exponent_auxi:w
              \exp_not:V \l_@@_arg_tl
              \exp_not:V \l_@@_tmp_tl \exp_not:N \q_nil
              \exp_not:V \l_@@_tmp_tl \exp_not:N \q_stop
          }
      }
  }
\cs_new_protected:Npn \@@_parse_exponent_auxi:w  { }
\cs_new_protected:Npn \@@_parse_exponent_auxii:nn #1#2
  {
    \quark_if_nil:nF {#2}
      {
        \tl_set:Nn \l_@@_arg_tl {#1}
        \tl_set:Ne \l_@@_exp_tl
          { \exp_not:V \l_@@_tmp_tl \exp_not:n {#2} }
      }
    \@@_parse_root:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_root:}
% \begin{macro}{\@@_parse_root_auxi:w}
% \begin{macro}{\@@_parse_root_auxii:nnnN}
%   Splitting at the complex root is much like splitting the exponent.
%   After dealing with the case where there is no complex root allowed,
%   use the first possible symbol to do the work.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_root:
  {
    \tl_if_empty:NTF \l_@@_input_root_tl
      { \tl_set_eq:NN \l_@@_real_tl \l_@@_arg_tl }
      {
        \tl_set:Ne \l_@@_tmp_tl
          { \tl_head:V \l_@@_input_root_tl }
        \tl_map_inline:Nn \l_@@_input_root_tl
          {
            \tl_replace_all:NnV \l_@@_arg_tl
              {##1} \l_@@_tmp_tl
          }
        \use:e
          {
            \cs_set_protected:Npe
              \exp_not:N \@@_parse_root_auxi:w
              ##1 \exp_not:V \l_@@_tmp_tl
              ##2 \exp_not:V \l_@@_tmp_tl
              ##3 \exp_not:N \q_stop
          }
            {
              \@@_parse_root_auxii:nnnN {##1} {##2} {##3}
                \exp_not:V \l_@@_tmp_tl
            }
        \use:e
          {
            \@@_parse_root_auxi:w
              \exp_not:V \l_@@_arg_tl
              \exp_not:V \l_@@_tmp_tl \exp_not:N \q_nil
              \exp_not:V \l_@@_tmp_tl \exp_not:N \q_stop
          }
      }
  }
\cs_new_protected:Npn \@@_parse_root_auxi:w  { }
%    \end{macrocode}
%   This is where the business end lies. We have five possibilities:
%   \begin{itemize}
%     \item There was no complex root at all: |#2| will be |\q_nil|
%     \item More than one complex root sign was present: |#3| will not
%       be equal to |\q_nil i|.
%     \item All of the number is in the complex part with a leading
%       root: |#1| will be empty. This includes the case where
%       the input was \emph{just} a root symbol (plus possibly sign,
%       exponent): we need to cover that.
%     \item All of the number was before the complex root: |#2| will
%       be empty and we need to check |#1| fully to split out the two
%       parts
%     \item The input has a real part with the complex part starting
%       with the root symbol: just the last token needs to be separated.
%   \end{itemize}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_root_auxii:nnnN #1#2#3#4
  {
    \quark_if_nil:nTF {#2}
      { \tl_set:Nn \l_@@_real_tl {#1} }
      {
        \str_if_eq:nnTF {#3} { \q_nil #4 }
          {
            \tl_set:Nn \l_@@_img_tl {#2}
            \tl_if_blank:nTF {#1}
              {
                \tl_if_blank:nT {#2}
                  { \tl_set:Nn \l_@@_img_tl { 1 } }
              }
              {
                \tl_if_blank:nTF {#2}
                  { \@@_parse_split:n {#1} }
                  { \@@_parse_sign_check:n {#1} }
              }
          }
          {
            \msg_error:nnV { siunitx } { duplicate-complex-root }
              \l_@@_input_tl
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_sign:}
% \begin{macro}{\@@_parse_sign_aux:Nw}
%   The first token of a number after a comparator could be a sign. A quick
%   check is made and if found stored. There is no need to worry about the
%   nature of the sign: we keep them regardless.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_sign:
  {
    \exp_after:wN \@@_parse_sign_aux:Nw
      \l_@@_arg_tl \q_stop
  }
\cs_new_protected:Npn \@@_parse_sign_aux:Nw #1#2 \q_stop
  {
    \tl_if_in:NnT \l_siunitx_number_input_sign_tl {#1}
      {
        \tl_set:Nn \l_@@_sign_tl {#1}
        \tl_set:Nn \l_@@_arg_tl {#2}
      }
    \tl_if_empty:NF \l_@@_arg_tl
      { \@@_parse_exponent: }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_sign_check:n}
% \begin{macro}{\@@_parse_sign_check:nN}
% \begin{macro}{\@@_parse_sign_check:nNw}
%   Here, we want to check that the last token in the input is a sign.
%   There cannot be anything after the sign, and there has to be at one
%   token before the sign: we can therefore signal a parsing error if we
%   need to.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_sign_check:n #1
  {
    \@@_parse_sign_check:nN { } #1 \q_recursion_tail \q_recursion_stop
  }
\cs_new_protected:Npn \@@_parse_sign_check:nN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      { \@@_parse_clear: }
    \tl_if_in:NnTF \l_siunitx_number_input_sign_tl {#2}
      { \@@_parse_sign_check:nNw {#1} #2 }
      { \@@_parse_sign_check:nN {#1#2} }
  }
\cs_new_protected:Npn \@@_parse_sign_check:nNw
  #1#2 #3 \q_recursion_tail \q_recursion_stop
  {
    \tl_if_blank:nTF {#3}
      {
        \tl_if_blank:nTF {#1}
          { \@@_parse_clear: }
          {
            \tl_set:Nn \l_@@_real_tl {#1}
            \tl_set:Nn \l_@@_join_tl {#2}
          }
      }
      { \@@_parse_clear: }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_split:n}
% \begin{macro}{\@@_parse_split:nN}
% \begin{macro}{\@@_parse_split:w}
%   Checking for a sign inside the leading part of the number is a simple loop.
%   There is the possibility that there is no number in the imaginary part
%   needs to be allowed for. Notice that we do a check that there is some
%   real part: this covers for example an original input |++1i|, which
%   otherwise would not be trapped.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_split:n #1
  {
    \@@_parse_split:nN { } #1 \q_recursion_tail \q_recursion_stop
  }
\cs_new_protected:Npn \@@_parse_split:nN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      { \tl_set:Nn \l_@@_img_tl {#1} }
    \tl_if_in:NnTF \l_siunitx_number_input_sign_tl {#2}
      {
        \tl_set:Nn \l_@@_real_tl {#1}
        \tl_set:Nn \l_@@_join_tl {#2}
        \@@_parse_split:w
      }
      { \@@_parse_split:nN {#1#2} }
  }
\cs_new_protected:Npn \@@_parse_split:w #1 \q_recursion_tail \q_recursion_stop
  {
    \tl_set:Ne \l_@@_img_tl
      {
        \tl_if_blank:nTF {#1}
          { 1 }
          { \exp_not:n {#1} }
     }
    \tl_if_empty:NT \l_@@_real_tl
      { \@@_parse_clear: }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_polar:nn}
%   Almost trivial but repeated in a couple of places so worth an auxiliary.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_polar:nn #1#2
  {
    \bool_if:NTF \l_siunitx_number_parse_bool
      { \siunitx_number_parse:nN {#1} \l_@@_mag_tl }
      { \tl_set:Nn \l_@@_mag_tl { \ensuremath {#1} } }
    \group_begin:
      \@@_suppress_non_polar:
      \siunitx_number_format:nN {#2} \l_@@_angle_tl
    \exp_args:NNNV \group_end:
    \tl_set:Nn \l_@@_angle_tl \l_@@_angle_tl
  }
%    \end{macrocode}
% \end{macro}
%
% \section{Formatting}
%
% \begin{variable}{\l_@@_bracket_close_tl, \l_@@_bracket_open_tl}
%   Purely internal for the present.
%    \begin{macrocode}
\tl_new:N \l_@@_bracket_close_tl
\tl_new:N \l_@@_bracket_open_tl
\tl_set:Nn \l_@@_bracket_open_tl { ( }
\tl_set:Nn \l_@@_bracket_close_tl { ) }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_unit_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_unit_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_complex_number:n, \siunitx_complex_number:e}
% \begin{macro}{\siunitx_complex_number:nn, \@@_number:nn}
% \begin{macro}{\siunitx_complex_quantity:nn, \siunitx_complex_quantity:en}
% \begin{macro}{\siunitx_complex_quantity:nnn, \@@_quantity:nnn}
%   The work here is pretty trivial: only conversion between forms makes
%   things a bit more intricate.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_complex_number:n #1
  {
    \bool_if:NTF \l_siunitx_number_parse_bool
      {
        \group_begin:
          \@@_suppress_negative:
          \@@_expand:n {#1}
          \bool_if:NTF \l_@@_force_polar_bool
            {
              \use:e
                {
                  \siunitx_complex_number:nn
                     \@@_convert_polar:V \l_@@_arg_tl
                 }
            }
            {
              \@@_parse:V \l_@@_arg_tl
              \@@_format_cartesian:n { }
            }
        \group_end:
      }
      {
        \siunitx_number_format:nN {#1} \l_@@_tmp_tl
        \siunitx_print_number:V \l_@@_tmp_tl
      }
  }
\cs_generate_variant:Nn \siunitx_complex_number:n { e, x }
\cs_new_protected:Npn \siunitx_complex_number:nn #1#2
  {
    \bool_lazy_or:nnTF
      { \tl_if_blank_p:n {#1} }
      { \tl_if_blank_p:n {#2} }
      {
        \msg_error:nnnn { siunitx } { invalid-polar-form }
          {#1} {#2}
      }
      { \@@_number:nn {#1} {#2} }
  }
\cs_new_protected:Npn \@@_number:nn #1#2
  {
    \bool_lazy_and:nnTF
      { \l_@@_force_cartesian_bool }
      { \l_siunitx_number_parse_bool }
      {
        \siunitx_complex_number:e
          { \@@_convert_cartesian:nn {#1} {#2} }
      }
      {
        \group_begin:
          \@@_suppress_negative:
          \@@_parse_polar:nn {#1} {#2}
          \@@_format_polar:n { }
        \group_end:
      }
  }
\cs_new_protected:Npn \siunitx_complex_quantity:nn #1#2
  {
    \bool_if:NTF \l_siunitx_number_parse_bool
      {
        \group_begin:
          \@@_suppress_negative:
          \@@_expand:n {#1}
          \bool_if:NTF \l_@@_force_polar_bool
            {
              \use:e
                {
                  \siunitx_complex_quantity:nnn
                     \@@_convert_polar:V \l_@@_arg_tl
                 }
            }
            {
              \@@_parse:V \l_@@_arg_tl
              \@@_format_cartesian:n
            }
              {#2}
        \group_end:
      }
      { \siunitx_quantity:nn {#1} {#2} }
  }
\cs_generate_variant:Nn \siunitx_complex_quantity:nn { e , x }
\cs_new_protected:Npn \siunitx_complex_quantity:nnn #1#2#3
  {
    \bool_lazy_or:nnTF
      { \tl_if_blank_p:n {#1} }
      { \tl_if_blank_p:n {#2} }
      {
        \msg_error:nnnn { siunitx } { invalid-polar-form }
          {#1} {#2}
      }
      { \@@_quantity:nnn {#1} {#2} {#3} }
  }
\cs_new_protected:Npn \@@_quantity:nnn #1#2#3
  {
    \bool_lazy_and:nnTF
      { \l_@@_force_cartesian_bool }
      { \l_siunitx_number_parse_bool }
      {
        \siunitx_complex_quantity:en
          { \@@_convert_cartesian:nn {#1} {#2} }
          {#3}
      }
      {
        \group_begin:
          \@@_suppress_negative:
          \@@_parse_polar:nn {#1} {#2}
          \@@_format_polar:n {#3}
        \group_end:
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_cartesian:n}
% \begin{macro}{\@@_format_cartesian_auxi:n}
% \begin{macro}{\@@_format_cartesian_auxii:n}
% \begin{macro}{\@@_drop_exponent:nnnnnnn}
% \begin{macro}{\@@_format_sign:nnnnnnn}
% \begin{macro}{\@@_extract_exponent:nw}
% \begin{macro}{\@@_extract_exponent_aux:w}
% \begin{macro}[EXP]{\@@_format_bracket:n}
%   We start here checking that there is something to do.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_cartesian:n #1
  {
    \bool_lazy_and:nnF
      { \tl_if_empty_p:N \l_@@_real_tl }
      { \tl_if_empty_p:N \l_@@_img_tl }
      { \@@_format_cartesian_auxi:n {#1} }
  }
%    \end{macrocode}
%  We split based on whether the number has a complex part at all,
%  then print the result.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_cartesian_auxi:n #1
  {
    \tl_clear:N \l_@@_tmp_tl
    \tl_if_empty:NTF \l_@@_img_tl
      {
        \siunitx_number_process:NN \l_@@_real_tl \l_@@_real_tl
        \tl_set:Ne \l_@@_tmp_tl
          { \siunitx_number_output:N \l_@@_real_tl }
      }
      { \@@_format_cartesian_auxii:n {#1} }
    \tl_if_blank:nTF {#1}
      { \siunitx_print_number:V \l_@@_tmp_tl }
      { \siunitx_quantity_print:VV \l_@@_tmp_tl \l_@@_unit_tl }
  }
%    \end{macrocode}
%   If we get to this stage we have both parts to a complex number. We
%   need to process both and do some massaging, then it's just a question
%   of reassembly with the right parts in the right places.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_cartesian_auxii:n #1
  {
    \@@_format_cartesian_units:n {#1}
    \tl_if_empty:NF \l_@@_real_tl
      { \exp_after:wN \@@_drop_exponent:nnnnnnn \l_@@_real_tl }
    \exp_after:wN \@@_format_sign:nnnnnnn \l_@@_img_tl
    \tl_set:Ne \l_@@_tmp_tl
      { \siunitx_number_output:NN \l_@@_img_tl \q_nil }
    \exp_after:wN \@@_extract_exponent:w \l_@@_tmp_tl \q_stop
    \tl_set:Ne \l_@@_tmp_tl
      {
        \bool_lazy_or:nnTF
          {
            \bool_lazy_and_p:nn
              { \l_siunitx_number_bracket_ambiguous_bool }
              { ! \tl_if_empty_p:N \l_@@_exp_tl }
          }
          {
            ! \bool_lazy_any_p:n
              {
                { \tl_if_blank_p:n {#1} }
                { \tl_if_empty_p:N \l_@@_real_tl }
                { \tl_if_empty_p:N \l_@@_img_tl }
              }
          }
          { \@@_format_bracket:n }
          { \use:n }
          {
            \siunitx_number_output:N \l_@@_real_tl
            \exp_not:V \l_@@_sign_tl
            \bool_if:NF \l_@@_root_after_bool
              { \exp_not:V \l_@@_output_root_tl }
             \exp_not:V \l_@@_tmp_tl
            \bool_if:NT \l_@@_root_after_bool
              { \exp_not:V \l_@@_output_root_tl }
           }
         \exp_not:V \l_@@_exp_tl
      }
  }
%    \end{macrocode}
%   No exponent for the real part. 
%    \begin{macrocode}
\cs_new_protected:Npn \@@_drop_exponent:nnnnnnn #1#2#3#4#5#6#7
  { \tl_set:Nn \l_@@_real_tl { {#1} {#2} {#3} {#4} {#5} { } { 0 } } }
%    \end{macrocode}
%   Ensure the imaginary part has a sign.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_sign:nnnnnnn #1#2#3#4#5#6#7
  {
    \tl_set:Ne \l_@@_img_tl
      {
        { }
        {
          \tl_if_blank:nTF {#2}
            { \tl_if_empty:NF \l_@@_real_tl { + } }
            { \exp_not:n {#2} }
        }
        \exp_not:n { {#3} {#4} {#5} {#6} {#7} }
      }
  }
%    \end{macrocode}
%   Pull out the formatted exponent: we also need the sign.
%   An imaginary part that is exactly $1$ is omitted, with only the complex
%   root printed. That means checking and removing a lone $1$ here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_extract_exponent:w
  #1 \q_nil #2 \q_nil #3 \q_nil #4 \q_nil #5 \q_nil #6 \q_nil #7 \q_nil #8
  \q_nil #9 \q_stop
  {
    \tl_set:Nn \l_@@_sign_tl {#1#2}
    \bool_lazy_all:nTF
      {
        { ! \l_@@_print_unity_bool }
        { \str_if_eq_p:nn {#3} { 1 } }
        { \tl_if_blank_p:n {#5} }
      }
      { \@@_extract_exponent_aux:nw {#6#7#8} }
      { \@@_extract_exponent_aux:nw {#3#4#5#6#7#8} }
         #9 \q_stop
  }
\cs_new:Npn \@@_extract_exponent_aux:nw
  #1#2 \q_nil #3 \q_nil #4 \q_stop
  {
    \tl_set:Nn \l_@@_tmp_tl {#1#2}
    \tl_set:Nn \l_@@_exp_tl {#3#4}
  }
\cs_new_protected:Npn \@@_format_bracket:n #1
  {
    \exp_not:V \l_@@_bracket_open_tl
    #1
    \exp_not:V \l_@@_bracket_close_tl
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_format_cartesian_units:n}
% \begin{macro}
%   {
%     \@@_format_cartesian_combine-exponent:n ,
%     \@@_format_cartesian_extract-exponent:n ,
%     \@@_format_cartesian_input:n
%   }
% \begin{macro}{\@@_format_combine-exponent:nn}
% \begin{macro}{\@@_format_tidy_exp:}
% \begin{macro}{\@@_format_tidy_exp:nn}
% \begin{macro}{\@@_format_tidy_exp:nN}
% \begin{macro}{\@@_format_tidy_exp:N}
% \begin{macro}[EXP]{\@@_extract_exp:nnnnnnn}
% \begin{macro}{\@@_drop_exp:N}
% \begin{macro}[EXP]{\@@_drop_exp:nnnnnnnN}
%   Formatting units needs to know the settings from the main module, and
%   the flow is then much the same as in \pkg{siunitx-compound}. We only
%   have to watch the fact there are two numbers to format.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_cartesian_units:n #1
  {
    \tl_if_blank:nTF {#1}
      {
        \siunitx_number_process:NN \l_@@_real_tl \l_@@_real_tl
        \siunitx_number_process:NN \l_@@_img_tl \l_@@_img_tl
        \tl_if_empty:NF \l_@@_real_tl
          { \@@_format_cartesian_tidy_exp: }
      }
      {
        \use:c
          { @@_format_cartesian_ \l_siunitx_quantity_prefix_mode_str :n } {#1}
      }
  }
\cs_new_protected:cpn { @@_format_cartesian_combine-exponent:n } #1
  {
    \siunitx_number_process:NN
      \l_@@_img_tl \l_@@_img_tl
    \fp_set:Nn \l_@@_tmp_fp
     {
       \exp_after:wN \@@_extract_exp:nnnnnnn
         \l_@@_img_tl
     }
    \tl_if_empty:NF \l_@@_real_tl
      {
        \siunitx_number_process:NN
          \l_@@_real_tl \l_@@_real_tl
        \@@_format_cartesian_tidy_exp:
        \@@_drop_exp:N \l_@@_real_tl
      }
    \@@_drop_exp:N \l_@@_img_tl
    \siunitx_unit_format_combine_exponent:nnN {#1}
      \l_@@_tmp_fp \l_@@_unit_tl
  }
\cs_new_protected:cpe { @@_format_cartesian_extract-exponent:n } #1
  {
    \exp_not:N \siunitx_unit_format_extract_prefixes:nNN {#1}
      \exp_not:N \l_@@_unit_tl \exp_not:N \l_@@_tmp_fp
    \exp_not:c { @@_format_extract-exponent:N }
      \exp_not:N \l_@@_img_tl
    \exp_not:N \tl_if_empty:NF \exp_not:N \l_@@_real_tl
      {
        \exp_not:c { @@_format_extract-exponent:N }
          \exp_not:N \l_@@_real_tl
      }
  }
\cs_new_protected:Npn \@@_format_cartesian_input:n #1
  {
    \siunitx_number_process:NN \l_@@_real_tl \l_@@_real_tl
    \siunitx_number_process:NN \l_@@_img_tl \l_@@_img_tl
    \tl_if_empty:NF \l_@@_real_tl 
      { \@@_format_cartesian_tidy_exp: }
    \siunitx_unit_format:nN {#1} \l_@@_unit_tl
  }
%    \end{macrocode}
%   Here, as we know this is only going to work if the exponents are integers,
%   we use a faster string comparison for the fire-off.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_cartesian_tidy_exp:
  {
    \exp_args:Nee \@@_format_cartesian_tidy_exp:nn
      {
        \exp_after:wN \@@_extract_exp:nnnnnnn
          \l_@@_real_tl
       }
       {
         \exp_after:wN \@@_extract_exp:nnnnnnn
           \l_@@_img_tl
       }
  }
\cs_new_protected:Npn \@@_format_cartesian_tidy_exp:nn #1#2
  {
    \str_if_eq:nnF {#1} {#2}
      {
        \fp_compare:nNnTF {#1} > {#2}
          {
            \fp_set:Nn \l_@@_tmp_fp {#1}
            \@@_format_cartesian_tidy_exp:nN
              {#1} \l_@@_img_tl
          }
          {
            \@@_format_cartesian_tidy_exp:nN
              {#2} \l_@@_real_tl
          }
      }
  }
\cs_new_protected:Npn \@@_format_cartesian_tidy_exp:nN #1#2
  {
    \group_begin:
      \keys_set:nn { siunitx }
        {
          exponent-mode  = fixed ,
          fixed-exponent = \fp_eval:n { round(#1,0) }
       }
      \siunitx_number_process:NN #2 #2
    \exp_args:NNNV \group_end:
    \tl_set:Nn #2 #2
  }
\cs_new_protected:cpn { @@_format_extract-exponent:N } #1
  {
    \tl_set:Ne #1
      { \siunitx_number_adjust_exponent:Nn #1 \l_@@_tmp_fp }
    \siunitx_number_process:NN #1 #1
  }
\cs_new:Npn \@@_extract_exp:nnnnnnn #1#2#3#4#5#6#7 { #6 0 #7 }
\cs_new_protected:Npn \@@_drop_exp:N #1
  { \exp_after:wN \@@_drop_exp:nnnnnnnN #1 #1 }
\cs_new_protected:Npn \@@_drop_exp:nnnnnnnN #1#2#3#4#5#6#7#8
  { \tl_set:Nn #8 { {#1} {#2} {#3} {#4} {#5} { } { 0 } } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_format_polar:n            ,
%     \@@_format_combine-exponent:n ,
%     \@@_format_extract-exponent:n ,
%     \@@_format_polar_input:n
%   }
% \begin{macro}{\@@_format_phase:}
%     We see similar ideas here to the Cartesian versions, but with only
%     the magnitude to adjust, things are rather simpler in the exponent
%     manipulations.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_polar:n #1
  {
    \tl_if_blank:nTF {#1}
      {
        \bool_if:NT \l_siunitx_number_parse_bool
          { \siunitx_number_process:NN \l_@@_mag_tl \l_@@_mag_tl }
      }
      {
        \bool_if:NTF \l_siunitx_number_parse_bool
          {
            \use:c
              { @@_format_polar_ \l_siunitx_quantity_prefix_mode_str :n } {#1}
          }
          { \@@_format_polar_input:n {#1} }
      }
    \tl_set:Ne \l_@@_tmp_tl
      {
        \bool_if:NTF \l_siunitx_number_parse_bool
          { \siunitx_number_output:N \l_@@_mag_tl }
          { \exp_not:V \l_@@_mag_tl }
      }
    \siunitx_print_number:V \l_@@_tmp_tl
    \l_@@_phase_tl { \@@_format_phase: }
    \siunitx_quantity_print:nV { } \l_@@_unit_tl
  }
\cs_new_protected:cpn { @@_format_polar_combine-exponent:n } #1
  {
    \siunitx_number_process:NN \l_@@_mag_tl \l_@@_mag_tl
    \fp_set:Nn \l_@@_tmp_fp
     { \exp_after:wN \@@_extract_exp:nnnnnnn \l_@@_mag_tl }
    \@@_drop_exp:N \l_@@_mag_tl
    \siunitx_unit_format_combine_exponent:nnN {#1}
      \l_@@_tmp_fp \l_@@_unit_tl
  }
\cs_new_protected:cpe { @@_format_polar_extract-exponent:n } #1
  {
    \exp_not:N \siunitx_unit_format_extract_prefixes:nNN {#1}
      \exp_not:N \l_@@_unit_tl \exp_not:N \l_@@_tmp_fp
    \exp_not:c { @@_format_extract-exponent:N }
      \exp_not:N \l_@@_mag_tl
  }
\cs_new_protected:Npn \@@_format_polar_input:n #1
  {
    \bool_if:NT \l_siunitx_number_parse_bool
      { \siunitx_number_process:NN \l_@@_mag_tl \l_@@_mag_tl }
    \siunitx_unit_format:nN {#1} \l_@@_unit_tl
  }
\cs_new_protected:Npn \@@_format_phase:
  {
    \group_begin:
      \bool_if:NTF \l_@@_polar_degree_bool
        {
          \exp_args:NV \siunitx_unit_options_apply:n \l_@@_symbol_degree_tl
          \siunitx_unit_format:VN \l_@@_symbol_degree_tl \l_@@_tmp_tl
        }
        { \tl_clear:N \l_@@_tmp_tl }
      \siunitx_quantity_print:VV \l_@@_angle_tl \l_@@_tmp_tl
    \group_end:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Conversion}
%
% \begin{macro}[EXP]
%   {
%     \@@_convert_cartesian:nn     ,
%     \@@_convert_cartesian_aux:nn ,
%     \@@_convert_cartesian_aux:ee
%   }
% \begin{macro}[EXP]{\@@_convert_cartesian_aux:w}
% \begin{macro}[EXP]
%   {
%     \@@_convert_cartesian_aux:nnn ,
%     \@@_convert_cartesian_aux:nen ,
%     \@@_convert_cartesian_aux:enn
%   }
%   Conversion to Cartesian form is easy as we have two inputs and need to
%   do no parsing here at all. In most cases the exponents for the two
%   output parts will be the same, but that is not certain.
%    \begin{macrocode}
\cs_new:Npn \@@_convert_cartesian:nn #1#2
  {
    \@@_convert_cartesian_aux:ee
      {
        \fp_to_tl:n
          { (#1) * cos \bool_if:NT \l_@@_polar_degree_bool { d } (#2) }
      }
      {
        \fp_to_tl:n
          { (#1) * sin \bool_if:NT \l_@@_polar_degree_bool { d } (#2) }
      }
  }
\cs_new:Npn \@@_convert_cartesian_aux:nn #1#2
  {
    \@@_convert_cartesian_aux:w #1 e 0 e \q_mark #2 e 0 e \q_stop
  }
\cs_generate_variant:Nn \@@_convert_cartesian_aux:nn { ee }
\cs_new:Npn \@@_convert_cartesian_aux:w
  #1 e #2 e #3 \q_mark #4 e #5 e #6 \q_stop
  {
    \int_compare:nNnTF {#2} = {#5}
      { \@@_convert_cartesian_aux:nnn {#1} {#4} {#2} }
      {
        \int_compare:nNnTF {#2} > {#5}
          {
            \@@_convert_cartesian_aux:nen
              {#1}
              { \fp_to_decimal:n { #4 * 10 ** (#5 - #2) } }
              {#2}
          }
          {
            \@@_convert_cartesian_aux:enn
              { \fp_to_decimal:n { #1 * 10 ** (#2 - #5) } }
              {#4}
              {#5}
          }
      }
  }
\cs_new:Npn \@@_convert_cartesian_aux:nnn #1#2#3
  {
    \fp_compare:nNnF {#1} = \c_zero_fp
      {#1}
    \fp_compare:nNnF {#2} = \c_zero_fp
      {
        \fp_compare:nNnF {#2} < \c_zero_fp { + }
        #2 i
      }
    \int_compare:nNnF {#3} = 0
      { e #3 }
  }
\cs_generate_variant:Nn \@@_convert_cartesian_aux:nnn { e , ne }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_convert_polar:n, \@@_convert_polar:V}
% \begin{macro}[EXP]{\@@_convert_polar_auxi:w}
% \begin{macro}[EXP]{\@@_convert_polar_auxii:nw}
% \begin{macro}[EXP]{\@@_convert_polar_auxiii:nw}
% \begin{macro}[EXP]{\@@_convert_polar_auxiv:nnw}
% \begin{macro}[EXP]{\@@_convert_polar_auxv:nnw}
% \begin{macro}[EXP]{\@@_convert_polar_auxvi:nnw}
% \begin{macro}[EXP]{\@@_convert_polar_auxvii:nnn, \@@_convert_polar_auxvii:enn}
% \begin{macro}[EXP]{\@@_convert_polar_auxviii:nnn}
% \begin{macro}[EXP]
%   {\@@_convert_polar_auxix:nnn, \@@_convert_polar_auxix:eee}
% \begin{macro}[EXP]
%   {\@@_convert_polar_auxix:nn, \@@_convert_polar_auxix:ee}
%    A simplified parser for complex numbers which works by expansion,
%    then converts to polar form.
%    \begin{macrocode}
\cs_new:Npn \@@_convert_polar:n #1
  { \@@_convert_polar_auxi:w #1 e e \q_stop }
\cs_generate_variant:Nn \@@_convert_polar:n { V }
\cs_new:Npn \@@_convert_polar_auxi:w #1 e #2 e #3 \q_stop
  { \@@_convert_polar_auxii:nw {#2} #1 \q_stop }
\cs_new:Npn \@@_convert_polar_auxii:nw #1#2#3 \q_stop
  {
    \bool_lazy_or:nnTF
      { \str_if_eq_p:nn {#2} { i } }
      { \str_if_eq_p:nn {#2#3} { +i } }
      { \@@_convert_polar_auxviii:nnn { } { 1 } {#1} }
      {
        \str_if_eq:nnTF {#2#3} { -i }
          { \@@_convert_polar_auxviii:nnn { } { -1 } {#1} }
          {
            \str_if_eq:nnTF {#2} { \pm }
              {
                \msg_expandable_error:nn { siunitx }
                  { cannot-convert-to-polar }
                  { 0 } { }
              }
              { \@@_convert_polar_auxiii:nnw {#1} {#2} #3 \pm \pm \q_stop }
          }
      }
  }
\cs_new:Npn \@@_convert_polar_auxiii:nnw #1#2#3 \pm #4 \pm #5 \q_stop
  {
    \tl_if_blank:nTF {#5}
      { \@@_convert_polar_auxiv:nnw {#1} {#2} #3 + + \q_stop }
      {
        \msg_expandable_error:nn { siunitx } { cannot-convert-to-polar }
        { 0 } { }
      }
  }
\cs_new:Npn \@@_convert_polar_auxiv:nnw #1#2#3 + #4 + #5 \q_stop
  {
    \tl_if_blank:nTF {#4}
      { \@@_convert_polar_auxv:nnw {#1} {#2} #3 - - \q_stop }
      {
        \str_if_eq:eeTF { \use:n #4 } { i }
          { \@@_convert_polar_auxviii:nnn {#2#3} { 1 } {#1} }
          { \@@_convert_polar_auxvi:nnw {#2#3} {#1} #4 i \q_nil i \q_stop }
      }
  }
\cs_new:Npn \@@_convert_polar_auxv:nnw #1#2#3 - #4 - #5 \q_stop
  {
    \tl_if_blank:nTF {#4}
      { \@@_convert_polar_auxvi:nnw { } {#1} #2#3 i \q_nil i \q_stop }
      {
        \str_if_eq:eeTF { \use:n #4 } { i }
          { \@@_convert_polar_auxviii:nnn { } { -1 } {#1} }
          { \@@_convert_polar_auxvi:nnw {#2#3} {#1} -#4 i \q_nil i \q_stop }
      }
  }
%    \end{macrocode}
%   Negative real values are special-cased here for efficiency.
%    \begin{macrocode}
\cs_new:Npn \@@_convert_polar_auxvi:nnw #1#2#3 i #4 i #5 \q_stop
  {
    \quark_if_nil:nTF {#4}
      {
        \tl_if_head_eq_meaning:nNTF {#3} -
          { \@@_convert_polar_auxvii:enn { \use_none:n #3 } { 180 } }
          { \@@_convert_polar_auxvii:nnn {#3} { 0 } }
            {#2}
      }
      { \@@_convert_polar_auxviii:nnn {#1} {#3} {#2} }
  }
\cs_new:Npn \@@_convert_polar_auxvii:nnn #1#2#3
  {
    { #1 \tl_if_blank:nF {#3} { e#3 } } {#2}
  }
\cs_generate_variant:Nn \@@_convert_polar_auxvii:nnn { e }
\cs_new:Npn \@@_convert_polar_auxviii:nnn #1#2#3
  {
    \@@_convert_polar_auxix:eee
      { \tl_if_blank:nTF {#1} { 0 } {#1} }
      { \tl_if_blank:nTF {#2} { 0 } {#2} }
      { \tl_if_blank:nF {#3} { e#3 } }
  }
\cs_new:Npn \@@_convert_polar_auxix:nnn #1#2#3
  {
    \@@_format_polar_auxx:ee
      { \fp_eval:n { sqrt ( (#1#3)^2 + (#2#3)^2 ) } }
      {
        \fp_eval:n
          { atan \bool_if:NT \l_@@_polar_degree_bool { d } (#2 , #1) }
      }
  }
\cs_generate_variant:Nn \@@_convert_polar_auxix:nnn { eee }
\cs_new:Npn \@@_format_polar_auxx:nn #1#2 { {#1} {#2} }
\cs_generate_variant:Nn \@@_format_polar_auxx:nn { ee }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Messages}
%
%    \begin{macrocode}
\msg_new:nnn { siunitx } { cannot-convert-to-polar }
  { Cannot~convert~input~to~polar~form. }
\msg_new:nnnn { siunitx } { duplicate-complex-root }
  { Duplicate~complex~root~in~"#1". }
  {
    Complex~numbers~may~have~only~exactly~one~root~symbol~present.
  }
\msg_new:nnnn { siunitx } { invalid-polar-form }
  { Invalid~polar~form~"#1:#2". }
  {
    Complex~numbers~in~polar~form~must~have~both~a~magnitude~and~and~
    angle.
  }
%    \end{macrocode}
%
% \subsection{Deprecated options}
% 
%    \begin{macrocode}
\keys_define:nn { siunitx }
  {
    complex-symbol-angle .code:n =
      {
        \msg_info:nnnn { siunitx } { option-deprecated }
          { number-angle-product }
          { complex-phase-command }
        complex-phase-command = {#1}
      }
  }
%    \end{macrocode}
%
% \subsection{Standard settings for module options}
%
% Some of these follow naturally from the point of definition
% (\foreign{e.g.}~boolean variables are always |false| to begin with),
% but for clarity everything is set here.
%    \begin{macrocode}
\keys_set:nn { siunitx }
  {
    complex-angle-unit    = degrees                ,
    complex-mode          = input                  ,
    complex-root-position = after-number           ,
    complex-phase-command = \ensuremath { \angle } ,
    complex-symbol-degree = \degree                ,
    input-complex-root    = ij                     ,
    output-complex-root   = \mathrm { i }          ,
    print-complex-unity   = false
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
