% \iffalse meta-comment
%
%% File: l3fp-convert.dtx Copyright(C) 2011-2012 The LaTeX3 Project
%%
%% 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
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3kernel 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
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%%
%
%<*driver>
\RequirePackage{l3bootstrap}
\GetIdInfo$Id: l3fp-convert.dtx 4090 2012-08-14 07:57:01Z joseph $
  {L3 Floating-point conversion}
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \textsf{l3fp-convert} package\\ Floating point conversion^^A
%   \thanks{This file describes v\ExplFileVersion,
%     last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\texttt{l3fp-convert} implementation}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=fp>
%    \end{macrocode}
%
% \subsection{Trimming trailing zeros}
%
% \begin{macro}[int, EXP]{\@@_trim_zeros:w}
% \begin{macro}[aux, EXP]
%   {\@@_trim_zeros_loop:w, \@@_trim_zeros_dot:w, \@@_trim_zeros_end:w}
%   If |#1| ends with a $0$, the \texttt{loop} auxiliary takes that zero
%   as an end-delimiter for its first argument, and the second argument
%   is the same \texttt{loop} auxiliary.  Once the last trailing zero is
%   reached, the second argument will be the \texttt{dot} auxiliary,
%   which removes a trailing dot if any.  We then clean-up with the
%   \texttt{end} auxiliary, keeping only the number.
%    \begin{macrocode}
\cs_new:Npn \@@_trim_zeros:w #1 ;
  {
    \@@_trim_zeros_loop:w #1
      ; \@@_trim_zeros_loop:w 0; \@@_trim_zeros_dot:w .; \s__stop
  }
\cs_new:Npn \@@_trim_zeros_loop:w #1 0; #2 { #2 #1 ; #2 }
\cs_new:Npn \@@_trim_zeros_dot:w #1 .; { \@@_trim_zeros_end:w #1 ; }
\cs_new:Npn \@@_trim_zeros_end:w #1 ; #2 \s__stop { #1 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Scientific notation}
%
% \begin{macro}[EXP]
%   {\fp_to_scientific:N, \fp_to_scientific:c, \fp_to_scientific:n}
%   The three public functions evaluate their argument, then pass it to
%   \cs{@@_to_scientific:w}.
%    \begin{macrocode}
\cs_new:Npn \fp_to_scientific:N #1 { \exp_after:wN \@@_to_scientific:w #1 }
\cs_generate_variant:Nn \fp_to_scientific:N { c }
\cs_new_nopar:Npn \fp_to_scientific:n
  {
    \exp_after:wN \@@_to_scientific:w
    \tex_romannumeral:D -`0 \@@_parse:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, EXP]
%   {
%     \@@_to_scientific:w,
%     \@@_to_scientific_normal:wnnnnn,
%     \@@_to_scientific_normal:wNw
%   }
%   Expressing an internal floating point number in scientific notation
%   is quite easy: no rounding, and the format is very well defined.
%   First cater for the sign: negative numbers ($|#2|=2$) start
%   with~|-|; we then only need to care about positive numbers and
%   \texttt{nan}.  Then filter the special cases: $\pm0$~are represented
%   as~|0|; infinities are converted to a number slightly larger than
%   the largest after an \enquote{invalid_operation} exception;
%   \texttt{nan} is represented as~|0| after an
%   \enquote{invalid_operation} exception.  In the normal case,
%   decrement the exponent and unbrace the $4$ brace groups, then in a
%   second step grab the first digit (previously hidden in braces) to
%   order the various parts correctly.  Finally trim zeros.  The whole
%   construction is within a call to \cs{tl_to_lowercase:n}, responsible
%   for creating |e| with category \enquote{other}.
%    \begin{macrocode}
\group_begin:
\char_set_catcode_other:N E
\tl_to_lowercase:n
  {
    \group_end:
    \cs_new:Npn \@@_to_scientific:w \s_@@ \@@_chk:w #1#2
      {
        \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi:
        \if_case:w #1 \exp_stop_f:
             \@@_case_return:nw { 0 }
        \or: \exp_after:wN \@@_to_scientific_normal:wnnnnn
        \or:
          \@@_case_use:nw
            {
              \@@_invalid_operation:nnw
                {
                  \exp_after:wN 1
                  \exp_after:wN E
                  \int_use:N \c_@@_max_exponent_int
                }
                { fp_to_scientific }
            }
        \or:
          \@@_case_use:nw
            {
              \@@_invalid_operation:nnw
                { 0 }
                { fp_to_scientific }
            }
        \fi:
        \s_@@ \@@_chk:w #1 #2
      }
    \cs_new:Npn \@@_to_scientific_normal:wnnnnn
        \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ;
      {
        \if_int_compare:w #2 = \c_one
          \exp_after:wN \@@_to_scientific_normal:wNw
        \else:
          \exp_after:wN \@@_to_scientific_normal:wNw
          \exp_after:wN E
          \int_use:N \__int_eval:w #2 - \c_one
        \fi:
        ; #3 #4 #5 #6 ;
      }
  }
\cs_new:Npn \@@_to_scientific_normal:wNw #1 ; #2#3;
  { \@@_trim_zeros:w #2.#3 ; #1 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Decimal representation}
%
% \begin{macro}[EXP]
%   {\fp_to_decimal:N, \fp_to_decimal:c, \fp_to_decimal:n}
%   All three public variants are based on the same \cs{@@_to_decimal:w}
%   after evaluating their argument to an internal floating point.
%    \begin{macrocode}
\cs_new:Npn \fp_to_decimal:N #1 { \exp_after:wN \@@_to_decimal:w #1 }
\cs_generate_variant:Nn \fp_to_decimal:N { c }
\cs_new_nopar:Npn \fp_to_decimal:n
  {
    \exp_after:wN \@@_to_decimal:w
    \tex_romannumeral:D -`0 \@@_parse:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, EXP]
