xref: /inferno-os/doc/limbo/addendum.ms (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1*46439007SCharles.Forsyth.TL
2*46439007SCharles.ForsythAddendum to
3*46439007SCharles.Forsyth.I "The Limbo Programming Language"
4*46439007SCharles.Forsyth.AU
5*46439007SCharles.ForsythVita Nuova
6*46439007SCharles.Forsyth.br
7*46439007SCharles.Forsyth30 March 2005
8*46439007SCharles.Forsyth.NH 1
9*46439007SCharles.ForsythIntroduction
10*46439007SCharles.Forsyth.LP
11*46439007SCharles.ForsythThis addendum provides a brief summary of several language changes to
12*46439007SCharles.ForsythLimbo since
13*46439007SCharles.Forsyth.I "The Limbo Programming Language"
14*46439007SCharles.Forsythwas last revised:
15*46439007SCharles.Forsyth.RS
16*46439007SCharles.Forsyth.IP •
17*46439007SCharles.Forsythbuffered channels
18*46439007SCharles.Forsyth.IP •
19*46439007SCharles.Forsythunrestricted \f5alt\f1
20*46439007SCharles.Forsyth.IP •
21*46439007SCharles.Forsythfunction references
22*46439007SCharles.Forsyth.IP •
23*46439007SCharles.Forsythexceptions
24*46439007SCharles.Forsyth.IP •
25*46439007SCharles.Forsythexponentiation
26*46439007SCharles.Forsyth.IP •
27*46439007SCharles.Forsythfixed-point types
28*46439007SCharles.Forsyth.RE
29*46439007SCharles.Forsyth.NH 1
30*46439007SCharles.ForsythBuffered channels
31*46439007SCharles.Forsyth.LP
32*46439007SCharles.ForsythA buffered channel can now be declared:
33*46439007SCharles.Forsyth.P1
34*46439007SCharles.Forsythc := chan[1] of int;
35*46439007SCharles.Forsyth.P2
36*46439007SCharles.ForsythHere the buffer size is 1. A send on this channel will succeed immediately
37*46439007SCharles.Forsythif there is a receiver waiting or if the buffer is empty. A receive on this
38*46439007SCharles.Forsythchannel will succeed immediately if there is a data item in the buffer. This allows us to
39*46439007SCharles.Forsythwrite a very simple locking mechanism:
40*46439007SCharles.Forsyth.P1
41*46439007SCharles.Forsythacquire(c: chan of int)
42*46439007SCharles.Forsyth{
43*46439007SCharles.Forsyth	c <-= 0;
44*46439007SCharles.Forsyth}
45*46439007SCharles.Forsyth
46*46439007SCharles.Forsythrelease(c: chan of int)
47*46439007SCharles.Forsyth{
48*46439007SCharles.Forsyth	<-c;
49*46439007SCharles.Forsyth}
50*46439007SCharles.Forsyth
51*46439007SCharles.Forsythnew(): chan of int
52*46439007SCharles.Forsyth{
53*46439007SCharles.Forsyth	return chan[1] of int;
54*46439007SCharles.Forsyth}
55*46439007SCharles.Forsyth.P2
56*46439007SCharles.ForsythThe declaration
57*46439007SCharles.Forsyth.P1
58*46439007SCharles.Forsythc := chan[0] of int;
59*46439007SCharles.Forsyth.P2
60*46439007SCharles.Forsythis equivalent to
61*46439007SCharles.Forsyth.P1
62*46439007SCharles.Forsyth	c := chan of int;
63*46439007SCharles.Forsyth.P2
64*46439007SCharles.ForsythAn attempt to create a channel with a negative buffer size will raise
65*46439007SCharles.Forsythan exception. An attempt to create a channel with a very large buffer
66*46439007SCharles.Forsythmay result in an immediate memory exception if there is not enough
67*46439007SCharles.Forsythroom for the buffer.
68*46439007SCharles.Forsyth.NH 1
69*46439007SCharles.ForsythUnrestricted
70*46439007SCharles.Forsyth.B alt
71*46439007SCharles.Forsyth.LP
72*46439007SCharles.ForsythThe implementation has changed to remove the restriction that only one process can be
73*46439007SCharles.Forsythwaiting in an
74*46439007SCharles.Forsyth.CW alt
75*46439007SCharles.Forsythto send or receive on a particular channel.
76*46439007SCharles.ForsythThe busy exception never occurs now. Thus you can do
77*46439007SCharles.Forsyth.P1
78*46439007SCharles.Forsythi()
79*46439007SCharles.Forsyth{
80*46439007SCharles.Forsyth	c := chan of int;
81*46439007SCharles.Forsyth	c1 := chan of int;
82*46439007SCharles.Forsyth	spawn p(c, c1);
83*46439007SCharles.Forsyth	<-c;
84*46439007SCharles.Forsyth	spawn p(c, c1);
85*46439007SCharles.Forsyth	<-c;
86*46439007SCharles.Forsyth	for(i := 0; i < 20; i++)
87*46439007SCharles.Forsyth		c1 <-= i;
88*46439007SCharles.Forsyth}
89*46439007SCharles.Forsyth
90*46439007SCharles.Forsythp(c: chan of int, c1: chan of int)
91*46439007SCharles.Forsyth{
92*46439007SCharles.Forsyth	c <-= 0;
93*46439007SCharles.Forsyth	for(;;)
94*46439007SCharles.Forsyth		alt{
95*46439007SCharles.Forsyth			i := <-c1 =>
96*46439007SCharles.Forsyth				;
97*46439007SCharles.Forsyth		}
98*46439007SCharles.Forsyth}
99*46439007SCharles.Forsyth.P2
100*46439007SCharles.ForsythThe two spawned processes can both wait on
101*46439007SCharles.Forsyth.CW c1
102*46439007SCharles.Forsythwithout fuss.
103*46439007SCharles.ForsythProcesses are queued on a strict FIFO basis so, in
104*46439007SCharles.Forsyththe example above, the two processes receive on
105*46439007SCharles.Forsyth.CW c1
106*46439007SCharles.Forsythalternately.
107*46439007SCharles.Forsyth.NH 1
108*46439007SCharles.ForsythFunction references
109*46439007SCharles.Forsyth.LP
110*46439007SCharles.ForsythFunction references may be declared as follows:
111*46439007SCharles.Forsyth.P1
112*46439007SCharles.Forsythfp: ref fn(s1: string, s2: string): int;
113*46439007SCharles.Forsyth.P2
114*46439007SCharles.ForsythGiven the function
115*46439007SCharles.Forsyth.P1
116*46439007SCharles.Forsythcmp(s1: string, s2: string): int
117*46439007SCharles.Forsyth{
118*46439007SCharles.Forsyth	if(s1 < s2)
119*46439007SCharles.Forsyth		return -1;
120*46439007SCharles.Forsyth	if(s1 > s2)
121*46439007SCharles.Forsyth		return 1;
122*46439007SCharles.Forsyth	return 0;
123*46439007SCharles.Forsyth}
124*46439007SCharles.Forsyth.P2
125*46439007SCharles.Forsytha reference to it can be created by assignment:
126*46439007SCharles.Forsyth.P1
127*46439007SCharles.Forsythfp = cmp;
128*46439007SCharles.Forsyth.P2
129*46439007SCharles.Forsythwhere the name can be qualified by an explicit module reference as usual:
130*46439007SCharles.Forsyth.P1
131*46439007SCharles.Forsythfp = mod->cmp;
132*46439007SCharles.Forsyth.P2
133*46439007SCharles.Forsythor it can be returned from a function:
134*46439007SCharles.Forsyth.P1
135*46439007SCharles.ForsythCmp: type ref fn(s1: string, s2: string): int;
136*46439007SCharles.Forsyth
137*46439007SCharles.Forsythrcmp(s1: string, s2: string): int
138*46439007SCharles.Forsyth{
139*46439007SCharles.Forsyth	return -cmp(s1, s2);
140*46439007SCharles.Forsyth}
141*46439007SCharles.Forsyth
142*46439007SCharles.Forsythchoose(i: int): Cmp
143*46439007SCharles.Forsyth{
144*46439007SCharles.Forsyth	if(i)
145*46439007SCharles.Forsyth		return rcmp;
146*46439007SCharles.Forsyth	return cmp;
147*46439007SCharles.Forsyth}
148*46439007SCharles.Forsyth.P2
149*46439007SCharles.Forsyth(the declaration of the synonym
150*46439007SCharles.Forsyth.CW Cmp
151*46439007SCharles.Forsythwas done only for clarity).
152*46439007SCharles.ForsythThey may be declared and passed as parameters:
153*46439007SCharles.Forsyth.P1
154*46439007SCharles.Forsythsort(a: array of string, f: ref fn(s1, s2: string): int): array of string
155*46439007SCharles.Forsyth{
156*46439007SCharles.Forsyth	# ...
157*46439007SCharles.Forsyth}
158*46439007SCharles.Forsyth	# ...
159*46439007SCharles.Forsythb := sort(a, cmp);
160*46439007SCharles.Forsythc := sort(a, rcmp);
161*46439007SCharles.Forsyth.P2
162*46439007SCharles.ForsythThe function is called via the reference by
163*46439007SCharles.Forsyth.P1
164*46439007SCharles.Forsyth	r := fp("fred", "bloggs");
165*46439007SCharles.Forsyth.P2
166*46439007SCharles.ForsythOtherwise function references behave just like any other reference type.
167*46439007SCharles.Forsyth.NH 1
168*46439007SCharles.ForsythExceptions
169*46439007SCharles.Forsyth.LP
170*46439007SCharles.ForsythBoth string exceptions and user defined exceptions are now provided.
171*46439007SCharles.ForsythThe
172*46439007SCharles.Forsyth.CW Sys
173*46439007SCharles.Forsythmodule interface to exceptions
174*46439007SCharles.Forsythhas been removed and replaced by new language constructs in limbo.
175*46439007SCharles.Forsyth.NH 2
176*46439007SCharles.ForsythString exceptions
177*46439007SCharles.Forsyth.LP
178*46439007SCharles.ForsythSimple string exceptions can be raised as follows
179*46439007SCharles.Forsyth.P1
180*46439007SCharles.Forsythraise \fIs\fP;
181*46439007SCharles.Forsyth.P2
182*46439007SCharles.Forsythwhere
183*46439007SCharles.Forsyth.I s
184*46439007SCharles.Forsythis any value of type string (it need not be constant).
185*46439007SCharles.Forsyth.LP
186*46439007SCharles.ForsythException handlers may be attached to a block (or sequence of statements) :-
187*46439007SCharles.Forsyth.P1
188*46439007SCharles.Forsyth{
189*46439007SCharles.Forsyth	foo();
190*46439007SCharles.Forsyth	bar();
191*46439007SCharles.Forsyth} exception e {
192*46439007SCharles.Forsyth"a" or "b" =>
193*46439007SCharles.Forsyth	sys->print("caught %s\en", e);
194*46439007SCharles.Forsyth	raise;
195*46439007SCharles.Forsyth"ab*" =>
196*46439007SCharles.Forsyth	sys->print("caught %s\en", e);
197*46439007SCharles.Forsyth	exit;
198*46439007SCharles.Forsyth"abcd*" =>
199*46439007SCharles.Forsyth	sys->print("caught %s\en", e);
200*46439007SCharles.Forsyth	raise e;
201*46439007SCharles.Forsyth"a*" =>
202*46439007SCharles.Forsyth	sys->print("caught %s\en", e);
203*46439007SCharles.Forsyth	raise "c";
204*46439007SCharles.Forsyth"*" =>
205*46439007SCharles.Forsyth	sys->print("caught %s\en", e);
206*46439007SCharles.Forsyth}
207*46439007SCharles.ForsythLL:
208*46439007SCharles.Forsyth.P2
209*46439007SCharles.Forsyth.LP
210*46439007SCharles.ForsythAny exception occurring within the block (and in nested function calls within the block) can
211*46439007SCharles.Forsythpotentially be caught by the exception handler. An exception is caught by a guard exactly
212*46439007SCharles.Forsythmaching the exception string or by a guard
213*46439007SCharles.Forsyth\f5\&"\fP\fIs\fP\f5*"\fP
214*46439007SCharles.Forsythwhere
215*46439007SCharles.Forsyth.I s
216*46439007SCharles.Forsythis a prefix of the exception string.
217*46439007SCharles.ForsythThe most specific match is used. Thus a raise of "a" will be caught by the first
218*46439007SCharles.Forsythguard and not by the fourth guard. A raise of "abcde" is caught by the third and not the second
219*46439007SCharles.Forsythor fourth. If a match is found, the sequence of statements following the guard are executed.
220*46439007SCharles.ForsythIf not, the system searches for a handler at a higher level.
221*46439007SCharles.Forsyth.LP
222*46439007SCharles.ForsythAs shown above, the exception is available through the exception identifier (e in this case) if given following the exception keyword.
223*46439007SCharles.Forsyth.LP
224*46439007SCharles.ForsythThe exception is reraised using
225*46439007SCharles.Forsyth.P1
226*46439007SCharles.Forsythraise;
227*46439007SCharles.Forsyth.P2
228*46439007SCharles.Forsythor
229*46439007SCharles.Forsyth.P1
230*46439007SCharles.Forsythraise e;
231*46439007SCharles.Forsyth.P2
232*46439007SCharles.Forsyth.LP
233*46439007SCharles.ForsythBoth the block and the exception code will fall through to the statement labelled
234*46439007SCharles.ForsythLL unless, of course, they do an explicit exit, return or raise first.
235*46439007SCharles.Forsyth.NH 2
236*46439007SCharles.ForsythUser-defined exceptions
237*46439007SCharles.Forsyth.LP
238*46439007SCharles.ForsythYou can declare your own exceptions:
239*46439007SCharles.Forsyth.P1
240*46439007SCharles.Forsythimplement Fibonacci;
241*46439007SCharles.Forsyth
242*46439007SCharles.Forsythinclude "sys.m";
243*46439007SCharles.Forsythinclude "draw.m";
244*46439007SCharles.Forsyth
245*46439007SCharles.ForsythFibonacci: module
246*46439007SCharles.Forsyth{
247*46439007SCharles.Forsyth	init: fn(nil: ref Draw->Context, argv: list of string);
248*46439007SCharles.Forsyth};
249*46439007SCharles.Forsyth.P3
250*46439007SCharles.Forsyth
251*46439007SCharles.Forsythinit(nil: ref Draw->Context, nil: list of string)
252*46439007SCharles.Forsyth{
253*46439007SCharles.Forsyth	sys := load Sys Sys->PATH;
254*46439007SCharles.Forsyth	for(i := 0; ; i++){
255*46439007SCharles.Forsyth		f := fibonacci(i);
256*46439007SCharles.Forsyth		if(f < 0)
257*46439007SCharles.Forsyth			break;
258*46439007SCharles.Forsyth		sys->print("F(%d) = %d\en", i, f);
259*46439007SCharles.Forsyth	}
260*46439007SCharles.Forsyth}
261*46439007SCharles.Forsyth.P3
262*46439007SCharles.Forsyth
263*46439007SCharles.ForsythFIB: exception(int, int);
264*46439007SCharles.Forsyth.P3
265*46439007SCharles.Forsyth
266*46439007SCharles.Forsythfibonacci(n: int): int
267*46439007SCharles.Forsyth{
268*46439007SCharles.Forsyth	{
269*46439007SCharles.Forsyth		fib(1, n, 1, 1);
270*46439007SCharles.Forsyth	}exception e{
271*46439007SCharles.Forsyth	FIB =>
272*46439007SCharles.Forsyth		(x, nil) := e;
273*46439007SCharles.Forsyth		return x;
274*46439007SCharles.Forsyth	"*" =>
275*46439007SCharles.Forsyth		sys->print("unexpected string exception %s raised\en", e);
276*46439007SCharles.Forsyth	* =>
277*46439007SCharles.Forsyth		sys->print("unexpected exception raised\en");
278*46439007SCharles.Forsyth	}
279*46439007SCharles.Forsyth	return 0;
280*46439007SCharles.Forsyth}
281*46439007SCharles.Forsyth.P3
282*46439007SCharles.Forsyth
283*46439007SCharles.Forsythfib(n: int, m: int, x: int, y: int) raises (FIB)
284*46439007SCharles.Forsyth{
285*46439007SCharles.Forsyth	if(n >= m)
286*46439007SCharles.Forsyth		raise FIB(x, y);
287*46439007SCharles.Forsyth
288*46439007SCharles.Forsyth	{
289*46439007SCharles.Forsyth		fib(n+1, m, x, y);
290*46439007SCharles.Forsyth	}exception e{
291*46439007SCharles.Forsyth	FIB =>
292*46439007SCharles.Forsyth		(x, y) = e;
293*46439007SCharles.Forsyth		x = x+y;
294*46439007SCharles.Forsyth		y = x-y;
295*46439007SCharles.Forsyth		raise FIB(x, y);
296*46439007SCharles.Forsyth	}
297*46439007SCharles.Forsyth}
298*46439007SCharles.Forsyth.P2
299*46439007SCharles.Forsyth.LP
300*46439007SCharles.Forsyth.CW FIB
301*46439007SCharles.Forsythis a declared exception that returns two integers. The values are supplied when raising the exception:
302*46439007SCharles.Forsyth.P1
303*46439007SCharles.Forsythraise FIB(3, 4);
304*46439007SCharles.Forsyth.P2
305*46439007SCharles.ForsythWhen caught the values can be recovered by treating the declared exception identifier
306*46439007SCharles.Forsythas if it were a tuple of 2 integers:
307*46439007SCharles.Forsyth.P1
308*46439007SCharles.Forsyth(x, y) = e;
309*46439007SCharles.Forsyth.P2
310*46439007SCharles.ForsythIn general each exception alternative treats the exception identifier appropriately : as a string
311*46439007SCharles.Forsythwhen the exception qualifier is a string, as the relevant tuple when the exception is declared.
312*46439007SCharles.Forsyth.LP
313*46439007SCharles.ForsythIf you do
314*46439007SCharles.Forsyth.P1
315*46439007SCharles.Forsyth"abcde" or FIB =>
316*46439007SCharles.Forsyth	(x, y) = e;
317*46439007SCharles.Forsyth	sys->print("%s\en", e);
318*46439007SCharles.Forsyth.P2
319*46439007SCharles.Forsythyou will get a compiler error as
320*46439007SCharles.Forsyth.CW e 's
321*46439007SCharles.Forsythtype is indeterminate within this alternative.
322*46439007SCharles.Forsyth.LP
323*46439007SCharles.ForsythReraising is the same as in the case of string exceptions.
324*46439007SCharles.Forsyth.LP
325*46439007SCharles.ForsythNote also the difference between the string guard
326*46439007SCharles.Forsyth\&\f5"*"\fP and the guard
327*46439007SCharles.Forsyth.CW *
328*46439007SCharles.Forsythin
329*46439007SCharles.Forsyththe function fibonacci.
330*46439007SCharles.ForsythThe former will match any string exception, the latter any exception. If a
331*46439007SCharles.Forsythstring exception does occur it matches the former as it is the most specific.
332*46439007SCharles.ForsythIf an unexpected user defined
333*46439007SCharles.Forsythexception occurs it matches the latter.
334*46439007SCharles.Forsyth.LP
335*46439007SCharles.ForsythThe main difference between declared exceptions and string exceptions is
336*46439007SCharles.Forsyththat the former must be caught by the immediate caller of a function that
337*46439007SCharles.Forsythraises them, otherwise they turn into a string exception whose name is derived
338*46439007SCharles.Forsythfrom that of the exception declaration.
339*46439007SCharles.Forsyth.NH 2
340*46439007SCharles.ForsythThe
341*46439007SCharles.Forsyth.CW raises
342*46439007SCharles.Forsythclause
343*46439007SCharles.Forsyth.LP
344*46439007SCharles.ForsythThe definition of the function fib in the above example also lists the user defined exceptions it can raise via the use of a
345*46439007SCharles.Forsyth.CW raises
346*46439007SCharles.Forsythclause. In this case there is just the one exception (\f5FIB\f1). These
347*46439007SCharles.Forsythclauses (if given) must be compatible between any declaration and definition of the function.
348*46439007SCharles.Forsyth.LP
349*46439007SCharles.ForsythThe compiler reports instances of functions which either raise some exception which
350*46439007SCharles.Forsythis not mentioned in their raises clause or does not raise some exception which is
351*46439007SCharles.Forsythmentioned in their raises clause. Currently the report is a warning.
352*46439007SCharles.Forsyth.NH 1
353*46439007SCharles.ForsythExponentiation
354*46439007SCharles.Forsyth.LP
355*46439007SCharles.ForsythThe exponentiation operator (written as
356*46439007SCharles.Forsyth.CW ** )
357*46439007SCharles.Forsythis now part of the Limbo language.
358*46439007SCharles.ForsythIts precedence is above that of multiplication, division and modulus but below
359*46439007SCharles.Forsyththat of the unary operators. It is right associative. Thus
360*46439007SCharles.Forsyth.P1
361*46439007SCharles.Forsyth3**4*2 = (3**4)*2 = 81*2 = 162
362*46439007SCharles.Forsyth-3**4 = (-3)**4 = 81
363*46439007SCharles.Forsyth2**3**2 = 2**(3**2) = 2**9 = 512
364*46439007SCharles.Forsyth.P2
365*46439007SCharles.ForsythThe type of the left operand must be
366*46439007SCharles.Forsyth.CW int ,
367*46439007SCharles.Forsyth.CW big
368*46439007SCharles.Forsythor
369*46439007SCharles.Forsyth.CW real .
370*46439007SCharles.ForsythThe type of the right operand must be
371*46439007SCharles.Forsyth.CW int .
372*46439007SCharles.ForsythThe type of the result is the type of the left operand.
373*46439007SCharles.Forsyth.NH 1
374*46439007SCharles.ForsythFixed point types
375*46439007SCharles.Forsyth.LP
376*46439007SCharles.ForsythA declaration of the form
377*46439007SCharles.Forsyth.P1
378*46439007SCharles.Forsythx: fixed(0.2, 12345.0);
379*46439007SCharles.Forsyth.P2
380*46439007SCharles.Forsythdeclares
381*46439007SCharles.Forsyth.CW x
382*46439007SCharles.Forsythto be a variable of a fixed point type. The scale of the type is
383*46439007SCharles.Forsyth1/5 and the maximum absolute value of the type is 12345.0.
384*46439007SCharles.Forsyth.LP
385*46439007SCharles.ForsythSimilarly
386*46439007SCharles.Forsyth.P1
387*46439007SCharles.Forsythx: fixed(0.125, 4096.0)
388*46439007SCharles.Forsyth.P2
389*46439007SCharles.Forsythspecifies a scale of 0.125 and a maximum absolute value of 4096.
390*46439007SCharles.ForsythThis requires only 17 bits so the underlying type will be
391*46439007SCharles.Forsyth.CW int
392*46439007SCharles.Forsythand the compiler
393*46439007SCharles.Forsythis free to allocate the remaining 15 bits to greater range or greater
394*46439007SCharles.Forsythaccuracy. In fact the compiler always chooses the latter.
395*46439007SCharles.Forsyth.LP
396*46439007SCharles.ForsythThe maximum absolute value is optional :-
397*46439007SCharles.Forsyth.P1
398*46439007SCharles.Forsythx: fixed(0.125);
399*46439007SCharles.Forsyth.P2
400*46439007SCharles.Forsythis equivalent to
401*46439007SCharles.Forsyth.P1
402*46439007SCharles.Forsythx: fixed(0.125, 2147483647.0 * 0.125);
403*46439007SCharles.Forsyth.P2
404*46439007SCharles.Forsythand ensures the underlying type is exactly an int ie the compiler has
405*46439007SCharles.Forsythno scope to add any extra bits for more accuracy.
406*46439007SCharles.Forsyth.LP
407*46439007SCharles.ForsythA binary fixed point type with 8 bits before the binary point and 24 after
408*46439007SCharles.Forsythmight therefore be declared as
409*46439007SCharles.Forsyth.P1
410*46439007SCharles.Forsythx: fixed(2.0**-24);
411*46439007SCharles.Forsyth.P2
412*46439007SCharles.Forsyth.LP
413*46439007SCharles.ForsythThe scale must be static: its value known at compile time and
414*46439007SCharles.Forsythit must be positive and real; similarly for the maximum absolute
415*46439007SCharles.Forsythvalue when specified.
416*46439007SCharles.Forsyth.LP
417*46439007SCharles.ForsythCurrently the only underlying base type supported is
418*46439007SCharles.Forsyth.CW int .
419*46439007SCharles.Forsyth.LP
420*46439007SCharles.ForsythA shorthand for fixed point types is available through the use of
421*46439007SCharles.Forsyth.CW type
422*46439007SCharles.Forsythdeclarations:
423*46439007SCharles.Forsyth.P1
424*46439007SCharles.Forsythfpt: type fixed(2.0**-16);
425*46439007SCharles.Forsyth.P2
426*46439007SCharles.ForsythWe can then do
427*46439007SCharles.Forsyth.P1
428*46439007SCharles.Forsythx, y, z: fpt;
429*46439007SCharles.Forsythzero: con fpt(0);
430*46439007SCharles.Forsyth
431*46439007SCharles.Forsythx = fpt(3.21);
432*46439007SCharles.Forsythy = fpt(4.678);
433*46439007SCharles.Forsythz = fpt(16r1234.5678);
434*46439007SCharles.Forsythz = -x;
435*46439007SCharles.Forsythz = x+y;
436*46439007SCharles.Forsythz = x-y;
437*46439007SCharles.Forsythz = x*y;
438*46439007SCharles.Forsythz = x/y;
439*46439007SCharles.Forsythsys->print("z=%f", real z);
440*46439007SCharles.Forsyth.P2
441*46439007SCharles.ForsythThere is no implicit numerical casting in Limbo so we have to use explicit
442*46439007SCharles.Forsythcasts to initialize fixed point variables. Note the use of a base to
443*46439007SCharles.Forsythinitialize
444*46439007SCharles.Forsyth.CW z
445*46439007SCharles.Forsythusing a new literal representation.
446*46439007SCharles.Forsyth.LP
447*46439007SCharles.ForsythGiven
448*46439007SCharles.Forsyth.P1
449*46439007SCharles.Forsythfpt1: type fixed(0.12345);
450*46439007SCharles.Forsythx: fpt1;
451*46439007SCharles.Forsythfpt2: type fixed(0.1234);
452*46439007SCharles.Forsythy: fpt2;
453*46439007SCharles.Forsythfpt3: type fixed(0.123);
454*46439007SCharles.Forsythz: fpt3;
455*46439007SCharles.Forsyth.P2
456*46439007SCharles.Forsyththen
457*46439007SCharles.Forsyth.P1
458*46439007SCharles.Forsythz = x*y;
459*46439007SCharles.Forsyth.P2
460*46439007SCharles.Forsythis illegal. We must add casts and do
461*46439007SCharles.Forsyth.P1
462*46439007SCharles.Forsythz = fpt3(x)*fpt3(y);
463*46439007SCharles.Forsyth.P2
464*46439007SCharles.Forsythie type equivalence between fixed point types requires equivalence of scale
465*46439007SCharles.Forsyth(and of maximum absolute value when specified).
466*46439007SCharles.Forsyth.LP
467*46439007SCharles.ForsythFixed point types may be used where any other numerical type (byte, int, big, real) can be used. So you can compare them, have a list of them, have a channel of them, cast them to or from string and so on.
468*46439007SCharles.Forsyth.LP
469*46439007SCharles.ForsythYou cannot use complement(~), not(!), and(&), or(|), xor(^) or modulus(%) on them as fixed point types are basically a form of real type.
470*46439007SCharles.Forsyth.NH 2
471*46439007SCharles.ForsythAccuracy
472*46439007SCharles.Forsyth.LP
473*46439007SCharles.ForsythA fixed point value is a multiple of its scale. Given fixed point values X, Y and
474*46439007SCharles.ForsythZ of scale s, t and u respectively, we can write
475*46439007SCharles.Forsyth.P1
476*46439007SCharles.ForsythX = sx
477*46439007SCharles.ForsythY = ty
478*46439007SCharles.ForsythZ = uz
479*46439007SCharles.Forsyth.P2
480*46439007SCharles.Forsythwhere x, y and z are integers.
481*46439007SCharles.Forsyth.LP
482*46439007SCharles.ForsythFor the multiplication Z = X*Y the accuracy achieved is given by
483*46439007SCharles.Forsyth.P1
484*46439007SCharles.Forsyth| z - (st/u)xy | < 1
485*46439007SCharles.Forsyth.P2
486*46439007SCharles.Forsythand for the division Z = X/Y
487*46439007SCharles.Forsyth.P1
488*46439007SCharles.Forsyth| z - (s/(tu))x/y | < 1
489*46439007SCharles.Forsyth.P2
490*46439007SCharles.ForsythThat is, the result is always within the result scale of the correct real value.
491*46439007SCharles.Forsyth.LP
492*46439007SCharles.ForsythThis also applies when casting a fixed point type to another, casting an
493*46439007SCharles.Forsythinteger to a fixed point type and casting a fixed point type to an integer. These
494*46439007SCharles.Forsythare all examples of the multiplication law with t = y = 1 since an
495*46439007SCharles.Forsythinteger may be thought of as a fixed point type with a scale of 1.
496