FizzBuzz

807 views
Skip to first unread message

keo...@gmail.com

unread,
Feb 28, 2007, 6:16:19 PM2/28/07
to
Hi,

recently there was a big fuzz on digg.com and the like about this
article:

http://tickletux.wordpress.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/

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

Coos Haak

unread,
Feb 28, 2007, 7:21:47 PM2/28/07
to
Op 28 Feb 2007 15:16:19 -0800 schreef keo...@gmail.com:

Why are you interested in my solution?
Why don't you give it a try?
Then we'll discuss it further.

--
Coos

CHForth, 16 bit DOS applications
http://home.hccnet.nl/j.j.haak/forth.html

Cesar Rabak

unread,
Feb 28, 2007, 7:42:02 PM2/28/07
to
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?

John Passaniti

unread,
Feb 28, 2007, 7:42:34 PM2/28/07
to
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
;

Andreas Kochenburger

unread,
Mar 1, 2007, 8:29:46 AM3/1/07
to
Hi
did you recently lose your driver's license?

<keo...@gmail.com> schrieb im Newsbeitrag
news:1172704579.4...@z35g2000cwz.googlegroups.com...

Andrew Haley

unread,
Mar 2, 2007, 7:29:39 AM3/2/07
to

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. )

Andrew.

Doug Hoffman

unread,
Mar 2, 2007, 8:04:01 AM3/2/07
to
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.

-Doug

Andrew Haley

unread,
Mar 2, 2007, 8:22:37 AM3/2/07
to

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.

Andrew.

J Thomas

unread,
Mar 2, 2007, 10:48:03 AM3/2/07
to
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.

: DUP. dup . ;

CREATE TABLE
' DUP. ,
' Fizz ,
' Buzz ,
' FizzBuzz ,

: do-it
CELLS TABLE + @ EXECUTE ;

: 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.

Bruce McFarling

unread,
Mar 2, 2007, 11:03:12 AM3/2/07
to
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.

Doug Hoffman

unread,
Mar 2, 2007, 12:34:23 PM3/2/07
to
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. ;-)

Gerry

unread,
Mar 3, 2007, 9:37:16 AM3/3/07
to

Nothing wrong with other solutions but a simple solution avoiding
nested ifs etc uses bit vectors. The constants can be stuck in line

hex
1249 constant 3vec
0421 constant 5vec
4000 constant probe
3vec 5vec or constant 3or5vec
decimal

: 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
;


Bruce McFarling

unread,
Mar 3, 2007, 10:31:29 AM3/3/07
to

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
;

J Thomas

unread,
Mar 3, 2007, 11:09:46 AM3/3/07
to
On Mar 3, 9:37 am, "Gerry" <g...@jackson9000.fsnet.co.uk> wrote:

> Nothing wrong with other solutions but a simple solution avoiding
> nested ifs etc uses bit vectors. The constants can be stuck in line
>
> hex
> 1249 constant 3vec
> 0421 constant 5vec
> 4000 constant probe
> 3vec 5vec or constant 3or5vec
> decimal
>
> : 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.

Bruce McFarling

unread,
Mar 3, 2007, 12:17:08 PM3/3/07
to
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.

Gerry

unread,
Mar 3, 2007, 1:16:10 PM3/3/07
to

I'm not disagreeing with you but would just point out that it's
trivial to add pretty printing to other versions.

hex
1249 constant 3vec
0421 constant 5vec
4000 constant probe
3vec 5vec or constant 3or5vec
decimal

: 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
;

Frank Buss

unread,
Mar 3, 2007, 3:30:50 PM3/3/07
to
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.

--
Frank Buss, f...@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

Bruce McFarling

unread,
Mar 3, 2007, 5:29:22 PM3/3/07
to
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 ;

: bang1 ( -- ) 101 1 DO I .FizzBuzz-item LOOP ;

CR CR .( bang1 ) CR bang1 CR CR

Doug Hoffman

unread,
Mar 3, 2007, 6:13:45 PM3/3/07
to
On Feb 28, 7:42 pm, John Passaniti <n...@JapanIsShinto.com> wrote:

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.

-Doug

Andrew Haley

unread,
Mar 4, 2007, 6:53:17 AM3/4/07
to
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?

Andrew.

J Thomas

unread,
Mar 5, 2007, 12:41:24 PM3/5/07
to
On Mar 3, 9:37 am, "Gerry" <g...@jackson9000.fsnet.co.uk> wrote:

> Nothing wrong with other solutions but a simple solution avoiding
> nested ifs etc uses bit vectors. The constants can be stuck in line
>
> hex
> 1249 constant 3vec
> 0421 constant 5vec
> 4000 constant probe
> 3vec 5vec or constant 3or5vec
> decimal
>
> : 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.

Andrew Haley

unread,
Mar 5, 2007, 1:15:33 PM3/5/07
to
J Thomas <jeth...@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.

Andrew.

J Thomas

unread,
Mar 5, 2007, 2:12:20 PM3/5/07
to
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.

Andrew Haley

unread,
Mar 5, 2007, 2:32:50 PM3/5/07
to
J Thomas <jeth...@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.

Andrew.

John Passaniti