%   {
%     \@@_to_decimal:w,
%     \@@_to_decimal_normal:wnnnnn,
%     \@@_to_decimal_large:Nnnw,
%     \@@_to_decimal_huge:wnnnn,
%   }
%   The structure is similar to \cs{@@_to_scientific:w}.  Insert |-| for
%   negative numbers.  Zero gives $0$, $\pm\infty$ and \nan{} yield an
%   \enquote{invalid operation} exception; note that $\pm\infty$
%   produces a very large output, which we don't expand now since it
%   most likely won't be needed.  Normal numbers with an exponent in the
%   range $[1,15]$ have that number of digits before the decimal
%   separator: \enquote{decimate} them, and remove leading zeros with
%   \cs{__int_value:w}, then trim trailing zeros and dot.  Normal
%   numbers with an exponent $16$ or larger have no decimal separator,
%   we only need to add trailing zeros.  When the exponent is
%   non-positive, the result should be $0.\meta{zeros}\meta{digits}$,
%   trimmed.
%    \begin{macrocode}
\cs_new:Npn \@@_to_decimal:w \s_@@ \@@_chk:w #1#2
  {
    \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi:
    \if_case:w #1 \exp_stop_f:
         \@@_case_return:nw { 0 }
    \or: \exp_after:wN \@@_to_decimal_normal:wnnnnn
    \or:
      \@@_case_use:nw
        {
          \@@_invalid_operation:nnw
            {
              \exp_after:wN \exp_after:wN \exp_after:wN 1
              \prg_replicate:nn \c_@@_max_exponent_int 0
            }
            { fp_to_decimal }
        }
    \or:
      \@@_case_use:nw
        {
          \@@_invalid_operation:nnw
            { 0 }
            { fp_to_decimal }
        }
    \fi:
    \s_@@ \@@_chk:w #1 #2
  }
