10.3.2.1. Conversion routines {The routines whole, fixed and float are intended to be used with the formatless output routines put, print and write when it is required to have a little extra control over the layout produced. Each of these routines has a width parameter whose absolute value specifies the length of the string to be produced by conversion of the arithmetic value V provided. Each of fixed and float has an after parameter to specify the number of digits required after the decimal point, and an exp parameter in float specifies the width allowed for the exponent. If V cannot be expressed as a string within the given width, even when the value of after, if provided, has been reduced, then a string filled with errorchar {10.2.1.t } is returned instead. Leading zeroes are replaced by spaces and a sign is normally included. The user can, however, specify that a sign is to be included only for negative values by specifying a negative width. If the width specified is zero, then the shortest possible string into which V can be converted, consistently with the other parameters, is returned. The following examples illustrate some of the possibilities: print(whole (i, -4)) which might print " 0", " 99", " -99", "9999" or, if i were greater than 9999, "****", where "*" is the yield of errorchar; print(whole (i, 4)) which would print " +99" rather than " 99"; print(whole (i, 0)) which might print "0", "99", "-99", "9999" or "99999"; print(fixed (x, -6,3)) which might print " 2.718", "27.183" or "271.83" (in which one place after the decimal point has heen sacrificed in order to fit the number in); print(fixed (x, 0,3)) which might print "2.718", "27.183" or "271.823"; print(float(x, 9,3,2)) which might print "-2.71810+0", "+2.71810-1", or "+2.7210+11" (in which one place after the decimal point has been sacrificed in order to make room for the unexpectedly large exponent).
}
a) MODE {?}NUMBER= UNION (« {L} REAL », « {L} INT »);
b) PROC whole = (NUMBER v, INT width)STRING: CASE v IN « ({L} INT x): (INT length := ABS width - (x < {L} 0 ¦ width > 0 | 1 | 0), {L} INT n := ABS x; IF width = 0 THEN {L} INT m := n; length := 0; WHILE m DO SKIP OD
FI; STRING s := subwhole (n, length); IF length = 0 | char in string (errorchar, LOC INT, s) THEN ABS width * errorchar ELSE (x< {L} 0 | "-" |: width>0 | "+" | "") PLUSTO s; (width /= 0 (ABS width - UPB s) * " " PLUSTO s); s FI)»,
« ({L} REAL x): fixed (x, width, 0) » ESAC;
c) PROC fixed (NUMBER v, INT width, after)STRING: CASE v IN « ({L} REAL x): IF INT length := ABS width - (x < {L} 0 ¦ width>0 | 1 | 0); after >=0 (length> after ¦ width = 0) THEN {L} REAL y = ABS x; IF width =0 THEN length := (after = 0 | 1 | 0); WHILE y + {L}.5* {L}.1 ^ after>={L}10 ^ length DO length +:= 1 OD; length +:= (after = 0 | 0 | after + 1) FI; STRING s := sub fixed (y, length, after); IF char in string (errorchar, LOC INT, s) THEN(length> UPB s y< {L} 10 | "0" PLUSTO s); (x< {L} 0 | "-" |: width>0 | "+" |"") PLUSTO s; (width /= 0 | (ABS width - UPB s) * " " PLUSTO s); s ELIF after> 0 THEN fixed (v, width, after - 1) ELSE ABS width * errorchar FI ELSE undefined; ABS width * errorchar FI», « ({L} INT x): fixed ({L} REAL (x), width, after) » ESAC;
d) PROC float = (NUMBER v, INT width, after, exp)STRING: CASE v IN « ({L} REAL x): IF INT before = ABS width - ABS exp - (after /= 0| after + 1| 0) -2; SIGN before + SIGN after> 0 THEN STRING s, {L} REAL y := ABS x, INT p := 0; {l} standardize(y, before, after, p); s := fixed({K} SIGN x * y, SIGN width * (ABS width - ABS exp - 1),## after) + "10" + whole (p, exp); IF exp = 0 ¦ char in string (errorchar, LOC INT, s) THEN float(x, width, (after /= 0| after - 1|0),## (exp>0 | exp + 1 | exp-1)) ELSE s FI ELSE undefined; ABS width * errorchar FI», « ({L} INT x): float({L} REAL (x), width, after, exp) » ESAC;
e) PROC {?}subwhole = (NUMBER v, INT width)STRING: # returns a string of maximum length 'width' containing a decimal representation of the positive integer 'v' # CASE v IN « ({L} INT x): BEGIN STRING s, {L} INT n := x; WHILE dig char ({S} (n MOD {L} 10)) PLUSTO s; n DO SKIP OD; (UPB s> width | width * errorchar | s) END » ESAC;
f) PROC {?}subfixed = (NUMBER v, INT width, after)STRING: # returns a string of maximum length 'width' containing a rounded decimal representation of the positive real number 'v'; if 'after' is greater than zero, this string contains a decimal point followed by 'after' digits s # CASE v IN « ({L} REAL x): BEGIN STRING s, INT before := 0; {L} REAL y := x + {L}.5 x {L}.1 ^ after; PROC choosedig = (REF {L} REAL y)CHAR: dig char((INT c := {S} ENTIER(y *:= {L}10.0); (c>9 | c := 9);## y -:= {K}c; c)); WHILE y > {L} 10.0 ^ before DO before +:= 1 OD; y /:= {L}10.0 ^ before; TO before DO s PLUSAB choosedig(y) OD; (after> 0 | s PLUSAB "."); TO after DO s PLUSAB choosedig(y) OD; (UPB s> width | width * errorchar | s) END » ESAC;
g) PROC {?}{l} standardize = (REF {L} REAL y, INT before, after, REF INT p)VOID: # adjusts the value of 'y' so that it may be transput according to the format n(before)d, n(after)d ; 'p' is set so that y * 10 ^ p is equal to the original value of 'y' # BEGIN {L} REAL g = {L}10.0 ^ before; {L} REAL h = g * {L}.1; WHILE y > g DO y *:= {L}.1; p +:= 1 OD; (y /= {L} 0.0| WHILE y<h DO y *:= {L}10.0; p-:= l OD); (y + {L}.5 * {L}.1 ^after>=g | y:=h; p +:= 1) END;
h) PROC {?}dig char = (INT x)CHAR: "0123456789abcdef"[x + 1];
i) PROC {?}string to {l} int = (STRING s, INT radix, REF {L} INT i)BOOL: # returns true if the absolute value of the result is < '140 max int # BEGIN {L} INT lr = {K} radix; BOOL safe := TRUE; {L} INT n := {L} 0, {L} INT m = {l} max int lr; {L} INT m1 = {l} max int - m * lr; FOR i FROM 2 TO UPB s WHILE {L} INT dig = {K} char dig(s [i]); safe := n < m ¦ n = m dig <= m1
DO n := n * lr + dig OD; IF safe THEN i := (s[l]="+" | n | -n); TRUE ELSE FALSE FI
END;
j) PROC {?}string to {l} real = (STRING s, REF {L} REAL r)BOOL: # returns true if the absolute value of the result is < '140 max real # BEGIN INT e := UPB s + 1; char in string(" ", e, s); INT p := e; char in string(". ", p, s); INT j := 1, length =0, {L} REAL x := {L} 0.0; # skip leading zeroes: # FOR i FROM 2 TO e -1 WHILE s[i]="0" ¦ s[i] ="." ¦ s[i] ="" DO j := i OD; FOR i FROM j + 1 TO e - 1 WHILE length < {l} real width DO IF s [i] /= "." THEN x := x * {L}10.0 + {K} char dig(s[j := i]); length +:= i FI # all significant digits converted #
OD;
# set preliminary exponent: # INT exp := (p>j | p-j-i | p-j), expart := 0; # convert exponent part: # BOOL safe := IF e< UPB s THEN string to int(s [e + 1: ], 10), expart) ELSE TRUE FI;
# prepare a representation of '140 max real to compare with the L REAL value to be delivered: # {L} REAL max stag := {l} max real, INT max exp := t); {l} standardize(max stag, length, 0, max exp); exp +:= expart; IF safe ¦ (exp> max exp ¦ exp = max exp x> max stag) THEN FALSE ELSE r := (s[1]="+" | x | -x) * {L} 10.0 ^ exp; TRUE FI
END;
k) PROC {?}char dig = (CHAR x)INT: (x = " "|0|INT i; char in string(x, i, "0123456789abcdef"); i - 1);
l) PROC char in string = (CHAR c, REF INT i, STRING s)BOOL: (BOOL found := FALSE; FOR k FROM LWB s TO UPB s WHILE found DO (c = s[k] | i := k; found := TRUE) OD; found);
m) INT {l} int width = # the smallest integral value such that ''140 max int' may be converted without error using the pattern n('140 int width)d # (INT c := 1; WHILE {L}10 ^ (c-1)< {L}.1 * {l} maxint DO c +:= 1 OD; c);
n) INT {l} real width = # the smallest integral value such that different strings are produced by conversion of 'L1.0' and of 'L1.0 + '140 small real' using the pattern d, n('140 real width - i)d # 1 - {S} ENTIER({l} ln({l} small real) / {l} ln({L} 10));
o) INT {l} exp width = # the smallest integral value
such that ''140 max real' may be converted without error using the pattern
d.n('140 real width - i)d e n('140 exp width)d # 1 + {S} ENTIER({l} ln({l}
ln({l} max real)/{l} ln({L} 10))/{l} ln({L} 10));
10.3.2.2. Transput modes a) MODE {?}SIMPLOUT = UNION(« {L} INT » , « {L} REAL », « {L} COMPL » , BOOL,## « {L} BITS » , CHAR, [ ]CHAR);
b) MODE {?}OUTTYPE = © an actual-declarer specifying a mode united from {2.1.3.6.a } a sufficient set of modes none of which is 'void' or contains 'flexible', 'reference to', 'procedure' or 'union of' ©;
c) MODE {?}SIMPLIN = UNION(«REF {L} INT », « REF {L} REAL », « REF {L} COMPL t»,## REF BOOL, « REF {L} BITS », REF CHAR, REF [ ] CHAR, REF STRING);
d) MODE {?}INTYPE = © an actual-declarer specifying a mode united from {2.1.3.6.a } 'reference to flexible row of character' together with a sufficient set of modes each of which is 'reference to' followed by a mode which does not contain 'flexible', 'reference to', 'procedure' or 'union of' ©;
{See the remarks after 10.2.3.1
concerning
the term "sufficient set".}
10.3.2.3. Straightening a) OP {?}STRAIGHTOUT = (OUTTYPE x) [ ] SIMPLOUT:## © the result of "straightening" 'x' ©;
b) OP {?}STRAIGHTIN = (INTYPE x) [ ] SIMPLIN:## © the result of straightening 'x' ©;
c) The result of "straightening" a given value V is a multiple value W {of one dimension} obtained as follows:
· it is required that V (if it is a name) be not nil;
· a counter i is set to 0:
· V is "traversed" {d} using
· W is composed of, a descriptor ((1, i)) and the elements obtained by traversing V:
· if V is not (is) a name, then the mode of the result is the mode specified by [ ] SIMPLOUT ([ ] SIMPLIN).
d) A value V is "traversed", using a counter i, as follows:
· i is increased
by one:
· the element of W selected by (i) is V:
· for j = l, ...,
u, the element (the subname) of V selected by (j) is traversed using
i;
· for j = l1,
... u1, the multiple value selected {2.1.3.4.i
} by
(the name generated {2.1.3.4.j
} by) the trim (j, (l2,
u2, 0), ..., (ln, un, 0)) is traversed
using i;
· the fields (the
subnames of V referring to the fields) of V1, taken in order,
are traversed using i.