unread,
Mar 6, 2007, 1:46:03 AM3/6/07
to
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.

Gerry

unread,
Mar 6, 2007, 6:57:30 AM3/6/07
to

Sorry I caused you some grief with the code. I must make an effort
with making my code more readable, after all its far less effort for 1
writer to do that compared to n readers decoding something.

Gerry

Doug Hoffman

unread,
Mar 6, 2007, 7:59:49 AM3/6/07
to
On Mar 6, 1:46 am, John Passaniti <put-my-first-name-

Your solution, in addition to excellent clarity and simplicity, IMO,
is also easily extensible. Consider the case where the problem is
expanded to include Boom (divisible by 7) and Zapp (divisible by 9):

: boom? ( n -- flag ) \ 0 if hit
7 mod 0= dup IF ." Boom" THEN ;

: zapp? ( n -- flag ) \ 0 if hit
9 mod 0= dup IF ." Zapp" THEN ;

: FizzBuzzBoomZapp
101 1 DO cr


i fizz?
i buzz? or

i boom? or
i zapp? or
0= IF i . THEN
LOOP ;

This is a reasonable variation of the original problem.
So 42 would yield FizzBoom and 45 would yield FizzBuzzZapp and so
forth. Two of your original definitions were re-usable.

-Doug

J Thomas

unread,
Mar 6, 2007, 8:32:01 AM3/6/07
to
On Mar 6, 1:46 am, John Passaniti <put-my-first-name-
h...@JapanIsShinto.com> wrote:
> 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.

I didn't at all intend to criticise your code. I think it is
excellent. The factoring is not a bad thing -- though I think the code
is a little more readable without it, and the factored definitions
that are used only once increase the code size a little. That isn't
any big deal, and in the context you were responding to -- a job
interview for a Forth job -- would show that you have the factoring
concept firmly in mind.

The lesson I got from this is that factoring into small short pieces
can impede readability, and that careful naming can reduce that
problem.

The lesson I got from my own experiments was that anything tricky
reduces readability and should be used only when there are clear
advantages that override that disadvantage.

Again, I meant no criticism. I thought that every solution except mine
was excellent. Gerry's solution had the disadvantage of not being what
a beginning Forth programmer would expect, which made it harder to
read. But in some systems his tests would be far faster. Of course,
more than half the time you're doing up to 3 mods or dmods to generate
a numeric string to . so it won't be that big a percentage
improvement.

Once again, as you point out, there was nothing about minimising code
size in the specs and there's no shame in not having the smallest code
when compiled on some particular system. I have no complaint about
your 1-minute code. I don't think it should be the standard for
judging code size since it's large, and that says nothing bad about
you or your code.

J Thomas

unread,
Mar 6, 2007, 8:37:35 AM3/6/07
to
On Mar 6, 6:57 am, "Gerry" <g...@jackson9000.fsnet.co.uk> wrote:

> Sorry I caused you some grief with the code. I must make an effort
> with making my code more readable, after all its far less effort for 1
> writer to do that compared to n readers decoding something.

It's no big deal. I wanted to note that code is more readable when it
does nothing unexpected. Your innovative solution was fundamentally
harder to read because it was innovative. Writing carefully to expose
your methods, along with careful documentation, could palliate that.
But anything that your readers don't expect is harder to read than
what they do expect, and there's no getting around that.

The Beez'

unread,
Mar 6, 2007, 10:27:38 AM3/6/07
to
This is a slight variation on that one (4tH only):

: zap dup 0 .r ; : fizz ." Fizz" ; : buzz ." Buzz" ; : fizzbuzz fizz
buzz ;
create foo ' zap , ' fizz , ' buzz , ' fizzbuzz ,
:this foo does> >r dup 5 mod 0= 2* over 3 mod 0= + cells r> + @c
execute drop ;
: bar 101 1 do i foo space loop ; bar

Hans Bezemer

Bruce McFarling

unread,
Mar 6, 2007, 10:34:22 AM3/6/07
to
On Mar 6, 6:57 am, "Gerry" <g...@jackson9000.fsnet.co.uk> wrote:
> Sorry I caused you some grief with the code. I must make
> an effort with making my code more readable, after all
> its far less effort for 1 writer to do that compared to
> n readers decoding something.

Ah, but a benefit of open-source is that the effort by
the one writer does not have to always be the code author.

Applying the rule, "explain magic numbers", I reckon
it gets to between first and second cup of coffee
stage for me, which for reasonably handy programmers
would probably push it back before the first cup.

hex

1249 constant 3vec \ = 0001001001001001, each 3rd bit set
0421 constant 5vec \ = 0000010000100001, each 5th bit set
4000 constant probe \ = 0100000000000000, edge of frame

Jerry Avins

unread,
Mar 6, 2007, 1:33:08 PM3/6/07
to

I prefer

binary

0001001001001001 constant 3vec \ each 3rd bit set
0000010000100001 constant 5vec \ 5th bit set
0100000000000000 constant probe \ edge of frame


3vec 5vec or constant 3or5vec

decimal

When a particular BASE is native to the problem, use it.

Jerry
--
Engineering is the art of making what you want from things you can get.
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