// square().

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

// Specification.
#include "cln/integer.h"


// Implementation.

#include "cl_I.h"
#include "cl_DS.h"
#include "cl_low.h"

namespace cln {

const cl_I square (const cl_I& x)
{
  // Methode:
  // x Fixnum -> direkt multiplizieren
  // sonst: zu DS machen, multiplizieren.
      if (fixnump(x))
        { var sint32 x_ = FN_to_L(x);
          // Werte direkt multiplizieren:
          var uint32 hi;
          var uint32 lo;
          mulu32((uint32)x_,(uint32)x_,hi=,lo=); // erst unsigned multiplizieren
          if (x_ < 0) { hi -= 2*(uint32)x_; } // dann Korrektur für Vorzeichen
          return L2_to_I(hi,lo);
        }
      CL_ALLOCA_STACK;
      var const uintD* xMSDptr;
      var uintC xlen;
      var const uintD* xLSDptr;
      I_to_NDS_nocopy(x, xMSDptr = , xlen = , xLSDptr = , cl_false,);
      var uintD* ergMSDptr;
      var uintC erglen = 2*xlen;
      var uintD* ergLSDptr;
      num_stack_alloc(erglen,ergMSDptr=,ergLSDptr=);
      var uintC len = xlen;
      var uintD MSD = mspref(xMSDptr,0);
      if (MSD==0)
        { mspref(ergMSDptr,0) = 0; mspref(ergMSDptr,1) = 0; len--; }
      cl_UDS_mul_square(xLSDptr,len,ergLSDptr);
      if ((sintD)MSD < 0)
        { subfrom_loop_lsp(xLSDptr,ergLSDptr lspop xlen,xlen);
          subfrom_loop_lsp(xLSDptr,ergLSDptr lspop xlen,xlen);
        }
      return DS_to_I(ergMSDptr,erglen);
}
// Bit complexity (x of length N): O(M(N)).

}  // namespace cln
