Magnanimous numbers

From Rosetta Code
Magnanimous numbers is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A magnanimous number is an integer where there is no place in the number where a + (plus sign) could be added between any two digits to give a non-prime sum.


E.G.
  • 6425 is a magnanimous number. 6 + 425 == 431 which is prime; 64 + 25 == 89 which is prime; 642 + 5 == 647 which is prime.
  • 3538 is not a magnanimous number. 3 + 538 == 541 which is prime; 35 + 38 == 73 which is prime; but 353 + 8 == 361 which is not prime.


Traditionally the single digit numbers 0 through 9 are included as magnanimous numbers as there is no place in the number where you can add a plus between two digits at all. (Kind of weaselly but there you are...) Except for the actual value 0, leading zeros are not permitted. Internal zeros are fine though, 1001 -> 1 + 001 (prime), 10 + 01 (prime) 100 + 1 (prime).

There are only 571 known magnanimous numbers. It is strongly suspected, though not rigorously proved, that there are no magnanimous numbers above 97393713331910, the largest one known.


Task
  • Write a routine (procedure, function, whatever) to find magnanimous numbers.
  • Use that function to find and display, here on this page the first 45 magnanimous numbers.
  • Use that function to find and display, here on this page the 241st through 250th magnanimous numbers.
  • Stretch: Use that function to find and display, here on this page the 391st through 400th magnanimous numbers


See also


C

Translation of: Go

<lang c>#include <stdio.h>

  1. include <string.h>

typedef int bool; typedef unsigned long long ull;

  1. define TRUE 1
  2. define FALSE 0

/* OK for 'small' numbers. */ bool is_prime(ull n) {

   ull d;
   if (n < 2) return FALSE;
   if (!(n % 2)) return n == 2;
   if (!(n % 3)) return n == 3;
   d = 5;
   while (d * d <= n) {
       if (!(n % d)) return FALSE;
       d += 2;
       if (!(n % d)) return FALSE;
       d += 4;
   }
   return TRUE;

}

void ord(char *res, int n) {

   char suffix[3];
   int m = n % 100;
   if (m >= 4 && m <= 20) {
       sprintf(res,"%dth", n);
       return;
   }
   switch(m % 10) {
       case 1:
           strcpy(suffix, "st");
           break;
       case 2:
           strcpy(suffix, "nd");
           break;
       case 3:
           strcpy(suffix, "rd");
           break;
       default:
           strcpy(suffix, "th");
           break;
   }
   sprintf(res, "%d%s", n, suffix);

}

bool is_magnanimous(ull n) {

   ull p, q, r;
   if (n < 10) return TRUE;
   for (p = 10; ; p *= 10) {
       q = n / p;
       r = n % p;
       if (!is_prime(q + r)) return FALSE;
       if (q < 10) break;
   }
   return TRUE;

}

void list_mags(int from, int thru, int digs, int per_line) {

   ull i = 0;
   int c = 0;
   char res1[13], res2[13];
   if (from < 2) {
       printf("\nFirst %d magnanimous numbers:\n", thru);
   } else {
       ord(res1, from);
       ord(res2, thru);
       printf("\n%s through %s magnanimous numbers:\n", res1, res2);
   }
   for ( ; c < thru; ++i) {
       if (is_magnanimous(i)) {
           if (++c >= from) {
               printf("%*llu ", digs, i);
               if (!(c % per_line)) printf("\n");
           }
       }
   }

}

int main() {

   list_mags(1, 45, 3, 15);
   list_mags(241, 250, 1, 10);
   list_mags(391, 400, 1, 10);
   return 0;

}</lang>

Output:
First 45 magnanimous numbers:
  0   1   2   3   4   5   6   7   8   9  11  12  14  16  20 
 21  23  25  29  30  32  34  38  41  43  47  49  50  52  56 
 58  61  65  67  70  74  76  83  85  89  92  94  98 101 110 

241st through 250th magnanimous numbers:
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407 

391st through 400th magnanimous numbers:
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081 

F#

The function

