inti.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
---------------------------> Sather 1.1 source file <--------------------------
-- 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. <----------


-- 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_LT{INTI}, $STR, $HASH

class INTI < $IS_LT{INTI}, $STR, $HASH is -- 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 immutable class. -- Author: Robert Griesemer (gri@icsi.berkeley.edu) include COMPARABLE; 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 -------------------------------------------------- object creation create:SAME is return #(0) end; create (x: INT): SAME is -- Creates an INTI from x z: SAME; if x.is_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(x:INTI):SAME is return x end; create(f:FLT):SAME is -- Would be much faster if INTI had set_bit. if f=0.0 then return #(0) end; neg ::= f<0.0; if neg then f := -f end; res ::= #SAME(0); val ::= #SAME(1); t ::= 1.0; loop while!(t<=f); t:=t.scale_by(1); val:=val*#(2) end; loop while!(val.is_non_zero); if f>=t then f:=f-t; res:=res+val end; val:=val/#(2); t:=t.scale_by(-1); end; -- loop if f/=0.0 then raise "INTI::create(FLT):INTI: value was not integer" end; if neg then res:=-res end; return res end; create(f:FLTD):SAME is -- Would be much faster if INTI had set_bit. if f=0.0d then return #(0) end; neg ::= f<0.0d; if neg then f := -f end; res ::= #SAME(0); val ::= #SAME(1); t ::= 1.0d; loop while!(t<=f); t:=t.scale_by(1); val:=val*#(2) end; loop while!(val.is_non_zero); if f>=t then f:=f-t; res:=res+val end; val:=val/#(2); t:=t.scale_by(-1); end; -- loop if f/=0.0d then raise "INTI::create(FLT):INTI: value was not integer" end; if neg then res:=-res end; return res end; --create(f:FLTX):SAME is raise "INTI::create(FLTX):SAME is undefined";end; --create(f:FLTDX):SAME is raise "INTI::create(FLTDX):SAME is undefined" end; --create(f:FLTI):SAME is return f.inti 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); neg ::= s[i] = '-'; if neg or 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 neg then z.len := -z.len end; return z end; create (s: STR): SAME is return #(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); neg ::= s[i] = '-'; if neg or 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 neg then z.len := -z.len end; return z end; create (s: FSTR): SAME is return #(s, 0) end; ----------------------------- 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; pow (j: SAME): SAME is -- Returns self raised to the power i. Returns 1 for i < 0. -- x ::= self; z ::= #SAME(1); i ::= j.int; 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;
-- find something to hash on. hash:INT is if asize <= 0 then return 289201 else hval ::= 0; loop i::=asize.times!; hval:=hval.bxor([i].hash).lrotate(3); end; return hval; end; 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) then return -y.len elsif (len < 0) /= (y.len < 0) then return len elsif len < 0 then return u_cmp(y, self) else return u_cmp(self, y) end end; is_eq(y: SAME): BOOL is return SYS::ob_eq(self, y) or (cmp(y) = 0) end; is_lt (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) and [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; is_non_pos: BOOL is return len <= 0 end; is_non_neg: BOOL is return len >= 0 end; is_non_zero: BOOL is return len /= 0 end; -------------------------------------------------- ternary predicates is_between(l,u:SAME):BOOL is -- True if self between l and u. return (l<=self and self<=u) or (u<=self and self<=l) end; is_within(tolerance,val:SAME):BOOL is return (self-val).abs<=tolerance; 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; flt: FLT is i ::= len.abs; z ::= 0.0; loop while!(i > 0); i := i-1; z := z*B.flt + [i].flt end; if len < 0 then z := -z end; return z end; fltd: FLTD is i ::= len.abs; z ::= 0.0d; loop while!(i > 0); i := i-1; z := z*B.fltd + [i].fltd end; if len < 0 then z := -z end; return z end; -- fltx: FLTX is -- i ::= len.abs; z ::= #FLTX(0.0); -- loop while!(i > 0); i := i-1; z := z*B.fltx + [i].fltx end; -- if len < 0 then z := -z end; -- return z -- end; -- fltdx: FLTDX is -- i ::= len.abs; z ::= #FLTDX(0.0); -- loop while!(i > 0); i := i-1; z := z*B.fltdx + [i].fltdx end; -- if len < 0 then z := -z end; -- return z -- end; -- flti: FLTI is -- i ::= len.abs; z ::= #FLTI(0.0); -- loop while!(i > 0); i := i-1; z := z*B.flti + [i].flti end; -- if len < 0 then z := -z end; -- return z -- end; abs: SAME is if len < 0 then z ::= copy; z.len := -len; return z else return self end end; negate: SAME is if len /= 0 then z ::= copy; z.len := -len; return z else return self end 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; exp2: SAME is -- 2^self -- self is INTI because of conflict with INT::exp2:INT return #SAME(2).pow(self) end; exp10: SAME is -- 10^self return #SAME(10).pow(self) end; sqrt: SAME is -- square root of self. -- Iteration algorithm: x[0]:=self; x[n+1]:=(x+a/x)/2 -- We stop when the value is constant or oscillating. -- A routine "INTI::div(INT):INTI" could speed this up. if len=0 then return #SAME(0) end; if len<0 then raise "INTI::sqrt: Argument is negative" end; x::=self; two::=#SAME(2); x0:SAME; loop x0:=x; x:=(x+self/x)/two; until!(x>=x0); end; return x0 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) end end; factorial: SAME is return mul(1, self.int) end; is_prime:BOOL is -- True if self is a prime number. -- Replace by a faster algorithm. if #SAME(2).evenly_divides(self) then return false end; loop d::=#SAME(3).step!((self.sqrt+#SAME(2))/#SAME(2), #SAME(2)); if d.evenly_divides(self) then return false end end; return true end; -------------------------------------------------- binary functions max (y: SAME): SAME is if cmp(y) > 0 then return self else return y end end; min (y: SAME): SAME is if cmp(y) < 0 then return self else return y end end; at_least(x:SAME):SAME is -- Same as `max(x)'. return self.max(x) end; at_most(x:SAME):SAME is -- Same as `min(x)'. return self.min(x) end; evenly_divides(i:SAME):BOOL is -- True if self evenly divides `i'. return (i%self).len=0 end; next_multiple_of(i:SAME):SAME -- The smallest value greater than or equal to self which is a -- multiple of `i'. pre i.len>0 is return ((self+i-#SAME(1))/i)*i end; gcd(i:SAME):SAME is -- The greatest common divisor of self and `i'. -- The result is non-negative and `x.gcd(0)=x.abs'. -- Uses Euclidean algorithm. Geddes, et. al. p. 34. c::=abs; d::=i.abs; loop until!(d.len=0); r::=c.mod(d); c:=d; d:=r end; return c end; extended_gcd(i:SAME, out self_factor, out i_factor: SAME): SAME is -- The three parts of the return value `g', `g1', and `g2' are such -- that `g' is the greatest common divisor of self and `i' and -- `g1*self+g2*i=g'. -- Uses the extended Euclidean algorithm. Geddes, et. al. p. 36. c::=abs; d::=i.abs; c1::=#SAME(1); d1::=#SAME(0); c2::=#SAME(0); d2::=#SAME(1); loop until!(d.len=0); q::=c/d; r::=c-q*d; r1::=c1-q*d1; r2::=c2-q*d2; c:=d; c1:=d1; c2:=d2; d:=r; d1:=r1; d2:=r2 end; self_factor := c1/(abs*c.abs); i_factor := c1/(abs*c.abs); return c.abs; end; lcm(i:SAME):SAME is -- The least common multiple of self and `i'. -- Geddes, et. al. p. 28. return (self*i).abs/gcd(i) end; is_relatively_prime_to(i:SAME):BOOL is -- True if self is relatively prime to `i'. return gcd(i)=#SAME(1) end; -------------------------------------------------- boolean algebra bnot:SAME is raise "INTI::bnot:SAME not implemented" end; band(a:SAME):SAME is raise "INTI::band(SAME):SAME not implemented" end; bor(a:SAME):SAME is raise "INTI::bor(SAME):SAME not implemented" end; bxor(a:SAME):SAME is raise "INTI::bxor(SAME):SAME not implemented" end; bnand(a:SAME):SAME is raise "INTI::bnand(SAME):SAME not implemented" end; bnor(a:SAME):SAME is raise "INTI::bnor(SAME):SAME not implemented" end; beqv(a:SAME):SAME is raise "INTI::beqv(SAME):SAME not implemented" end; boole(a:SAME,b:INT):SAME is raise "INTI::boole(SAME,INT):SAME not implemented" end; bcount:INT is raise "INTI::bcount:INT not implemented" end; lshift(a:INT):SAME is raise "INTI::lshift(INT):SAME not implemented" end; rshift(a:INT):SAME is raise "INTI::rshift(INT):SAME not implemented" end; urshift(a:INT):SAME is raise "INTI::urshift(INT):SAME not implemented" end; lrotate(a:INT):SAME is raise "INTI::lrotate(INT):SAME not implemented" end; rrotate(a:INT):SAME is raise "INTI::rrotate(INT):SAME not implemented" end; bit(a:INT):BOOL is raise "INTI::bit(INT):BOOL not implemented" end; set_bit(a:INT,c:BOOL):SAME is raise "INTI::set_bit(INT,BOOL):SAME not implemented" end; set_bit(a:INT):SAME is raise "INTI::set_bit(INT):SAME not implemented" end; unset_bit(a:INT):SAME is raise "INTI::unset_bit(INT):SAME not implemented" end; lowest_bit:INT is raise "INTI::lowest_bit:INT not implemented" end; highest_bit:INT is raise "INTI::highest_bit:INT not implemented" end; is_exp2:BOOL is raise "INTI::is_exp2:BOOL not implemented" end; next_exp2:SAME is raise "INTI::next_exp2:SAME not implemented" end; low_bits(a:INT):SAME is raise "INTI::low_bits(INT):SAME not implemented" end; high_bits(a:INT):SAME is raise "INTI::high_bits(INT):SAME not implemented" end; -------------------------------------------------- iterators times! -- Yields self times without returning anything. pre self>=#SAME(0) is i::=self; loop until!(i<=#SAME(0)); yield; i:=i-#SAME(1) end end; times!:SAME -- Yield successive integers from 0 up to self-1. pre self>=#SAME(0) is r:SAME; loop until!(r>=self); yield r; r:=r+#SAME(1) end end; for!(once i:SAME):SAME -- Yields `i' successive integers starting with self. pre i>=#SAME(0) is r::=self; e::=self+i; loop until!(r>=e); yield r; r:=r+#SAME(1) end end; up!:SAME is -- Yield successive integers from self up. r::=self; loop yield r; r:=r+#SAME(1) end end; upto!(once i:SAME):SAME is -- Yield successive integers from self to `i' inclusive. r::=self; loop until!(r>i); yield r; r:=r+#SAME(1) end end; downto!(once i:SAME):SAME is -- Yield successive integers from self down to `i' inclusive. r::=self; loop until!(r<i); yield r; r:=r-#SAME(1) end end; step!(once num,once step:SAME):SAME -- Yield `num' integers starting with self and stepping by `step'. pre num>=#SAME(0) is r::=self; last::=self+(num-#SAME(1))*step; if step>#SAME(0) then loop until!(r>last); yield r; r:=r+step end elsif step<#SAME(0) then loop until!(r<last); yield r; r:=r+step end else loop num.times!; yield r end end end; sum!(i:SAME):SAME is -- Yields the sum of all previous values of `i'. r:SAME; loop r:=r+i; yield r end end; product!(i:SAME):SAME is -- Yields the product of all previous values of `i'. r::=#SAME(1); loop r:=r*i; yield r end 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 if len < 0 then s := s + '-' end; if len.abs = 1 then return [0].str_in(s) else -- 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 end 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; end