\cs_new:Npn \@@_to_decimal_normal:wnnnnn
    \s_@@ \@@_chk:w 1 #1 #2 #3#4#5#6 ;
  {
    \int_compare:nNnTF {#2} > \c_zero
      {
        \int_compare:nNnTF {#2} < \c_sixteen
          {
            \@@_decimate:nNnnnn { \c_sixteen - #2 }
              \@@_to_decimal_large:Nnnw
          }
          {
            \exp_after:wN \exp_after:wN
            \exp_after:wN \@@_to_decimal_huge:wnnnn
            \prg_replicate:nn { #2 - \c_sixteen } { 0 } ;
          }
        {#3} {#4} {#5} {#6}
      }
      {
        \exp_after:wN \@@_trim_zeros:w
        \exp_after:wN 0
        \exp_after:wN .
        \tex_romannumeral:D -`0 \prg_replicate:nn { - #2 } { 0 }
        #3#4#5#6 ;
      }
  }
\cs_new:Npn \@@_to_decimal_large:Nnnw #1#2#3#4;
  {
    \exp_after:wN \@@_trim_zeros:w \__int_value:w
      \if_int_compare:w #2 > \c_zero
        #2
      \fi:
      \exp_stop_f:
      #3.#4 ;
  }
\cs_new:Npn \@@_to_decimal_huge:wnnnn #1; #2#3#4#5 { #2#3#4#5 #1 }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Token list representation}
%
% \begin{macro}[EXP]{\fp_to_tl:N, \fp_to_tl:c, \fp_to_tl:n}
%   These three public functions evaluate their argument, then pass it
%   to \cs{@@_to_tl:w}.
%    \begin{macrocode}
\cs_new:Npn \fp_to_tl:N #1 { \exp_after:wN \@@_to_tl:w #1 }
\cs_generate_variant:Nn \fp_to_tl:N { c }
\cs_new_nopar:Npn \fp_to_tl:n
  {
    \exp_after:wN \@@_to_tl:w
    \tex_romannumeral:D -`0 \@@_parse:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_to_tl:w, \@@_to_tl_normal:nnnnn}
%   A structure similar to \cs{@@_to_scientific:w} and
%   \cs{@@_to_decimal:w}, but without the \enquote{invalid operation}
%   exception.  First filter special cases.  We express normal numbers
%   in decimal notation if the exponent is in the range $[-2,16]$, and
%   otherwise use scientific notation.
%    \begin{macrocode}
\cs_new:Npn \@@_to_tl:w \s_@@ \@@_chk:w #1#2
  {
    \if_meaning:w 2 #2 \exp_after:wN - \tex_romannumeral:D -`0 \fi:
    \if_case:w #1 \exp_stop_f:
           \@@_case_return:nw { 0 }
    \or:   \exp_after:wN \@@_to_tl_normal:nnnnn
    \or:   \@@_case_return:nw { \tl_to_str:n {inf} }
    \else: \@@_case_return:nw { \tl_to_str:n {nan} }
    \fi:
  }
\cs_new:Npn \@@_to_tl_normal:nnnnn #1
  {
    \if_int_compare:w #1 > \c_sixteen
      \exp_after:wN \@@_to_scientific_normal:wnnnnn
    \else:
      \if_int_compare:w #1 < - \c_two
        \exp_after:wN \exp_after:wN
        \exp_after:wN \@@_to_scientific_normal:wnnnnn
      \else:
        \exp_after:wN \exp_after:wN
        \exp_after:wN \@@_to_decimal_normal:wnnnnn
      \fi:
    \fi:
    \s_@@ \@@_chk:w 1 0 {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Formatting}
%
% This is not implemented yet, as it is not yet clear what a correct
% interface would be, for this kind of structured conversion from a
% floating point (or other types of variables) to a string.  Ideas
% welcome.
%
% \subsection{Convert to dimension or integer}
%
% \begin{macro}[EXP]{\fp_to_dim:N, \fp_to_dim:c, \fp_to_dim:n}
%   These three public functions rely on \cs{fp_to_decimal:n}
%   internally.  We make sure to produce |pt| with category other.
%    \begin{macrocode}
\cs_new:Npx \fp_to_dim:N #1
  { \exp_not:N \fp_to_decimal:N #1 \tl_to_str:n {pt} }
\cs_generate_variant:Nn \fp_to_dim:N { c }
\cs_new:Npx \fp_to_dim:n #1
  { \exp_not:N \fp_to_decimal:n {#1} \tl_to_str:n {pt} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\fp_to_int:N, \fp_to_int:c, \fp_to_int:n}
%   These three public functions evaluate their argument, then pass it
%   to \cs{fp_to_int:w}.
%    \begin{macrocode}
\cs_new:Npn \fp_to_int:N #1 { \exp_after:wN \@@_to_int:w #1 }
\cs_generate_variant:Nn \fp_to_int:N { c }
\cs_new_nopar:Npn \fp_to_int:n
  {
    \exp_after:wN \@@_to_int:w
    \tex_romannumeral:D -`0 \@@_parse:n
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_to_int:w}
%   To convert to an integer, first round to $0$ places (to the nearest
%   integer), then express the result as a decimal number: the
%   definition of \cs{@@_to_decimal:w} is such that there will be no
%   trailing dot nor zero.
%    \begin{macrocode}
\cs_new:Npn \@@_to_int:w #1;
  {
    \exp_after:wN \@@_to_decimal:w \tex_romannumeral:D -`0
    \@@_round:Nwn \@@_round_to_nearest:NNN #1; { 0 }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Convert from a dimension}
%
% \begin{macro}[EXP]{\dim_to_fp:n}
% \begin{macro}[aux, EXP]
%   {
%     \@@_from_dim_test:N,
%     \@@_from_dim:Nw,
%     \@@_from_dim_ii:wNNnnnnnn,
%     \@@_from_dim_iii:wnnnnwN,
%   }
%   The dimension expression (which can in fact be a glue expression) is
%   evaluated, converted to a number (\emph{i.e.}, expressed in scaled
%   points), then multiplied by $2^{-16} = 0.0000152587890625$ to give a
%   value expressed in points.  The auxiliary \cs{@@_mul_npos_o:Nww}
%   expects the desired \meta{final sign} and two floating point
%   operands (of the form \cs{s_@@} \ldots{} |;|) as arguments.
%    \begin{macrocode}
\cs_new:Npn \dim_to_fp:n #1
  {
    \exp_after:wN \@@_from_dim_test:N
    \__int_value:w \etex_glueexpr:D #1 ;
  }
\cs_new:Npn \@@_from_dim_test:N #1
  {
    \if_meaning:w 0 #1
      \@@_case_return:nw \c_zero_fp
    \else:
      \if_meaning:w - #1
        \exp_after:wN \@@_from_dim:Nw
        \exp_after:wN 2
        \__int_value:w
      \else:
        \exp_after:wN \@@_from_dim:Nw
        \exp_after:wN 0
        \__int_value:w #1
      \fi:
    \fi:
  }
\cs_new:Npn \@@_from_dim:Nw #1 #2;
  {
    \@@_pack_twice_four:wNNNNNNNN \@@_from_dim_ii:wNNnnnnnn ;
    #2 000 0000 00 {10}987654321; #1
  }
\cs_new:Npn \@@_from_dim_ii:wNNnnnnnn #1; #2#3#4#5#6#7#8#9
  { \@@_from_dim_iii:wnnnnwN #1 {#2#300} {0000} ; }
\cs_new:Npn \@@_from_dim_iii:wnnnnwN #1; #2#3#4#5#6; #7
  {
    \@@_mul_npos_o:Nww #7
      \s_@@ \@@_chk:w 1 #7 {#5} #1 ;
      \s_@@ \@@_chk:w 1 0 {-4} {1525} {8789} {0625} {0000} ;
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Use and eval}
%
% \begin{macro}[EXP]{\fp_use:N, \fp_use:c, \fp_eval:n}
%   Those public functions are simple copies of the decimal conversions.
%    \begin{macrocode}
\cs_new_eq:NN \fp_use:N \fp_to_decimal:N
\cs_generate_variant:Nn \fp_use:N { c }
\cs_new_eq:NN \fp_eval:n \fp_to_decimal:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\fp_abs:n}
%   Trivial but useful.  See the implementation of \cs{fp_add:Nn} for an
%   explanation of why to use \cs{@@_parse:n}, namely, for better error
%   reporting.
%    \begin{macrocode}
\cs_new:Npn \fp_abs:n #1
  { \fp_to_decimal:n { abs \@@_parse:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintChanges
%
% \PrintIndex
