1. Tight programming exercise, using bad programming practices

A friend who is studying, was asked to create pseudo-code for the following problem:

  • Your algorithm should:

  • o Search a string of at least five numbers (for example, 37540)
    o Identify all of the substrings that form numbers that are divisible by 3.
    o For example, applying the algorithm on the string 37540 should produce the
    following substrings (not necessarily in this order): 0; 3; 75; 54; 375; 540.

    OK, did that for him, but just for the heck of it, I also provided the following code,
    as an example of a few bad programming practices to see how small I could make it,
    while still being mostly legible.
    Other than making the two value related statements into one, can anyone make it smaller?

procedure tiny() 
sequence s1,s2,s3="37540" 
atom a1 integer i1,i2=0 
while i2<5 do i2=i2+1 i1=i2-1 
while i1<5 do i1=i1+1 s1=s3[i2..i1] 
s2=value(s1) a1=s2[2] 
if floor(a1/3)=(a1/3) then 
puts(1,s1&", ") end if 
end while end while 
end procedure 
tiny()  
new topic     » topic index » view message » categorize

2. Re: Tight programming exercise, using bad programming practices

s3 should be a parameter and it should use length(s3) rather than 5. for loops ought to be slightly shorter. Using a bit of edit-fu I knocked up a quick table to help me visualize things:

    r3   &0r3 &1r3 &2r3 &3r3 &4r3 &5r3 &6r3 &7r3 &8r3 &9r3 
0    0    0    1    2    0    1    2    0    1    2    0   
1    1    1    2    0    1    2    0    1    2    0    1   
2    2    2    0    1    2    0    1    2    0    1    2   
3    0    0    1    2    0    1    2    0    1    2    0   
4    1    1    2    0    1    2    0    1    2    0    1   
5    2    2    0    1    2    0    1    2    0    1    2   
6    0    0    1    2    0    1    2    0    1    2    0   
7    1    1    2    0    1    2    0    1    2    0    1   
8    2    2    0    1    2    0    1    2    0    1    2   
9    0    0    1    2    0    1    2    0    1    2    0   

We can generalise that appending digit D to some number N shifts the remainder by D%3, in other words we do not need to extract the slice, except for display.

Putting these ideas into practice, and squishing it up just how you like it:

procedure tiny(sequence s) 
integer l=length(s), r3 
for i=1 to l do r3 = 0 for j=i to l do 
r3 = remainder(r3+s[j]-'0',3) 
if r3=0 then puts(1,s[i..j]&", ") end if 
end for end for 
end procedure 
tiny("37540") 
new topic     » goto parent     » topic index » view message » categorize

3. Re: Tight programming exercise, using bad programming practices

petelomax said...

..

We can generalise that appending digit D to some number N shifts the remainder by D%3, in other words we do not need to extract the slice, except for display.

Putting these ideas into practice, and squishing it up just how you like it:

procedure tiny(sequence s) 
integer l=length(s), r3 
for i=1 to l do r3 = 0 for j=i to l do 
r3 = remainder(r3+s[j]-'0',3) 
if r3=0 then puts(1,s[i..j]&", ") end if 
end for end for 
end procedure 
tiny("37540") 

Pete, '0' is 48, divisible by 3, so that expression could be simplified a little more. In Orac the applicable line would then become:

r3=(r3+s.j)%3 

Spock

new topic     » goto parent     » topic index » view message » categorize

4. Re: Tight programming exercise, using bad programming practices

Also, by using "for" instead of "while" for the loops, there are less variables to be defined. Nice!
AFAIK, the general algo of attacking the input number as a char string (sequence) with a nested loop,
is better than attempting a pure arithmetic approach. Or any other way?

new topic     » goto parent     » topic index » view message » categorize

5. Re: Tight programming exercise, using bad programming practices

The bad practices shown, are the lack of indention, meaningful variable names, comments. Multiple statements on a line. Thats all I hope ;)
Thats the approach I would have needed to use on my first computer, a 1 MHz Sinclair ZX-81 with 768 bytes of ram. Ah, the good old days.. :)
I though the question was fairly evil to ask of a non-programmer, coming up with the nested loop I mean. But I did want to show him the way it should not be done too.
By looking at a task and coming up with the algo, we have to analize what our brains are actually doing and then put that into code.
The improvements suggested are more examples of that.
Not everyone has the talent mentioned above, so regardless of how easy Euphoria might be, we can't all be programmers.
Thanks guys

