-- This  file  is  free software,  which comes along with SmartEiffel.  This
-- software is distributed in the hope that it will be useful,  but  WITHOUT
-- ANY  WARRANTY;  without  even the  implied warranty of MERCHANTABILITY or
-- FITNESS FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You  are  allowed  to  redistribute it and sell it, alone or as a part of
-- another product.
--
-- Copyright(C) 1994-2002: INRIA - LORIA (INRIA Lorraine) - ESIAL U.H.P.
--			   - University of Nancy 1 - FRANCE
-- Copyright(C) 2003:      INRIA - LORIA (INRIA Lorraine) - I.U.T. Charlemagne
--			   - University of Nancy 2 - FRANCE
--
--		 Dominique COLNET, Suzanne COLLIN, Olivier ZENDRA,
--			   Philippe RIBET, Cyril ADRIAN
--
-- http://SmartEiffel.loria.fr - SmartEiffel@loria.fr
--
deferred class LARGE_INTEGER
--
-- To implement NUMBER (do not use this class, see NUMBER).
--

inherit ABSTRACT_INTEGER

feature

   is_zero: BOOLEAN is False

   is_one: BOOLEAN is False

   is_equal(other: NUMBER): BOOLEAN is
	 -- Compares two LARGE_INTEGERs. As they both have same sign
	 -- comparison is done with absolute values.
      local
	 i: INTEGER; n2: like Current
      do
	 n2 ?= other
	 if n2 /= Void then
	    from
	       i := value.upper
	       Result := i = n2.value.upper
	    until
	       not Result or else i < 0
	    loop
	       Result := value.item(i) = n2.value.item(i)
	       i := i - 1
	    end
	 end
      end