This task uses Extensible Prime Generator (F#) <lang fsharp> // Generate Magnanimous numbers. Nigel Galloway: March 20th., 2020 let rec fN n g = match (g/n,g%n) with

                 (0,_)                    -> true
                |(α,β) when isPrime (α+β) -> fN (n*10) g
                |_                        -> false

let Magnanimous = let Magnanimous = fN 10 in seq{yield! {0..9}; yield! Seq.initInfinite id |> Seq.skip 10 |> Seq.filter Magnanimous} </lang>

The Tasks

First 45

<lang fsharp> Magnanimous |> Seq.take 45 |> Seq.iter (printf "%d "); printfn "" </lang>

Output:
0 1 2 3 4 5 6 7 8 9 11 12 14 16 20 21 23 25 29 30 32 34 38 41 43 47 49 50 52 56 58 61 65 67 70 74 76 83 85 89 92 94 98 101 110
Magnanimous[241] to Magnanimous[250]

<lang fsharp> Magnanimous |> Seq.skip 240 |> Seq.take 10 |> Seq.iter (printf "%d "); printfn "";; </lang>

Output:
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407
Magnanimous[391] to Magnanimous[400]

<lang fsharp> Magnanimous |> Seq.skip 390 |> Seq.take 10 |> Seq.iter (printf "%d "); printfn "";; </lang>

Output:
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081

Factor

Translation of: Julia
Works with: Factor version 0.99 2020-01-23

<lang factor>USING: grouping io kernel lists lists.lazy math math.functions math.primes math.ranges prettyprint sequences ;

magnanimous? ( n -- ? )
   dup 10 < [ drop t ] [
       dup log10 >integer [1,b] [ 10^ /mod + prime? not ] with
       find nip >boolean not
   ] if ;
magnanimous ( n -- seq )
   0 lfrom [ magnanimous? ] lfilter ltake list>array ;
show ( seq from to -- ) rot subseq 15 group simple-table. nl ;

400 magnanimous [ "First 45 magnanimous numbers" print 0 45 show ] [ "241st through 250th magnanimous numbers" print 240 250 show ] [ "391st through 400th magnanimous numbers" print 390 400 show ] tri</lang>

Output:
First 45 magnanimous numbers
0  1  2  3  4  5  6  7  8  9  11 12 14 16  20
21 23 25 29 30 32 34 38 41 43 47 49 50 52  56
58 61 65 67 70 74 76 83 85 89 92 94 98 101 110

241st through 250th magnanimous numbers
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407

391st through 400th magnanimous numbers
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081

Go

<lang go>package main

import "fmt"

// OK for 'small' numbers. func isPrime(n uint64) bool {

   switch {
   case n < 2:
       return false
   case n%2 == 0:
       return n == 2
   case n%3 == 0:
       return n == 3
   default:
       d := uint64(5)
       for d*d <= n {
           if n%d == 0 {
               return false
           }
           d += 2
           if n%d == 0 {
               return false
           }
           d += 4
       }
       return true
   }

}

func ord(n int) string {

   m := n % 100
   if m >= 4 && m <= 20 {
       return fmt.Sprintf("%dth", n)
   }
   m %= 10
   suffix := "th"
   if m < 4 {
       switch m {
       case 1:
           suffix = "st"
       case 2:
           suffix = "nd"
       case 3:
           suffix = "rd"
       }
   }
   return fmt.Sprintf("%d%s", n, suffix)

}

func isMagnanimous(n uint64) bool {

   if n < 10 {
       return true
   }
   for p := uint64(10); ; p *= 10 {
       q := n / p
       r := n % p
       if !isPrime(q + r) {
           return false
       }
       if q < 10 {
           break
       }
   }
   return true

}

func listMags(from, thru, digs, perLine int) {

   if from < 2 {
       fmt.Println("\nFirst", thru, "magnanimous numbers:")
   } else {
       fmt.Printf("\n%s through %s magnanimous numbers:\n", ord(from), ord(thru))
   }
   for i, c := uint64(0), 0; c < thru; i++ {
       if isMagnanimous(i) {
           c++
           if c >= from {
               fmt.Printf("%*d ", digs, i)
               if c%perLine == 0 {
                   fmt.Println()
               }
           }
       }
   }

}

func main() {

   listMags(1, 45, 3, 15)
   listMags(241, 250, 1, 10)
   listMags(391, 400, 1, 10)

}</lang>

Output:
First 45 magnanimous numbers:
  0   1   2   3   4   5   6   7   8   9  11  12  14  16  20 
 21  23  25  29  30  32  34  38  41  43  47  49  50  52  56 
 58  61  65  67  70  74  76  83  85  89  92  94  98 101 110 

