Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.forth    |    Forth programmers eat a lot of Bratwurst    |    117,927 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 116,453 of 117,927    |
|    Anton Ertl to Anton Ertl    |
|    Re: Best Euler #13 =?UTF-8?B?c29sdXRpb24    |
|    03 May 24 12:22:51    |
   
   From: anton@mips.complang.tuwien.ac.at   
      
   anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:   
   >Gerry Jackson's answer inspired my solution: sum up each column, the   
   >way you would do it by hand. This not only avoids the need for   
   >bignums and the uncertainty about the correctness that some of the   
   >other solutions have, it is also the most efficient: In this digitwise   
   >solution, every digit is only added, while in the conversion   
   >solutions, each digit costs at least an add, a subtract, and a   
   >multiply (and more in the case of FP); my solution does the subtracts   
   >for the whole column once instead of 100 times:   
   >   
   >s" euler13.input" slurp-file 2constant input   
   >   
   >: sumcolumn ( ucarry1 c-addr -- ucarry2 )   
   > 5100 bounds ?do   
   > i c@ +   
   > 51 +loop   
   > '0' 100 * - 0 # drop ;   
   >   
   >: sum ( -- c-addr2 u2 )   
   > 0 <<#   
   > input drop 50 1 mem-do   
   > i sumcolumn   
   > loop   
   > 0 #s #> ;   
   >   
   >sum drop 10 type cr   
   >   
   >This outputs "5537376230".   
      
   One additional observation inspires an optimization: You can add up to   
   25 digits without overflowing a byte. So you can do the sum of up to   
   25 sequences of digits in SIMD style with the ordinary +; with 8-byte   
   cells, you can add 8 digits with one +. With AVX-512, you can add all   
   the digits of one line at once, but unfortunately, Gforth does not   
   support this properly (and my vector package is designed for long   
   vectors and has too much overhead for short vectors). So I   
   implemented this for working with 8-byte cells;   
      
   here 5114 allot 14 + constant input   
      
   s" euler13.input" r/o open-file throw   
   input 5100 rot read-file throw 5100 <> throw   
      
   create sum25buf 256 allot   
      
   : sum25 ( -- )   
    sum25buf 8 + input 6 - 4 0 do { d s }   
    s 0 25 0 do ( addr w )   
    over @ $ffff000000000000 and + swap 51 + swap loop   
    $3030000000000000 25 * - d ! drop   
    d cell+ s 56 + s cell+ do   
    i 0 25 0 do ( daddr saddr w )   
    over @ + swap 51 + swap loop   
    nip $3030303030303030 25 * - over !   
    cell+   
    cell +loop   
    drop   
    d 64 + s 25 51 * +   
    loop   
    2drop ;   
      
   : sumcolumn ( ucarry1 c-addr -- ucarry2 )   
    256 bounds ?do   
    i c@ +   
    64 +loop   
    0 # drop ;   
      
   : sum ( -- c-addr2 u2 )   
    sum25   
    0 <<#   
    sum25buf 14 + 50 1 mem-do   
    i sumcolumn   
    loop   
    0 #s #> ;   
      
   sum drop 10 type cr   
      
   This is quite messy, especially dealing with the two extra bytes per   
   line. Does it at least pay off in speed? Calling it with   
      
   perf stat ~/gforth/gforth-fast
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca