Task: Extra primes


C++: #include <iomanip>
#include <iostream>

unsigned int next_prime_digit_number(unsigned int n) {
    if (n == 0)
        return 2;
    switch (n % 10) {
    case 2:
        return n + 1;
    case 3:
    case 5:
        return n + 2;
    default:
        return 2 + next_prime_digit_number(n/10) * 10;
    }
}

bool is_prime(unsigned int n) {
    if (n < 2)
        return false;
    if ((n & 1) == 0)
        return n == 2;
    if (n % 3 == 0)
        return n == 3;
    if (n % 5 == 0)
        return n == 5;
    static constexpr unsigned int wheel[] = { 4,2,4,2,4,6,2,6 };
    unsigned int p = 7;
    for (;;) {
        for (unsigned int w : wheel) {
            if (p * p > n)
                return true;
            if (n % p == 0)
                return false;
            p += w;
        }
    }
}

unsigned int digit_sum(unsigned int n) {
    unsigned int sum = 0;
    for (; n > 0; n /= 10)
        sum += n % 10;
    return sum;
}

int main() {
    std::cout.imbue(std::locale(""));
    const unsigned int limit1 = 10000;
    const unsigned int limit2 = 1000000000;
    const int last = 10;
    unsigned int p = 0, n = 0;
    unsigned int extra_primes[last];
    std::cout << "Extra primes under " << limit1 << ":\n";
    while ((p = next_prime_digit_number(p)) < limit2) {
        if (is_prime(digit_sum(p)) && is_prime(p)) {
            ++n;
            if (p < limit1)
                std::cout << std::setw(2) << n << ": " << p << '\n';
            extra_primes[n % last] = p;
        }
    }
    std::cout << "\nLast " << last << " extra primes under " << limit2 << ":\n";
    for (int i = last - 1; i >= 0; --i)
        std::cout << n-i << ": " << extra_primes[(n-i) % last] << '\n';
    return 0;
}










Ada: with Ada.Text_Io;

procedure Extra_Primes is

   type Number   is new Long_Integer range 0 .. Long_Integer'Last;

   package Number_Io is new Ada.Text_Io.Integer_Io (Number);

   function Is_Prime (A : Number) return Boolean is
      D : Number;
   begin
      if A < 2       then return False; end if;
      if A in 2 .. 3 then return True;  end if;
      if A mod 2 = 0 then return False; end if;
      if A mod 3 = 0 then return False; end if;
      D := 5;
      while D * D <= A loop
         if A mod D = 0 then
            return False;
         end if;
         D := D + 2;
         if A mod D = 0 then
            return False;
         end if;
         D := D + 4;
      end loop;
      return True;
   end Is_Prime;

   subtype Digit is Number range 0 .. 9;
   type Digit_Array is array (Positive range <>) of Digit;

   function To_Digits (N : Number) return Digit_Array is
      Image : constant String := Number'Image (N);
      Res   : Digit_Array (2 .. Image'Last);
   begin
      for A in Image'First + 1 .. Image'Last loop
         Res (A) := Character'Pos (Image (A)) - Character'Pos ('0');
      end loop;
      return Res;
   end To_Digits;

   function All_Prime (Dig : Digit_Array) return Boolean is
     (for all D of Dig => Is_Prime (D));

   function Sum_Of (Dig : Digit_Array) return Number is
      Sum : Number := 0;
   begin
      for D of Dig loop
         Sum := Sum + D;
      end loop;
      return Sum;
   end Sum_Of;

   use Ada.Text_Io;
   Count : Natural := 0;
begin
   for N in Number range 1 .. 9_999 loop
      if Is_Prime (N) then
         declare
            Dig : constant Digit_Array := To_Digits (N);
         begin
            if All_Prime (Dig) and Is_Prime (Sum_Of (Dig)) then
               Count := Count + 1;
               Number_Io.Put (N, Width => 4); Put ("  ");
               if Count mod 8 = 0 then
                  New_Line;
               end if;
            end if;
         end;
      end if;
   end loop;
   New_Line;
   Put_Line (Count'Image & " extra primes.");
end Extra_Primes;