The author suggests that most self-called programmers can't solve the following problem:
Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".
As I am interested but not yet very proficient in stack based programming languages, I ask you: how would you solve this problem in FORTH?
> The author suggests that most self-called programmers can't solve the > following problem:
> Write a program that prints the numbers from 1 to 100. But for > multiples of three print "Fizz" instead of the number and for the > multiples of five print "Buzz". For numbers which are multiples of > both three and five print "FizzBuzz".
> As I am interested but not yet very proficient in stack based > programming languages, I ask you: how would you solve this problem in > FORTH?
> Keo
Why are you interested in my solution? Why don't you give it a try? Then we'll discuss it further.
keo...@gmail.com wrote: > As I am interested but not yet very proficient in stack based > programming languages, I ask you: how would you solve this problem in > FORTH?
: fizz? 3 mod 0= dup if ." fizz" endif ; : buzz? 5 mod 0= dup if ." buzz" endif ;
: doit 101 1 do i fizz? i buzz? or 0= if i . endif cr loop ;
> The author suggests that most self-called programmers can't solve the > following problem:
> Write a program that prints the numbers from 1 to 100. But for > multiples of three print "Fizz" instead of the number and for the > multiples of five print "Buzz". For numbers which are multiples of > both three and five print "FizzBuzz".
> As I am interested but not yet very proficient in stack based > programming languages, I ask you: how would you solve this problem in > FORTH?
Cesar Rabak <csra...@yahoo.com.br> wrote: > keo...@gmail.com escreveu: > [snipped] >> As I am interested but not yet very proficient in stack based >> programming languages, I ask you: how would you solve this problem in >> FORTH?
> Did you study the solution given in the post # 53?
The code is over-factored, making it hard to read. There is also too much stack noise: this problem really doesn't need DUP SWAP etc.
A simple solution is
: bang 100 1 do i 15 mod 0= if ." FizzBuzz " else i 3 mod 0= if ." Fizz " else i 5 mod 0= if ." Buzz " else i . then then then loop ;
There are many more complex and efficient solutions possible.
( "the numbers from 1 to 100" is ambiguous. I'm assuming a half-open interval. )
> Cesar Rabak <csra...@yahoo.com.br> wrote: > > keo...@gmail.com escreveu: > > [snipped] > >> As I am interested but not yet very proficient in stack based > >> programming languages, I ask you: how would you solve this problem in > >> FORTH?
> > Did you study the solution given in the post # 53?
> The code is over-factored, making it hard to read. There is also too > much stack noise: this problem really doesn't need DUP SWAP etc.
> A simple solution is
> : bang > 100 1 do > i 15 mod 0= if ." FizzBuzz " else > i 3 mod 0= if ." Fizz " else > i 5 mod 0= if ." Buzz " else > i . then then then > loop ;
John Passaniti's solution is a bit cleaner IMO. He factors fizz and buzz, which eliminates the need for 15 mod.
Doug Hoffman <dhoff...@talkamerica.net> wrote: > On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid> > wrote: >> Cesar Rabak <csra...@yahoo.com.br> wrote: >> > keo...@gmail.com escreveu: >> > [snipped] >> >> As I am interested but not yet very proficient in stack based >> >> programming languages, I ask you: how would you solve this problem in >> >> FORTH?
>> > Did you study the solution given in the post # 53?
>> The code is over-factored, making it hard to read. There is also too >> much stack noise: this problem really doesn't need DUP SWAP etc.
>> A simple solution is
>> : bang >> 100 1 do >> i 15 mod 0= if ." FizzBuzz " else >> i 3 mod 0= if ." Fizz " else >> i 5 mod 0= if ." Buzz " else >> i . then then then >> loop ; > John Passaniti's solution is a bit cleaner IMO. He factors fizz and > buzz, which eliminates the need for 15 mod.
And adds a couple of DUPs and an OR. Shrug.
It's quite a clever solution. There's not much in it, really, and either would be from my POV perfectly acceptable.
On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
> Cesar Rabak <csra...@yahoo.com.br> wrote: > > keo...@gmail.com escreveu: > > [snipped] > >> As I am interested but not yet very proficient in stack based > >> programming languages, I ask you: how would you solve this problem in > >> FORTH?
> > Did you study the solution given in the post # 53?
> The code is over-factored, making it hard to read. There is also too > much stack noise: this problem really doesn't need DUP SWAP etc.
I don't see any problem with that code. It looks fine to me.
> A simple solution is
> : bang > 100 1 do > i 15 mod 0= if ." FizzBuzz " else > i 3 mod 0= if ." Fizz " else > i 5 mod 0= if ." Buzz " else > i . then then then > loop ;
Your solution looks fine to me too.
Your code brings up something for me. I notice those three then then thens. Forth doesn't usually have a way to skip over the rest of a loop and then repeat. We have ways to break out of the loop, but not a command to skip to the end of the loop. So we have ugly things like then then then to do it, both in DO loops and in BEGIN loops.
I've never felt the need for an improvement there. Multiple THENs don't actually cause a performance hit, only a very slight compile- time hit. Wil Baden made his THENS command which palliates it.
Somehow I never noticed until now that you can get a similar result with multiple BEGINs.
: bang1 0 BEGIN BEGIN 1+ cr dup 3 mod DUP 0= if ." Fizz" then over 5 mod dup 0= if ." Buzz" then or 0= UNTIL dup . dup 100 > UNTIL ;
I certainly don't want to propose this as clear writing or even adequate code (like, the method would run over if you changed the limit to 99BEG), it's just that I never thought of this as a single loop with a continuation. If you had a word that was just like UNTIL except it left a copy of the dest, it would effectively skip to (but not past) the end of the loop on failure or execute the rest of the loop on success.
BEGIN ... SKIP-TO-REPEAT ... SKIP-TO-REPEAT ... SKIP-TO-REPEAT ... WHILE ... REPEAT
Again, I've never felt the need to have something like this, I've always just accepted THEN THEN THEN as good enough.
Additional control structure words might someimes make the flow of control clearer, provided we all remembered what they did. What we already have is adequate.
: bang2 101 0 do i 3 mod 0= 1 and i 5 mod 0= 2 and or case 0 of i . endof 1 of Fizz endof 2 of Buzz endof 3 of FizzBuzz endof endcase loop ;
This one doesn't read better either, but at least the most common cases are tested the most often. A jump table might be more efficient but also less readable.
: which-action ( n -- n 0|1|2|3 ) dup i 3 mod 0= 1 and i 5 mod 0= 2 and or ;
: Bang3 0 begin 1+ dup 101 < while which-action do-it repeat drop ;
I guess when the first methods I learned give a result that isn't too long, then that's the most readable. There's nothing hard to understand about nested IF THENs. Just, if they get too complex you can lose track of how deeply they're nested and which places which result happens.
On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
> A simple solution is > : bang > 100 1 do > i 15 mod 0= if ." FizzBuzz " else > i 3 mod 0= if ." Fizz " else > i 5 mod 0= if ." Buzz " else > i . then then then > loop ;
Factor it and you'll be there. John Passaniti has a good factoring.
On Mar 2, 8:22 am, Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
> And adds a couple of DUPs and an OR. Shrug.
> It's quite a clever solution. There's not much in it, really, and > either would be from my POV perfectly acceptable.
Yes. It's no big deal one way or the other. My first version looked more like John's and was coded as fast as I could type it (as I suspect was the case for you and John and most Forthers). But I do worry a bit when I see triply nested IF-ELSE-THENs.
In the Mops kernel we have always had NIF, which is the same as 0= IF. I find NIF to be very useful. Using that and after seeing John's code, my favorite would be the following:
: fizz? ( n -- flag ) \ flag is 0 if hit 3 mod dup NIF ." Fizz" THEN ;
: buzz? ( n -- flag ) \ flag is 0 if hit 5 mod dup NIF ." Buzz" THEN ;
: FizzBuzz 101 1 DO cr i fizz? i buzz? * IF i . THEN LOOP ;
-Doug
p.s. Wait! I forgot to use objects! I must be coming down with the flu or something. ;-)
> On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid> > wrote:
> > Cesar Rabak <csra...@yahoo.com.br> wrote: > > > keo...@gmail.com escreveu: > > > [snipped] > > >> As I am interested but not yet very proficient in stack based > > >> programming languages, I ask you: how would you solve this problem in > > >> FORTH?
> > > Did you study the solution given in the post # 53?
> > The code is over-factored, making it hard to read. There is also too > > much stack noise: this problem really doesn't need DUP SWAP etc.
> I don't see any problem with that code. It looks fine to me.
> > A simple solution is
> > : bang > > 100 1 do > > i 15 mod 0= if ." FizzBuzz " else > > i 3 mod 0= if ." Fizz " else > > i 5 mod 0= if ." Buzz " else > > i . then then then > > loop ;
> Your solution looks fine to me too.
> Your code brings up something for me. I notice those three then then > thens. Forth doesn't usually have a way to skip over the rest of a > loop and then repeat. We have ways to break out of the loop, but not a > command to skip to the end of the loop. So we have ugly things like > then then then to do it, both in DO loops and in BEGIN loops.
> I've never felt the need for an improvement there. Multiple THENs > don't actually cause a performance hit, only a very slight compile- > time hit. Wil Baden made his THENS command which palliates it.
> Somehow I never noticed until now that you can get a similar result > with multiple BEGINs.
> : bang1 > 0 BEGIN BEGIN 1+ cr > dup 3 mod DUP 0= if ." Fizz" then > over 5 mod dup 0= if ." Buzz" then > or 0= UNTIL > dup . > dup 100 > > UNTIL ;
> I certainly don't want to propose this as clear writing or even > adequate code (like, the method would run over if you changed the > limit to 99BEG), it's just that I never thought of this as a single > loop with a continuation. If you had a word that was just like UNTIL > except it left a copy of the dest, it would effectively skip to (but > not past) the end of the loop on failure or execute the rest of the > loop on success.
> BEGIN ... SKIP-TO-REPEAT ... SKIP-TO-REPEAT ... SKIP-TO-REPEAT ... > WHILE ... REPEAT
> Again, I've never felt the need to have something like this, I've > always just accepted THEN THEN THEN as good enough.
> Additional control structure words might someimes make the flow of > control clearer, provided we all remembered what they did. What we > already have is adequate.
> : bang2 > 101 0 do > i 3 mod 0= 1 and > i 5 mod 0= 2 and or > case > 0 of i . endof > 1 of Fizz endof > 2 of Buzz endof > 3 of FizzBuzz endof > endcase > loop ;
> This one doesn't read better either, but at least the most common > cases are tested the most often. A jump table might be more efficient > but also less readable.
> : which-action ( n -- n 0|1|2|3 ) > dup > i 3 mod 0= 1 and > i 5 mod 0= 2 and or ;
> : Bang3 > 0 begin > 1+ dup 101 < > while > which-action do-it > repeat drop ;
> I guess when the first methods I learned give a result that isn't too > long, then that's the most readable. There's nothing hard to > understand about nested IF THENs. Just, if they get too complex you > can lose track of how deeply they're nested and which places which > result happens.
Nothing wrong with other solutions but a simple solution avoiding nested ifs etc uses bit vectors. The constants can be stuck in line
: bang cr 0 101 1 do ?dup 0= if probe then 3or5vec over and 0= if i . then 3vec over and if ." fizz" then 5vec over and if ." buzz" then 1 rshift cr loop drop ;
On Feb 28, 7:42 pm, John Passaniti <n...@JapanIsShinto.com> wrote:
> keo...@gmail.com wrote: > > As I am interested but not yet very proficient in stack based > > programming languages, I ask you: how would you solve this problem in > > FORTH?
> : fizz? 3 mod 0= dup if ." fizz" endif ; > : buzz? 5 mod 0= dup if ." buzz" endif ;
> : doit 101 1 do > i fizz? > i buzz? > or 0= if i . endif > cr > loop > ;
one reason I find this one well factored is that when I tried, I found it was easy to make the pretty printing as a separate factor:
: fizz? ( n -- fl ) 3 MOD 0= DUP IF ." Fizz" THEN ; : buzz? ( n -- fl ) 5 MOD 0= DUP IF ." Buzz" THEN ; : ?.fizzbuzz-WS ( fl1 fl2 -- fl1 fl2 ) 2DUP AND IF CR ELSE 2DUP OR IF SPACE THEN THEN ;
: bang1 ( -- ) 101 1 DO I fizz? I buzz? ?.fizzbuzz-WS OR 0= IF I . THEN LOOP ;
> : bang > cr 0 101 1 > do > ?dup 0= if probe then > 3or5vec over and 0= if i . then > 3vec over and if ." fizz" then > 5vec over and if ." buzz" then > 1 rshift cr > loop > drop > ;
Very nice! I think I can make that solution more readable, though less efficient.
variable 5mod variable 3mod
\ repeated test3 will count to 3 and then start over at 0. Leaves a true flag every 3rd time. : test3 ( -- flag ) 3mod @ 1+ dup 3 = if drop 0 then dup 3mod ! 0= ;
: test5 ( -- flag ) 5mod @ 1+ dup 5 = if drop 0 then dup 5mod ! 0= ;
: bang 0 3mod ! 0 5mod ! 101 1 do cr test3 dup if ." Fizz" then 0= test5 dup if ." Buzz" then 0= and if i . then loop ;
We could get rid of the if in the tests.
: test3 ( -- flag ) 3mod @ 1+ dup 3 = 3 and xor dup 3mod ! 0= ;
We could get rid of the variables.
: test3 ( n -- n' flag ) 1+ dup 3 = 3 and xor dup 0= ;
We could factor the test to get rid of the constants.
: testN ( n limit -- n' limit flag ) >r 1+ dup r@ = r@ and xor r> over 0= ;
But it isn't getting more readable.
We can write for size and speed -- for efficiency. But an optimising compiler might likely do it better. It isn't clear what to optimise, either. On some processors MOD is slow. On others it isnt. With an onchip data stack fetching variables might be very slow. Or maybe not. Branches might be slow, but maybe not a few extra calls worth. It makes no sense to try to optimise portable code beyond the obvious things like taking unneeded calculations out of loops.
We can write for simplicity, to make the whole thing simpler which reduces debugging effort and maybe decreases maintenance costs, and the simpler code may be easier to find algorithmic improvements etc. But simplicity is an esthetic judgement. What looks simple to one person may look complex to another. My preference is to make it look simpler to *me* since if the code ever does get maintained by someone else I can't predict who'll do it. So I might as well get the benefits now.
Writing to be easy for other people to read, it's better to avoid subtle ideas. Anything that people find hard to understand before the first cup of coffee is a problem.
This time around I'd say that all the 1-minute solutions are good, and the things I put more time into come out worse.
On Mar 3, 11:09 am, "J Thomas" <jethom...@gmail.com> wrote:
> Writing to be easy for other people to read, it's better to avoid > subtle ideas. Anything that people find hard to understand before the > first cup of coffee is a problem.
That's why I liked John Passiniti's factoring ... it was easy enough for me to read to directly add the pretty printing into the main loop when I didn't like the way it printed ... it only took two iterations to get it exactly right, which would be a record for me ... and then that could come directly out as a word rather than being handled in multiple locations.
The test of whether something is easy for other people to read is other people trying to add a capability.
On 3 Mar, 17:17, "Bruce McFarling" <agil...@netscape.net> wrote:
> On Mar 3, 11:09 am, "J Thomas" <jethom...@gmail.com> wrote:
> > Writing to be easy for other people to read, it's better to avoid > > subtle ideas. Anything that people find hard to understand before the > > first cup of coffee is a problem.
> That's why I liked John Passiniti's factoring ... it was easy enough > for me to read to directly add the pretty printing into the main loop > when I didn't like the way it printed ... it only took two iterations > to get it exactly right, which would be a record for me ... and then > that could come directly out as a word rather than being handled in > multiple locations.
> The test of whether something is easy for other people to read > is other people trying to add a capability.
I'm not disagreeing with you but would just point out that it's trivial to add pretty printing to other versions.
: bang cr 0 101 1 do ?dup 0= if probe then 3or5vec over and 0= if i 2 .r then 3vec over and if ." fizz" then 5vec over and if ." buzz" then dup 1 = if cr else space then 1 rshift loop drop ;
On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote: >> A simple solution is
>>: bang >> 100 1 do >> i 15 mod 0= if ." FizzBuzz " else >> i 3 mod 0= if ." Fizz " else >> i 5 mod 0= if ." Buzz " else >> i . then then then >> loop ;
You wouldn't get the job, because you missed 100.
My first try was this:
: fizzbuzz 101 1 do i 3 mod 0 = dup if ." Fizz" then i 5 mod 0 = dup if ." Buzz" then invert swap invert and if i . then cr loop ;
A bit like John's solution (is ENDIF ANS Forth?), but I have still to learn more Forth.
On Mar 3, 1:16 pm, "Gerry" <g...@jackson9000.fsnet.co.uk> wrote:
> I'm not disagreeing with you but would just point out that it's > trivial to add pretty printing to other versions.
The fact that you can add it to yours factored out as a single word (I'll take your word for it that it factors out) is nowhere near the same stress test as the fact that I can add it factored out as a single word to John's.
But, yes, right aligned is even prettier
: fizz? ( n -- fl ) 3 MOD 0= DUP IF ." Fizz" THEN ; : buzz? ( n -- fl ) 5 MOD 0= DUP IF ." Buzz" THEN ; : ?.number ( n fl1 fl2 -- fl1 fl2 ) 2DUP 2>R OR 0= IF 2 .R THEN 2R> ;
: .FizzBuzz-WS ( fl1 fl2 -- ) AND IF CR ELSE SPACE THEN ;
: .FizzBuzz-item ( n -- ) DUP fizz? OVER buzz? ?.number .FizzBuzz-WS ;
On Feb 28, 7:42 pm, John Passaniti <n...@JapanIsShinto.com> wrote:
> keo...@gmail.com wrote: > > As I am interested but not yet very proficient in stack based > > programming languages, I ask you: how would you solve this problem in > > FORTH?
> : fizz? 3 mod 0= dup if ." fizz" endif ; > : buzz? 5 mod 0= dup if ." buzz" endif ;
> : doit 101 1 do > i fizz? > i buzz? > or 0= if i . endif > cr > loop > ;
My first solution (i.e. 1-minute solution) was this:
: fizz? ( n -- flag ) 3 mod 0= ;
: buzz? ( n -- flag ) 5 mod 0= ;
0 value notfound
: FizzBuzz 101 1 DO cr true to notfound i fizz? IF ." Fizz" false to notfound THEN i buzz? IF ." Buzz" false to notfound THEN notfound IF i . THEN LOOP ;
Interesting that we both chose exactly the same names to factor out.
I knew that a local variable would be better than a global, but I was thinking in terms of something that might be viewed by many non-Forth programmers. But I also had a nagging feeling that something was not quite right. When I saw your solution it answered that question as you had the better, no variable at all, solution. Nice.
Frank Buss <f...@frank-buss.de> wrote: > On Mar 2, 7:29 am, Andrew Haley <andre...@littlepinkcloud.invalid> >> wrote: >>> A simple solution is
>>>: bang >>> 100 1 do >>> i 15 mod 0= if ." FizzBuzz " else >>> i 3 mod 0= if ." Fizz " else >>> i 5 mod 0= if ." Buzz " else >>> i . then then then >>> loop ; > You wouldn't get the job, because you missed 100.
When you removed my "I'm assuming a half-open interval" comment, were you being deliberately deceitful?
> : bang > cr 0 101 1 > do > ?dup 0= if probe then > 3or5vec over and 0= if i . then > 3vec over and if ." fizz" then > 5vec over and if ." buzz" then > 1 rshift cr > loop > drop > ;
....
> As the perpetrator of this solution I'm very interested to know if it > is generally considered good or bad, be as rude as you like I'm not > the suicidal type. I'm rather surprised that you found it hard to read > - I suppose a 2 line comment describing the method would have helped.
Yes, I think a 2 line comment would have done wonders.
I looked at it and saw some magic numbers. What are they for? Then I looked at what you were doing with them, and it appeared you were taking the I value and doing OVER AND 0= and getting correct results. How could you do that? Did you have some advanced mathematical method I'd never heard of? I tried to imagine how it could work and had no idea. So before I did anything else I copied the code to a Forth and tried it and verified that yes indeed, it did work.
Then I held my breath and decided that no matter how arcane it was, I could understand it, all I had to do was study it. I looked closer at the magic numbers. When I switched from hex to binary in my head I noticed that 3vec had every third bit set. Ah! And then 5vec had every fifth bit set. Then it was obvious except for the details. probe was set to #4000, it needed to be reset precisely when both cycles were complete, so bit 14 was the first digit that would work, do it exactly 15 times and reset. If the numbers had been 5 and 7 it would have been harder to do.
There's nothing wrong with this. On a system where division is slow it will run fast. On a system where nesting is slow and division is fast, it will run slow. It isn't a method that's obvious with no comments before the first cup of coffee. I was slow to see it partly because I was ready to believe it might be something arcane I'd never seen before at all, that I might have trouble with.
If we're going to judge readability, compare it with Andrew Haley's solution.
: bang 100 1 do i 15 mod 0= if ." FizzBuzz " else i 3 mod 0= if ." Fizz " else i 5 mod 0= if ." Buzz " else i . then then then loop ;
This solution has absolutely nothing unexpected. First case. Second case. Third case. Fourth case. Precisely one of the four paths will be taken. No trickiness about executing the Buzz path after the Fizz path has already gone through. Nothing tricky anywhere. The code is bigger than other good solutions. It will take longer to run than some -- more than half the time you do 3 mods and 3 elses. But there's nothing here that can be misunderstood.
Readability isn't the only issue. Speaking for myself, I like to see elegant solutions and new ideas. But the most-readable code won't have anything new and it won't have anything that's shorter than unexpected. Ideally it will appear to do exactly what the specs call for, one requirement matching up with one stretch of code. So you go down the list and see yes it did this, yes it did that, until you get to the end. The only way Andrew's code misses this (apart from the idea shared by everybody except computer programmers that when you say "one to a hundred" it means start from 1 and continue until you've done 100) is that the divisible-by-both case comes out of order.
J Thomas <jethom...@gmail.com> wrote: > If we're going to judge readability, compare it with Andrew Haley's > solution. > : bang > 100 1 do > i 15 mod 0= if ." FizzBuzz " else > i 3 mod 0= if ." Fizz " else > i 5 mod 0= if ." Buzz " else > i . then then then > loop ; > This solution has absolutely nothing unexpected. First case. Second > case. Third case. Fourth case. Precisely one of the four paths will be > taken. No trickiness about executing the Buzz path after the Fizz path > has already gone through. Nothing tricky anywhere. The code is bigger > than other good solutions.
No it isn't. AFAIK it's the smallest, both in the size of the source and the object. John Passaniti's gets close, but it's 584 bytes long whereas mine was 576. [AMD64 gforth.] Not that I was trying for small size -- that was just a side-effect of a simple solution.
On Mar 5, 1:15 pm, Andrew Haley <andre...@littlepinkcloud.invalid> wrote:
> J Thomas <jethom...@gmail.com> wrote: > > This solution has absolutely nothing unexpected. First case. Second > > case. Third case. Fourth case. Precisely one of the four paths will be > > taken. No trickiness about executing the Buzz path after the Fizz path > > has already gone through. Nothing tricky anywhere. The code is bigger > > than other good solutions.
> No it isn't. AFAIK it's the smallest, both in the size of the source > and the object. John Passaniti's gets close, but it's 584 bytes long > whereas mine was 576. [AMD64 gforth.] Not that I was trying for small > size -- that was just a side-effect of a simple solution.
I'm surprised. It has redundant code, I'd expect it to be larger.
John's code has surplus definitions and surplus calls due to his factoring. If the headers count that will push up his size, if you only count code then it's just a couple of extra calls.
With gForth 0.6.2
unused : bang 100 1 do i 15 mod 0= if ." FizzBuzz " else i 3 mod 0= if ." Fizz " else i 5 mod 0= if ." Buzz " else i . then then then loop ; unused - .
got 304.
unused : bang 101 1 do cr i 3 mod 0= dup if ." Fizz" then i 5 mod 0= dup if ." Buzz" then or 0= if i . then loop ; unused - .
gave 228.
: bang 101 1 do cr i 5 mod 0= i 3 mod 0= 2dup or 0= if i . then if ." Fizz" then if ." Buzz" then loop ;
gave 224 because it uses 2DUP in place of DUP DUP . It's harder to read.
J Thomas <jethom...@gmail.com> wrote: > On Mar 5, 1:15 pm, Andrew Haley <andre...@littlepinkcloud.invalid> > wrote: >> J Thomas <jethom...@gmail.com> wrote: >> > This solution has absolutely nothing unexpected. First case. Second >> > case. Third case. Fourth case. Precisely one of the four paths will be >> > taken. No trickiness about executing the Buzz path after the Fizz path >> > has already gone through. Nothing tricky anywhere. The code is bigger >> > than other good solutions.
>> No it isn't. AFAIK it's the smallest, both in the size of the source >> and the object. John Passaniti's gets close, but it's 584 bytes long >> whereas mine was 576. [AMD64 gforth.] Not that I was trying for small >> size -- that was just a side-effect of a simple solution. > I'm surprised. It has redundant code, I'd expect it to be larger. > John's code has surplus definitions and surplus calls due to his > factoring. If the headers count
Well, yeah. Of course they count! I mean, someone had to pay for that RAM they're in...
> that will push up his size, if you only count code then it's just a > couple of extra calls.
J Thomas wrote: > I'm surprised. It has redundant code, I'd expect it to be larger.
The point of FizzBuzz is that it is part of a coding skill test given to job candidates. The author's claim is that many job candidates can't code, and tests like FizzBuzz are used to weed such weaker candidates out.
My response in comp.lang.forth was simply to provide the original poster an example of what he wanted-- how would the solution to FizzBuzz look in Forth. One assumes that the original poster understood that there are endless variations on a theme. One assumes the original poster understands that one can optimize for different things-- size, speed, clarity, programmer effort, generality, reusability, etc.
> John's code has surplus definitions and surplus calls due to his > factoring. If the headers count that will push up his size, if you > only count code then it's just a couple of extra calls.
If the problem statement for FizzBuzz had said, "minimize code size" or "generalize your code so that other multiples can print out different messages" then the choices I made would have been different. This is why context matters. In a job interview, I would have taken less than a minute to code my solution and would have been able to move on to other problems. Those of you who are agonizing over if an additional term could be factored out or are counting the number of bytes generated are the ones who might have less time for the more substantive questions during the interview.