241st through 250th magnanimous numbers:
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407 

391st through 400th magnanimous numbers:
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081 

Julia

<lang julia>using Primes

function ismagnanimous(n)

   n < 10 && return true
   for i in 1:ndigits(n)-1
       q, r = divrem(n, 10^i)
       !isprime(q + r) && return false
   end
   return true

end

function magnanimous(N)

   mvec, i = Int[], 0
   while length(mvec) < N
       if ismagnanimous(i)
           push!(mvec, i)
       end
       i += 1
   end
   return mvec

end

const mag400 = magnanimous(400) println("First 45 magnanimous numbers:\n", mag400[1:24], "\n", mag400[25:45]) println("\n241st through 250th magnanimous numbers:\n", mag400[241:250]) println("\n391st through 400th magnanimous numbers:\n", mag400[391:400])

</lang>

Output:
First 45 magnanimous numbers:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 16, 20, 21, 23, 25, 29, 30, 32, 34, 38, 41]
[43, 47, 49, 50, 52, 56, 58, 61, 65, 67, 70, 74, 76, 83, 85, 89, 92, 94, 98, 101, 110]

241st through 250th magnanimous numbers:
[17992, 19972, 20209, 20261, 20861, 22061, 22201, 22801, 22885, 24407]

391st through 400th magnanimous numbers:
[486685, 488489, 515116, 533176, 551558, 559952, 595592, 595598, 600881, 602081]


Phix

<lang Phix>function magnanimous(integer n)

   integer p = 1, r = 0
   while n>=10 do
       r += remainder(n,10)*p
       n = floor(n/10)
       if not is_prime(n+r) then return false end if
       p *= 10
   end while
   return true

end function

sequence mag = {} integer n = 0 while length(mag)<400 do

   if magnanimous(n) then mag &= n end if
   n += 1

end while puts(1,"First 45 magnanimous numbers: ") pp(mag[1..45],{pp_Indent,30,pp_IntCh,false,pp_Maxlen,100}) printf(1,"magnanimous numbers[241..250]: %v\n", {mag[241..250]}) printf(1,"magnanimous numbers[391..400]: %v\n", {mag[391..400]})</lang>

Output:
First 45 magnanimous numbers: {0,1,2,3,4,5,6,7,8,9,11,12,14,16,20,21,23,25,29,30,32,34,38,41,43,
                               47,49,50,52,56,58,61,65,67,70,74,76,83,85,89,92,94,98,101,110}
magnanimous numbers[241..250]: {17992,19972,20209,20261,20861,22061,22201,22801,22885,24407}
magnanimous numbers[391..400]: {486685,488489,515116,533176,551558,559952,595592,595598,600881,602081}

Raku

Works with: Rakudo version 2020.02

<lang perl6>my @magnanimous = lazy flat ^10, (10 .. 1001).hyper.map( {

   my $last;
   (1 .. .chars - 1).map: -> \c { ++$last and last unless (.substr(0,c) + .substr(c)).is-prime }
   next if $last;
   $_

} ),

(1002 .. ∞).hyper.map: {

   # optimization for numbers > 1001; First and last digit can not both be even or both be odd
   next if (.substr(0,1) % 2 + .substr(*-1) % 2) %% 2;
   my $last;
   (1 .. .chars - 1).map: -> \c { ++$last and last unless (.substr(0,c) + .substr(c)).is-prime }
   next if $last;
   $_

}

put 'First 45 magnanimous numbers'; put @magnanimous[^45]».fmt('%3d').batch(15).join: "\n";

put "\n241st through 250th magnanimous numbers"; put @magnanimous[240..249];

put "\n391st through 400th magnanimous numbers"; put @magnanimous[390..399];</lang>

Output:
First 45 magnanimous numbers
  0   1   2   3   4   5   6   7   8   9  11  12  14  16  20
 21  23  25  29  30  32  34  38  41  43  47  49  50  52  56
 58  61  65  67  70  74  76  83  85  89  92  94  98 101 110

241st through 250th magnanimous numbers
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407

391st through 400th magnanimous numbers
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081

REXX

