-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
So I have a simple class demonstrating a couple ways to solve the first Euler problem:
defmodule EulerExample do
@doc """
Returns the sum of all values below a given number which are multiples
of 3 or 5.
This example uses a Stream to lazy load desired values. I expect it to be
faster with much larger values.
## Example
iex> EulerExample.sum_of_multiples(10)
23
"""
@spec sum_of_multiples_1(integer) :: integer
def sum_of_multiples_1(value) do
value
|> find_range
|> create_stream_of_desired_values
|> Enum.sum
end
@doc """
Returns the sum of all values below a given number which are multiples
of 3 or 5.
This example uses tail call recursion. I expect it to be faster with smaller
initial values.
## Example
iex> EulerExample.sum_of_multiples(10)
23
"""
@spec sum_of_multiples_2(integer) :: integer
def sum_of_multiples_2(value) do
value
|> find_range
|> Enum.to_list
|> sum_of_multiples_2(0)
end
defp sum_of_multiples_2([], acc), do: acc
defp sum_of_multiples_2([head|tail], acc) do
value_to_add = if desired_value?(head), do: head, else: 0
sum_of_multiples_2(tail, (acc + value_to_add))
end
@spec create_stream_of_desired_values(Range.t) :: Stream.t
defp create_stream_of_desired_values(range) do
Stream.filter(range, fn(x) -> desired_value?(x) end)
end
@spec find_range(integer) :: Range.t
defp find_range(value) do
Range.new(0, value - 1)
end
@spec desired_value?(integer) :: integer
defp desired_value?(number) do
cond do
rem(number, 3) == 0 -> true
rem(number, 5) == 0 -> true
true -> false
end
end
endI then set up the benchmarks:
defmodule Example do
use Bmark
bmark :runner1, runs: 5 do
EulerExample.sum_of_multiples_1(100)
end
bmark :runner2, runs: 5 do
EulerExample.sum_of_multiples_2(100)
end
endAnd then run the benchmarks:
$ mix bmark
$ mix bmark.cmp results/example.runner1.results results/example.runner2.results
results/example.runner1.results: results/example.runner2.results:
30 1418
26 26
25 24
23 22
23 19
25.4 -> 301.8 (+1088.19%) with p < 1
t = 0.9904844302351117, 8 degrees of freedom
For some reason I always get a little over 1ms on the last example that runs.
defmodule Example do
use Bmark
bmark :runner1, runs: 5 do
EulerExample.sum_of_multiples_1(100)
end
bmark :runner2, runs: 5 do
EulerExample.sum_of_multiples_2(100)
end
bmark :runner3, runs: 5 do
EulerExample.sum_of_multiples_2(100)
end
endresults/example.runner1.results: results/example.runner2.results:
31 22
24 20
24 18
22 20
22 18
24.6 -> 19.6 (-20.33%) with p < 0.025
t = 2.7441064997422586, 8 degrees of freedom
results/example.runner1.results: results/example.runner3.results:
31 1626
24 23
24 18
22 19
22 18
24.6 -> 340.8 (+1285.37%) with p < 1
t = 0.9841097775094585, 8 degrees of freedom
In case it ends up mattering I'm using:
$ elixir -v
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Elixir 1.2.4
on OS X 10.11.4
Metadata
Metadata
Assignees
Labels
No labels