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