<div class="gmail_quote">Neil,</div><div class="gmail_quote"><br></div><div class="gmail_quote">Thanks for taking the time to comment.</div><div class="gmail_quote"><br></div><div class="gmail_quote"><br></div><div class="gmail_quote">

On Sun, Jul 24, 2011 at 09:34, Neil Van Dyke <span dir="ltr">&lt;<a href="mailto:neil@neilvandyke.org" target="_blank">neil@neilvandyke.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


Rodolfo Carvalho wrote at 07/24/2011 12:25 AM:<div><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
For me solution 1 is compact, however it allocates the list without need (which gives out of memory error for large N). Solution 2 is more memory efficient, but more verbose.<br>
</blockquote>
<br></div>
I think that solution 2 is on the path to being relatively better, due to space efficiency, as you said.  Solution 1 is the kind of thing you might do if you&#39;re teaching concepts like &quot;apply&quot; or if you&#39;re more experienced with conventional mathematics than programming, but that you probably wouldn&#39;t do in a reusable library.<br>


</blockquote><div><br></div><div><br></div><div>Ok. I&#39;ll keep that one for the &quot;one-liner contest&quot; :D</div><div><br></div><div>But to my surprise it performed faster than sol. 2 on my tests for &quot;small enough N&quot;. Clearly for large N it goes out of memory and/or takes a lot of time paginating.</div>


<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Note that &quot;compose&quot; is a procedure, so you don&#39;t want to be calling it on each iteration.<br></blockquote><div><br></div><div><br></div><div>That&#39;s right. As one might guess I&#39;ve taken it from solution 1 down to solution 2 but it should be written differently to avoid the excessive (and useless) calls.</div>


<div>In solution 1 &quot;compose&quot; is evaluated only once, I believe.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
You still need a &quot;number-&gt;english-letter-count&quot; procedure.<br></blockquote><div><br></div><div><br></div><div>Yes. Yesterday I didn&#39;t mean to &quot;solve&quot; the problem, nor to solve it efficiently. It was more of an exploration.</div>


<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Were I implementing this Project Euler solution for a reusable library, I would probably: (1) adapt &quot;number-&gt;english&quot; from &quot;<a href="http://www.neilvandyke.org/numspell-scheme/" target="_blank">http://www.neilvandyke.org/<u></u>numspell-scheme/</a>&quot; to use &quot;and&quot; and no punctuation; (2) use &quot;string-length&quot; and that new &quot;number-&gt;problem-english&quot; procedure to have a slow initial implementation for the problem solution; (3) adapt &quot;number-&gt;problem-english&quot; to be &quot;number-&gt;problem-english-<u></u>letter-count&quot; without doing the string ports or other string allocation; (4) test the two implementations against each other; (5) investigate a potential third solution, looking at the algorithm and number patterns, to see whether I can make the the entire program or just the letter-counting procedure be constant-time.<br>


</blockquote><div><br></div><div><br></div><div>Yes, were I implementing this problem efficiently I would not generate the intermediate string representation of numbers -- it is useless in this case.</div><div>There is a linear relationship between N and the number of letters used up to N, which makes me believe that (5) is the way to go.</div>


<div>(The plots that I&#39;ve generated so far induce me into confirming that conclusion.)</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">


<br>
Were I doing this solution for homework or to post on the Project Euler site, in step #1 above, I would write a new &quot;number-&gt;problem-english&quot; procedure from scratch, rather than adapt the one from the PLaneT package.<br>



<br>
After all the inner-loop code has been optimized, if you wanted to shave a couple more instructions off the iteration over 1..1000, you could try named-&quot;let&quot; and counting down (so that your test for loop exit is &quot;zero?&quot;), and see whether that&#39;s any faster.  That&#39;s how I&#39;d write it normally, as a matter of personal style, but I&#39;m not certain that&#39;d be faster in current version of Racket.  For a reusable library, you probably wouldn&#39;t care about any difference, but you might care if you&#39;re trying to win questionable Internet contests about whose language could beat up who else&#39;s language.<br>


</blockquote><div><br></div><div><br></div><div>Thanks for pointing me to named-let.</div><div><br></div><div>Previously I have also implemented 2 others solutions using recursion, and earlier today after reading this email I wrote another one using named-let.</div>

<div><br></div><div><br></div><div><div>; Solve recursively // Solution 3</div><div>(define (recur-letter-count-of-integers-up-to n)</div><div>  (if (zero? n)</div><div>      0</div><div>      (+ ((compose string-length integer-&gt;string) n)</div>

<div>         (recur-letter-count-of-integers-up-to (sub1 n)))))</div><div><br></div><div>; Solve recursively, tail call // Solution 4</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>(define (tail-letter-count-of-integers-up-to n [acc 0])</div>

<div>  (if (zero? n)</div><div>      acc</div><div>      (tail-letter-count-of-integers-up-to</div><div>       (sub1 n)</div><div>       (+ (string-length (integer-&gt;string n))</div><div>          acc))))</div><div><br>

</div><div>; Solve using a named-let // Solution 5</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>(define (let-letter-count-of-integers-up-to n)</div><div>  (let f ([i n]</div><div>          [acc 0])</div>

<div>    (if (zero? i)</div><div>        acc</div><div>        (f (sub1 i) (+ (string-length (integer-&gt;string i))</div><div>                       acc)))))</div></div><div><br></div><div><br></div><div><br></div><div>
In my experiments, when I analyzed values up to 100000 (one hundred thousand), the solution using named-let (5) was consistently faster than the recursive/tail call (4).</div>
<div>I couldn&#39;t think of a reason to explain that.</div><div><br></div><div>The first one using recursion in a bad way (3) was the worst in execution time.</div><div><br></div><div>However, analyzing a range up to 1000000 (one million) changes the &quot;big picture&quot;, so that comparing the speed of the implementations is not independent of input range.</div>

<div><br></div><div>Here&#39;s the code I am using to run the different implementations, time the execution, generate tables and plots and put it all into slides:</div><div><meta http-equiv="content-type" content="text/html; charset=utf-8"><a href="http://bazaar.launchpad.net/~rhcarvalho/+junk/racket/view/head:/project-euler-17.rkt">http://bazaar.launchpad.net/~rhcarvalho/+junk/racket/view/head:/project-euler-17.rkt</a></div>

<div><br></div><div>[]&#39;s</div><div><br></div><div>Rodolfo Carvalho</div><meta http-equiv="content-type" content="text/html; charset=utf-8"></div>