Re: Goto (Was Re: Open Source)
- Posted by Juergen Luethje <j.lue at ?m?.de> Oct 25, 2007
- 817 views
Pete Lomax wrote: > Juergen Luethje wrote: > > > If I didn't make a mistake, this translates to the following Eu program: > <snip> > > I actually would prefer to write the code this way: > <snip> > > Now this is short and pretty clear. Without using GOTO, the structure of > > the program (2 nested loops) is directly visible. So the "nature" of the > > program can be understood immediately and intuitively. > No arguments here, but you did need two attempts even on such a trivial piece > of code I probably better shouldn't do things like that before breakfast. > > Sorry, I do not know anything about COBOL. > Try this then: > > -- optimised best-fit algorithm > include sort.e > > integer required > required = 2482 > -- expected results with first sizes set: > --Exact 2482: 12 505, 10 425, 7 396, 6 391, 5 388, 1 377 > -- expected results with second sizes set: > --Lower 2324: 6 798, 5 734, 3 410, 2 382 > --Higher 2520: 5 734, 4 650, 3 410, 2 382, 1 344 > required = 1659 > -- expected results with first sizes set: > --Exact 1659: 11 488, 7 396, 6 391, 3 384 > -- expected results with second sizes set: > --Lower 1590: 6 798, 3 410, 2 382 > --Higher 1728: 5 734, 4 650, 1 344 > > sequence sizes > -- sizes = {377,378,384,387,388,391,396,422,424,425,488,505} > sizes = {798,344,650,410,382,734} > > sequence incset > > integer lowbest, lowlevel, highbest, highlevel, worktot, level, item > sequence lowset, highset > > procedure display(integer tot, integer level, sequence incset) > integer item > printf(1,"%d ",tot) > for i = 1 to level do > item = incset[i] > printf(1,"%d %d ",{item,sizes[item]}) > end for > puts(1," key <cr>") > if getc(0) then end if > puts(1,"\n") > end procedure > > function find_combination(integer jumpToDa200) > -- > -- this section tries to find a set of sizes which add up to the > -- required amount exactly. > -- > if jumpToDa200 then goto da200 end if > level = 1 > lowbest = 0 > highbest = 999999999 > item = length(sizes) > incset=repeat(0,item) > worktot=0 > da100:: > incset[level] = item > worktot += sizes[item] > if worktot = required then return 0 end if -- found exact fit > if worktot > required then goto da200 end if -- too big > -- > -- this set is smaller than required - save it if it is best so far > -- > if worktot > lowbest then > lowbest = worktot > lowlevel = level > lowset = incset > end if > if item > 1 then -- more to be tested > item -= 1 > level += 1 -- leave item in table; > goto da100 > end if > goto da300 > da200:: > -- > -- this set is larger than required - save it if it is best so far > -- > if worktot < highbest then > highbest = worktot > highlevel = level > highset = incset > end if > da300:: > -- > -- now we need to backtrack; remove item from running total and look > -- at the next instead. > -- > worktot -= sizes[item] > if item > 1 then -- more to be tested > item -= 1 -- look at next (overwrite item in table) > goto da100 > end if > -- > -- we have exhausted all possibilities at this level; backtrack to > -- a previous level. > -- > incset[level] = 0 > level -= 1 > if level = 0 then return 1 end if -- all done > item = incset[level] > goto da300 > > end function > > procedure main() > sizes=sort(sizes) > if not find_combination(0) then > while 1 do > display(worktot,level,incset) > -- if da200() then exit end if > if find_combination(1) then exit end if > end while > end if > puts(1,"lower figure ") > display(lowbest,lowlevel,lowset) > puts(1,"higher figure ") > display(highbest,highlevel,highset) > end procedure > main() There are only GOTOs in one routine, and this is my translated code (untested):
function find_combination(integer jumpToDa200) -- -- this section tries to find a set of sizes which add up to the -- required amount exactly. -- if not jumpToDa200 then level = 1 lowbest = 0 highbest = 999999999 item = length(sizes) incset=repeat(0,item) worktot=0 end if while 1 do flag = FALSE if not jumpToDa200 then while 1 do incset[level] = item worktot += sizes[item] if worktot = required then return 0 end if -- found exact fit if worktot > required then flag = TRUE exit end if -- too big -- -- this set is smaller than required - save it if it is best so far -- if worktot > lowbest then lowbest = worktot lowlevel = level lowset = incset end if if item <= 1 then exit end if -- more to be tested item -= 1 level += 1 -- leave item in table; end while end if if jumpToDa200 or flag = TRUE then -- -- this set is larger than required - save it if it is best so far -- if worktot < highbest then highbest = worktot highlevel = level highset = incset end if end if while 1 do -- -- now we need to backtrack; remove item from running total and look -- at the next instead. -- worktot -= sizes[item] if item > 1 then -- more to be tested item -= 1 -- look at next (overwrite item in table) exit end if -- -- we have exhausted all possibilities at this level; backtrack to -- a previous level. -- incset[level] = 0 level -= 1 if level = 0 then return 1 end if -- all done item = incset[level] end while end while end function
> I wasn't really keeping track but I think it just took me a shade under an > hour to hack > that into something working, then again I know how it works and I've managed > that trick > once before, and that I tried and failed many moons ago when I was still an Eu > novice. > While messing about I trigered two fatal crashes in Edita (in re-indent and > CtrlBracket) > which I fixed (as part of that hour), so at least it was not a complete and > utter waste > of time > > One thing I would like to say is that the original of that code was used as > part of the compilation process in a team of ten programmers for many years, > so any restructuring or rewrite would, I felt, carry a strong chance of > (re-)introducing > bugs that had been ironed out long ago. I agree. > OTOH if you translate some code from > language A to language B then a) that is a big enough upheaval anyway, and b) > if you don't test it thoroughly then you know what to expect. I agree. However, proper testing sometimes is not so easy. I mean a situation when you have copied e.g. some COBOL code from a website (and you can understand COBOL code), but you don't have a COBOL interpreter or compiler available on your system. Then you can test your translated Eu program, but you can't test the original program, and so you can't compare the behaviour of both versions of the programm. Especially in such a situation it's good when you can translate as much as possible (at least in the beginning of the translation) just by using 'search and replace', e.g. when translating a BASIC programm: - replace "ElseIf" with "elsif" - replace "Wend" with "end while" - replace "Next" with "end for" - etc. The more similar Euphoria is to the language in which the source code is written, the more parts of the code can be translated in such a safe "mechanical" way. So if the source code contains GOTO, I agree that translation especially of complex code might be safer when Euohoria had a GOTO statement, too. > The point that this is the only real nasty I have encountered in 5+ years with > Eu is not a small point either. I also only remember 1 time, when I had severe problems with translating code to Euphoria that contained GOTO. My first goal was to create a running Eu programm, by changing as few as possible in the code. So I created code for Matt's OOEU, which does support GOTO. Then I removed the GOTOs step by step and so in the end I had a program for the standard Eu interpreter. Regards, Juergen