/src/lib/numeric/mutable_big_integer.e
http://github.com/tybor/Liberty · Specman e · 3242 lines · 2778 code · 118 blank · 346 comment · 173 complexity · 1607f00f3277ea7f98b3afbcb3c85bf5 MD5 · raw file
Large files are truncated click here to view the full file
- -- This file is part of a Liberty Eiffel library.
- -- See the full copyright at the end.
- --
- class MUTABLE_BIG_INTEGER
- --
- -- A class used to represent multiprecision integers that makes efficient use of allocated space
- -- by allowing a number to occupy only part of an array so that the arrays do not have to be
- -- reallocated as often. When performing an operation with many iterations the array used to
- -- hold a number is only reallocated when necessary and does not have to be the same size as
- -- the number it represents. A mutable number allows calculations to occur on the same number
- -- without having to create a new number for every step of the calculation as it occurs with
- -- NUMBERs.
- --
- inherit
- HASHABLE
- redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory
- end
- COMPARABLE
- redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory, is_equal
- end
- insert
- PLATFORM
- redefine copy, fill_tagged_out_memory, out_in_tagged_out_memory, is_equal
- end
- create {ANY}
- from_integer, from_integer_64, from_string, copy
- feature {ANY} -- Creation / initialization from INTEGER_32 or INTEGER_64:
- from_integer (value: INTEGER)
- -- Create or initialize `Current' using `value' as an initializer.
- do
- if capacity = 0 then
- storage := storage.calloc(4)
- capacity := 4
- end
- offset := 0
- if value > 0 then
- negative := False
- put(value, 0)
- integer_length := 1
- elseif value < 0 then
- negative := True
- put(#-value, 0)
- integer_length := 1
- else
- check
- value = 0
- end
- set_with_zero
- end
- ensure
- to_integer_32 = value
- end
- is_integer_32: BOOLEAN
- -- Does `Current' fit on an INTEGER_32?
- do
- if integer_length = 0 then
- Result := True
- elseif integer_length = 1 then
- if item(offset) > 0 then
- Result := True
- elseif negative then
- Result := item(offset) = 0x80000000
- end
- end
- ensure
- Result implies is_integer_64
- Result implies integer_length <= 1
- end
- to_integer_32: INTEGER
- -- Convert `Current' as a 32 bit INTEGER.
- require
- is_integer_32
- do
- if integer_length > 0 then
- Result := item(offset)
- if negative then
- Result := #-Result
- end
- end
- end
- from_integer_64 (value: INTEGER_64)
- -- Create or set `Current' using `value' as an initializer.
- local
- v32: INTEGER
- do
- if capacity < 2 then
- storage := storage.calloc(4)
- capacity := 4
- end
- if value > 0 then
- negative := False
- put(value.low_32, 0)
- offset := 0
- v32 := value.high_32
- if v32 = 0 then
- integer_length := 1
- else
- put(v32, 1)
- integer_length := 2
- end
- elseif value < 0 then
- negative := True
- put((#-value).low_32, 0)
- offset := 0
- v32 := (#-value).high_32
- if v32 = 0 then
- integer_length := 1
- else
- put(v32, 1)
- integer_length := 2
- end
- else
- check
- value = 0
- end
- set_with_zero
- end
- ensure
- to_integer_64 = value
- end
- is_integer_64: BOOLEAN
- -- Does `Current' fit on an INTEGER_64?
- do
- if integer_length <= 1 then
- Result := True
- elseif integer_length = 2 then
- if negative then
- if item(offset + 1) > 0 then
- Result := True
- elseif item(offset) = 0 then
- Result := item(offset + 1) = 0x80000000
- end
- else
- Result := item(offset + 1) > 0
- end
- end
- ensure
- not Result implies not is_integer_32
- Result implies integer_length <= 2
- end
- to_integer_64: INTEGER_64
- -- Convert `Current' as a INTEGER_64.
- require
- is_integer_64
- local
- v: INTEGER_64
- do
- inspect
- integer_length
- when 0 then
- when 1 then
- Result := unsigned_32_to_integer_64(item(offset))
- if negative then
- Result := -Result
- end
- when 2 then
- Result := unsigned_32_to_integer_64(item(offset))
- v := item(offset + 1)
- v := v.bit_shift_left(32)
- Result := Result.bit_xor(v)
- if negative then
- Result := #-Result
- end
- end
- end
- feature {ANY} -- Creation / initialization from STRING:
- from_string (str: STRING)
- -- Create or initialize `Current' using `value' as an
- -- initializer. (value = [-][0-9]^+)
- local
- i: INTEGER; cc: CHARACTER; neg: BOOLEAN; ten: like Current
- do
- --|*** This feature should be improved one day... (Vincent Croizier, 25/12/2004)
- create ten.from_integer(10)
- from
- i := 1
- variant
- str.count - i
- until
- not str.item(i).is_separator
- loop
- i := i + 1
- end
- cc := str.item(i)
- i := i + 1
- if cc = '+' then
- cc := str.item(i)
- i := i + 1
- elseif cc = '-' then
- neg := True
- cc := str.item(i)
- i := i + 1
- end
- check
- cc.is_digit
- end
- from_integer(cc.value)
- from
- variant
- str.count - i
- until
- i > str.count
- loop
- cc := str.item(i)
- if cc.is_digit then
- multiply(ten)
- add_integer(cc.value)
- else
- check
- cc.is_separator
- end
- i := str.count -- terminate the loop
- end
- i := i + 1
- end
- if neg then
- negate
- end
- end
- feature {ANY} -- Conversion tool
- force_to_real_64: REAL_64
- -- only a tool
- -- unsigned conversion *** require ou changer export ? *** (Dom Oct 4th 2004) ***
- local
- i: INTEGER
- do
- from
- i := offset + integer_length - 1
- until
- i < offset or else Result > Maximum_real_64
- loop
- Result := Result * Real_base + unsigned_32_to_integer_64(storage.item(i)).force_to_real_64
- i := i - 1
- end
- if Result = Maximum_real_64 and then storage.item(offset) /= 0 then
- Result := Maximum_real_64 * 2
- end
- if negative then
- Result := -Result
- end
- end
- feature {NUMBER}
- from_native_array (na: NATIVE_ARRAY[INTEGER]; cap: INTEGER; neg: BOOLEAN)
- require
- na.item(cap - 1) /= 0
- do
- negative := neg
- offset := 0
- integer_length := cap
- if cap > capacity then
- capacity := capacity_from_lower_bound(capacity, cap)
- storage := storage.calloc(capacity)
- end
- storage.slice_copy(0, na, 0, cap - 1)
- end
- to_integer_general_number: INTEGER_GENERAL_NUMBER
- local
- na: like storage
- do
- if is_integer_64 then
- create {INTEGER_64_NUMBER} Result.make(to_integer_64)
- else
- na := storage.calloc(integer_length)
- na.slice_copy(0, storage, offset, offset + integer_length - 1)
- create {BIG_INTEGER_NUMBER} Result.from_native_array(na, integer_length, negative)
- end
- end
- feature {ANY} -- Addition:
- add (other: like Current)
- -- Add `other' into `Current'.
- --
- -- See also `add_integer', `add_integer_64', `add_natural'.
- require
- other /= Void
- do
- -- Choose the appropriate absolute operator depending on `Current' and `other' sign.
- if other.integer_length = 0 then
- -- Nothing to do, `Current' remains unchanged.
- elseif integer_length = 0 then
- -- `Current' is zero so simply copy the value of other
- Current.copy(other)
- elseif negative = other.negative then
- -- same sign
- add_magnitude(other)
- else
- -- different sign
- subtract_magnitude(other)
- end
- end
- add_to (other, res: like Current)
- -- Add `other' and `Current', and put the result in `res'.
- require
- other /= Void
- res /= Void
- res /= Current
- res /= other
- do
- --|*** Must be optimized later (Vincent Croizier, 15/07/04) ***
- res.copy(Current)
- res.add(other)
- end
- add_integer (other: INTEGER)
- -- Add `other' into `Current'.
- local
- inc: BOOLEAN; v, i, n: INTEGER
- do
- if other = 0 then
- -- Nothing to do, `Current' remains unchanged
- elseif integer_length = 0 then
- -- `Current' is null so simply copy the value of other
- from_integer(other)
- elseif negative = (other < 0) then
- -- Same sign
- if other < 0 then
- v := #-other
- else
- v := other
- end
- -- Add `v' into `storage'
- from
- inc := mbi_add(item(offset), v, storage_at(storage, offset))
- i := offset + 1
- n := offset + integer_length
- until
- not inc or else i >= n
- loop
- inc := mbi_inc(storage_at(storage, i))
- i := i + 1
- end
- if inc then
- check
- i = n
- end
- -- Extend the number length by 1
- if n < capacity then
- integer_length := integer_length + 1
- put(1, n)
- else
- -- It's good only if the reallocation initialize
- -- `storage' with 0.
- v := item(offset)
- capacity := capacity * 2
- storage := storage.calloc(capacity)
- offset := 0
- put(v, 0)
- put(1, integer_length)
- integer_length := integer_length + 1
- end
- end
- -- Different sign
- elseif integer_length = 1 then
- if other < 0 then
- v := #-other
- else
- v := other
- end
- if mbi_subtract(item(offset), v, storage_at(storage, offset)) then
- negative := not negative
- put(-item(offset), offset)
- end
- if item(offset) = 0 then
- integer_length := 0
- negative := False
- end
- else
- if other < 0 then
- v := #-other
- else
- v := other
- end
- if mbi_subtract(item(offset), v, storage_at(storage, offset)) then
- from
- i := offset + 1
- inc := mbi_dec(storage_at(storage, i))
- n := offset + integer_length - 1
- until
- not inc
- loop
- check
- i < n
- end
- i := i + 1
- inc := mbi_dec(storage_at(storage, i))
- end
- if item(n) = 0 then
- integer_length := integer_length - 1
- end
- end
- end
- end
- add_integer_64 (other: INTEGER_64)
- -- Add `other' into `Current'.
- do
- register1.from_integer_64(other)
- add(register1)
- end
- add_natural (other: like Current)
- -- Same behavior as `add', but this one works only when `Current'
- -- and `other' are both positive numbers and are both greater than
- -- zero. The only one advantage of using `add_natural' instead of the
- -- general `add' is the gain of efficiency.
- require
- not is_zero and not is_negative
- not other.is_zero and not other.is_negative
- do
- add_magnitude(other)
- end
- feature {ANY} -- Subtract:
- subtract (other: like Current)
- -- Subtract `other' from `Current'.
- require
- other /= Void
- do
- if other = Current then
- set_with_zero
- elseif other.integer_length = 0 then
- -- nothing to do, `Current' remains unchanged
- elseif integer_length = 0 then
- -- current is null so simply copy the value of other, the sign is also fixed
- copy(other)
- negative := not other.negative
- elseif negative = other.negative then
- -- same sign
- subtract_magnitude(other)
- else
- -- different sign
- add_magnitude(other)
- end
- end
- subtract_to (other, res: like Current)
- -- Subtract `other' from `Current' and put it in `res'.
- require
- other /= Void
- res /= Void
- res /= Current
- res /= other
- do
- --|*** Must be optimized later (Vincent Croizier, 15/07/04) ***
- res.copy(Current)
- res.subtract(other)
- end
- subtract_integer (other: INTEGER)
- do
- if other = Minimum_integer then
- add_integer(1)
- add_integer(Maximum_integer)
- else
- add_integer(-other)
- end
- end
- feature {ANY} -- To divide:
- divide (other: like Current)
- -- Put the quotient of the Euclidian division of
- -- `Current' by `other' in `Current'.
- -- (The contents of `other' is not changed.)
- require
- not other.is_zero
- other /= Current
- do
- -- `divide_with_remainder_to' already uses `register1'.
- divide_with_remainder_to(other, register2)
- end
- mod (other: like Current)
- -- Put the remainder of the Euclidian division of
- -- `Current' by `other' in `Current'.
- -- (The contents of `other' is not changed.)
- require
- not other.is_zero
- other /= Current
- local
- quotient: like Current
- do
- --|*** Must be optimized (Vincent Croizier, 12/07/04) ***
- create quotient.from_integer(0)
- remainder_with_quotient_to(other, quotient)
- ensure
- not negative and abs_compare(other) = -1
- end
- divide_with_remainder_to (other, remainder: like Current)
- -- Euclidian division.
- -- Calculates the `quotient' and `remainder' of `Current'
- -- divided by `other'.
- -- Quotient is put in `Current'.
- -- (The contents of `other' is not changed.)
- require
- not other.is_zero
- remainder /= Void
- remainder /= other
- remainder /= Current
- do
- Current.remainder_with_quotient_to(other, remainder)
- Current.swap_with(remainder)
- ensure
- not remainder.negative and remainder.abs_compare(other) = -1
- end
- remainder_with_quotient_to (other, quotient: like Current)
- -- Euclidian division.
- -- Calculates the `quotient' and `remainder' of `Current'
- -- divided by `other'.
- -- Remainder is put in `Current'.
- -- (The contents of `other' is not changed.)
- --
- -- Note: Uses Algorithm D in Knuth section 4.3.1.
- require
- not other.is_zero
- quotient /= Void
- quotient /= other
- quotient /= Current
- local
- cmp, shift, dlen, qlen, j, k, v1, v2, u1, u2, rem: INTEGER; qhat, rhat, v2qhat_1, v2qhat_2, d_offset: INTEGER
- q_storage, d_storage: like storage; q_capacity: like capacity; current_negative, borrow: BOOLEAN
- do
- if integer_length = 0 then
- -- Dividend is zero:
- quotient.set_with_zero
- set_with_zero
- else
- current_negative := negative
- cmp := Current.abs_compare(other)
- if cmp < 0 then
- -- Dividend less than divisor:
- quotient.set_with_zero
- -- Sign correction
- set_negative(False)
- divide_sign_correction_bis(other, quotient, current_negative)
- elseif cmp = 0 then
- -- Dividend equal to divisor:
- if negative = other.negative then
- quotient.from_integer(1)
- else
- quotient.from_integer(-1)
- end
- set_with_zero
- elseif other.integer_length = 1 then
- -- Special case one word divisor:
- quotient.swap_with(Current)
- --|*** replace by "from_unsigned_integer" ? (Vincent Croizier)
- set_with_zero
- rem := quotient.divide_one_word(other.item(other.offset))
- if rem /= 0 then
- put(rem, 0)
- set_integer_length(1)
- else
- check
- is_zero
- end
- end
- -- Sign correction
- divide_sign_correction_bis(other, quotient, current_negative)
- else
- -- Copy divisor storage to protect divisor:
- register1.copy(other)
- -- D1 normalize the divisor:
- shift := register1.normalize
- if shift /= 0 then
- shift_left(shift)
- end
- -- D2 Initialize j:
- from
- d_storage := register1.storage
- d_offset := register1.offset
- dlen := register1.integer_length
- j := offset + integer_length - 1
- u2 := storage.item(j)
- k := register1.offset + dlen - 1
- v1 := register1.item(k)
- v2 := register1.item(k - 1)
- if unsigned_greater_or_equal(u2, v1) then
- k := integer_length - dlen
- qlen := k + 1
- else
- qlen := integer_length - dlen
- k := qlen - 1
- j := j - 1
- u1 := u2
- u2 := storage.item(j)
- end
- -- Resize quotient if necessary
- q_capacity := quotient.capacity
- if q_capacity < qlen then
- -- reallocation
- q_capacity := capacity_from_lower_bound(q_capacity, qlen)
- q_storage := storage.calloc(q_capacity)
- else
- q_storage := quotient.storage
- end
- -- To avoid invariant violation on `quotient'
- quotient.set_with_zero
- until
- k < 0
- loop
- j := j - 1 -- D3 Calculate qhat - estimate qhat
- if u1 = v1 then
- qhat := ~0
- else
- qhat := mbi_divide(u1, u2, v1, $rhat) -- Correct qhat
- if qhat = 0 then
- else
- v2qhat_1 := mbi_multiply(v2, qhat, $v2qhat_2)
- if unsigned_greater_than(v2qhat_1, rhat) then
- qhat := qhat - 1
- if mbi_subtract(v2qhat_2, v2, $v2qhat_2) then
- v2qhat_1 := v2qhat_1 - 1
- end
- if mbi_add(rhat, v1, $rhat) then
- elseif unsigned_greater_than(v2qhat_1, rhat) then
- qhat := qhat - 1
- elseif j < 0 then
- if v2qhat_1 = rhat and then v2qhat_2 /= 0 then
- qhat := qhat - 1
- end
- elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, storage.item(j)) then
- qhat := qhat - 1
- end
- elseif j < 0 then
- if v2qhat_1 = rhat and then v2qhat_2 /= 0 then
- qhat := qhat - 1
- end
- elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, storage.item(j)) then
- qhat := qhat - 1
- end
- end
- end
- -- D4 Multiply and subtract:
- if qhat = 0 then
- q_storage.put(0, k)
- else
- borrow := multiply_and_subtract(u1, qhat, d_storage, d_offset, storage, j - dlen + 2, dlen)
- -- D5 Test remainder: Result is negative ?
- if borrow then
- -- D6 Add back
- borrow := add_back(u1, d_storage, d_offset, storage, j - dlen + 2, dlen)
- check
- borrow
- end
- q_storage.put(qhat - 1, k)
- else
- q_storage.put(qhat, k)
- end
- end
- -- D7 loop on j
- k := k - 1
- u1 := storage.item(j + 1)
- u2 := storage.item(j)
- end
- -- Remove leading zero of quotient
- k := qlen - 1
- if q_storage.item(k) = 0 then
- qlen := k
- end
- quotient.set_all(q_storage, q_capacity, qlen, 0, False)
- -- Remove leading zero of remainder
- from
- j := dlen - 1
- until
- j < 0 or else storage.item(j) /= 0
- loop
- j := j - 1
- end
- j := j + 1
- check
- j >= 0
- end
- if j = 0 then
- set_with_zero
- else
- offset := 0
- integer_length := j
- negative := False
- end
- -- D8 Unnormalize:
- if shift > 0 then
- shift_right(shift)
- end
- -- Sign correction
- divide_sign_correction_bis(other, quotient, current_negative)
- end
- end
- ensure
- not negative and abs_compare(other) = -1
- end
- divide_to (other, quotient, remainder: like Current)
- -- Euclidian division.
- -- Calculates the `quotient' and `remainder' of `Current'
- -- divided by `other'. (The contents of `Current' and `other' are
- -- not changed.)
- --
- -- Note: Uses Algorithm D in Knuth section 4.3.1.
- require
- not other.is_zero
- quotient /= Void
- remainder /= Void
- quotient /= other
- quotient /= Current
- remainder /= other
- remainder /= Current
- local
- cmp, shift, nlen, dlen, qlen, j, k, v1, v2, u1, u2, rem: INTEGER
- qhat, rhat, v2qhat_1, v2qhat_2, d_offset: INTEGER; q_storage, r_storage, d_storage: like storage
- q_capacity, r_capacity: like capacity; borrow: BOOLEAN
- do
- if integer_length = 0 then
- -- Dividend is zero:
- quotient.set_with_zero
- remainder.set_with_zero
- else
- cmp := Current.abs_compare(other)
- if cmp < 0 then
- -- Dividend less than divisor:
- quotient.set_with_zero
- remainder.copy(Current)
- -- Sign correction
- remainder.set_negative(False)
- divide_sign_correction(other, quotient, remainder)
- elseif cmp = 0 then
- -- Dividend equal to divisor:
- if negative = other.negative then
- quotient.from_integer(1)
- else
- quotient.from_integer(-1)
- end
- remainder.set_with_zero
- elseif other.integer_length = 1 then
- -- Special case one word divisor:
- quotient.copy(Current)
- --|*** replace by "from_unsigned_integer" ? (Vincent Croizier)
- remainder.set_with_zero
- rem := quotient.divide_one_word(other.item(other.offset))
- if rem /= 0 then
- remainder.put(rem, 0)
- remainder.set_ilo(1, 0)
- else
- check
- remainder.is_zero
- end
- end
- -- Sign correction
- divide_sign_correction(other, quotient, remainder)
- else
- -- Copy divisor storage to protect divisor:
- register1.copy(other)
- --|***
- remainder.copy(Current)
- -- D1 normalize the divisor:
- shift := register1.normalize
- if shift /= 0 then
- remainder.shift_left(shift)
- end
- -- D2 Initialize j:
- from
- r_storage := remainder.storage
- r_capacity := remainder.capacity
- check
- remainder.offset = 0
- end
- nlen := remainder.integer_length -- To avoid invariant class violation
- remainder.set_with_zero
- d_storage := register1.storage
- d_offset := register1.offset
- dlen := register1.integer_length
- j := nlen - 1
- u2 := r_storage.item(j)
- k := register1.offset + dlen - 1
- v1 := register1.item(k)
- v2 := register1.item(k - 1)
- if unsigned_greater_or_equal(u2, v1) then
- k := nlen - dlen
- qlen := k + 1
- else
- qlen := nlen - dlen
- k := qlen - 1
- j := j - 1
- u1 := u2
- u2 := r_storage.item(j)
- end
- -- Resize quotient if necessary
- q_capacity := quotient.capacity
- if q_capacity < qlen then
- -- reallocation
- q_capacity := capacity_from_lower_bound(q_capacity, qlen)
- q_storage := storage.calloc(q_capacity)
- else
- q_storage := quotient.storage
- end
- -- To avoid invariant violation on `quotient'
- quotient.set_with_zero
- until
- k < 0
- loop
- j := j - 1 -- D3 Calculate qhat - estimate qhat
- if u1 = v1 then
- qhat := ~0
- else
- qhat := mbi_divide(u1, u2, v1, $rhat) -- Correct qhat
- if qhat = 0 then
- else
- v2qhat_1 := mbi_multiply(v2, qhat, $v2qhat_2)
- if unsigned_greater_than(v2qhat_1, rhat) then
- qhat := qhat - 1
- if mbi_subtract(v2qhat_2, v2, $v2qhat_2) then
- v2qhat_1 := v2qhat_1 - 1
- end
- if mbi_add(rhat, v1, $rhat) then
- elseif unsigned_greater_than(v2qhat_1, rhat) then
- qhat := qhat - 1
- elseif j < 0 then
- if v2qhat_1 = rhat and then v2qhat_2 /= 0 then
- qhat := qhat - 1
- end
- elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, r_storage.item(j)) then
- qhat := qhat - 1
- end
- elseif j < 0 then
- if v2qhat_1 = rhat and then v2qhat_2 /= 0 then
- qhat := qhat - 1
- end
- elseif v2qhat_1 = rhat and then unsigned_greater_than(v2qhat_2, r_storage.item(j)) then
- qhat := qhat - 1
- end
- end
- end
- -- D4 Multiply and subtract:
- if qhat = 0 then
- q_storage.put(0, k)
- else
- borrow := multiply_and_subtract(u1, qhat, d_storage, d_offset, r_storage, j - dlen + 2, dlen)
- -- D5 Test remainder: Result is negative ?
- if borrow then
- -- D6 Add back
- borrow := add_back(u1, d_storage, d_offset, r_storage, j - dlen + 2, dlen)
- check
- borrow
- end
- q_storage.put(qhat - 1, k)
- else
- q_storage.put(qhat, k)
- end
- end
- -- D7 loop on j
- k := k - 1
- u1 := r_storage.item(j + 1)
- u2 := r_storage.item(j)
- end
- -- Remove leading zero of quotient
- k := qlen - 1
- if q_storage.item(k) = 0 then
- qlen := k
- end
- quotient.set_all(q_storage, q_capacity, qlen, 0, False)
- -- Remove leading zero of remainder
- from
- j := dlen - 1
- until
- j < 0 or else r_storage.item(j) /= 0
- loop
- j := j - 1
- end
- j := j + 1
- check
- j >= 0
- end
- if j = 0 then
- check
- remainder.is_zero
- end
- else
- remainder.set_all(r_storage, r_capacity, j, 0, False)
- end
- -- D8 Unnormalize:
- if shift > 0 then
- remainder.shift_right(shift)
- end
- -- Sign correction
- divide_sign_correction(other, quotient, remainder)
- end
- end
- ensure
- is_a_good_divide(other, quotient, remainder)
- not remainder.negative and remainder.abs_compare(other) = -1
- end
- shift_left (n: INTEGER)
- -- Shift bits of magnitude by `n' position left. (Note that no bit can
- -- be lost because the `storage' area is automatically extended when
- -- it is necessary.)
- require
- n > 0
- local
- new_storage: like storage; left, right: INTEGER_8
- new_capacity, new_integer_length, new_head, word_shift, i, j, k, val1, val2, val3: INTEGER
- do
- if integer_length > 0 then
- word_shift := n |>>> 5
- left := (n & 0x0000001F).to_integer_8 -- Optimistic prediction
- new_integer_length := integer_length + word_shift
- if left = 0 then
- -- Just word shift
- if offset >= word_shift then
- -- no need to deplace the number in the storage
- from
- i := offset
- offset := offset - word_shift
- integer_length := new_integer_length
- until
- i = offset
- loop
- i := i - 1
- put(0, i)
- end
- elseif capacity >= new_integer_length then
- -- deplacing the number
- from
- i := offset + integer_length - 1
- j := word_shift + integer_length - 1
- until
- i < offset
- loop
- put(item(i), j)
- i := i - 1
- j := j - 1
- end
- from
- check
- j = word_shift - 1
- end
- until
- j < 0
- loop
- put(0, j)
- j := j - 1
- end
- offset := 0
- integer_length := new_integer_length
- else
- -- reallocation
- new_capacity := capacity_from_lower_bound(capacity, new_integer_length)
- new_storage := storage.calloc(new_capacity)
- from
- i := offset + integer_length
- j := word_shift + integer_length
- until
- i = offset
- loop
- i := i - 1
- j := j - 1
- new_storage.put(item(i), j)
- end
- storage := new_storage
- capacity := new_capacity
- offset := 0
- integer_length := new_integer_length
- end
- else
- right := 32 - left -- Compute real `integer_length'
- i := offset + integer_length - 1
- val1 := item(i)
- new_head := val1 |>>> right
- if new_head = 0 then
- -- new_integer_length is good
- if capacity < new_integer_length then
- -- reallocation
- new_capacity := capacity_from_lower_bound(capacity, new_integer_length)
- new_storage := storage.calloc(new_capacity)
- from
- j := new_integer_length - 1
- check
- i = offset + integer_length - 1
- j = word_shift + integer_length - 1
- val1 = item(i)
- end
- until
- i = offset
- loop
- i := i - 1
- val2 := item(i)
- new_storage.put(val1 |<< left | (val2 |>>> right), j)
- val1 := val2
- j := j - 1
- end
- new_storage.put(val1 |<< left, j)
- storage := new_storage
- capacity := new_capacity
- offset := 0
- integer_length := new_integer_length
- elseif offset > word_shift then
- from
- check
- j = 0
- end
- until
- j = word_shift
- loop
- put(0, j)
- j := j + 1
- end
- from
- k := offset
- check
- i = offset + integer_length - 1
- j = word_shift
- end
- until
- k = i
- loop
- val3 := item(k)
- put(val3 |<< left | (val2 |>>> right), j)
- val2 := val3
- k := k + 1
- j := j + 1
- end
- put(val1 |<< left | (val2 |>>> right), j)
- offset := 0
- integer_length := new_integer_length
- else
- from
- j := new_integer_length - 1
- check
- i = offset + integer_length - 1
- j = word_shift + integer_length - 1
- val1 = item(i)
- end
- until
- i = offset
- loop
- i := i - 1
- val2 := item(i)
- put(val1 |<< left | (val2 |>>> right), j)
- val1 := val2
- j := j - 1
- end
- put(val1 |<< left, j)
- from
- until
- j = 0
- loop
- j := j - 1
- put(0, j)
- end
- offset := 0
- integer_length := new_integer_length
- end
- else
- new_integer_length := new_integer_length + 1
- if capacity < new_integer_length then
- -- Reallocation
- new_capacity := capacity_from_lower_bound(capacity, new_integer_length)
- new_storage := storage.calloc(new_capacity)
- from
- j := new_integer_length - 2
- check
- i = offset + integer_length - 1
- j = word_shift + integer_length - 1
- val1 = item(i)
- end
- new_storage.put(new_head, j + 1)
- until
- i = offset
- loop
- i := i - 1
- val2 := item(i)
- new_storage.put(val1 |<< left | (val2 |>>> right), j)
- val1 := val2
- j := j - 1
- end
- new_storage.put(val1 |<< left, j)
- storage := new_storage
- capacity := new_capacity
- offset := 0
- integer_length := new_integer_length
- elseif offset > word_shift then
- from
- check
- j = 0
- end
- until
- j = word_shift
- loop
- put(0, j)
- j := j + 1
- end
- from
- k := offset
- check
- i = offset + integer_length - 1
- end
- until
- k = i
- loop
- val3 := item(k)
- put(val3 |<< left | (val2 |>>> right), j)
- val2 := val3
- k := k + 1
- j := j + 1
- end
- put(val1 |<< left | (val2 |>>> right), j)
- put(new_head, j + 1)
- offset := 0
- integer_length := new_integer_length
- else
- from
- j := new_integer_length - 2
- check
- i = offset + integer_length - 1
- j = word_shift + integer_length - 1
- val1 = item(i)
- end
- until
- i = offset
- loop
- i := i - 1
- val2 := item(i)
- put(val1 |<< left | (val2 |>>> right), j)
- val1 := val2
- j := j - 1
- end
- put(val1 |<< left, j)
- put(new_head, new_integer_length - 1)
- from
- until
- j = 0
- loop
- j := j - 1
- put(0, j)
- end
- offset := 0
- integer_length := new_integer_length
- end
- end
- end
- end
- end
- shift_right (n: INTEGER)
- -- Right shift `Current' n bits. (`Current' is left in normal form.)
- require
- n > 0
- local
- n_ints, n_bits: INTEGER
- do
- if integer_length > 0 then
- n_ints := n |>>> 5
- n_bits := n & 0x0000001F
- integer_length := integer_length - n_ints
- offset := offset + n_ints
- if n_bits = 0 then
- else
- primitive_shift_right(n_bits.to_integer_8)
- end
- end
- end
- feature {ANY} -- GCD
- gcd (other: like Current)
- -- Compute GCD of `Current' and `other'.
- -- GCD is put in `Current' (`other' is not modified).
- require
- other /= Void
- do
- if other = Current then
- Current.abs
- elseif other.is_zero then
- Current.abs
- elseif Current.is_zero then
- Current.copy(other)
- Current.abs
- else
- from
- register2.copy(other)
- Current.mod(register2)
- if Current.is_zero then
- Current.swap_with(register2)
- Current.abs
- else
- register2.mod(Current)
- end
- until
- register2.is_zero
- loop
- Current.mod(register2)
- if Current.is_zero then
- Current.swap_with(register2)
- else
- register2.mod(Current)
- end
- end
- end
- ensure
- is_positive or is_zero and other.is_zero
- end
- feature {ANY} -- To multiply:
- multiply (other: like Current)
- -- Multiply `Current' by `other'.
- require
- other /= Void
- do
- if other = Current then
- multiply_to(other, register1)
- swap_with(register1)
- elseif is_zero or other.is_zero then
- set_with_zero
- elseif Current.is_one then
- copy(other)
- elseif other.is_one then
- elseif Current.is_one_negative then
- copy(other)
- set_negative(not negative)
- elseif other.is_one_negative then
- set_negative(not negative)
- else
- --|*** Must be replaced by an algorithm switch. (Vincent Croizier, 09/07/04)
- multiply_like_human(other)
- end
- end
- multiply_to (other, res: like Current)
- -- Multiply the contents of `Current' and `other' and place the
- -- result in `res'. (`Current' and `other' are not modified.)
- require
- other /= Void
- res /= Void
- res /= Current
- do
- if is_zero or other.is_zero then
- res.set_with_zero
- elseif Current.is_one then
- res.copy(other)
- elseif other.is_one then
- res.copy(Current)
- elseif Current.is_one_negative then
- res.copy(other)
- res.set_negative(not res.negative)
- elseif other.is_one_negative then
- res.copy(Current)
- res.set_negative(not negative)
- else
- --|*** Must be replace by an algorithm switch. (Vincent Croizier, 01/05/04)
- multiply_to_like_human(other, res)
- end
- end
- multiply_integer (other: INTEGER; res: like Current)
- -- Multiply the contents of `Current' and `other' and place the
- -- result in `res'. (`Current' is not modified.)
- require
- res /= Current
- res /= Void
- local
- overflow, res_integer_length, res_capacity, i, k, up_i, v: INTEGER; res_storage: like storage
- do
- if other = 0 or else is_zero then
- res.set_with_zero
- elseif other = Minimum_integer then
- res.set_negative(not negative)
- shift_left(31)
- else
- if other > 0 then
- res.set_negative(negative)
- v := other
- else
- res.set_negative(not negative)
- v := -other
- end
- -- Pessimistic estimation
- res_integer_length := integer_length + 1 -- Reallocation ?
- if res.capacity < res_integer_length then
- if capacity < res_integer_length then
- res_capacity := capacity * 2
- else
- res_capacity := capacity_from_upper_bound(capacity, res_integer_length)
- end
- set_capacity(res_capacity)
- res_storage := storage.calloc(res_capacity)
- res.set_storage(res_storage)
- else
- res_storage := res.storage
- end
- res.set_offset(0)
- -- Multiply
- from
- k := 0
- i := offset
- up_i := offset + integer_length - 1
- overflow := mbi_multiply(item(i), v, storage_at(res_storage, k))
- until
- i = up_i
- loop
- i := i + 1
- k := k + 1
- overflow := mbi_multiply_with_add(item(i), v, overflow, storage_at(res_storage, k))
- end
- if overflow = 0 then
- res.set_integer_length(res_integer_length - 1)
- else
- check
- k + 1 = integer_length
- end
- res.put(overflow, integer_length)
- end
- end
- end
- feature {MUTABLE_BIG_INTEGER} -- to multiply
- multiply_like_human (other: like Current)
- -- Simple multiply.
- -- Complexity = O(`integer_length'*`other.integer_length').
- require
- not is_zero
- not other.is_zero
- local
- old_offset, new_integer_length: INTEGER
- do
- -- Pessimistique estimation
- new_integer_length := integer_length + other.integer_length -- Reallocation ?
- if capacity < new_integer_length then
- register1.swap_with(Current)
- register1.multiply_to_like_human(other, Current)
- -- Multiply in place
- elseif offset + new_integer_length <= capacity then
- multiply_like_human_aux_reverse(other)
- elseif offset >= other.integer_length then
- multiply_like_human_aux(other)
- else
- old_offset := offset
- offset := capacity - integer_length
- storage.slice_copy(offset, storage, old_offset, old_offset + integer_length - 1)
- multiply_like_human_aux(other)
- end
- end
- multiply_like_human_aux (other: like Current)
- -- Only used by `multiply_to_like_human'.
- require
- not is_zero
- not other.is_zero
- offset >= other.integer_length
- local
- other_offset, other_integer_length, overflow, i, j, k, up_i, up_j, down_k, v: INTEGER
- other_storage: like storage
- do
- other_offset := other.offset
- other_integer_length := other.integer_length
- other_storage := other.storage -- First pass
- from
- k := 0
- i := other_offset
- up_i := other_offset + other_integer_length - 1
- j := offset
- up_j := offset + integer_length - 1
- v := storage.item(j)
- overflow := mbi_multiply(other_storage.item(i), v, storage_at(storage, k))
- until
- i = up_i
- loop
- i := i + 1
- k := k + 1
- overflow := mbi_multiply_with_add(other_storage.item(i), v, overflow, storage_at(storage, k))
- end
- k := k + 1
- check
- k <= j
- end
- storage.put(overflow, k)
- from
- down_k := 1
- until
- j = up_j
- loop
- j := j + 1
- from
- k := down_k
- i := other_offset
- v := storage.item(j)
- overflow := mbi_multiply_with_add(other_storage.item(i), v, storage.item(k), storage_at(storage, k))
- until
- i = up_i
- loop
- i := i + 1
- k := k + 1
- overflow := mbi_multiply_with_2_add(other_storage.item(i), v, overflow, storage.item(k), storage_at(storage, k))
- end
- k := k + 1
- check
- k <= j
- end
- storage.put(overflow, k)
- down_k := down_k + 1
- end
- -- Adjust `res.integer_length'
- if overflow = 0 then
- integer_length := integer_length + other_integer_length - 1
- else
- integer_length := integer_length + other_integer_length
- end
- negative := negative /= other.negative
- offset := 0
- end
- multiply_like_human_aux_reverse (other: like Current)
- -- Only used by `multiply_to_like_human'.
- require
- not is_zero
- not other.is_zero
- offset + integer_length <= capacity - other.integer_length
- local
- other_offset, other_integer_length, overflow, i, j, k, up_i, down_j, down_k, v: INTEGER
- other_storage: like storage; inc: BOOLEAN
- do
- other_offset := other.offset
- other_integer_length := other.integer_length
- other_storage := other.storage -- First pass
- from…