Note that there are some explanatory texts on larger screens.

plurals
  1. POWhy is this OCaml code so slow?
    primarykey
    data
    text
    <p>I am a OCaml newbie. I wrote a simple program in OCaml to generate the fair and square numbers ( a number that is a palindrome and the square of another palindrome, more details here: <a href="https://code.google.com/codejam/contest/2270488/dashboard#s=p2" rel="nofollow">https://code.google.com/codejam/contest/2270488/dashboard#s=p2</a> ) as follows:</p> <p>Update 1: Optimized algorithm (takes around 20 secs on my laptop):</p> <pre><code>open Printf;; let rec _is_palindrome s i j = i &gt;= j || (s.[i] = s.[j] &amp;&amp; _is_palindrome s (i + 1) (j - 1)) ;; let is_palindrome s = let sl = String.length s in sl &gt; 0 &amp;&amp; (_is_palindrome s 0 (sl - 1)) ;; let rec del_zeros s = let sl = String.length s in if (sl &lt; 1) then s else (if s.[0] = '0' then del_zeros (String.sub s 1 (sl - 1)) else s ) ;; let c2i c = Char.code c - Char.code '0' ;; let i2c i = Char.chr (i + Char.code '0') ;; (* only for finding fair and square numbers *) let square s = let slen = String.length s in if slen &lt; 1 then "" else let reslen = 2 * slen in let t = ref 0 in t := 0; (* fast check *) (let i = reslen/2 in for j = (slen - 1) downto 0 do if (i - 1 - j) &gt;= 0 &amp;&amp; (i - 1 - j) &lt; slen then t := !t + (c2i s.[j]) * (c2i s.[i - 1 - j]); done; if !t &gt; 9 then (* jump out *) raise (Invalid_argument "carry"); ); (let res = String.make reslen '0' in (* do the square cal now *) for i = (reslen - 1) downto 1 do t := 0; for j = (slen - 1) downto 0 do if (i - 1 - j) &gt;= 0 &amp;&amp; (i - 1 - j) &lt; slen then t := !t + (c2i s.[j]) * (c2i s.[i - 1 - j]); done; if !t &gt; 9 then (* jump out *) raise (Invalid_argument "carry"); res.[i] &lt;- i2c !t; done; del_zeros res ); ;; let rec check_fs fsns p = try let sq = square p in if (is_palindrome sq) then sq :: fsns else fsns with Invalid_argument "carry" -&gt; fsns ;; (* build the fair and square number list *) (* dfs *) let rec create_fair_square_nums fsns p sum max_num_digs = let l = String.length p in if l &gt; max_num_digs || sum &gt; 9 then fsns else let fsns = create_fair_square_nums fsns ("0" ^ p ^ "0") sum max_num_digs in let fsns = create_fair_square_nums fsns ("1" ^ p ^ "1") (sum + 1) max_num_digs in let fsns = create_fair_square_nums fsns ("2" ^ p ^ "2") (sum + 4) max_num_digs in let fsns = create_fair_square_nums fsns ("3" ^ p ^ "3") (sum + 9) max_num_digs in let fsns = check_fs fsns p in fsns ;; let rec print_fsns fsns = List.iter (fun s -&gt; printf "%s " s) fsns; printf "\n" ;; let num_str_cmp s1 s2 = let len1 = String.length s1 in let len2 = String.length s2 in match (len1 - len2) with | 0 -&gt; String.compare s1 s2 | cmp -&gt; cmp ;; (* works *) let max_dig = 51;; let fsns = let fsns = create_fair_square_nums [] "" 0 max_dig in let fsns = create_fair_square_nums fsns "0" 0 max_dig in let fsns = create_fair_square_nums fsns "1" 1 max_dig in let fsns = create_fair_square_nums fsns "2" 4 max_dig in create_fair_square_nums fsns "3" 9 max_dig ;; let fsns = List.sort num_str_cmp fsns;; print_fsns fsns;; </code></pre> <p>My original code (naive solution, too slow):</p> <pre><code>open Printf;; let rec _is_palindrome s i j = if i &lt; j then if s.[i] = s.[j] then _is_palindrome s (i + 1) (j - 1) else false else true ;; let is_palindrome s = if (String.length s &lt; 1) then false else _is_palindrome s 0 ((String.length s) - 1) ;; let rec del_zeros s = let sl = String.length s in if (sl &lt; 1) then s else (if s.[0] = '0' then del_zeros (String.sub s 1 (sl - 1)) else s ) ;; let c2i c = Char.code c - Char.code '0' ;; let i2c i = Char.chr (i + Char.code '0') ;; (* only positive number *) let square s = (* including the carry dig *) let slen = String.length s in let res = ( if slen &gt; 0 then let reslen = 2 * slen in let res = String.make reslen '0' in let t = ref 0 in for i = (reslen - 1) downto 1 do t := c2i (res.[i]); for j = (slen - 1) downto 0 do if (i - 1 - j) &gt;= 0 &amp;&amp; (i - 1 - j) &lt; slen then (t := !t + (c2i s.[j]) * (c2i s.[i - 1 - j]); (* printf "%d, %d: %d\n" j (i - 1 - j) !t; *) ) done; (* printf "%d: %d\n" i !t; *) if !t &gt; 9 then (res.[i - 1] &lt;- Char.chr (Char.code res.[i - 1] + (!t / 10)); t := !t mod 10 ); res.[i] &lt;- i2c !t; done; res; else "" ) in (* printf "square %s -&gt; %s\n" s res; *) del_zeros res ;; let extend_palindrome new_ps n = ("0" ^ n ^ "0") :: ("1" ^ n ^ "1") :: ("2" ^ n ^ "2") :: ("3" ^ n ^ "3") :: new_ps ;; let rec extend_palindromes new_ps ps = match ps with | [] -&gt; new_ps | h :: t -&gt; let new_ps = extend_palindrome new_ps h in extend_palindromes new_ps t ;; let rec check_fs fsns ps = match ps with | [] -&gt; fsns | h :: t -&gt; let sq = square h in if (is_palindrome sq) then check_fs (sq :: fsns) t else check_fs fsns t ;; (* build the fair and square number list *) let rec create_fair_square_nums fsns ps max_num_digs = match ps with | h :: t -&gt; if String.length h &gt; max_num_digs then fsns else let ps = extend_palindromes [] ps in let fsns = check_fs fsns ps in create_fair_square_nums fsns ps max_num_digs | [] -&gt; raise (Invalid_argument "fsn should not be []") ;; let rec print_fsns fsns = List.iter (fun s -&gt; printf "%s " s) fsns; printf "\n" ;; let num_str_cmp s1 s2 = let len1 = String.length s1 in let len2 = String.length s2 in match (len1 - len2) with | 0 -&gt; String.compare s1 s2 | cmp -&gt; cmp ;; (* works *) let max_dig = 50;; let fsns = let fsns0 = create_fair_square_nums [] [""] max_dig in let fsns1 = create_fair_square_nums [] ["0"; "1"; "2"; "3"] max_dig in (* print_fsns fsns0; print_fsns fsns1; *) ["0"; "1"; "4"; "9"] @ fsns0 @ fsns1 ;; (* print_fsns fsns;; *) let fsns = List.sort num_str_cmp fsns;; print_fsns fsns;; </code></pre> <p>This code generates the fair and square numbers which is within 10^100.</p> <p>This code should have some (or many) problems regarding the performance. It run for more than 30 mins before I killed it. When max_dig = 14 it finishes quickly (&lt; 1min).</p> <p>Any suggestion on improving this code or criticism to it are both welcome.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload