Two minute challenge

Started by cormullion, December 22, 2008, 05:50:59 AM

Previous topic - Next topic

didi

#15
( for ( x 1 100 )
  ( set 'y "" )
  ( if ( = 0 ( mod x 5 ))  ( push "Buzz" y))
  ( if ( = 0 ( mod x 3 ))  ( push "Bizz" y))
  ( if ( = y "" ) ( push ( string x ) y ))
  ( print y " " )
 )


result:

1 2 Bizz 4 Buzz Bizz 7 8 Bizz Buzz 11 Bizz 13 14 BizzBuzz 16 17 Bizz 19 Buzz Bizz 22 23 Bizz Buzz 26 Bizz 28 29 BizzBuzz 31 32 Bizz 34 Buzz Bizz 37 38 Bizz Buzz 41 Bizz 43 44 BizzBuzz 46 47 Bizz 49 Buzz Bizz 52 53 Bizz Buzz 56 Bizz 58 59 BizzBuzz 61 62 Bizz 64 Buzz Bizz 67 68 Bizz Buzz 71 Bizz 73 74 BizzBuzz 76 77 Bizz 79 Buzz Bizz 82 83 Bizz Buzz 86 Bizz 88 89 BizzBuzz 91 92 Bizz 94 Buzz Bizz 97 98 Bizz Buzz

unixtechie

#16
Yours looks nice because of the minimalism you got through using an output accumulator instead of direct logic.

..a slightly modified version with "lazy generators" instead of modulo division


(set 'step3 3)
(set 'step5 5)
(set 'lgen3 step3)
(set 'lgen5 step5)

( for ( x 1 100 )
 ( set 'acc "" )
 ( and ( = x lgen3 )  ( push "Bizz" acc) (inc lgen3 step3))
 ( and ( = x lgen5 )  ( push "Buzz" acc) (inc lgen5 step5))
 ( and ( = acc "" ) ( push ( string x ) acc ))
 ( println acc )
)
(exit)

Versions in which logic is used (rather than string operations) cut appr. 1-2 second(s) per 1 million iteration loops:

your version runs at 14.28 sec

yours modified  at 13.75

and the one with logic plus "lazy accs" in place of modulo division is at 12.6 seconds on my machine



The unpleasant thing however is that perl does this script verbatim (i.e. the same 1 million iterations) in 1.7 seconds (!!)



If I switch off output buffering in it ($| = 1;), the time increases to 6 seconds.



Newlisp does it approx twice as slow.  -- Why?

cormullion

#17
Struggling to make a more functional version:




(define (/? a b) (= 0 (% a b)))

(define (action i)
    (cond ((= 0 (% i 15)) "fizzbuzz")
          ((= 0 (% i 3))  "fizz")
          ((= 0 (% i 5))  "buzz")
          (true           i)))
   
(map println (map action (sequence 1 100)))

cormullion

#18
Quote from: "unixtechie"Newlisp does it approx twice as slow.  -- Why?


That's another aspect of a challenge: any given algorithm will probably suit either Perl or newLISP better, and is unlikely to be completely language-agnostic. Typically, Perl runs "Perl code" better and faster than any other language can. But newLISP can run "newLISP code" better than it runs "Perl code". (I wrote a bit about this once http://unbalanced-parentheses.nfshost.com/andcounting">//http://unbalanced-parentheses.nfshost.com/andcounting.)



Don't know about "unpleasant". I'd trade quite a bit of performance to not have to look at Perl... :)

xytroxon

#19
Day two (or is it three?) of the "two minute" challenge...



Examinaton of the curious effect of the product of mods...



;for number :0000000001111111111222222222233333333334
;-----------:123456789o123456789o123456789o123456789o
;(% fizz 3) :1201201201201201201201201201201201201201
;(% buzz 5) :1234012340123401234012340123401234012340
;(*(%3)(%5)):nn0n00nn00n0nn0nn0n00nn00n0nn0nn0n00nn00
;X->fizzbuzz:--f-bf--fb-f--X--f-bf--fb-f--X--f-bf--fb

(for (number 1 100)
   (setq fizz (% number 3) buzz (% number 5) fizzbuzz (* fizz buzz))
   (when (zero? fizz)(print "Fizz"))
   (when (zero? buzz)(print "Buzz"))
   (when (not (zero? fizzbuzz))(print number))
   (print ", ")
)
(exit)

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz,



Inline version:

(for (number 1 100)
   (when (zero? (% number 3))(print "Fizz"))
   (when (zero? (% number 5))(print "Buzz"))
   (when (not (zero? (* (% number 3)(% number 5))))(print number))
   (print ", ")
)
(exit)


Area proposed for major research grant funding:

The effects of (% number 15) aka "Factoring In The Overlooked And True Modulus of FizzBuzz" ;O



-- xytroxon
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976

xytroxon

#20
Quote from: "xytroxon"Day two (or is it three?) of the "two minute" challenge...



Area proposed for major research grant funding:

The effects of (% number 15) aka "Factoring In The Overlooked And True Modulus of FizzBuzz" ;O


Damm!
(cond ((= 0 (% i 15)) "fizzbuzz")
Looks like cormullion beat me too it!!!



Have to start refreshing this thread more often... and eating... and (sniff) taking a bath... ;)



-- xytroxon
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976

unixtechie

#21
Quote
Damm!
(cond ((= 0 (% i 15)) "fizzbuzz")
Looks like cormullion beat me too it!!!


It's very wrong to use and hardcode "3*5" into this solution.



Supposing the numbers you were given were something like 6 and 15. Your program would think it should check for multiples of 90, while in fact it's multiples of 30.



To correctly solve this you'd have to decompose the given numbers into their (don't know proper terms in English) the prime numbers and find the smallest common ???



Unless you want to do it, use a clean reasoning scheme which generalizes without introducing bugs

Lutz

#22
My 3 cents:


(for (i 1 100)
  (cond
    ((zero? (% i 15)) (println "FizzBuzz"))
    ((zero? (% i 5)) (println "Buzz"))
    ((zero? (% i 3)) (println "Fizz"))
    (true (println i))))

(for (i 1 100)
  (let (buff " ")
    (if (zero? (% i 3)) (setf (last buff) "Fizz "))
    (if (zero? (% i 5)) (setf (last buff) "Buzz"))
    (if (= buff " ") (println i) (println buff))))

(for (i 1 100)
  (let (buff (string (if (zero? (% i 3)) "Fizz" "")
          (if (zero? (% i 5)) "Buzz" "")))
    (println (if (empty? buff) i buff))))


all of them variations of previously shown solutions, more or less.

xytroxon

#23

;for number :0000000001111111111222222222233333333334
;-----------:123456789o123456789o123456789o123456789o
;(% fizz 3) :1201201201201201201201201201201201201201
;(% buzz 5) :1234012340123401234012340123401234012340
;(*(%3)(%5)):nn0n00nn00n0nn0nn0n00nn00n0nn0nn0n00nn00
;(+(%3)(%5)):nnnnnnnnnnnnnn0nnnnnnnnnnnnnn0nnnnnnnnnn
;X->fizzbuzz:--f-bf--fb-f--X--f-bf--fb-f--X--f-bf--fb

; "if-not" version with product and sum of mods
(for (number 1 100)
   (setq fizz (% number 3) buzz (% number 5))
   (if-not (zero? (* fizz buzz))
      (print number ", ")
      (if-not (zero? (+ fizz buzz))
         (if-not (zero? buzz)
            (print "fizz, ")
            (print "buzz, ")
         )
         (print "FIZZ-BUZZ, ")
      )
   )
)
(exit)
\"Many computers can print only capital letters, so we shall not use lowercase letters.\"

-- Let\'s Talk Lisp (c) 1976

cormullion

#24
That's what I like to see - dedication to newlisp, on Xmas day! nice job...

DrDave

#25
Quote from: "unixtechie"
Quote
Damm!
(cond ((= 0 (% i 15)) "fizzbuzz")
Looks like cormullion beat me too it!!!

Actually, I didn't post the code, but you'll see I already covered using COND with three predicates in the second post of this thread:
Quote from: "DrDave"Thanks for posting that, Mr. C. I resorted to using COND, plus for ease of reading, defined three other functions that are predicates for the testing for being a factor of 15, 5, or 3. I accessed the numbers by using DOTIMES, forgeting that it starts at 0. So I guess I get points off for covering 0-99 instead of 1-100, LOL
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.

\"Getting Started with Erlang\"  version 5.6.2

DrDave

#26
Lutz,



This does not give the correct output on my system. Instead of FizzBuzz in the appropriate places, it gives Buzzizz. In other words, it has the Fizz and Buzz pieces reversed, plus it chops off the F from Fizz.
Quote from: "Lutz"
(for (i 1 100)
  (let (buff " ")
    (if (zero? (% i 3)) (setf (last buff) "Fizz "))
    (if (zero? (% i 5)) (setf (last buff) "Buzz"))
    (if (= buff " ") (println i) (println buff))))




I discovered that if you replace the next-to-last line with this:
     (if (zero? (% i 5)) (setf (nth -1 buff) "Buzz"))

then it displays correctly. Some strange bug with LAST?
...it is better to first strive for clarity and correctness and to make programs efficient only if really needed.

\"Getting Started with Erlang\"  version 5.6.2

Lutz

#27
Thanks for catching this. There is a problem of 'last' on strings in combination with 'setf' and on non-UTF-8 versions. When using (buff -1) instead of (last buff), it will work:


(for (i 1 100)
  (let (buff " ")
    (if (zero? (% i 3)) (setf (buff -1) "Fizz "))
    (if (zero? (% i 5)) (setf (buff -1) "Buzz"))
    (if (= buff " ") (println i) (println buff))))


I will do a 10.0.1 maintenance release fixing this beginning January.

Lutz

#28
here is another interesting one:


(for (i 1 100)
  (let (buff "")
    (if (zero? (% i 5)) (push "Buzz" buff))
    (if (zero? (% i 3)) (push "Fizz" buff))
    (println (if (empty? buff) i buff))))


Initializing 'buff' as a string tells 'push' to do string prepending instead of list pushing when 'buff' would be 'nil' or a list. The 'empty?' predicate works on strings and lists alike.

ale870

#29
I'm sorry but I saw this topic only now!

I wish to post my solution. It is neither the fastest nor the shortest, but it uses an original method :-)



See here:

(dotimes (x 100)
  (setq fac (factor x))

(setq f1 (find 3 fac))
(setq f2 (find 5 fac))

(if (and f1 f2) (println "Fizz Buzz")
(if f1 (println "Fizz")
(if f2 (println "Buzz") (println x) )
)
)
)


I use factorial function, since every number that can be divided for 3 or 5 have last item list as 3 or five. More: if one number can be divided either for three and five last two numbers will be (3 5)



Use the following line for "debugging" purposes:

(print x ": " fac " --> ")


Just after setq functions:


(setq f1 (find 3 fac))
(setq f2 (find 5 fac))

(print x ": " fac " --> ")


Here first 20 numbers...


1: nil --> 1
2: (2) --> 2
3: (3) --> Fizz
4: (2 2) --> 4
5: (5) --> Buzz
6: (2 3) --> Fizz
7: (7) --> 7
8: (2 2 2) --> 8
9: (3 3) --> Fizz
10: (2 5) --> Buzz
11: (11) --> 11
12: (2 2 3) --> Fizz
13: (13) --> 13
14: (2 7) --> 14
15: (3 5) --> Fizz Buzz
16: (2 2 2 2) --> 16
17: (17) --> 17
18: (2 3 3) --> Fizz
19: (19) --> 19
20: (2 2 5) --> Buzz
--