The majority of the time consumed was in generated a list (sparse array) of suitable primes.
The genP subroutine could use a lot of optimization if wanted.
The magna function was quite simple to code and pretty fast. <lang REXX>/*REXX pgm finds/displays magnanimous #s (#s with a inserted + sign to sum to a prime).*/ parse arg bet.1 bet.2 bet.3 highP . /*obtain optional arguments from the CL*/ if bet.1== | bet.1=="," then bet.1= 1..45 /* " " " " " " */ if bet.2== | bet.2=="," then bet.2= 241..250 /* " " " " " " */ if bet.3== | bet.3=="," then bet.3= 391..400 /* " " " " " " */ if highP== | highP=="," then highP= 1000000 /* " " " " " " */ call genP /*gen primes up to highP (1 million).*/

    do j=1  for 3                               /*process three magnanimous "ranges".  */
    parse var   bet.j   LO  '..'  HI            /*obtain the first range (if any).     */
    if HI==  then HI= LO                      /*Just a single number?   Then use LO. */
    if HI==0   then iterate                     /*Is HI a zero?   Then skip this range.*/
    #= 0;                                 $=    /*#:  magnanimous # cnt;  $:  is a list*/
         do k=0  until #==HI                    /* [↑]  traispe through the number(s). */
         if \magna(k)  then iterate             /*Not magnanimous?  Then skip this num.*/
         #= # + 1                               /*bump the magnanimous number count.   */
         if #>=LO  then $= $ k                  /*In range►  Then add number ──► $ list*/
         end   /*k*/
    say
    say center(' 'LO   "──►"   HI   'magnanimous numbers ',  126, "─")
    say strip($)
    end        /*j*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ magna: procedure expose @. !.; parse arg x /*obtain the number to be examined. */

      if x<10  then return 1                    /*single digit numbers are magnanimous.*/
                 do  s= 1  to  length(x)-1      /*traipse thr number, inserting + sign.*/
                 parse var  x   y  +(s)  z;   sum= y + z  /*parse 2 parts of #, sum 'em*/
                 if !.sum  then iterate         /*Sum is a prime?  Then so far so good.*/
                           else return 0        /*Nope?            Then not magnanimous*/
                 end   /*s*/
      return 1                                  /*Pass all the tests, it's magnanimous.*/

/*──────────────────────────────────────────────────────────────────────────────────────*/ genP: @.1=2; @.2=3; @.3=5; @.4=7; @.5=11; @.6= 13; nP=6 /*assign low primes; # primes. */

     !.= 0; !.2=1; !.3=1; !.5=1; !.7=1; !.11=1; !.13= 1 /*assign primality to numbers. */
      do lim=nP  until lim>=highP;  end         /*only keep primes up to the sqrt(HI). */
      do j=@.nP+4  by 2  to highP               /*only find odd primes from here on.   */
      if j// 3==0  then iterate                 /*is J divisible by  #3  Then not prime*/
      parse var j  -1 _;if _==5  then iterate /*Is last digit a "5"?     "   "    "  */
      if j// 7==0  then iterate                 /*is J divisible by  7?    "   "    "  */
      if j//11==0  then iterate                 /* " "     "      " 11?    "   "    "  */
      if j//13==0  then iterate                 /*is "     "      " 13?    "   "    "  */
          do k=7  while k*k<=j                  /*divide by some generated odd primes. */
          if j // @.k==0  then iterate j        /*Is J divisible by  P?  Then not prime*/
          end   /*k*/                           /* [↓]  a prime  (J)  has been found.  */
      nP= nP+1;         @.nP= j;   !.j= 1       /*bump P cnt;  assign P to @.  and  !. */
      end      /*j*/;              return</lang>
output   when using the default inputs:
──────────────────────────────────────────────── 1 ──► 45 magnanimous numbers ────────────────────────────────────────────────
0 1 2 3 4 5 6 7 8 9 11 12 14 16 20 21 23 25 29 30 32 34 38 41 43 47 49 50 52 56 58 61 65 67 70 74 76 83 85 89 92 94 98 101 110
and took 0.00 seconds.


────────────────────────────────────────────── 241 ──► 250 magnanimous numbers ───────────────────────────────────────────────
17992 19972 20209 20261 20861 22061 22201 22801 22885 24407
and took 0.31 seconds.


────────────────────────────────────────────── 391 ──► 400 magnanimous numbers ───────────────────────────────────────────────
486685 488489 515116 533176 551558 559952 595592 595598 600881 602081