new topic     » goto parent     » topic index » view message » categorize

6. Re: Tight programming exercise, using bad programming practices

fizzpopsoft said...

Also, by using "for" instead of "while" for the loops, there are less variables to be defined. Nice!
AFAIK, the general algo of attacking the input number as a char string (sequence) with a nested loop,
is better than attempting a pure arithmetic approach. Or any other way?

There is another way, in this case, since the linear sum of all characters in a multiple of 3 is itself also divisble by 3 (ditto for multiples of 9). Therefore, we can just add chars together, like so:

procedure tiny2(seq s)  
for i=1 to~s do int n=0 
for j=i to~s do n+=s.j 
if n%3=0 then puts(1,s[i..j]&", ") 
end if end for end for 
end procedure 

I guess judges would probably disqualify this since it is Orac rather than genuine Euphoria. On the other hand, it is surprisingly readable given that it is the most compact.

Spock

new topic     » goto parent     » topic index » view message » categorize

7. Re: Tight programming exercise, using bad programming practices

And yet there is also this, which loses points for having no real trickery of any note at all blink

procedure tiny(sequence s)  
integer l=length(s),n 
for i=1 to l do n=0 for j=i to l do n=n*10+s[j]-'0' 
if remainder(n,3)=0 then printf(1,"%d, ",n) end if 
end for end for  
end procedure  

Pete

PS I am a bit surprised Orac does not have "for i ~s do"

new topic     » goto parent     » topic index » view message » categorize

8. Re: Tight programming exercise, using bad programming practices

petelomax said...

And yet there is also this, which loses points for having no real trickery of any note at all blink

procedure tiny(sequence s)  
integer l=length(s),n 
for i=1 to l do n=0 for j=i to l do n=n*10+s[j]-'0' 
if remainder(n,3)=0 then printf(1,"%d, ",n) end if 
end for end for  
end procedure  

Pete

PS I am a bit surprised Orac does not have "for i ~s do"

Dang! It should have, eh? In fact, keywords like do and then are also redundant since the parser knows exactly where the expression ends. This would give us stuff like:

 
for i ~s 
 
for i ~s to 1 -- reverse direction 
 
while x 
 
if x = CASE1 
 
elsif x = CASE2 
 
proc myproc() 
 
func myfunc() 
 

BTW, using eg proc instead of procedure could be done seamlessly [ie, without breaking existing stuff] since the parser can easily know the difference between the keyword proc at the top-level versus a variable called proc at the routine level.

Putting it all together we get:

proc tiny2(seq s)   
for i ~s int n = 0  
for j ~s n += s.j  
if n%3 = 0 puts(1,s[i to j]&", ") 
end end end end 

But we can't really have stuff like that because that would make Euphoria even easier to use.

Spock

new topic     » goto parent     » topic index » view message » categorize

9. Re: Tight programming exercise, using bad programming practices

Spock said...

keywords like do and then are also redundant since the parser knows exactly where the expression ends.

I'd be ok if then were changed such that absence meant just one single statement follows, and no end if, otherwise, as now, <block> end if must follow. eg

if a=b puts(1,"a=b\n") 
if a=b then puts(1,"a=b\n") else puts(1,"a!=b\n") end if 

If asked to vote, my personal choice would be if only, and against a similar change to do/for/while, since one-liner loops are pretty rare anyway.

Spock said...
if x = CASE1 
elsif x = CASE2 

I think that elsif/else should (remain) illegal without a then.

Spock said...
end end end end 

I think that is a very bad idea and would argue quite strongly against dropping the end qualifier, in my opinion it is one of Eu's greatest strengths, and has saved me from myself countless times.

Spock said...

But we can't really have stuff like that because that would make Euphoria even easier to use.

Ha ha. Joking aside, for me the whole ease of use point is what it does, in terms of friendly error messages, with whatever you have had to type, whether terse or verbose, rather than C++'s idea of playing at mini Dr Evil: "There is a bug <tee-hee>, somewhere in your code".

Pete

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu