// cl_I_to_LF().

// General includes.
#include "cl_sysdep.h"

// Specification.
#include "cl_LF.h"


// Implementation.

#include "cl_LF_impl.h"
#include "cln/integer.h"
#include "cl_I.h"
#include "cl_DS.h"
#include "cl_F.h"

namespace cln {

const cl_LF cl_I_to_LF (const cl_I& x, uintC len)
{
// Methode:
// x=0 -> Ergebnis 0.0
// Merke Vorzeichen von x.
// x:=(abs x)
// Exponent:=(integer-length x)
// Mantisse enthalte die höchstwertigen 16n Bits des Integers x (wobei die
//   führenden 16-(e mod 16) Nullbits zu streichen sind).
// Runde die weiteren Bits weg:
//   Kommen keine mehr -> abrunden,
//   nächstes Bit = 0 -> abrunden,
//   nächstes Bit = 1 und Rest =0 -> round-to-even,
//   nächstes Bit = 1 und Rest >0 -> aufrunden.
// Bei Aufrundung: rounding overflow -> Mantisse um 1 Bit nach rechts schieben
//   und Exponent incrementieren.
      if (eq(x,0)) { return encode_LF0(len); } // x=0 -> Ergebnis 0.0
      var cl_signean sign = -(cl_signean)minusp(x); // Vorzeichen von x
      var cl_I abs_x = (sign==0 ? x : -x);
      var uintL exp = integer_length(abs_x); // (integer-length x) < intDsize*2^intCsize
      // Teste, ob exp <= LF_exp_high-LF_exp_mid :
      if (   (log2_intDsize+intCsize < 32)
          && ((uintL)(intDsize*bitc(intCsize)-1) <= (uintL)(LF_exp_high-LF_exp_mid))
         )
        {} // garantiert exp <= intDsize*2^intCsize-1 <= LF_exp_high-LF_exp_mid
        else
        { if (!(exp <= (uintL)(LF_exp_high-LF_exp_mid))) { cl_error_floating_point_overflow(); } }
      // Long-Float bauen:
      var Lfloat y = allocate_lfloat(len,exp+LF_exp_mid,sign);
      var uintD* y_mantMSDptr = arrayMSDptr(TheLfloat(y)->data,len);
      var const uintD* x_MSDptr;
      var uintC x_len;
      I_to_NDS_nocopy(abs_x, x_MSDptr=,x_len=,,cl_false,); // NDS zu x bilden, x_len>0
      // x_MSDptr/x_len/.. um (exp mod 16) Bits nach rechts shiften und in
      // y einfüllen (genauer: nur maximal len Digits davon):
      {var uintL shiftcount = exp % intDsize;
       // Die NDS fängt mit intDsize-shiftcount Nullbits an, dann kommt eine 1.
       if (x_len > len)
         { x_len -= 1+len;
           if (shiftcount>0)
             { var uintD carry_rechts =
                 shiftrightcopy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,len,shiftcount,mspref(x_MSDptr,0));
               // Mantisse ist gefüllt. Runden:
               if ( ((sintD)carry_rechts >= 0) // nächstes Bit =0 -> abrunden
                    || ( ((carry_rechts & ((uintD)bit(intDsize-1)-1)) ==0) // =1, Rest >0 -> aufrunden
                         && !test_loop_msp(x_MSDptr mspop 1 mspop len,x_len)
                         // round-to-even
                         && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
                  )    )
                 goto ab; // aufrunden
                 else
                 goto auf; // aufrunden
             }
             else
             { copy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,len);
               // Mantisse ist gefüllt. Runden:
               var const uintD* ptr = x_MSDptr mspop 1 mspop len;
               if ( (x_len==0) // keine Bits mehr -> abrunden
                    || ((sintD)mspref(ptr,0) >= 0) // nächstes Bit =0 -> abrunden
                    || ( ((mspref(ptr,0) & ((uintD)bit(intDsize-1)-1)) ==0) // =1, Rest >0 -> aufrunden
                         && !test_loop_msp(ptr mspop 1,x_len-1)
                         // round-to-even
                         && ((lspref(ptr,0) & bit(0)) ==0)
                  )    )
                 goto ab; // aufrunden
                 else
                 goto auf; // aufrunden
             }
           auf: // aufrunden
             if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
               // Übertrag durchs Aufrunden
               { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
                 // Exponenten incrementieren:
                 if (   (log2_intDsize+intCsize < 32)
                     && ((uintL)(intDsize*bitc(intCsize)-1) < (uintL)(LF_exp_high-LF_exp_mid))
                    )
                   // garantiert exp < intDsize*2^intCsize-1 <= LF_exp_high-LF_exp_mid
                   { (TheLfloat(y)->expo)++; } // jetzt exp <= LF_exp_high-LF_exp_mid
                   else
                   { if (++(TheLfloat(y)->expo) == LF_exp_high+1) { cl_error_floating_point_overflow(); } }
               }
           ab: // abrunden
             ;
         }
         else // x_len <= len
         { var uintD carry_rechts;
           len -= x_len;
           x_len -= 1;
           if (shiftcount>0)
             { carry_rechts = shiftrightcopy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,x_len,shiftcount,mspref(x_MSDptr,0)); }
             else
             { copy_loop_msp(x_MSDptr mspop 1,y_mantMSDptr,x_len); carry_rechts = 0; }
          {var uintD* y_ptr = y_mantMSDptr mspop x_len;
           msprefnext(y_ptr) = carry_rechts; // Carry als nächstes Digit
           clear_loop_msp(y_ptr,len); // dann len-x_len Nulldigits
         }}
      }
      return y;
}

}  // namespace cln
