Definitions
In mathematics, additive primes are prime numbers for which the sum of their decimal digits are also primes.



Task
Write a program to determine (and show here) all additive primes less than 500.

Optionally, show the number of additive primes.



Also see

   the OEIS entry:   A046704 additive primes.
   the prime-numbers entry:   additive primes.
   the geeks for geeks entry: additive prime number.
   the prime-numbers fandom: additive primes.


program AdditivePrimes;
{$IFDEF FPC}
{$MODE DELPHI}{$CODEALIGN proc=16}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}
{$DEFINE DO_OUTPUT}
 
uses
  sysutils;
 
const
  RANGE = 500; // 1000*1000;//
  MAX_OFFSET = 0; // 1000*1000*1000;//
 
type
  tNum = array [0 .. 15] of byte;
 
  tNumSum = record
    dgtNum, dgtSum: tNum;
    dgtLen, num: Uint32;
  end;
 
  tpNumSum = ^tNumSum;
 
function isPrime(n: Uint32): boolean;
const
  wheeldiff: array [0 .. 7] of Uint32 = (+6, +4, +2, +4, +2, +4, +6, +2);
var
  p: NativeUInt;
  flipflop: Int32;
begin
  if n < 64 then
    EXIT(n in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
      53, 59, 61])
  else
  begin
    IF (n AND 1 = 0) OR (n mod 3 = 0) OR (n mod 5 = 0) then
      EXIT(false);
    result := true;
    p := 1;
    flipflop := 6;
 
    while result do
    Begin
      p := p + wheeldiff[flipflop];
      if p * p > n then
        BREAK;
      result := n mod p <> 0;
      flipflop := flipflop - 1;
      if flipflop < 0 then
        flipflop := 7;
    end
  end
end;
 
procedure IncNum(var NumSum: tNumSum; delta: Uint32);
const
  BASE = 10;
var
  carry, dg: Uint32;
  le: Int32;
Begin
  if delta = 0 then
    EXIT;
  le := 0;
  with NumSum do
  begin
    num := num + delta;
    repeat
      carry := delta div BASE;
      delta := delta - BASE * carry;
      dg := dgtNum[le] + delta;
      IF dg >= BASE then
      Begin
        dg := dg - BASE;
        inc(carry);
      end;
      dgtNum[le] := dg;
      inc(le);
      delta := carry;
    until carry = 0;
    if dgtLen < le then
      dgtLen := le;
    // correct sum of digits // le is >= 1
    delta := dgtSum[le];
    repeat
      dec(le);
      delta := delta + dgtNum[le];
      dgtSum[le] := delta;
    until le = 0;
  end;
end;
 
var
  NumSum: tNumSum;
  s: AnsiString;
  i, k, cnt, Nr: NativeUInt;
  ColWidth, MAXCOLUMNS, NextRowCnt: NativeUInt;
 
BEGIN
  ColWidth := Trunc(ln(MAX_OFFSET + RANGE) / ln(10)) + 2;
  MAXCOLUMNS := 80;
  NextRowCnt := MAXCOLUMNS DIV ColWidth;
 
  fillchar(NumSum, SizeOf(NumSum), #0);
  NumSum.dgtLen := 1;
  IncNum(NumSum, MAX_OFFSET);
  setlength(s, ColWidth);
  fillchar(s[1], ColWidth, ' ');
  // init string
  with NumSum do
  Begin
    For i := dgtLen - 1 downto 0 do
      s[ColWidth - i] := AnsiChar(dgtNum[i] + 48);
    // reset digits lenght to get the max changed digits since last update of string
    dgtLen := 0;
  end;
  cnt := 0;
  Nr := NextRowCnt;
  For i := 0 to RANGE do
    with NumSum do
    begin
      if isPrime(dgtSum[0]) then
        if isPrime(num) then
        Begin
          cnt := cnt + 1;
          dec(Nr);
 
          // correct changed digits in string s
          For k := dgtLen - 1 downto 0 do
            s[ColWidth - k] := AnsiChar(dgtNum[k] + 48);
          dgtLen := 0;
{$IFDEF DO_OUTPUT}
          write(s);
          if Nr = 0 then
          begin
            writeln;
            Nr := NextRowCnt;
          end;
{$ENDIF}
        end;
      IncNum(NumSum, 1);
    end;
  if Nr <> NextRowCnt then
    write(#10);
  writeln(cnt, ' additive primes found.');
END.
 