Challenge: Reversible Primes
A prime number is a number that is only divisible by 1 and itself, for example, 7
. An emirp↗ is a prime number that results in a different prime when its decimal digits are reversed. For example, 107
and 701
are a pair of emirps, and 3,049
and 9,403
.
Palindromic numbers are not emirps. 101
is a prime and its reverse is itself -- it is not an emirp.
Your task for this challenge is write a generator that will add up all the first n
emirps. To be precise, you should write a generator emirp
which takes a @ud
number n
as an input, and returns a @ud
number which is the sum of the first n
emirps.
Example usage:
> +emirp 10638
The first 10 emirps are 13, 17, 31, 37, 71, 73, 79, 97, 107, 113
, and their sum is 638
.
Solutions
These solutions were submitted by the Urbit community as part of a competition in ~2024.3. They are made available under the MIT License and CC0. We ask you to acknowledge authorship should you utilize these elsewhere.
Solution #1
By ~nodmel-todsyr. A very fast and efficient solution.
:: emirp.hoon:: Finds a sum of first n emirp numbers|^|= [n=@ud]=/ i 0=/ sum 0=/ number 13=| emirps=(set @ud)|-?: =(i n)sum=^ x=@ud emirps (find-emirp number emirps)%= $i +(i)sum (add sum x):: iterating only over 6k +- 1 numbersnumber (add ?:(=((mod x 6) 1) 4 2) x)==:: Finds a smallest emirp which is greater than or equal to x.:: Adds flipped emirp to the set of emirps:: If emirp is in the set, returns it immediately::++ find-emirp|= [x=@ud emirps=(set @ud)]^- [@ud (set @ud)]=/ flipped (flip x)?: (~(has in emirps) x)[x emirps]?: &(!=(x flipped) (is-prime x) (is-prime flipped))[x (~(put in emirps) flipped)]$(x (add ?:(=((mod x 6) 1) 4 2) x)):: Checks if x is a prime.::++ is-prime|= [x=@ud]^- ??: (lte x 3)(gth x 1)?: |(=((mod x 2) 0) =((mod x 3) 0))%.n=/ limit p:(sqt x)=/ j 5|-?: (gth j limit)%.y?: |(=((mod x j) 0) =((mod x (add 2 j)) 0))%.n$(j (add j 6)):: Flips a number.::++ flip|= [number=@ud]^- @ud=/ m 0=/ rip (curr div 10)=/ last (curr mod 10)|-?: =(number 0)m%= $number (rip number)m (add (mul 10 m) (last number))==--
Solution #2
By ~ramteb-tinmut. Well-commented, easy to read, and fast.
:: emirp.hoon:: Return the sum of the first n emirp numbers::|= target=@ud=/ emirp-candidate 13 :: starting at the first emirp makes sense=| emirps=(list @ud)=<sieve|%++ sieve:: When the target is reached, sum the list of emirps::?: =(target (lent emirps))|-?~ emirps0(add i.emirps $(emirps t.emirps)):: Whilst below target, recurse on is-emirp after incrementing::%= sieveemirps (is-emirp emirp-candidate)emirp-candidate (add emirp-candidate 1)==++ is-emirp|= candidate=@ud=/ reversed (reverse-ud candidate):: Check if candidate number is a palindrome::?: !=(reversed candidate):: Is it also a prime?::?: (is-prime [candidate (sqt candidate)]):: Check if the reverse is also a prime:::?: (is-prime [reversed (sqt reversed)]):: Success! - store the emirp::(into emirps 1 candidate):: The reverse is not a prime:::emirps:: Not prime::emirps:: Palindrome & invalid::emirps++ is-prime=/ divisor 2|= [candidate=@ud root=[@ @]]:: Fastest check first - has the divisor reached our input candidate?::?: =(candidate divisor)%.y:: Ensure non-zero modulo::?: =((mod candidate divisor) 0)%.n:: If not a prime, then number must have a divisor less than or equal to its square root. There's an edge case if the square root is not a whole number, in which case we need to round up:::?: &(=(+3.root 0) (gth divisor +2.root))%.y?: (gth divisor (add 1 +2.root))%.y:: Increment divisor and repeat::%= $divisor (add divisor 1)==++ reverse-ud|= number=@ud^- @ud=/ reversed 0:: Return reversed @ud when number reaches zero::|-?: =(0 number)reversed:: Otherwise loop until all digits are swapped:::=. reversed (add (mul 10 reversed) (mod number 10))$(number (div number 10))--
Unit Tests
Following a principle of test-driven development, the unit tests below allow us to check for expected behavior. To run the tests yourself, follow the instructions in the Unit Tests section.
/+ *test/= emirp /gen/emirp|%++ test-01%+ expect-eq!> `@ud`13!> (emirp 1)++ test-02%+ expect-eq!> `@ud`30!> (emirp 2)++ test-03%+ expect-eq!> `@ud`169!> (emirp 5)++ test-04%+ expect-eq!> `@ud`638!> (emirp 10)++ test-05%+ expect-eq!> `@ud`6.857!> (emirp 25)++ test-06%+ expect-eq!> `@ud`32.090!> (emirp 50)++ test-07%+ expect-eq!> `@ud`115.370!> (emirp 100)++ test-08%+ expect-eq!> `@ud`4.509.726!> (emirp 500)--