feature{NUMBER}

   append_in(str:STRING) is
      local
	 i:INTEGER
	 s: STRING
      do
	 if is_negative then
	    str.extend('-')
	 end
	 str.append(storage.item(storage.upper).to_string)
	 from
	    i := storage.upper
	 until
	    i = storage.lower
	 loop
	    i := i - 1
	    s := storage.item(i).to_string
	    str.extend_multiple('0', (Base.log10.truncated_to_integer - s.count))
	    str.append(storage.item(i).to_string)
	 end
      end

   value: FAST_ARRAY[INTEGER] is
      do
	 Result := storage
      end


   make_from_fixed_array(fa: FAST_ARRAY[INTEGER]) is
      require
	 fa /= Void
      do
	 check
	    correct_fixed(fa)
	 end
	 storage := fa
      end


   make_smaller(int: INTEGER) is
      -- Creation of a large_integer with a too important integer
      do
	 !!storage.make(2)
	 storage.put((int \\ Base).abs,0)
	 storage.put((int // Base).abs,1)
      end

   make_from_large_product(int, other: INTEGER) is
      -- Creation of a large_integer with the multiplication of 2 integer
      do
	 temp_2_digints.put((other \\ Base).abs, 0)
	 temp_2_digints.put((other // Base).abs, 1)
	 storage := mult_fixed_with_integer(temp_2_digints,int.abs)
      end


   make_from_product(int, other: INTEGER) is
      local
	 v11, v12, v13, v21, v22, v23: INTEGER
	 ret: INTEGER
	 d1, d2, d3: INTEGER
      do
	 !!storage.make(2)
	 d1 := int.abs
	 d2 := other.abs
	 v11 := d1 // (Half_base_2)
	 v13 := d1 \\ (Half_base_2)
	 v12 := v13 // Half_base
	 v13 := v13 \\ Half_base
	 v21 := d2 // (Half_base_2)
	 v23 := d2 \\ (Half_base_2)
	 v22 := v23 // Half_base
	 v23 := v23 \\ Half_base

	 if Base_is_impair then
	    d1 :=v23 * v12 + v13 * v22
	    d2 := d1 // Half_base
	    d1 := (d1 - (d2 * Half_base)) * Half_base + v23 * v13
	    if d1 >= 2 * Half_base_2 then
	       d1 := d1 - (2 * (Half_base_2))
	       ret := 2
	    else
	       if d1 >= Half_base_2 then
		  d1 := d1 - (Half_base_2)
		  ret := 1
	       else
		  ret := 0
	       end
	    end
	    d2 := ret + d2 + (v23 * v11) + (v13 * v21) + (v12 * v22) + ((v11 * v22) \\ Half_base) * Half_base + ((v21 * v12) \\ Half_base) * Half_base
	    d3 := (v11 * v22) // Half_base + (v21 * v12) // Half_base + v11 * v21
	    ret := d2 // Rest_base
	    storage.put(d1 + (d2 - (ret * Rest_base)) * (Half_base_2), 0)
	    storage.put(d3 * (Half_base_2 // Rest_base) + ret, 1)
	 else
	    ret := v13 * v23
	    v11 := v12 * v23
	    v21 := v22 * v13
	    d1 := ret // Half_base + v11 \\ Half_base + v21 \\ Half_base
	    d2 := d1 \\ Half_base
	    storage.put((d1 - (d2 * Half_base)) * Half_base + ret \\ Half_base, 0)
	    storage.put(d2 + v11 // Half_base + v21 // Half_base + (v12 * v22), 1)
	 end
      end

   make_big is
      do
	 !!storage.make(3)
	 storage.put(1, 2)
      end


feature{NONE}

   create_positive(fa: FAST_ARRAY[INTEGER]): ABSTRACT_INTEGER is
	 -- creates a simplified positive ABSTRACT_INTEGER
	 -- from a correct FAST_ARRAY or a one item FIXED
      require
	 fa /= Void
	 internal_correct_fixed(fa)
      do
	 if (fa.upper > 0) then
	    !LARGE_POSITIVE_INTEGER!Result.make_from_fixed_array(clone(fa))
	 elseif (fa.upper = 0) then
	    !SMALL_INTEGER!Result.make(fa.item(0))
	 else
	    Result ?= zero
	 end
      ensure
	 Result /= Void
	 Result.is_abstract_integer
      end

   create_negative(fa: FAST_ARRAY[INTEGER]): ABSTRACT_INTEGER is
	 -- creates a simplified negative ABSTRACT_INTEGER
	 -- from a correct FAST_ARRAY or a one item FIXED
      require
	 fa /= Void
	 internal_correct_fixed(fa)
      do
	 if fa.upper > 0 then
	    !LARGE_NEGATIVE_INTEGER!Result.make_from_fixed_array(clone(fa))
	 elseif fa.upper = 0 then
	    !SMALL_INTEGER!Result.make(- (fa.item(0)))
	 else
	    Result ?= zero
	 end
      ensure
	 Result /= Void
	 Result.is_abstract_integer
      end

   create_positive_directly(fa: FAST_ARRAY[INTEGER]): ABSTRACT_INTEGER is
	 -- creates a simplified positive ABSTRACT_INTEGER
	 -- from a correct FAST_ARRAY or a one item FIXED
      require
	 fa /= Void
	 internal_correct_fixed(fa)
      do
	 if (fa.upper > 0) then
	    !LARGE_POSITIVE_INTEGER!Result.make_from_fixed_array(fa)
	 elseif (fa.upper = 0) then
	    !SMALL_INTEGER!Result.make(fa.item(0))
	 else
	    Result ?= zero
	 end
      ensure
	 Result /= Void
	 Result.is_abstract_integer
      end

   create_negative_directly(fa: FAST_ARRAY[INTEGER]): ABSTRACT_INTEGER is
	 -- creates a simplified negative ABSTRACT_INTEGER
	 -- from a correct FAST_ARRAY or a one item FIXED
      require
	 fa /= Void
	 internal_correct_fixed(fa)
      do
	 if fa.upper > 0 then
	    !LARGE_NEGATIVE_INTEGER!Result.make_from_fixed_array(fa)
	 elseif fa.upper = 0 then
	    !SMALL_INTEGER!Result.make(- (fa.item(0)))
	 else
	    Result ?= zero
	 end
      ensure
	 Result /= Void
	 Result.is_abstract_integer
      end

feature {NONE} -- Conversion tool

   fixed_array_to_double(fa: FAST_ARRAY[INTEGER]): DOUBLE is
	 -- only a tool
	 -- unsigned conversion
      require
	 fa /= Void
	 correct_fixed(fa)
      local
	 i : INTEGER
      do
	 from
	    i := fa.upper - 1
	    Result := fa.item(fa.upper).to_double
	 until
	    (i < 0) or else (Result > Maximum_double)
	 loop
	    Result := (Result * Double_base) + fa.item(i).to_double
	    i := i - 1
	 end
	 if (Result = Maximum_double) and then (fa.item(0) /= 0) then
	    Result := Maximum_double * 2
	 end
      end


feature{NONE} -- Operations tools

      add_fixed_array_with_integer_in_himself_from(fa1: INTEGER; fa2: FAST_ARRAY[INTEGER]; n: INTEGER) is
	 -- only a tool used by some features in positive
	 -- and negative large integers
	 -- result is stored in fa2
	 -- Make the addition between fa2 and fa1 which is shifted by
	 -- n and return the result in fa2 to have a
	 -- good memory gestion.
      require
	 fa2 /= Void
      local
	 i, carry, partial_sum,
	 initial_larger_upper: INTEGER
      do
	 initial_larger_upper := fa2.upper
	 partial_sum := fa2.item(n) + fa1
	 if partial_sum >= Base or else partial_sum < 0 then
	    carry := 1
	    fa2.put(partial_sum - Base, n)
	 else
	    carry := 0
	    fa2.put(partial_sum, n)
	 end
	 from
	    i := n + 1
	 until
	    (i > initial_larger_upper)
	 loop
	    partial_sum := fa2.item(i) + carry
	    if partial_sum >= Base or else partial_sum < 0 then
	       carry := 1
	       fa2.put(partial_sum - Base, i)
	    else
	       carry := 0
	       fa2.put(partial_sum, i)
	    end
	    i := i + 1
	 end
	 if (carry /= 0) then
	    fa2.add_last(carry)
	 end
      ensure
	 fa2.item(fa2.upper) /= 0
      end

   add_fixed_arrays(fa1, fa2: FAST_ARRAY[INTEGER]): FAST_ARRAY[INTEGER] is
	 -- only a tool used by some features in positive
	 -- and negative large integers
	 -- Give a FAST_ARRAY[INTEGER] for the creation of an
	 -- large_integer after an addition.
      require
	 fa1 /= Void
	 fa2 /= Void
      local
	 smaller, larger: FAST_ARRAY[INTEGER]
	 i, carry, partial_sum,
	 initial_smaller_upper, initial_larger_upper: INTEGER
      do
	 if fa1.upper >= fa2.upper then
	    smaller := fa2
	    larger := fa1
	 else
	    smaller := fa1
	    larger := fa2
	 end
	 from
	    initial_smaller_upper := smaller.upper
	    initial_larger_upper := larger.upper
	    !!Result.make(larger.count + 1)
	    i := 0
	    carry := 0
	 until
	    i > initial_smaller_upper
	 loop
            partial_sum := larger.item(i) + smaller.item(i) + carry
            if partial_sum >= Base or else partial_sum < 0 then
               carry := 1
               Result.put(partial_sum - Base, i)
            else
               carry := 0
               Result.put(partial_sum, i)
            end
	    i := i + 1
	 end
	 from
	 until
	    (i > initial_larger_upper)
	 loop
            partial_sum := larger.item(i) + carry
            if partial_sum >= Base or else partial_sum < 0 then
               carry := 1
               Result.put(partial_sum - Base, i)
            else
               carry := 0
               Result.put(partial_sum, i)
            end
	    i := i + 1
	 end
	 if (carry = 0) then
	    Result.remove_last
	 else
	    Result.put(carry,i)
	 end
      ensure
	 Result.item(Result.upper) /= 0
      end

      add_fixed_arrays_in_himself(fa1, fa2: FAST_ARRAY[INTEGER]) is
	 -- only a tool used by some features in positive
	 -- and negative large integers
	 -- result is stored in fa2
	 -- Make the addition and return the result in fa2 to have a
	 -- good memory gestion.
      require
	 fa1 /= Void
	 fa2 /= Void
      local
	 smaller, larger: FAST_ARRAY[INTEGER]
	 i, carry, partial_sum,
	 initial_smaller_upper, initial_larger_upper: INTEGER
      do
	 if fa1.upper >= fa2.upper then
	    smaller := fa2
	    larger := fa1
	 else
	    smaller := fa1
	    larger := fa2
	 end
	 from
	    initial_smaller_upper := smaller.upper
	    initial_larger_upper := larger.upper
	    i := 0
	    carry := 0
	 until
	    i > initial_smaller_upper
	 loop
            partial_sum := larger.item(i) + smaller.item(i) + carry
            if partial_sum >= Base or else partial_sum < 0 then
               carry := 1
               fa2.put(partial_sum - Base, i)
            else
               carry := 0
               fa2.put(partial_sum, i)
            end
	    i := i + 1
	 end
	 from
	 until
	    (i > initial_larger_upper)
	 loop
            partial_sum := larger.item(i) + carry
            if partial_sum >= Base or else partial_sum < 0 then
               carry := 1
               fa2.put(partial_sum - Base, i)
            else
               carry := 0
               fa2.put(partial_sum, i)
            end
	    i := i + 1
	 end
	 if (carry /= 0) then
	    fa2.add_last(carry)
	 end
      ensure
	 fa2.item(fa2.upper) /= 0
      end

      add_fixed_arrays_in_himself_from(fa1, fa2: FAST_ARRAY[INTEGER]; n: INTEGER) is
	 -- only a tool used by some features in positive
	 -- and negative large integers
	 -- result is stored in fa2
	 -- Make the addition between fa2 and fa1 which is shifted by
	 -- n and return the result in fa2 to have a
	 -- good memory gestion.
      require
	 fa1 /= Void
	 fa2 /= Void
      local
	 i, carry, partial_sum,
	 initial_smaller_upper, initial_larger_upper: INTEGER
      do
	 from
	    initial_smaller_upper := fa1.upper + n
	    initial_larger_upper := fa2.upper
	    i := n
	    carry := 0
	 until
	    i > initial_smaller_upper
	 loop
	    partial_sum := fa2.item(i) + fa1.item(i - n) + carry
	    if partial_sum >= Base or else partial_sum < 0 then
	       carry := 1
	       fa2.put(partial_sum - Base, i)
	    else
	       carry := 0
	       fa2.put(partial_sum, i)
	    end
	    i := i + 1
	 end
	 from
	 until
	    (i > initial_larger_upper)
	 loop
	    partial_sum := fa2.item(i) + carry
	    if partial_sum >= Base or else partial_sum < 0 then
	       carry := 1
	       fa2.put(partial_sum - Base, i)
	    else
	       carry := 0
	       fa2.put(partial_sum, i)
	    end
	    i := i + 1
	 end
	 if (carry /= 0) then
	    fa2.add_last(carry)
	 end
      ensure
	 fa2.item(fa2.upper) /= 0
      end

   difference_between_fixed_arrays(larger, smaller: FAST_ARRAY[INTEGER]):FAST_ARRAY[INTEGER] is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- Give a FAST_ARRAY[INTEGER] for the creation of an
	 -- large_integer after an subtraction.
      require
	 smaller /= Void
	 larger /= Void
	 not fixed_array_greater_than(smaller, larger) -- smaller <= larger
      local
	 i, last_not_zero, carry, partial_sum, larger_upper, smaller_upper: INTEGER
      do
	 from
	    larger_upper := larger.upper
	    smaller_upper := smaller.upper
	    i := 0
	    !!Result.make(larger.count)
	    carry := 0
	    last_not_zero := -1
	 until
	    i > smaller_upper
	 loop
	    partial_sum := larger.item(i) - smaller.item(i) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       Result.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       Result.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	 end
	 from
	 until
	    (i > larger_upper)
	 loop
	    partial_sum := larger.item(i) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       Result.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       Result.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	 end
	 Result.resize(last_not_zero + 1)
      ensure
	  internal_correct_fixed(Result)
      end

   difference_between_fixed_arrays_in_himself(larger, smaller: FAST_ARRAY[INTEGER]) is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- result is stored in larger
	 -- Make the subtraction and return the result in larger to have a
	 -- good memory gestion.
	 -- Use this function if you know that larger is greater than
	 -- smaller.
      require
	 smaller /= Void
	 larger /= Void
	 not fixed_array_greater_than(smaller, larger) -- smaller <= larger
      local
	 i, last_not_zero, carry, partial_sum, larger_upper,smaller_upper: INTEGER
      do
	 from
	    larger_upper := larger.upper
	    smaller_upper := smaller.upper
	    i := 0
	    carry := 0
	    last_not_zero := -1
	 until
	    i > smaller_upper
	 loop
	    partial_sum := larger.item(i) - smaller.item(i) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       larger.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       larger.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	 end
	 from
	 until
	    (i > larger_upper)
	 loop
	    partial_sum := larger.item(i) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       larger.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       larger.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	 end
	 larger.resize(last_not_zero + 1)
      ensure
	 internal_correct_fixed(larger)
      end

   difference_between_fixed_arrays_in_himself_from(larger, smaller: FAST_ARRAY[INTEGER]; n: INTEGER) is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- result is stored in larger
	 -- Make the subtraction between larger and smaller which is
	 -- shifted by n and return the result in larger to have a
	 -- good memory gestion.
	 -- Use this function if you know that larger is greater than
	 -- smaller.
      require
	 smaller /= Void
	 larger /= Void
	 not fixed_array_greater_than(smaller, larger) -- smaller <= larger
      local
	 a, i, last_not_zero, carry, partial_sum, larger_upper,smaller_upper: INTEGER
      do
	 from
	    larger_upper := larger.upper
	    smaller_upper := smaller.upper
	    i := n
	    a := 0
	    carry := 0
	    last_not_zero := n - 1
	 until
	    a > smaller_upper
	 loop
	    partial_sum := larger.item(i) - smaller.item(a) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       larger.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       larger.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	    a := a + 1
	 end
	 from
	 until
	    (i > larger_upper)
	 loop
	    partial_sum := larger.item(i) - carry
	    if (partial_sum < 0) then
	       carry := 1
	       larger.put(partial_sum + Base , i)
	       if (partial_sum + Base ) /= 0 then
		  last_not_zero := i
	       end
	    else
	       carry := 0
	       larger.put(partial_sum, i)
	       if partial_sum /= 0 then
		  last_not_zero := i
	       end
	    end
	    i := i + 1
	 end
	 larger.resize(last_not_zero + 1)
      ensure
	 internal_correct_fixed(larger)
      end

   mult_fixed_with_integer(fa: FAST_ARRAY[INTEGER]; int: INTEGER): FAST_ARRAY[INTEGER] is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- Give a FAST_ARRAY[INTEGER] for the creation of an
	 -- large_integer after an multiplication between a
	 -- large_integer and a small_integer.
      require
	 fa /= Void
	 int /= 0
      local
	 v11, v12, v13, v21, v22, v23: INTEGER
	 ret, retenue: INTEGER
	 d1, d2, d3: INTEGER
	 i, bsup : INTEGER
      do
	 !!Result.make(((nb_c(fa.item(fa.upper)) + 9 * (fa.count - 1) + nb_c(int)) / 9).ceiling)
	 from
	    v11 := int // (Half_base_2)
	    v13 := int \\ (Half_base_2)
	    v12 := v13 // Half_base
	    v13 := v13 \\ Half_base
	    i := Result.lower - 1
	    retenue := 0
	    bsup := fa.upper
	 until
	    i = Result.upper
	 loop
	    i := i + 1
	    if (i <= bsup) then
	       v21 := fa.item(i) // (Half_base_2)
	       v23 := fa.item(i) \\ (Half_base_2)
	       v22 := v23 // Half_base
	       v23 := v23 \\ Half_base
	       if Rest_base = 10 then
		  d1 := v23 * v12 + v13 * v22
		  d2 := d1 // Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + v23 * v13
		  if d1 >= 2 * Half_base_2 then
		     d1 := d1 - (2 * (Half_base_2))
		     ret := 2
		  else
		     if d1 >= Half_base_2 then
			d1 := d1 - (Half_base_2)
			ret := 1
		     else
			ret := 0
		     end
		  end
		  d2 := ret + d2 + (v23 * v11) + (v13 * v21) + (v12 * v22) + ((v11 * v22) \\ Half_base) * Half_base + ((v21 * v12) \\ Half_base) * Half_base
		  d3 := (v11 * v22) // Half_base + (v21 * v12) // Half_base + v11 * v21
		  ret := d2 // Rest_base
		  d1 := d1 + (d2 - (ret * Rest_base)) * (Half_base_2)
		  d2 := d3 * (Half_base_2 // Rest_base) + ret
	       else
		  ret := v13 * v23
		  v11 := v12 * v23
		  v21 := v22 * v13
		  d1 := ret // Half_base + v11 \\ Half_base + v21 \\ Half_base
		  d2 := d1 \\ Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + ret \\ Half_base
		  d2 := d2 + v11 // Half_base + v21 // Half_base + (v12 * v22)
	       end
	       d3 := d1 + retenue
	       if d3 >= Base or else d3 < 0 then
		  retenue := d2 + 1
		  Result.put(d3 - Base, i)
	       else
		  retenue := d2
		  Result.put(d3, i)
	       end
	    else
	       if retenue >= Base or else retenue < 0 then
		  Result.put(retenue - Base, i)
	       else
		  Result.put(retenue, i)
	       end
	    end
	 end
	 if Result.item(Result.upper) = 0 then
	    Result.remove_last
	 end
      ensure
	 internal_correct_fixed(Result)
      end

   mult_fixed_with_integer_in_temp(fa: FAST_ARRAY[INTEGER]; int: INTEGER) is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- Give a FAST_ARRAY[INTEGER] for the creation of an
	 -- large_integer after an multiplication between a
	 -- large_integer and a small_integer.
      require
	 fa /= Void
	 int /= 0
      local
	 v11, v12, v13, v21, v22, v23: INTEGER
	 ret, retenue: INTEGER
	 d1, d2, d3: INTEGER
	 i, bsup : INTEGER
      do
	 temp_after_mult.resize(((nb_c(fa.item(fa.upper)) + nb_c(int) + 9 * (fa.count - 1)) / 9).ceiling)
	 from
	    v11 := int // (Half_base_2)
	    v13 := int \\ (Half_base_2)
	    v12 := v13 // Half_base
	    v13 := v13 \\ Half_base
	    i := temp_after_mult.lower - 1
	    retenue := 0
	    bsup := fa.upper
	 until
	    i = temp_after_mult.upper
	 loop
	    i := i + 1
	    if (i <= bsup) then
	       v21 := fa.item(i) // (Half_base_2)
	       v23 := fa.item(i) \\ (Half_base_2)
	       v22 := v23 // Half_base
	       v23 := v23 \\ Half_base
	       if Rest_base = 10 then
		  d1 := v23 * v12 + v13 * v22
		  d2 := d1 // Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + v23 * v13
		  if d1 >= 2 * Half_base_2 then
		     d1 := d1 - (2 * (Half_base_2))
		     ret := 2
		  else
		     if d1 >= Half_base_2 then
			d1 := d1 - (Half_base_2)
			ret := 1
		     else
			ret := 0
		     end
		  end
		  d2 := ret + d2 + (v23 * v11) + (v13 * v21) + (v12 * v22) + ((v11 * v22) \\ Half_base) * Half_base + ((v21 * v12) \\ Half_base) * Half_base
		  d3 := (v11 * v22) // Half_base + (v21 * v12) // Half_base + v11 * v21
		  ret := d2 // Rest_base
		  d1 := d1 + (d2 - (ret * Rest_base)) * (Half_base_2)
		  d2 := d3 * (Half_base_2 // Rest_base) + ret
	       else
		  ret := v13 * v23
		  v11 := v12 * v23
		  v21 := v22 * v13
		  d1 := ret // Half_base + v11 \\ Half_base + v21 \\ Half_base
		  d2 := d1 \\ Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + ret \\ Half_base
		  d2 := d2 + v11 // Half_base + v21 // Half_base + (v12 * v22)
	       end
	       d3 := d1 + retenue
	       if d3 >= Base or else d3 < 0 then
		  retenue := d2 + 1
		  temp_after_mult.put(d3 - Base, i)
	       else
		  retenue := d2
		  temp_after_mult.put(d3, i)
	       end
	    else
	       if retenue >= Base or else retenue < 0 then
		  temp_after_mult.put(retenue - Base, i)
	       else
		  temp_after_mult.put(retenue, i)
	       end
	    end
	 end
	 if temp_after_mult.item(temp_after_mult.upper) = 0 then
	    temp_after_mult.remove_last
	 end
      ensure
	 internal_correct_fixed(temp_after_mult)
      end

   mult_fixed_with_integer_in(fa1: FAST_ARRAY[INTEGER]; int: INTEGER; fa2: FAST_ARRAY[INTEGER]) is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- result is stored in fa2
	 -- Make after the multiplication between a large_integer and
	 -- a small_integer i shift and return the result in fa2 to have a
	 -- good memory gestion.
	 -- Use this function if you know that larger is greater than
	 -- smaller.
      require
	 fa1 /= Void
	 fa2 /= Void
	 int > 0
      local
	 v11, v12, v13, v21, v22, v23: INTEGER
	 ret, retenue: INTEGER
	 d1, d2, d3: INTEGER
	 i, bsup : INTEGER
      do
	 fa2.resize(((fa1.item(fa1.upper).log10.truncated_to_integer + int.log10.truncated_to_integer + 9 * (fa1.count - 1) + 2) / 9).ceiling)
	 from
	    v11 := int // (Half_base_2)
	    v13 := int \\ (Half_base_2)
	    v12 := v13 // Half_base
	    v13 := v13 \\ Half_base
	    i := fa2.lower - 1
	    retenue := 0
	    bsup := fa1.upper
	 until
	    i = fa2.upper
	 loop
	    i := i + 1
	    if (i <= bsup) then
	       v21 := fa1.item(i) // (Half_base_2)
	       v23 := fa1.item(i) \\ (Half_base_2)
	       v22 := v23 // Half_base
	       v23 := v23 \\ Half_base

	       if Rest_base = 10 then
		  d1 := v23 * v12 + v13 * v22
		  d2 := d1 // Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + v23 * v13
		  if d1 >= 2 * Half_base_2 then
		     d1 := d1 - (2 * (Half_base_2))
		     ret := 2
		  else
		     if d1 >= Half_base_2 then
			d1 := d1 - Half_base_2
			ret := 1
		     else
			ret := 0
		     end
		  end
		  d2 := ret + d2 + (v23 * v11) + (v13 * v21) + (v12 * v22) + ((v11 * v22) \\ Half_base) * Half_base + ((v21 * v12) \\ Half_base) * Half_base
		  d3 := (v11 * v22) // Half_base + (v21 * v12) // Half_base + v11 * v21
		  ret := d2 // Rest_base
		  d1 := d1 + (d2 - (ret * Rest_base)) * (Half_base_2)
		  d2 := d3 * (Half_base_2 // Rest_base) + ret
	       else
		  ret := v13 * v23
		  v11 := v12 * v23
		  v21 := v22 * v13
		  d1 := ret // Half_base + v11 \\ Half_base + v21 \\ Half_base
		  d2 := d1 \\ Half_base
		  d1 := (d1 - (d2 * Half_base)) * Half_base + ret \\ Half_base
		  d2 := d2 + v11 // Half_base + v21 // Half_base + (v12 * v22)
	       end
	       d3 := d1 + retenue
	       if d3 >= Base or else d3 < 0 then
		  retenue := d2 + 1
		  fa2.put(d3 - Base, i)
	       else
		  retenue := d2
		  fa2.put(d3, i)
	       end
	    else
	       if retenue >= Base or else retenue < 0 then
		  fa2.put(retenue - Base, i)
	       else
		  fa2.put(retenue, i)
	       end
	    end
	 end
	 if fa2.item(fa2.upper) = 0 then
	    fa2.remove_last
	 end
      ensure
	 internal_correct_fixed(fa2)
      end

   mult_2_fixed(fa1, fa2: FAST_ARRAY[INTEGER]): FAST_ARRAY[INTEGER] is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- Give a FAST_ARRAY[INTEGER] for the creation of an
	 -- large_integer after the multiplication of 2 large_integer.
      require
	 fa1 /= Void
	 fa2 /= Void
      local
	 i : INTEGER
      do
	 !!Result.make(((fa1.item(fa1.upper).log10.truncated_to_integer + 9 * (fa1.count - 1) + fa2.item(fa2.upper).log10.truncated_to_integer + 9 * (fa2.count - 1) + 2) / 9).ceiling)
	 from
	    mult_fixed_with_integer_in(fa1, fa2.item(fa2.upper), Result)
	    i := fa2.upper - 1
	 until
	    i < 0
	 loop
	    shift(Result)
	    if (fa2.item(i) /= 0) then
	       mult_fixed_with_integer_in(fa1, fa2.item(i), temp_from_mult)
	       add_fixed_arrays_in_himself(temp_from_mult, Result)
	    end
	    i := i - 1
	 end
      ensure
	  internal_correct_fixed(Result)
      end

   mult_2_fixed_in_temp(fa1, fa2: FAST_ARRAY[INTEGER]) is
	 -- only a tool used by some features in positive and negative
	 -- large integers
	 -- Warning : temp can be an empty array if result is zero
	 -- Result is stored in temp_after_mult
	 -- Make the multiplication between 2 large_integer and the
	 -- result is stored in tmp_from_div to have a good memory gestion
      require
	 fa1 /= Void
	 fa2 /= Void
      local
	 i : INTEGER
      do
	 from
	    mult_fixed_with_integer_in(fa1, fa2.item(fa2.upper), temp_after_mult)
	    i := fa2.upper - 1
	 until
	    i < 0
	 loop
	    shift(temp_after_mult)
	    if (fa2.item(i) /= 0) then
	       mult_fixed_with_integer_in(fa1, fa2.item(i), temp_from_mult)
	       add_fixed_arrays_in_himself(temp_from_mult, temp_after_mult)
	    end
	    i := i - 1
	 end
      ensure
	  internal_correct_fixed(temp_after_mult)
      end

   -- constants for integer division

   fa_one: FAST_ARRAY[INTEGER] is
      once
	 !!Result.make(0)
	 Result.add_last(1)
      ensure
	 Result /= Void and then (Result.item(0) = 1)
      end

   divise_fixed_array(dividende, divisor : FAST_ARRAY[INTEGER]) is
	 -- quotient is stored in temp_quotient, remainder in temp_remainder
	 -- Make the division between 2 abstract_integer.
	 -- quotient is stored in temp_quotient.
	 -- remainder is stored in temp_remainder.
      require
	 dividende /= Void
	 internal_correct_fixed(dividende)
	 divisor /= Void
	 internal_correct_fixed(divisor)
	 divisor.upper >= 0
      local
	 double_num, double_den, approx : DOUBLE
	 n, val: INTEGER
	 t, td: BOOLEAN
      do
	 if fixed_array_greater_than(divisor, dividende) then
	    temp_quotient.resize(0)
	    temp_remainder.copy(dividende)
	 elseif dividende.is_equal(divisor) then
	    temp_quotient.copy(fa_one)
	    temp_remainder.resize(0)
	 else
	    from
	       temp_remainder.copy(dividende)
	       temp_quotient.resize(0)
	       t := True
	    until
	       (temp_remainder.upper < 0)
		  or else fixed_array_greater_than(divisor, temp_remainder)
	    loop
	       n := temp_remainder.upper - divisor.upper
	       if (n = 0) then
		  double_num := temp_remainder.item(temp_remainder.upper)
		  double_den := divisor.item(divisor.upper)
		  if (divisor.upper > 0) then
		     double_num := (double_num * Double_base)
			+ temp_remainder.item(temp_remainder.upper - 1)
		     double_den := (double_den * Double_base)
			+ divisor.item(divisor.upper - 1)
		  end
	       else
		  double_num := temp_remainder.item(temp_remainder.upper)
		  double_num := (double_num * Double_base)
		     + temp_remainder.item(temp_remainder.upper - 1)
		  double_den := divisor.item(divisor.upper)
		  n := n - 1
	       end
	       approx := double_num / (double_den + 1)
	       if approx < 1 then
		  approx := 1.01
	       end
	       if (approx >= Double_base) then
		  temp_2_digints.put((approx / Double_base).truncated_to_integer, 1)
		  temp_2_digints.put((approx - (Double_base * temp_2_digints.item(1))).truncated_to_integer, 0)
		  td := False
		  if t then
		     t := False
		     temp_quotient.resize(2 + n)
		  end
	       else
		  val := approx.truncated_to_integer
		  td := True
		  if t then
		     t := False
		     temp_quotient.resize(1 + n)
		  end
	       end
	       if td then
		  add_fixed_array_with_integer_in_himself_from(val, temp_quotient, n)
		  mult_fixed_with_integer_in_temp(divisor, val)
	       else
		  add_fixed_arrays_in_himself_from(temp_2_digints, temp_quotient, n)
		  mult_2_fixed_in_temp(temp_2_digints, divisor)
	       end
	       difference_between_fixed_arrays_in_himself_from(temp_remainder, temp_after_mult, n)
	    end
	 end
      ensure
	 internal_correct_fixed(temp_remainder)
	 internal_correct_fixed(temp_quotient)
      end

   shift(fa: FAST_ARRAY[INTEGER]) is
      require
	 fa /= Void
      local
	 i : INTEGER
      do
	 from
	    i := fa.upper
	    fa.resize(fa.upper + 2)
	 until
	    i < 0
	 loop
	    fa.put(fa.item(i), i + 1)
	    i := i - 1
	 end
	 fa.put(0,0)
      end

feature {NONE} -- Comparison tools

   fixed_array_greater_than(fa1, fa2: FAST_ARRAY[INTEGER]): BOOLEAN is
      require
	 fa1 /= Void
	 internal_correct_fixed(fa1)
	 fa2 /= Void
	 internal_correct_fixed(fa2)
      local
	 i : INTEGER
      do
	 if (fa1.upper = fa2.upper) then
	    from
	       i := fa1.upper
	    until
	       (i < 0) or else ( (fa1 @ i) /= (fa2 @ i) )
	    loop
	       i := i - 1
	    end
	    Result := (i >= 0) and then ((fa1 @ i) > (fa2 @ i))
	 else
	    Result := fa1.upper > fa2.upper
	 end
      end


feature{NUMBER} -- validity check

   internal_correct_fixed(fa: FAST_ARRAY[INTEGER]): BOOLEAN is
      do
	 Result := correct_fixed(fa)
		    or else ((fa.upper = 0) and then (fa.item(0) /= 0))
		    or else (fa.upper = -1)
      end

   correct_fixed(fa: FAST_ARRAY[INTEGER]): BOOLEAN is
      local
	 i : INTEGER
      do
	 from
	    i := fa.upper
	    Result := ((fa.upper >= 1) and then (fa.item(fa.upper) /= 0 ))
	 until
	    (i < 0) or else (not Result)
	 loop
	    Result := (fa.item(i) >= 0)
	    i := i - 1
	 end
      end

feature {NONE}

   storage : FAST_ARRAY[INTEGER]

   view: STRING is
	 -- for debugging only
	 -- print storage contents
      local
	 i : INTEGER
      do
	 !!Result.make(0) 
	 from
	    i := storage.lower
	 variant
	    storage.upper - i
	 until
	    i > storage.upper
	 loop
	    Result.append( i.to_string ) 
	    Result.append( once " -> " ) 
	    Result.append( storage.item(i).to_string ) 
	    Result.append_character('%N') 
	    i := i + 1 
	 end
      end

invariant

   correct_fixed(storage)

end -- LARGE_INTEGER
