On Sunday, March 16, 2014 8:52:35 PM UTC+1, Stefan Schwarz wrote:
>
> Hello,
>
> I started with Julia last week and to get into tracks I tried to implement
> some of the Project Euler question, that I've already done in Mathematica 
> (being a Mathematica developer for ~10 years)
>
> The specifics of this question is about problem #21:
>
> Let d(*n*) be defined as the sum of proper divisors of *n* (numbers less 
> than *n* which divide evenly into *n*).
> If d(*a*) = *b* and d(*b*) = *a*, where *a* [image: ≠] *b*, then *a* and 
> *b* are an amicable pair and each of *a* and *b* are called amicable 
> numbers.
>
> For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 
> 44, 55 and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 
> 2, 4, 71 and 142; so d(284) = 220.
>
> Evaluate the sum of all the amicable numbers under 10000.
>
>
> In Mathematica this was done very easily with:
>
> DivSum[n_] := DivisorSigma[1, n] - n
> AmicableQ[n_Integer] := DivSum[n] != n && DivSum[DivSum[n]] == n
> Plus @@ Select[Range[9999], AmicableQ] // Timing
>
>
> Yielding a tuple of time and the result: {0.178553, 31626}
>
> Which is correct. So I tried to achieve the same in Julia:
>
>  function divisors(n::Int, prop::Bool=false)
>     if(!prop)
>         filter((x) -> rem(n, x) == 0, [1:n])
>     else
>         filter((x) -> rem(n, x) == 0, [1:n-1])
>     end
> end
>
>  
>
> function divsum(n::Int)
>     sum(divisors(n, true))
> end
>
>  
>
> function amicable(n::Int)
>     divsum(n) != n && divsum(divsum(n)) == n
> end
>
>  
>
> This yielded the correct result, but awful timing:
>
> @time sum(filter(x -> amicable(x),[1:9999]))
>
>
> elapsed time: 24.025008574 seconds (4310013792 bytes allocated) 
>
>
> So. I did something wrong, apparently. Rats.
>
> So I started to think about, where the hot spot was and
> decided to pick the divisors function to be the suspect.
>
> So I rewrote it:
>
> function factors(n)
>     f = [one(n)]
>     for (p,e) in factor(n)
>         f = reduce(vcat, f, [f*p^j for j in 1:e])
>     end
>     return f
> end
>
>  
>
> function sum_prop_factors(n)
>     sum(factors(n))-n
> end
>
>  
>
> I did even left out the sorting before returning f back, since it isn't 
> needed at all.
>
> Executing this:
>
> @time sum(filter(x -> sum_prop_factors(x) != x && 
> sum_prop_factors(sum_prop_factors(x))==x, [2:9999]))
>
>
> yielded:
>
> elapsed time: 0.207550349 seconds (39478048 bytes allocated) 
>
>  
>
>
(Accidentally sent this off before really finishing it...my fault.)

Although there is a huge speedup to my former implementation, there is 
still a measurable distance to Mathematica's
execution speed (and yes. I cleared system caches etc.)

So the question I like to ask is, does anybody have a better idea to 
implement this in Julia?

The problem I have is, that I did not use specific Mathematica 
functionality, but a straight forward implementation.

>From what I've seen so far, there is the gospel that Julia is always faster 
approaching even the 
execution speed of C. I claim, that there is a better and even faster 
solution to my Mathematica implementation.

If someone can enlighten me on that matter would be wonderful.

Cheers

Stefan

 

Reply via email to