PlummersSoftwareLLC / Primes

Prime Number Projects in C#/C++/Python
https://plummerssoftwarellc.github.io/PrimeView/
2.46k stars 573 forks source link

Erlang solution #909

Closed jesperes closed 1 year ago

jesperes commented 1 year ago

Description

Straight-forward Erlang solution.

Contributing requirements

rbergen commented 1 year ago

@jesperes Thank you for submitting this, I always like it when we can add another language to the collection. As a former user of CouchDB and RabbitMQ, I'm particularly pleased to see a solution in Erlang.

I've reviewed the solution, and I think we will have to change the faithfulness qualification. This relates to the second requirement for faithful solutions as mentioned in the respective section of the contributing guidelines:

  • It uses a class to encapsulate the sieve, or a (closest) equivalent feature in your language if a class construct is not available. This class must contain the full state of the sieve. Each iteration should re-create a new instance of this class from scratch.

As far as I can tell, the solution is currently purely procedural. I recognize that Erlang may not offer a class-like structure to use, but as has been documented many times in earlier PRs that doesn't change the evaluation of this part of the rules.

jesperes commented 1 year ago

Admittedly, it uses the non-functional atomics module to store the bits, but apart from that it isn't fundamentally different from e.g. Elixir/solution_2. How would you recommend I modify the solution if I want to keep it faithful?

rbergen commented 1 year ago

I'm not sure it is possible to create an Erlang solution that is faithful by the contributor guidelines definition. There's quite a few languages that don't offer a structure in which the "entire sieve state" (by now established to be at least the sieve buffer and sieve limit) can be captured. That means that there are languages for which only "unfaithful" solutions exist, even though their authors would have made them faithful if it were possible. That said, in the case of the Elixir solution you refer to, there is a function that does create an object-like structure:

  def create_sieve(size) do
    size = div2(size)
    <<-1::size(size)>>
  end

This structure is then passed to/between functions that are involved with calculating the sieve and processing results. If you could do something similar in your Erlang solution, that would be enough to qualify the solution as faithful.

It may help when I add that the label "faithful" in the context of Primes can be considered an unfortunate choice of words. It's a label for a number of implementation characteristics that could be viewed as more or less arbitrary. That being as it may, it's just the nomenclature we've settled on over the past 2 years. (In fact, when Dave uses the "faithful" denomination, he means a blend of "base algorithm", some of the faithful characteristics as discussed here, and 1 bit per prime.)

jesperes commented 1 year ago

Ok, I'll rewrite it to store the sieve buffer and the sieve limit in a record (in Erlang terminology).

jesperes commented 1 year ago

Refactored the code to use a #sieve record:

-spec sieve_new(Size :: integer()) -> sieve().
sieve_new(Size) ->
  #sieve{q = math:sqrt(Size),
         size = Size,
         bits = atomics:new(Size, [])}.

Hopefully this satisfies the "faithful" criteria.