Files
EWF/contrib/ise_library/math/eapml/readable_integer_x.e
2012-06-15 14:24:23 +02:00

1742 lines
38 KiB
Plaintext

note
description: "Functionality to query the status of an arbitrary precision integer"
author: "Colin LeMahieu"
date: "$Date$"
revision: "$Revision$"
quote: "The urge to save humanity is almost always a false front for the urge to rule. - H.L. Mencken"
deferred class
READABLE_INTEGER_X
inherit
ANY
undefine
default_create,
is_equal,
copy
redefine
out
select
out
end
DEBUG_OUTPUT
undefine
default_create,
is_equal,
copy,
out
redefine
debug_output
end
NUMERIC
rename
plus as plus_value alias "+",
minus as minus_value alias "-",
product as product_value alias "*",
quotient as quotient_value alias "/",
opposite as opposite_value alias "-"
undefine
default_create,
out
redefine
copy,
is_equal
end
COMPARABLE
undefine
default_create,
out
redefine
copy,
is_equal,
three_way_comparison
end
INTEGER_X_ASSIGNMENT
rename
add as add_special,
sub as sub_special,
mul as mul_special,
bit_xor_lshift as bit_xor_lshift_special,
bit_xor as bit_xor_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_ACCESS
rename
add as add_special,
sub as sub_special,
mul as mul_special,
cmp as cmp_special,
tdiv_qr as tdiv_qr_special,
sizeinbase as sizeinbase_special,
bit_xor_lshift as bit_xor_lshift_special,
bit_xor as bit_xor_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_ARITHMETIC
rename
abs as abs_integer_x,
cmp as cmp_special,
bit_xor_lshift as bit_xor_lshift_special,
bit_xor as bit_xor_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_COMPARISON
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_LOGIC
rename
add as add_special,
sub as sub_special,
mul as mul_special,
bit_and as bit_and_integer_x,
bit_complement as bit_complement_integer_x,
bit_or as bit_or_integer_x,
bit_test as bit_test_integer_x,
bit_xor as bit_xor_integer_x,
bit_xor_lshift as bit_xor_lshift_integer_x
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_IO
rename
sizeinbase as sizeinbase_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_RANDOM
rename
add as add_special,
sub as sub_special,
mul as mul_special,
cmp as cmp_special,
bit_xor_lshift as bit_xor_lshift_special,
bit_xor as bit_xor_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_SIZING
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_NUMBER_THEORY
rename
abs as abs_integer_x,
mod as mod_integer_x,
gcd as gcd_integer_x,
bit_and as bit_and_integer_x,
bit_complement as bit_complement_integer_x,
bit_or as bit_or_integer_x,
bit_test as bit_test_integer_x,
bit_xor as bit_xor_integer_x,
powm as powm_integer_x,
bit_xor_lshift as bit_xor_lshift_integer_x,
invert_gf as invert_gf_integer_x
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
INTEGER_X_DIVISION
rename
abs as abs_integer_x,
cmp as cmp_special,
mod as mod_integer_x,
bit_xor_lshift as bit_xor_lshift_special,
bit_xor as bit_xor_special
export
{NONE}
all
undefine
default_create,
is_equal,
copy,
out
end
SPECIAL_UTILITY
export
{INTEGER_X_FACILITIES}
all
undefine
default_create,
is_equal,
copy,
out
end
feature {NONE} -- Initialization
default_create
-- Initialize `Current' to zero
do
create item.make_filled (0, 1)
count := 0
ensure then
zero: is_zero
end
make_set (other: READABLE_INTEGER_X)
-- Initialize `Current' to be a copy of `other'
do
create item.make_filled (0, 0)
set_from_other (other)
ensure
equal: Current ~ other
end
make_from_integer (i: INTEGER)
-- Initialize `Current' from `i'.
do
default_create
set_from_integer (i)
ensure
set: as_integer = i
end
make_from_integer_64 (i: INTEGER_64)
-- Initialize `Current' from `i'.
do
default_create
set_from_integer_64 (i)
ensure
set: as_integer_64 = i
end
make_from_integer_32 (i: INTEGER_32)
-- Initialize `Current' from `i'.
do
default_create
set_from_integer_32 (i)
ensure
set: as_integer_32 = i
end
make_from_integer_16 (i: INTEGER_16)
-- Initialize `Current' from `i'.
do
default_create
set_from_integer_16 (i)
ensure
set: as_integer_16 = i
end
make_from_integer_8 (i: INTEGER_8)
-- Initialize `Current' from `i'.
do
default_create
set_from_integer_8 (i)
ensure
set: as_integer_8 = i
end
make_from_natural (n: NATURAL)
-- Initialize `Current' from `n'.
do
default_create
set_from_natural (n)
ensure
set: as_natural = n
end
make_from_natural_64 (n: NATURAL_64)
-- Initialize `Current' from `n'.
do
default_create
set_from_natural_64 (n)
ensure
set: as_natural_64 = n
end
make_from_natural_32 (n: NATURAL_32)
-- Initialize `Current' from `n'.
do
default_create
set_from_natural_32 (n)
ensure
set: as_natural_32 = n
end
make_from_natural_16 (n: NATURAL_16)
-- Initialize `Current' from `n'.
do
default_create
set_from_natural_16 (n)
ensure
set: as_natural_16 = n
end
make_from_natural_8 (n: NATURAL_8)
-- Initialize `Current' from `n'.
do
default_create
set_from_natural_8 (n)
ensure
set: as_natural_8 = n
end
make_from_string (s: STRING)
-- Initialize `Current' from `s' where `s' is a base 10 string
require
s_not_empty: not s.is_empty
do
default_create
set_str (Current, s, 10)
end
make_from_hex_string (s: STRING)
-- Initialize `Current' from `s' where `s' is a base 16 string
require
s_not_empty: not s.is_empty
do
default_create
set_str (Current, s, 16)
end
make_from_string_base (s: STRING base: INTEGER)
-- Initialize `Current' from `s' where `s' is a string of base `base'
require
s_not_empty: not s.is_empty
base_too_small: base >= 2
base_too_big: base <= 62
do
default_create
set_str (Current, s, base)
end
make_random (bits_a: INTEGER)
-- Initialize as a random number of `bits_a' bits
require
valid_bits: bits_a > 0
do
default_create
set_random (bits_a)
ensure
correct_bits: bits <= bits_a
end
make_random_prime (bits_a: INTEGER)
-- Initialise a random number of `bits_a' bits that is probably prime
require
valid_bits: bits_a > 0
do
default_create
from
set_random (bits_a)
until
is_probably_prime
loop
set_random (bits_a)
end
ensure
prime: is_probably_prime
correct_bits: bits <= bits_a
end
make_from_bytes (bytes_array: SPECIAL[NATURAL_8] first: INTEGER last: INTEGER)
-- Initialize from byte array
require
last_after_first: last >= first
valid_offset: bytes_array.valid_index (first)
valid_end: bytes_array.valid_index (last)
do
default_create
input (Current, last - first + 1, 1, 1, -1, bytes_array, first)
end
make_random_max (max_value: like Current)
--Generate a uniform random integer in the range 0 to max_value-1, inclusive.
require
positive_max: max_value.is_positive
do
default_create
urandomm (Current, random_state, max_value)
ensure
valid_range: Current < max_value
end
make_limbs (limbs: INTEGER)
-- Initialize `Current' with space for `limbs' limbs in the internal representation
do
create item.make_filled (0, limbs)
count := 0
ensure
is_zero
end
make_bits (bits_a: INTEGER)
do
create item.make_filled (0, (bits_a + (limb_bits - 1)) // limb_bits)
count := 0
ensure
is_zero
end
feature -- Constants
one: like Current
-- Neutral element for "*" and "/"
deferred
end
zero: like Current
-- Neutral element for "+" and "-"
deferred
end
feature -- Comparison
is_less alias "<" (other: like Current): BOOLEAN
-- Is current object less than `other'?
do
Result := three_way_comparison (other) < 0
end
is_equal (other: like Current): BOOLEAN
-- Is `other' attached to an object considered
-- equal to current object?
do
Result := three_way_comparison (other) = 0
end
three_way_comparison (other: like Current): INTEGER
-- Perform a three way comparison between `Current' and `other'
do
Result := compare (Current, other).three_way_comparison (0)
end
feature -- Measurement
bytes: INTEGER
-- Minimum number of bytes the absolute value of this number would occupy
do
Result := (bits + 7).bit_and (0xfffffff8).bit_shift_right (3)
end
bits: INTEGER
-- Minimum number of bits the absolute value of this number would occupy
do
Result := size_in_base (2)
ensure
valid_result: Result >= 1
end
feature -- Status report
divisible (other: like Current): BOOLEAN
-- May `Current' be divided by `other'?
do
Result := not other.is_zero
end
exponentiable (other: NATURAL_32_REF): BOOLEAN
-- May `Current' be elevated to the power `other'?
do
Result := True
end
fits_natural: BOOLEAN
-- Does `Current' fit in a {NATURAL} without truncation?
do
Result := fits_natural_32
end
fits_natural_64: BOOLEAN
-- Does `Current' fit in a {NATURAL_64} without truncation?
local
n: INTEGER
do
resize (2)
n := count
Result := n >= 0 and n <= 2
end
fits_natural_32: BOOLEAN
-- Does `Current' fit in a {NATURAL_32} without truncation?
local
n: INTEGER
do
n := count
Result := n = 0 or n = 1
end
fits_natural_16: BOOLEAN
-- Does `Current' fit in a {NATURAL_16} without truncation?
local
n: INTEGER_32
do
n := count
Result := n = 0 or (n = 1 and then item [0] <= (0).to_natural_16.max_value)
end
fits_natural_8: BOOLEAN
-- Does `Current' fit in a {NATURAL_8} without truncation?
local
n: INTEGER_32
do
n := count
Result := n = 0 or (n = 1 and then item [0] <= (0).to_natural_8.max_value)
end
fits_integer: BOOLEAN
-- Does `Current' fit in an {INTEGER} without truncation?
do
Result := fits_integer_32
end
fits_integer_64: BOOLEAN
-- Does `Current' fit in an {INTEGER_64} without truncation?
local
n: INTEGER
limb1: NATURAL_32
limb2: NATURAL_32
do
n := count
limb1 := item [0]
if n = 0 or n = 1 or n = -1 then
Result := True
elseif n = 2 then
limb2 := item [1]
Result := not limb2.bit_test (31)
elseif n = -2 then
limb2 := item [1]
if limb2.bit_test (31) then
Result := limb2.bit_and (0x7fffffff) = 0 and limb1 = 0
else
Result := True
end
end
end
fits_integer_32: BOOLEAN
-- Does `Current' fit in an {INTEGER_32} without truncation?
local
n: INTEGER_32
limb: NATURAL_32
do
n := count
limb := item [0]
if
n = 0
then
Result := True
elseif n = 1 then
Result := not limb.bit_test (31)
elseif n = -1 then
if limb.bit_test (31) then
Result := limb.bit_and (0x7fffffff) = 0
else
Result := True
end
end
end
fits_integer_16: BOOLEAN
-- Does `Current' fit in an {INTEGER_16} without truncation?
local
n: INTEGER
limb: NATURAL_32
do
n := count
limb := item [0]
if n = 0 then
Result := True
elseif n = 1 then
Result := limb <= (0).to_integer_16.max_value.to_natural_32
elseif n = -1 then
Result := limb <= (0).to_integer_16.min_value.to_integer_32.abs.to_natural_32
else
Result := False
end
end
fits_integer_8: BOOLEAN
-- Does `Current' fit in an {INTEGER_8} without truncation?
local
n: INTEGER
limb: NATURAL_32
do
n := count
limb := item [0]
if n = 0 then
Result := True
elseif n = 1 then
Result := limb <= (0).to_integer_8.max_value.to_natural_32
elseif n = -1 then
Result := limb <= (0).to_integer_8.min_value.to_integer_32.abs.to_natural_32
end
end
is_odd: BOOLEAN
-- Is `Current' odd
do
Result := count /= 0 and then item [0].bit_test (0)
end
is_even: BOOLEAN
-- Is `Current' even?
do
Result := not is_odd
end
is_zero: BOOLEAN
-- Is `Current' equal to zero
do
Result := sign = 0
end
is_positive: BOOLEAN
-- Is `Current' positive
do
Result := sign = 1
end
is_negative: BOOLEAN
-- Is `Current' negative
do
Result := sign = -1
end
sign: INTEGER
-- Return the sign of `Current' where -1 is negative, 0 is zero, and 1 is positive
do
Result := count.three_way_comparison (0)
ensure
is_positive implies (Result = 1)
is_zero implies (Result = 0)
is_negative implies (Result = -1)
end
size_in_base (base: INTEGER): INTEGER
-- What is the size of the string representing the absolute value of `Current' in base `base'
require
base_too_small: base >= 2
base_too_big: base <= 62
do
Result := sizeinbase (Current, base)
end
feature -- Primality testing
is_composite: BOOLEAN
-- Is `Current' a composite number?
do
Result := probab_prime_p (Current, 10) = 0
end
is_prime: BOOLEAN
-- Is `Current' definitely a prime number?
do
Result := probab_prime_p (Current, 10) = 2
end
is_probably_prime: BOOLEAN
-- Is `Current' probably a prime number?
-- May return `False' if `Current' is actually prime.
do
Result := probab_prime_p (Current, 10) > 0
end
feature {INTEGER_X_FACILITIES}-- Element change
set_from_other (other: READABLE_INTEGER_X)
local
other_count: INTEGER
do
other_count := other.count
resize (other_count)
item.copy_data (other.item, 0, 0, other_count)
count := other_count
end
set_from_integer (value_a: INTEGER)
-- Initialize `Current' from `value_a'.
do
set_from_integer_32 (value_a)
ensure
value_a > 0 implies count = 1
value_a = 0 implies count = 0
value_a < 0 implies count = -1
fits_integer
as_integer = value_a
end
set_from_integer_64 (value_a: INTEGER_64)
-- Initialize `Current' from `value_a'
local
new_value: NATURAL_64
upper_limb: NATURAL_32
new_count: INTEGER
do
resize (2)
new_value := value_a.abs.to_natural_64
item [0] := new_value.to_natural_32
upper_limb := (new_value |>> 32).to_natural_32
item [1] := upper_limb
new_count := value_a.three_way_comparison (0)
new_count := new_count * ((upper_limb /= 0).to_integer + 1)
count_set (new_count)
ensure
value_a > 0 implies (count = 1 or count = 2)
value_a = 0 implies (count = 0)
value_a < 0 implies (count = -1 or count = -2)
fits_integer_64
as_integer_64 = value_a
end
set_from_integer_32 (value_a: INTEGER_32)
-- Initialize `Current' from `value_a'.
local
limb: NATURAL_32
do
if value_a < 0 then
limb := value_a.to_natural_32.bit_not + 1
else
limb := value_a.to_natural_32
end
item [0] := limb
count_set (value_a.three_way_comparison (0))
ensure
value_a > 0 implies count = 1
value_a = 0 implies count = 0
value_a < 0 implies count = -1
fits_integer_32
as_integer_32 = value_a
end
set_from_integer_16 (value_a: INTEGER_16)
-- Initialize `Current' from `value_a'.
local
limb: NATURAL_32
do
if value_a < 0 then
limb := value_a.to_natural_32.bit_not + 1
else
limb := value_a.to_natural_32
end
item [0] := limb
count_set (value_a.three_way_comparison (0))
ensure
value_a > 0 implies count = 1
value_a = 0 implies count = 0
value_a < 0 implies count = -1
fits_integer_16
as_integer_16 = value_a
end
set_from_integer_8 (value_a: INTEGER_8)
-- Initialize `Current' from `value_a'.
local
limb: NATURAL_32
do
if value_a < 0 then
limb := value_a.to_natural_32.bit_not + 1
else
limb := value_a.to_natural_32
end
item [0] := limb
count_set (value_a.three_way_comparison (0))
ensure
value_a > 0 implies count = 1
value_a = 0 implies count = 0
value_a < 0 implies count = -1
fits_integer_8
as_integer_8 = value_a
end
set_from_natural (value_a: NATURAL)
-- Initialize `Current' from `value_a'.
do
set_from_natural_32 (value_a)
ensure
value_a = 0 implies count = 0
value_a /= 0 implies count = 1
fits_natural
as_natural = value_a
end
set_from_natural_64 (value_a: NATURAL_64)
-- Initialize `Current' from `value_a'.
local
upper_limb: NATURAL_32
new_count: INTEGER
do
resize (2)
item [0] := value_a.to_natural_32
upper_limb := (value_a |>> 32).to_natural_32
item [1] := upper_limb
new_count := value_a.three_way_comparison (0)
new_count := new_count + (upper_limb /= 0).to_integer
count_set (new_count)
ensure
value_a = 0 implies count = 0
value_a /= 0 implies (count = 1 or count = 2)
fits_natural_64
as_natural_64 = value_a
end
set_from_natural_32 (value_a: NATURAL_32)
-- Initialize `Current' from `value_a'.
do
item [0] := value_a
if
value_a /= 0
then
count_set (1)
else
count_set (0)
end
ensure
value_a = 0 implies count = 0
value_a /= 0 implies count = 1
fits_natural_32
as_natural_32 = value_a
end
set_from_natural_16 (value_a: NATURAL_16)
-- Initialize `Current' from `value_a'.
do
item [0] := value_a.to_natural_32
if
value_a /= 0
then
count_set (1)
else
count_set (0)
end
ensure
value_a = 0 implies count = 0
value_a /= 0 implies count = 1
fits_natural_16
as_natural_16 = value_a
end
set_from_natural_8 (value_a: NATURAL_8)
-- Initialize `Current' from `value_a'.
do
item [0] := value_a.to_natural_32
if
value_a /= 0
then
count_set (1)
else
count_set (0)
end
ensure
value_a = 0 implies count = 0
value_a /= 0 implies count = 1
fits_natural_8
as_natural = value_a
end
set_from_string (s: STRING)
-- Initialize `Current' from `s' where `s' is a base 10 string
require
s_not_empty: not s.is_empty
do
set_str (Current, s, 10)
end
set_random (bits_a: INTEGER)
-- Initialize `Current' to random bits up to `bits_a' bits
require
valid_bits: bits_a >= 1
do
urandomb (Current, random_state, bits_a)
ensure
bits <= bits_a
end
feature -- Conversion with possible truncation.
-- Negatives wrap around in the negatives, non-negatives wrap around in the non-negatives
as_integer: INTEGER
-- Return the value of `Current' truncated to an {INTEGER}
do
Result := as_integer_32
end
as_integer_64: INTEGER_64
-- Return the value of `Current' truncated to an {INTEGER_64}
local
size: INTEGER
unsigned_result: NATURAL_64
do
size := count
if size > 1 then
unsigned_result := item [1].to_natural_64.bit_shift_left (32)
end
unsigned_result := unsigned_result.bit_or (item [0].to_natural_64)
if size > 0 then
Result := unsigned_result.to_integer_64.bit_and (0x7fff_ffff_ffff_ffff)
elseif size < 0 then
Result := (unsigned_result.to_integer_64 - 1).bit_and (0x7fff_ffff_ffff_ffff).bit_not
else
Result := 0
end
end
as_integer_32: INTEGER_32
-- Return the value of `Current' truncated to an {INTEGER_32}
local
size: INTEGER
zl: NATURAL_32
do
size := count
zl := item [0]
if size > 0 then
Result := zl.to_integer_32.bit_and (0x7fffffff)
elseif size < 0 then
Result := (zl.to_integer_32 - 1).bit_and (0x7fffffff).bit_not
else
Result := 0
end
end
as_integer_16: INTEGER_16
-- Return the value of `Current' truncated to an {INTEGER_16}
local
size: INTEGER
limb: NATURAL_32
do
size := count
limb := item [0]
if size > 0 then
Result := limb.to_integer_16.bit_and (0x7fff)
elseif size < 0 then
Result := (limb.to_integer_16 - 1).bit_and (0x7fff).bit_not
else
Result := 0
end
end
as_integer_8: INTEGER_8
-- Return the value of `Current' truncated to an {INTEGER_8}
local
size: INTEGER
limb: NATURAL_32
do
size := count
limb := item [0]
if size > 0 then
Result := limb.to_integer_8.bit_and (0x7f)
elseif size < 0 then
Result := (limb.to_integer_8 - 1).bit_and (0x7f).bit_not
else
Result := 0
end
end
as_natural: NATURAL
-- Return the value of the absolute value of `Current' truncated to a {NATURAL}
do
Result := as_natural_32
end
as_natural_64: NATURAL_64
-- Return the value of the absolute value of `Current' truncated to a {NATURAL_64}
local
n: INTEGER
data: SPECIAL [NATURAL_32]
do
n := count
data := item
if
n = 0
then
Result := 0
elseif n = 1 then
Result := data [0]
else
Result := data [1]
Result := Result |<< 32
Result := Result.bit_or (data [0])
end
end
as_natural_32: NATURAL_32
-- Return the value of the absolute value of `Current' truncated to a {NATURAL_32}
do
if
count = 0
then
Result := 0
else
Result := item [0]
end
end
as_natural_16: NATURAL_16
-- Return the value of the absolute value of `Current' truncated to a {NATURAL_16}
do
if
count = 0
then
Result := 0
else
Result := item [0].as_natural_16
end
end
as_natural_8: NATURAL_8
-- Return the value of the absolute value of `Current' truncated to a {NATURAL_8}
do
if
count = 0
then
Result := 0
else
Result := item [0].as_natural_8
end
end
feature -- Lossless conversion
to_integer: INTEGER
-- Return the value of `Current' as an {INTEGER}
require
fits: fits_integer_32
do
Result := as_integer_32
ensure
Current ~ (create {INTEGER_X}.make_from_integer (Result))
end
to_integer_64: INTEGER_64
-- Return the value of `Current' as an {INTEGER_64}
require
fits: fits_integer_64
do
Result := as_integer_64
ensure
Current ~ (create {INTEGER_X}.make_from_integer_64 (Result))
end
to_integer_32: INTEGER_32
-- Return the value of `Current' as an {INTEGER_32}
require
fits: fits_integer_32
do
Result := as_integer_32
ensure
Current ~ (create {INTEGER_X}.make_from_integer_32 (Result))
end
to_integer_16: INTEGER_16
-- Return the value of `Current' as an {INTEGER_16}
require
fits: fits_integer_16
do
Result := as_integer_16
ensure
Current ~ (create {INTEGER_X}.make_from_integer_16 (Result))
end
to_integer_8: INTEGER_8
-- Return the value of `Current' as an {INTEGER_8}
require
fits: fits_integer_8
do
Result := as_integer_8
ensure
Current ~ (create {INTEGER_X}.make_from_integer_8 (Result))
end
to_natural: NATURAL_32
-- Return the value of `Current' as a {NATURAL}
require
fits: fits_natural
do
Result := to_natural_32
ensure
Current ~ (create {INTEGER_X}.make_from_natural (Result))
end
to_natural_64: NATURAL_64
-- Return the value of `Current' as a {NATURAL_64}
require
fits: fits_natural_64
do
Result := as_natural_64
ensure
Current ~ (create {INTEGER_X}.make_from_natural_64 (Result))
end
to_natural_32: NATURAL_32
-- Return the value of `Current' as a {NATURAL_32}
require
fits: fits_natural_32
do
Result := as_natural_32
ensure
Current ~ (create {INTEGER_X}.make_from_natural_32 (Result))
end
to_natural_16: NATURAL_16
-- Return the value of `Current' as a {NATURAL_16}
require
fits: fits_natural_16
do
Result := as_natural_16
ensure
Current ~ (create {INTEGER_X}.make_from_natural_16 (Result))
end
to_natural_8: NATURAL_8
-- Return the value of `Current' as a {NATURAL_8}
require
fits: fits_natural_8
do
Result := as_natural_8
ensure
Current ~ (create {INTEGER_X}.make_from_natural_8 (Result))
end
to_bytes (target: SPECIAL [NATURAL_8] offset: INTEGER)
-- Convert the absolute value of `Current' to a byte array
require
big_enough: bytes <= target.upper - offset + 1
local
junk: TUPLE [junk: INTEGER]
do
create junk
output (target, offset, junk, 1, 1, -1, Current)
ensure
reversable: (create {INTEGER_X}.make_from_bytes (target, offset, offset + bytes - 1)) ~ Current
end
as_bytes: SPECIAL[NATURAL_8]
-- Convert the absolute value of `Current' to a byte array
do
create Result.make_filled (0, bytes)
to_bytes (Result, Result.lower)
ensure
reversable: (create {INTEGER_X}.make_from_bytes (Result, Result.lower, Result.upper)) ~ Current
end
to_fixed_width_byte_array (target: SPECIAL [NATURAL_8] first: INTEGER last: INTEGER)
require
valid_first: target.valid_index (first)
valid_last: target.valid_index (last)
enough_space: last - bytes + 1 >= first
local
junk: TUPLE [junk: INTEGER_32]
do
create junk
target.fill_with (0x0, first, last)
output (target, first + (last - first - bytes + 1), junk, 1, 1, -1, Current)
ensure
reversable: (create {INTEGER_X}.make_from_bytes (target, first, last)) ~ Current
end
as_fixed_width_byte_array (byte_size: INTEGER): SPECIAL[NATURAL_8]
-- Convert the absolute value of `Current' to a byte array of `byte_size' bytes
require
enough_space: bytes <= byte_size
do
create Result.make_filled (0, byte_size)
to_fixed_width_byte_array (Result, 0, byte_size - 1)
ensure
reversable: (create {INTEGER_X}.make_from_bytes (Result, Result.lower, Result.upper)) ~ Current
end
feature -- Duplication
copy (other: like Current)
-- Update `Current' to be a copy of `other'
local
usize: INTEGER
size: INTEGER
do
usize := other.count
size := usize.abs
resize (size)
item.copy_data (other.item, 0, 0, size)
count := usize
end
feature {INTEGER_X_FACILITIES}-- Basic operations stateful
abs
-- Modify `Current' to be non-negative
do
abs_integer_x (Current, Current)
ensure
non_negative: not is_negative
end
plus (other: like Current)
-- Modify `Current' to be the sum of `Current' and `other'
do
add (Current, Current, other)
end
minus (other: like Current)
-- Modify `Current' to be the subtraction of `Current' and `other'
do
sub (Current, Current, other)
end
product (other: like Current)
-- Modify `Current' to be the product of `Current' and `other'
do
mul (Current, Current, other)
end
quotient (other: like Current)
-- Modify `Current' to be the quotient by truncation division of `Current' by `other'
do
tdiv_q (Current, Current, other)
end
opposite
-- Modify `Current' to be the opposite sign or do nothing if `Current'.is_zero
do
neg (Current, Current)
end
feature -- Basic operations stateless
abs_value: like Current
-- Return the absolute value of `Current'
do
Result := identity
Result.abs
ensure
non_negative: not Result.is_negative
same_absolute_value: (Result ~ (Current)) or (Result ~ (-Current))
end
plus_value alias "+" (other: like Current): like Current
-- Return the sum of `Current' and `other'
do
Result := identity
Result.plus (other)
ensure then
Result - Current ~ other
Result - other ~ Current
end
minus_value alias "-" (other: like Current): like Current
-- Return the subtraction of `Current' and `other'
do
Result := identity
Result.minus (other)
ensure then
Result + other ~ Current
Current - Result ~ other
end
product_value alias "*" (other: like Current): like Current
-- Return the product of `Current' and `other'
do
Result := identity
Result.product (other)
ensure then
Result / Current ~ other
Result / other ~ Current
end
quotient_value alias "/" (other: like Current): like Current
-- Return the integer quotient by truncation division of `Current' by `other'
do
Result := identity
Result.quotient (other)
end
identity alias "+": like Current
-- Return the identity of `Current'
do
Result := deep_twin
end
opposite_value alias "-": like Current
-- Return the negative of `Current'
do
Result := identity
Result.opposite
end
feature {INTEGER_X_FACILITIES}-- Bit operations stateful
bit_complement (bit_a: INTEGER)
-- Modify `Current' to have bit `bit_a' complemented
do
bit_complement_integer_x (Current, bit_a)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_and (other: like Current)
-- Modify `Current' to be the bitwise AND of `Current' and `other'
do
bit_and_integer_x (Current, Current, other)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_or (other: like Current)
-- Modify `Current' to be the bitwise OR of `Current' and `other'
do
bit_or_integer_x (Current, Current, other)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_xor (other: like Current)
-- Modify `Current' to be the bitwise XOR of `Current' and `other'
do
bit_xor_integer_x (Current, Current, other)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_not
-- Modify `Current' to be a bitwise NOT of `Current'
do
bit_one_complement (Current, Current)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_xor_left_shift (other: like Current left_shift_bits: INTEGER)
-- Modify `Current' to be the bitwise XOR of `Current' and (`other' shifted left `left_shift_bits' bits)
do
bit_xor_lshift_integer_x (Current, Current, other, left_shift_bits)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_shift_right (bits_a: INTEGER)
-- Modify `Current' to be bit shifted right `bits_a' bits
do
tdiv_q_2exp (Current, Current, bits_a)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_shift_left (bits_a: INTEGER)
-- Modify `Current' to be bit shifted left `bits_a' bits
do
mul_2exp (Current, Current, bits_a)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
set_bit (value: BOOLEAN; bit_a: INTEGER)
-- Modify `Current' and set bit `bit_a' if `value' is True
do
if value then
bit_set (Current, bit_a)
else
bit_clear (Current, bit_a)
end
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
feature -- Bit operations stateless
-- All bit operations are performed as if the number was stored in two-complement format
bit_complement_value (bit_a: INTEGER): like Current
-- Return a copy of `Current' with bit `bit_a' complemented
require
valid_i: bit_a >= 0
do
Result := identity
Result.bit_complement (bit_a)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_and_value alias "&" (other: like Current): like Current
-- Return the bitwise AND of `Current' and `other'
do
Result := identity
Result.bit_and (other)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_or_value alias "|" (other: like Current): like Current
-- Return the bitwise OR of `Current' and `other'
do
Result := identity
Result.bit_or (other)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_xor_value (other: like Current): like Current
-- Return the bitwise XOR of `Current' and `other'
do
Result := identity
Result.bit_xor (other)
ensure
Result.bit_xor_value (Current) ~ other
Result.bit_xor_value (other) ~ Current
end
bit_xor_left_shift_value (other: like Current left_shift_bits: INTEGER): like Current
-- Return the bitwise XOR of `Current' and (`other' shifted left `left_shift_bits' bits)
do
Result := identity
Result.bit_xor_left_shift (other, left_shift_bits)
ensure
is_negative implies not old is_positive
is_positive implies not old is_negative
end
bit_not_value: like Current
-- Return the a bitwise NOT of `Current'
do
Result := identity
Result.bit_not
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_shift_left_value alias "|<<" (bits_a: INTEGER): like Current
-- Return `Current' bit shifted left `bits_a' bits
require
n_nonnegative: bits_a >= 0
do
Result := identity
Result.bit_shift_left (bits_a)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_shift_right_value alias "|>>" (bits_a: INTEGER): like Current
-- Return `Current' bit shifted right `bits_a' bits, truncating lower bits
require
n_nonnegative: bits_a >= 0
do
Result := identity
Result.bit_shift_right (bits_a)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
bit_test (bit_a: INTEGER): BOOLEAN
-- Is bit at position `bit_a' set
require
n_nonnegative: bit_a >= 0
do
Result := bit_test_integer_x (Current, bit_a)
end
set_bit_value (value: BOOLEAN; bit_a: INTEGER): like Current
-- Return a copy of `Current' with bit `bit_a' set if `value' is True
require
n_nonnegative: bit_a >= 0
do
Result := identity
Result.set_bit (value, bit_a)
ensure
is_negative implies not Result.is_positive
is_positive implies not Result.is_negative
end
feature {INTEGER_X_FACILITIES}-- Discrete operations stateful
powm (exponent: like Current; modulus: like Current)
-- Modify `Current' to be (`Current' raised to `exponent') modulo `modulus'
-- Negative `exponent' is supported if an inverse base^-1 mod mod exists {INTEGER_X}.invert
-- If `exponent' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
do
powm_integer_x (Current, Current, exponent, modulus)
end
inverse (modulus: like Current)
-- Set `Current' to be the inverse of `Current' modulo `modulus'
-- If `Current' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
local
has_inverse: BOOLEAN
do
has_inverse := invert (Current, Current, modulus)
if not has_inverse then
(create {INVERSE_EXCEPTION}).raise
end
ensure
coprime: coprime (modulus)
end
modulo (mod: like Current)
-- Set `Current' to `Current' modulo `modulus'
do
mod_integer_x (Current, Current, mod)
end
gcd (op1: like Current; op2: like Current)
-- Set `Current' to the Greatest Common Divisor between `op1' and `op2'
do
gcd_integer_x (Current, op1, op2)
ensure
positive_result: Current.is_positive
op1.coprime (op2) = (Current ~ one)
end
feature -- Discrete operations stateless
powm_value (exponent: like Current; modulus: like Current): like Current
-- Return (`Current' raised to `exponent') modulo `modulus'.
-- Negative `exponent' is supported if an inverse base^-1 mod mod exists {INTEGER_X}.invert
-- If an inverse doesn't exist then a divide by zero is raised
do
Result := identity
Result.powm (exponent, modulus)
end
inverse_value (modulus: like Current): like Current
-- Return the inverse of `Current' modulo `modulus'
-- If `Current' does not have an inverse modulo `modulus', an {INVERSE_EXCEPTION} will be raised
do
Result := identity
Result.inverse (modulus)
ensure
correct_result: ((Result * Current) \\ modulus) ~ (one)
coprime: coprime (modulus)
end
modulo_value alias "\\" (modulus: like Current): like Current
-- Return `Current' modulo `modulus'
do
Result := identity
Result.modulo (modulus)
end
gcd_value (other: like Current): like Current
-- Return the Greatest Common Divisor between `Current' and `other'
do
Result := identity
Result.gcd (Current, other)
ensure
positive_result: Result.is_positive
coprime (other) = (Result ~ one)
end
coprime (other: like Current): BOOLEAN
-- Are `Current' and `other' coprime?
do
Result := gcd_value (other) ~ (one)
ensure
Result = (gcd_value (other) ~ (one))
end
feature {INTEGER_X_FACILITIES}-- Galois field arithmetic stateful
invert_gf (other: like Current)
require
not is_negative
not other.is_negative
do
invert_gf_integer_x (Current, Current, other)
ensure
not is_negative
other.identity ~ old other.identity
end
feature -- Galois field arithmetic stateless
invert_gf_value (other: like Current): like Current
require
not is_negative
not other.is_negative
do
Result := identity
Result.invert_gf (other)
ensure
not Result.is_negative
identity ~ old identity
other.identity ~ old other.identity
end
feature -- Output
debug_output: STRING
-- Return a debug string of `Current'
do
Result := out_hex
end
out: STRING
-- Return a hexicedimal representation of the value of `Current'
do
Result := out_hex
end
out_decimal: STRING
-- Return a decimal representation of the value of `Current'
do
Result := out_base (10)
end
out_hex: STRING
-- Return a hexidecimal representation ofthe value of `Current'
do
Result := out_base (16)
end
out_base (base: INTEGER_32): STRING
-- Return a representation of `Current' in base `base'
require
base_too_small: base >= 2
base_too_big: base <= 62
do
Result := get_string (Current, base)
end
feature {NONE} -- Implementation
random_state: RANDOM_NUMBER_GENERATOR
once
create {LINEAR_CONGRUENTIAL_RNG}Result.make (32)
end
feature {INTEGER_X_FACILITIES}
normalized: BOOLEAN
-- Does `count' represent the number of non-zero limbs in `item'
do
Result := normalize (item, 0, count) = count
end
components_set (item_value: SPECIAL [NATURAL_32] count_value: INTEGER)
-- Set `item' and `count' simultaneously
do
item_set (item_value)
count_set (count_value)
end
capacity: INTEGER
-- Number of limbs allocated in `item'
do
Result := item.capacity
end
item: SPECIAL [NATURAL_32] assign item_set
-- Backing storage for the number
item_set (value_a: SPECIAL [NATURAL_32])
-- Change `item' to `value_a'
do
item := value_a
end
count: INTEGER assign count_set
-- `count.abs' is the number of limbs in `item' that have meaning
-- If `size' is negative this is a negative number.
attribute
end
count_set (value_a: INTEGER)
-- Change `count' to `value_a'
do
count := value_a
end
resize (new_alloc: INTEGER)
-- Change the space for integer to at least `new_alloc' limbs.
local
allocate_size: INTEGER_32
do
if new_alloc > capacity then
allocate_size := new_alloc.max (1)
item := item.aliased_resized_area_with_default (0, allocate_size)
end
end
set_components (item_a: SPECIAL [NATURAL_32] count_a: INTEGER)
do
item := item_a
count := count_a
end
invariant
-- normalized: normalized
capacity >= 1
count <= item.count
item.count = item.capacity
end