home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
sa104os2.zip
/
SATHR104.ZIP
/
SATHER
/
LIBRARY
/
INTI.SA
< prev
next >
Wrap
Text File
|
1995-02-05
|
17KB
|
486 lines
-- Copyright (C) International Computer Science Institute, 1994. COPYRIGHT --
-- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
-- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in --
-- the file "Doc/License" of the Sather distribution. The license is also --
-- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA. --
--------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
----------------------------------------------------------------------
-- inti.sa: Implementation of arbitrary large integers. An integer x is
-- represented by n digits to a base B:
--
-- x = sign * (x[n-1]*B^(n-1) + x[n-2]*B^(n-2) + ... + x[1]*B + x[0])
--
-- The n digits x[i] of x are hold in an array with asize >= n. The
-- sign and n are encoded in a private feature len, with the following
-- semantics:
--
-- n = |len|, sign = sign(len)
-- and the value 0 is represented by len = 0
--
-- The operations div (/) and mod (%) obey the following rules
-- (euclidean definition):
--
-- x = (x/y)*y + x%y and 0 <= x%y < |y|
--
-- All (non-private) methods are non-destructive, i.e. they do not
-- modify their arguments. Thus, INTI behaves like a value class.
--
-- Author: Robert Griesemer (gri@icsi.berkeley.edu)
-- Created: 20 Oct 1993 (Sather 0.2)
-- Modified: 1 Jul 1994 (Sather 1.0), 27 Jul 1994
--
-- Copyright (C) 1993, International Computer Science Institute
--
-- COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
-- and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
-- LICENSE contained in the file: sather/doc/license.txt of the
-- Sather distribution. The license is also available from ICSI,
-- 1947 Center St., Suite 600, Berkeley CA 94704, USA.
----------------------------------------------------------------------
class INTI < $IS_EQ{SAME}, $IS_LT{SAME}, $STR is
include AREF{INT};
private attr len: INT;
private const log2B := 15;
private const log10D := 4;
private const B := 2 ^ log2B; -- binary base
private const D := 10 ^ log10D; -- decimal base; D <= B must hold
-------------------------------------------------- private routines (self = void)
private u_plus (x, y: SAME): SAME is
xl: INT := x.len.abs;
yl: INT := y.len.abs;
l: INT := xl.min(yl);
i: INT := 0;
c: INT := 0;
z: SAME;
--
z := new(xl.max(yl) + 1);
loop while!(i < l); c := c + x[i] + y[i]; z[i] := c%B; c := c/B; i := i+1 end;
loop while!(i < xl); c := c + x[i]; z[i] := c%B; c := c/B; i := i+1 end;
loop while!(i < yl); c := c + y[i]; z[i] := c%B; c := c/B; i := i+1 end;
if c /= 0 then z[i] := c; i := i+1 end;
z.len := i;
return z
end;
private u_minus (x, y: SAME): SAME is
xl: INT := x.len.abs;
yl: INT := y.len.abs;
i: INT := 0;
c: INT := 0;
z: SAME;
--
z := new(xl);
loop while!(i < yl); c := c + x[i] - y[i]; z[i] := c%B; c := c/B; i := i+1 end;
loop while!(i < xl); c := c + x[i]; z[i] := c%B; c := c/B; i := i+1 end;
loop while!((i > 0) and (z[i-1] = 0)); i := i-1 end;
z.len := i;
return z
end;
private u_times (x, y: SAME): SAME is
xl: INT := x.len.abs;
yl: INT := y.len.abs;
i, j, k, d, c: INT;
--
i := xl + yl; z: SAME := new(i);
loop while!(i > 0); i := i-1; z[i] := 0 end;
loop while!(i < xl); d := x[i];
if d /= 0 then j := 0; k := i; c := 0;
loop while!(j < yl); c := c + z[k] + d*y[j]; z[k] := c%B; c := c/B; j := j+1; k := k+1 end;
if c /= 0 then z[k] := c; k := k+1 end
end;
i := i+1
end;
z.len := k;
return z
end;
private copy: SAME is
i: INT := len.abs;
z: SAME := new(i+1); z.len := len;
loop while!(i > 0); i := i-1; z[i] := [i] end;
return z
end;
private u_div_mod (x, y: SAME): SAME is
xl: INT := x.len.abs;
yl: INT := y.len.abs;
i, j, k, c, d, q, y1, y2: INT;
--
x := x.copy;
if yl = 1 then
i := xl-1; c := 0; d := y[0];
loop while!(i >= 0); c := c*B + x[i]; x[i+1] := c/d; c := c%d; i := i-1 end;
x[0] := c
elsif xl >= yl then
x[xl] := 0; d := (B/2 - 1) / y[yl-1] + 1;
if d /= 1 then
y := y.copy; i := 0; c := 0;
loop while!(i < xl); c := c + d*x[i]; x[i] := c%B; c := c/B; i := i+1 end;
x[i] := c; i := 0; c := 0;
loop while!(i < yl); c := c + d*y[i]; y[i] := c%B; c := c/B; i := i+1 end;
assert c = 0
end;
y1 := y[yl-1]; y2 := y[yl-2]; i := xl;
loop while! (i >= yl);
if x[i] /= y1 then q := (x[i]*B + x[i-1]) / y1 else q := B-1 end;
loop while!(y2 * q > (x[i]*B + x[i-1] - y1*q)*B + x[i-2]); q := q-1 end;
j := i-yl; k := 0; c := 0;
loop while!(k < yl); c := c + x[j] - q*y[k]; x[j] := c%B; c := c/B; j := j+1; k := k+1 end;
if c+x[i] /= 0 then j := i-yl; k := 0; c := 0;
loop while!(k < yl); c := c + x[j] + y[k]; x[j] := c%B; c := c/B; j := j+1; k := k+1 end;
x[i] := q-1
else x[i] := q
end;
i := i-1
end;
if d /= 1 then i := yl; c := 0;
loop while!(i > 0); i := i-1; c := c*B + x[i]; x[i] := c/d; c := c%d end;
end
end;
return x
end;
private get_u_div (x, y, q: SAME): SAME is
i: INT := x.len.abs;
yl: INT := y.len.abs;
loop while!((i >= yl) and (q[i] = 0)); i := i-1 end;
z: SAME := new(i-yl+1); z.len := i-yl+1;
loop while!(i >= yl); z[i-yl] := q[i]; i := i-1 end;
return z
end;
private get_u_mod (x, y, q: SAME): SAME is
i: INT := x.len.abs.min(y.len.abs) - 1;
loop while!((i >= 0) and (q[i] = 0)); i := i-1 end;
z: SAME := new(i+1); z.len := i+1;
loop while!(i >= 0); z[i] := q[i]; i := i-1 end;
return z
end;
private u_cmp (x, y: SAME): INT is
i: INT := x.len.abs;
j: INT := y.len.abs;
z: INT;
if (i = j) and (i /= 0) then i := i-1;
loop while!((i /= 0) and (x[i] = y[i])); i := i-1 end;
z := x[i] - y[i]
else z := i - j
end;
return z
end;
private u_times_plus (x: SAME, y, c: INT): SAME
pre (0 <= y) and (y < B) and (0 <= c) and (c < B) is
xl: INT := x.len.abs;
i: INT := 0;
z: SAME := new(xl+1);
loop while!(i < xl); c := c + x[i]*y; z[i] := c%B; c := c/B; i := i+1 end;
if c /= 0 then z[i] := c; i := i+1 end;
z.len := i;
return z
end;
private u_mod (x: SAME, d: INT): INT pre (1 <= d) and (d < B) is -- x /= 0; x will be modified
xl: INT := x.len.abs;
i: INT := xl;
c: INT := 0;
loop while!(i > 0); i := i-1; c := c*B + x[i]; x[i] := c/d; c := c%d end;
if x[xl-1] = 0 then x.len := xl-1 end;
return c
end;
-------------------------------------------------- binary arithmetics
plus (y: SAME): SAME is
z: SAME;
if (len < 0) = (y.len < 0) then z := u_plus(self, y);
elsif u_cmp(self, y) < 0 then z := u_minus(y, self); z.len := -z.len
else z := u_minus(self, y);
end;
if len < 0 then z.len := -z.len end;
return z
end;
minus (y: SAME): SAME is
z: SAME;
if (len < 0) /= (y.len < 0) then z := u_plus(self, y);
elsif u_cmp(self, y) < 0 then z := u_minus(y, self); z.len := -z.len
else z := u_minus(self, y);
end;
if len < 0 then z.len := -z.len end;
return z
end;
times (y: SAME): SAME is
z: SAME;
if (len = 0) or (y.len = 0) then z := #SAME(0)
elsif (len.abs = 1) and (y.len.abs = 1) then z := #SAME([0] * y[0])
else
if len.abs < y.len.abs then z := u_times(self, y)
else z := u_times(y, self)
end
end;
if (len < 0) /= (y.len < 0) then z.len := -z.len end;
return z
end;
div (y: SAME): SAME is
z: SAME;
if len.abs < y.len.abs then z := #SAME(0)
else
qr: SAME := u_div_mod(self, y);
z := get_u_div(self, y, qr);
if (len < 0) and (get_u_mod(self, y, qr).len /= 0) then z := u_times_plus(z, 1, 1) end;
if (len < 0) /= (y.len < 0) then z.len := -z.len end
end;
return z
end;
mod (y: SAME): SAME is
z: SAME;
if len.abs < y.len.abs then z := self
else
z := get_u_mod(self, y, u_div_mod(self, y));
if (len < 0) and (z.len /= 0) then z := u_minus(y, z) end
end;
return z
end;
pow (i: INT): SAME is
-- Returns self raised to the power i. Returns 1 for i < 0.
--
x ::= self; z ::= #SAME(1);
loop while!(i > 0);
-- z * x^i = self ^ i0
if i.is_odd then z := z*x end;
x := x.square; i := i/2
end;
return z
end;
-------------------------------------------------- binary relations
cmp (y: SAME): INT is
-- Returns a value with the property x rel y = (x.cmp(y) rel 0),
-- where rel stands for one of the relations =, /=, <, <=, > or >=.
--
if (len < 0) /= (y.len < 0) then return len
elsif len < 0 then return u_cmp(y, self)
-- else return u_cmp(self, y) -- NLP
end; return u_cmp(self, y); -- NLP
-- end -- NLP
end;
is_eq(y: SAME): BOOL is return SYS::ob_eq(self, y) or (cmp(y) = 0) end;
is_neq(y: SAME): BOOL is return ~SYS::ob_eq(self, y) and (cmp(y) /= 0) end;
is_lt (y: SAME): BOOL is return cmp(y) < 0 end;
is_leq (y: SAME): BOOL is return cmp(y) <= 0 end;
is_gt (y: SAME): BOOL is return cmp(y) > 0 end;
is_geq (y: SAME): BOOL is return cmp(y) >= 0 end;
-------------------------------------------------- unary predicates
is_even: BOOL is assert B.is_even; return (len = 0) or [0].is_even end;
is_odd: BOOL is assert B.is_even; return (len = 0) or [0].is_odd end;
is_pos: BOOL is return len > 0 end;
is_neg: BOOL is return len < 0 end;
is_zero: BOOL is return len = 0 end;
-------------------------------------------------- unary functions
int: INT is
i ::= len.abs; z ::= 0;
loop while!(i > 0); i := i-1; z := z*B + [i] end;
if len < 0 then z := -z end;
return z
end;
inti: INTI is return self end;
abs: SAME is
if len < 0 then z ::= copy; z.len := -len; return z
-- else return self -- NLP
end; return self; -- NLP
-- end -- NLP
end;
negate: SAME is
if len /= 0 then z ::= copy; z.len := -len; return z
-- else return self -- NLP
end; return self; -- NLP
-- end -- NLP
end;
sign: INT is return len.sign end;
square: SAME is return self * self end;
cube: SAME is return self * self * self end;
log2: INT is
-- Returns the largest n with 2^n <= self for self > 0 (logarithmus dualis).
--
assert len > 0;
return (len-1)*log2B + [len-1].highest_bit
end;
sqrt: SAME is raise "INTI::sqrt: SAME not implemented" end;
private mul (a, b: INT): SAME is
m: INT;
if a < b then m := (a+b)/2; return mul(a, m) * mul(m+1, b)
-- else return #SAME(a) -- NLP
end; return #SAME(a); -- NLP
-- end -- NLP
end;
factorial: SAME is return mul(1, self.int) end;
-------------------------------------------------- binary functions
max (y: SAME): SAME is
-- if cmp(y) > 0 then return self else return y end -- NLP
if cmp(y) > 0 then return self; end; return y; -- NLP
end;
min (y: SAME): SAME is
-- if cmp(y) < 0 then return self else return y end -- NLP
if cmp(y) < 0 then return self; end; return y; -- NLP
end;
gcd (y: SAME): SAME post result.is_pos is
-- Returns the greatest common divisor of self and y.
-- The result is always > 0.
--
if y.len = 0 then return self.abs
-- else return y.gcd(self % y) -- NLP
end; return y.gcd(self % y); -- NLP
-- end -- NLP
end;
-------------------------------------------------- output
private append_int (s: FSTR, x, n: INT): FSTR pre x >= 0 is
-- Append a decimal version of x to s using at most n digits
-- (filled up with 0's) and return s.
--
i ::= s.length;
loop s := s + (x%10).digit_char; x := x/10; n := n-1; until!(x = 0) end;
loop while!(n > 0); s := s + '0'; n := n-1 end;
j ::= s.length-1;
loop while!(i < j); ch ::= s[i]; s[i] := s[j]; s[j] := ch; i := i+1; j := j-1 end;
return s
end;
str_in (s: FSTR, n, b: INT, f: CHAR): FSTR pre b.is_bet(2, 16) is
-- Append a string representation of self to s using at least n digits
-- to the base b and return s. If less then n digits are used for the
-- representation of self (including its sign), the remaining left_most
-- positions are filled with character f.
--
x ::= copy; i ::= s.length;
loop s := s + u_mod(x, b).digit_char; n := n-1; until!(x.len = 0) end;
if self.len < 0 then s := s + '-'; n := n-1 end;
loop while!(n > 0); s := s + f; n := n-1 end;
j ::= s.length-1;
loop while!(i < j); ch ::= s[i]; s[i] := s[j]; s[j] := ch; i := i+1; j := j-1 end;
return s
end;
str_in (s: FSTR): FSTR is
-- Append a decimal string version of self to s and return s.
--
if len = 0 then return s + '0'
-- else -- NLP
end; -- NLP
if len < 0 then s := s + '-' end;
if len.abs = 1 then return [0].str_in(s)
-- else -- NLP
end; -- NLP
-- compute output in reverse order in
-- chunks of log10D decimal digits
-- and append it in correct order to s
x ::= copy; -- working copy
d: FLIST{INT}; -- working buffer
loop d := d.push(u_mod(x, D)); until!(x.len = 0) end;
s := d.pop.str_in(s);
loop while!(d.size > 0); s := d.pop.str_in(s, log10D, 10, '0') end;
return s
-- end -- NLP
-- end -- NLP
end;
private shared buf: FSTR; -- Buffer for string output.
str: STR is
-- A decimal string version of self.
buf.clear; buf := str_in(buf); return buf.str
end;
-------------------------------------------------- object creation
create (x: INT): SAME is
-- Creates an INTI of x.
--
z: SAME;
if x = INT::nil then -- prevent overflow
z := -(#INTI(2) ^ (INT::asize-1))
else
a ::= x.abs; i ::= 0;
z := new(a.highest_bit / log2B + 1);
loop while!(a /= 0); z[i] := a%B; a := a/B; i := i+1 end;
if x < 0 then z.len := -i else z.len := i end
end;
return z
end;
create (s: STR, i: INT): SAME pre (0 <= i) and (i < s.length) is
-- Creates an INTI of its decimal string
-- representation in s starting at index i.
-- Returns 0i if no integer is found in s.
-- Syntax: [['-'] {digit}]
--
z ::= #SAME(0);
if s[i] = '-' then i := i+1 end;
d ::= 0; j ::= i;
loop while!((i < s.length) and s[i].is_digit);
d := d*10 + s[i].digit_value; i := i+1;
if i-j = log10D then z := u_times_plus(z, D, d); d := 0; j := i end
end;
if i-j > 0 then z := u_times_plus(z, 10^(i-j), d) end;
if s[0] = '-' then z.len := -z.len end;
return z
end;
create (s: STR): SAME is
return #SAME(s, 0)
end;
create (s: FSTR, i: INT): SAME pre (0 <= i) and (i < s.length) is
-- Creates an INTI of its decimal string
-- representation in s starting at index i.
-- Returns 0i if no integer is found in s.
-- Syntax: [['-'] {digit}]
--
z ::= #SAME(0);
if s[i] = '-' then i := i+1 end;
d ::= 0; j ::= i;
loop while!((i < s.length) and s[i].is_digit);
d := d*10 + s[i].digit_value; i := i+1;
if i-j = log10D then z := u_times_plus(z, D, d); d := 0; j := i end
end;
if i-j > 0 then z := u_times_plus(z, 10^(i-j), d) end;
if s[0] = '-' then z.len := -z.len end;
return z
end;
create (s: FSTR): SAME is
return #SAME(s, 0)
end;
end