Strange plus numbers

From Rosetta Code
Revision as of 22:17, 24 February 2021 by Bastet (talk | contribs) (→‎{{header|C}}: simplify as it's not a task about sieving)
Strange plus 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.

n   is a strange plus number if the sum of the first two digits is prime and the sum of the second two digits is also prime.

Where     100   <   n   <   500

APL

Works with: Dyalog APL

<lang APL>(∧⌿ 2 3 5 7 11 13 17 ∊⍨ 2 +⌿ 10 (⊥⍣¯1) X)/X←100+⍳399</lang>

Output:
111 112 114 116 120 121 123 125 129 141 143 147 149 161 165 167 202 203
      205 207 211 212 214 216 230 232 234 238 250 252 256 258 292 294
      298 302 303 305 307 320 321 323 325 329 341 343 347 349 383 385
      389 411 412 414 416 430 432 434 438 470 474 476 492 494 498


AppleScript

<lang applescript>------------------- STRANGE PLUS NUMBERS -----------------

-- isStrangePlus :: Int -> Bool on isStrangePlus(n)

   set ds to digits(n)
   
   script sumIsSmallPrime
       on |λ|(a, b)
           {2, 3, 5, 7, 11, 13, 17} contains (a + b)
       end |λ|
   end script
   
   zipWith(sumIsSmallPrime, ds, rest of ds) does not contain false

end isStrangePlus



TEST -------------------------

on run

   set xs to filter(isStrangePlus, enumFromTo(100, 500))
   
   intercalate("\n\n", ¬
       {"'Strange Plus' numbers found in range [100..500]", ¬
           "Full list:", ¬
           ("(total " & (length of xs) as string) & ")", ¬
           unlines(map(unwords, chunksOf(10, map(str, xs))))})

end run



GENERIC ------------------------

-- chunksOf :: Int -> [a] -> a on chunksOf(k, xs)

   script
       on go(ys)
           set ab to splitAt(k, ys)
           set a to item 1 of ab
           if {} ≠ a then
               {a} & go(item 2 of ab)
           else
               a
           end if
       end go
   end script
   result's go(xs)

end chunksOf


-- digits :: Int -> [Int] on digits(n)

   script go
       on |λ|(x)
           x as integer
       end |λ|
   end script
   map(go, characters of (n as string))

end digits


-- enumFromTo :: Int -> Int -> [Int] on enumFromTo(m, n)

   if m ≤ n then
       set lst to {}
       repeat with i from m to n
           set end of lst to i
       end repeat
       lst
   else
       {}
   end if

end enumFromTo


-- intercalate :: String -> [String] -> String on intercalate(delim, xs)

   set {dlm, my text item delimiters} to ¬
       {my text item delimiters, delim}
   set s to xs as text
   set my text item delimiters to dlm
   s

end intercalate


-- filter :: (a -> Bool) -> [a] -> [a] on filter(p, xs)

   tell mReturn(p)
       set lst to {}
       set lng to length of xs
       repeat with i from 1 to lng
           set v to item i of xs
           if |λ|(v, i, xs) then set end of lst to v
       end repeat
       if {text, string} contains class of xs then
           lst as text
       else
           lst
       end if
   end tell

end filter


-- mReturn :: First-class m => (a -> b) -> m (a -> b) on mReturn(f)

   -- 2nd class handler function lifted into 1st class script wrapper. 
   if script is class of f then
       f
   else
       script
           property |λ| : f
       end script
   end if

end mReturn


-- map :: (a -> b) -> [a] -> [b] on map(f, xs)

   -- The list obtained by applying f
   -- to each element of xs.
   tell mReturn(f)
       set lng to length of xs
       set lst to {}
       repeat with i from 1 to lng
           set end of lst to |λ|(item i of xs, i, xs)
       end repeat
       return lst
   end tell

end map


-- min :: Ord a => a -> a -> a on min(x, y)

   if y < x then
       y
   else
       x
   end if

end min


-- splitAt :: Int -> [a] -> ([a], [a]) on splitAt(n, xs)

   if n > 0 and n < length of xs then
       if class of xs is text then
           {items 1 thru n of xs as text, ¬
               items (n + 1) thru -1 of xs as text}
       else
           {items 1 thru n of xs, items (n + 1) thru -1 of xs}
       end if
   else
       if n < 1 then
           {{}, xs}
       else
           {xs, {}}
       end if
   end if

end splitAt


-- str :: a -> String on str(x)

   x as string

end str


-- unlines :: [String] -> String on unlines(xs)

   -- A single string formed by the intercalation
   -- of a list of strings with the newline character.
   set {dlm, my text item delimiters} to ¬
       {my text item delimiters, linefeed}
   set s to xs as text
   set my text item delimiters to dlm
   s

end unlines


-- unwords :: [String] -> String on unwords(xs)

   set {dlm, my text item delimiters} to ¬
       {my text item delimiters, space}
   set s to xs as text
   set my text item delimiters to dlm
   return s

end unwords


-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] on zipWith(f, xs, ys)

   set lng to min(length of xs, length of ys)
   set lst to {}
   if 1 > lng then
       return {}
   else
       tell mReturn(f)
           repeat with i from 1 to lng
               set end of lst to |λ|(item i of xs, item i of ys)
           end repeat
           return lst
       end tell
   end if

end zipWith</lang>

Output:
'Strange Plus' numbers found in range [100..500]

Full list:

(total 65)

111 112 114 116 120 121 123 125 129 141
143 147 149 161 165 167 202 203 205 207
211 212 214 216 230 232 234 238 250 252
256 258 292 294 298 302 303 305 307 320
321 323 325 329 341 343 347 349 383 385
389 411 412 414 416 430 432 434 438 470
474 476 492 494 498

C

Generalized solution: a number is strange iff the sum of two consecutive digits is always prime. Numbers < 10 are considered non-strange.

<lang c>#include <stdio.h>

static int p[19] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0,

                   0, 1, 0, 1, 0, 0, 0, 1, 0};

int isstrange(long n) {

   if (n < 10) return 0;
   for (; n >= 10; n /= 10) {
       if (!p[n%10 + (n/10)%10]) return 0;
   }
   return 1;

}

int main(void) {

   long n;
   int k = 0;
   for (n = 101; n < 500; n++) {
       if (isstrange(n)) {
           printf("%d%c", n, ++k%10 ? ' ' : '\n');
       }
   }
   return 0;

}</lang>

Output:
111 112 114 116 120 121 123 125 129 141
143 147 149 161 165 167 202 203 205 207
211 212 214 216 230 232 234 238 250 252
256 258 292 294 298 302 303 305 307 320
321 323 325 329 341 343 347 349 383 385
389 411 412 414 416 430 432 434 438 470
474 476 492 494 498

Factor

Works with: Factor version 0.99 2021-02-05

<lang factor>USING: grouping grouping.extras io kernel math math.primes math.ranges math.text.utils prettyprint sequences ;

strange+? ( n -- ? )
   dup 10 < [ drop f ]
   [ 1 digit-groups [ + ] 2 clump-map [ prime? ] all? ] if ;

"Strange plus numbers in (100, 500):" print nl 100 500 (a,b) [ strange+? ] filter dup 10 group [ [ pprint bl ] each nl ] each nl length pprint " strange plus numbers found." print</lang>

Output:
Strange plus numbers in (100, 500):

111 112 114 116 120 121 123 125 129 141 
143 147 149 161 165 167 202 203 205 207 
211 212 214 216 230 232 234 238 250 252 
256 258 292 294 298 302 303 305 307 320 
321 323 325 329 341 343 347 349 383 385 
389 411 412 414 416 430 432 434 438 470 
474 476 492 494 498 

65 strange plus numbers found.

Haskell

<lang haskell>import Data.List (intercalate) import Data.List.Split (chunksOf)


STRANGE PLUS NUMBERS -----------------

isStrangePlus :: Int -> Bool isStrangePlus n =

 all
   (\(a, b) -> (a + b) `elem` [2, 3, 5, 7, 11, 13, 17])
   $ (zip <*> tail) (digits n)


digits :: Int -> [Int] digits = fmap (read . return) . show


TEST -------------------------

main =

 let xs = filter isStrangePlus [100 .. 500]
  in (putStrLn . intercalate "\n\n")
       [ "\"Strange Plus\" numbers found in range [100..500]",
         "(total " <> (show . length) xs <> ")",
         "Full list:",
         unlines
           (unwords <$> chunksOf 10 (show <$> xs))
       ]</lang>
Output:
"Strange Plus" numbers found in range [100..500]

(total 65)

Full list:

111 112 114 116 120 121 123 125 129 141
143 147 149 161 165 167 202 203 205 207
211 212 214 216 230 232 234 238 250 252
256 258 292 294 298 302 303 305 307 320
321 323 325 329 341 343 347 349 383 385
389 411 412 414 416 430 432 434 438 470
474 476 492 494 498

Maple

<lang maple>select(n->(u->isprime(add(u[1..2])) and isprime(add(u[2..3])))(convert(n,base,10)),[$101..499]);</lang>

Output:
[111, 112, 114, 116, 120, 121, 123, 125, 129, 141, 143, 147,
 149, 161, 165, 167, 202, 203, 205, 207, 211, 212, 214, 216,
 230, 232, 234, 238, 250, 252, 256, 258, 292, 294, 298, 302,
 303, 305, 307, 320, 321, 323, 325, 329, 341, 343, 347, 349,
 383, 385, 389, 411, 412, 414, 416, 430, 432, 434, 438, 470,
 474, 476, 492, 494, 498]

Python

Using sympy.isprime

<lang python>Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license()" for more information. >>> from sympy import isprime

>>> [x for x in range(101,500)

if isprime(sum(int(c) for c in str(x)[:2])) and
   isprime(sum(int(c) for c in str(x)[1:]))]

[111, 112, 114, 116, 120, 121, 123, 125, 129, 141, 143, 147, 149, 161, 165, 167, 202, 203, 205, 207, 211, 212, 214, 216, 230, 232, 234, 238, 250, 252, 256, 258, 292, 294, 298, 302, 303, 305, 307, 320, 321, 323, 325, 329, 341, 343, 347, 349, 383, 385, 389, 411, 412, 414, 416, 430, 432, 434, 438, 470, 474, 476, 492, 494, 498] >>> </lang>


Or, as we may not need to wake up sympy just to check membership of {2, 3, 5, 7, 11, 13, 17}:

<lang python>Strange Plus Numbers


  1. isStrangePlus :: Int -> Bool

def isStrangePlus(n):

   True all consecutive decimal digit
      pairs in n have prime sums.
   
   def test(a, b):
       return a + b in [2, 3, 5, 7, 11, 13, 17]
   xs = digits(n)
   return all(map(test, xs, xs[1:]))


  1. ------------------- TEST AND DISPLAY -------------------
  2. main :: IO ()

def main():

   List and count of Strange Plus Numbers
   xs = [
       n for n in range(100, 1 + 500)
       if isStrangePlus(n)
   ]
   print('\n"Strange Plus" numbers in range [100..500]\n')
   print('(Total: ' + str(len(xs)) + ')\n')
   print(
       '\n'.join(
           ' '.join(
               str(x) for x in row
           ) for row in chunksOf(10)(xs)
       )
   )


  1. ----------------------- GENERIC ------------------------
  1. chunksOf :: Int -> [a] -> a

def chunksOf(n):

   A series of lists of length n, subdividing the
      contents of xs. Where the length of xs is not evenly
      divible, the final list will be shorter than n.
   
   def go(xs):
       return (
           xs[i:n + i] for i in range(0, len(xs), n)
       ) if 0 < n else None
   return go


  1. digits :: Int -> [Int]

def digits(n):

   Component digits of a decimal number.
   return [int(c) for c in str(n)]


  1. MAIN ---

if __name__ == '__main__':

   main()</lang>
Output:
"Strange Plus" numbers in range [100..500]

(Total: 65)

111 112 114 116 120 121 123 125 129 141
143 147 149 161 165 167 202 203 205 207
211 212 214 216 230 232 234 238 250 252
256 258 292 294 298 302 303 305 307 320
321 323 325 329 341 343 347 349 383 385
389 411 412 414 416 430 432 434 438 470
474 476 492 494 498

Raku

<lang perl6>unit sub MAIN ($start = 100, $end = 500); put +$_, " matching numbers from $start to $end:\n", $_ given

 ($start .. $end).hyper(:256batch,:8degree).grep: { all .comb.rotor(2 => -1).map: { .sum.is-prime } };</lang>
Output:
65 matching numbers from 100 to 500:
111 112 114 116 120 121 123 125 129 141 143 147 149 161 165 167 202 203 205 207 211 212 214 216 230 232 234 238 250 252 256 258 292 294 298 302 303 305 307 320 321 323 325 329 341 343 347 349 383 385 389 411 412 414 416 430 432 434 438 470 474 476 492 494 498

REXX

<lang rexx>/*REXX pgm lists strange+ integers (within a range); sum of adjacent dec. digs is prime.*/ parse arg LO HI . /*obtain optional arguments from the CL*/ if LO== | LO=="," then LO= 101 /*Not specified? Then use the default.*/ if HI== | HI=="," then HI= 499 /* " " " " " " */ !.= 0;  !.2= 1;  !.3= 1;  !.5= 1;  !.7= 1 /*build array of sums that are prime. */

         !.11= 1;   !.13= 1;  !.17= 1           /*  "     "    "   "    "   "    "     */

$= /*the list of strange+ numbers (so far)*/

  1. = 0 /* " number " " " " " */
    do j=LO  to  HI;       L= length(j)         /*look for strange+ numbers in range.  */
    if L==1  then iterate                       /*Number too short?   Then skip it.    */
             do k=1  for L-1                    /*examine the difference in the digits.*/
             parse var  j   =(k)  y  +1  z  +1  /*get two adjacent decimal digits: Y Z */
             sum= y + z                         /*sum of two adjacent decimal digits.  */
             if \!.sum  then iterate j          /*Sum not prime?  Then skip this number*/
             end   /*k*/
    #= # + 1                                    /*bump the number of "strange+" numbers*/
    $= $ j                                      /*append the number to the  $  list.   */
    end   /*j*/
                                                /*stick a fork in it,  we're all done. */

say # ' strange plus numbers found between ' LO " and " HI ' (inclusive)' say say strip($)</lang>

output   when using the default inputs:
65  strange plus numbers found between  101  and  499  (inclusive)

111 112 114 116 120 121 123 125 129 141 143 147 149 161 165 167 202 203 205 207 211 212 214 216
230 232 234 238 250 252 256 258 292 294 298 302 303 305 307 320 321 323 325 329 341 343 347 349
383 385 389 411 412 414 416 430 432 434 438 470 474 476 492 494 498

Ring

<lang ring> load "stdlib.ring"

row = 0 see "Strange plus numbers are:"

for n = 100 to 500

   flag = 1
   str = string(n)
   for m = 1 to len(str)-1
       num1 = number(str[m])
       num2 = number(str[m+1])
       pr = num1+num2
       if not isprime(pr)
          flag = 0
          exit
       ok
    next
    if flag = 1
       row = row + 1
       if (row-1) % 11 = 0
          see nl
       else
          see " " + str
       ok
    ok

next </lang>

Output:
Strange plus numbers are:
 112 114 116 120 121 123 125 129 141 143
 149 161 165 167 202 203 205 207 211 212
 216 230 232 234 238 250 252 256 258 292
 298 302 303 305 307 320 321 323 325 329
 343 347 349 383 385 389 411 412 414 416
 432 434 438 470 474 476 492 494 498

Wren

Simple brute force is adequate for this. <lang ecmascript>var primes = [2, 3, 5, 7, 11, 13, 17] var count = 0 var d = [] System.print("Strange plus numbers in the open interval (100, 500) are:\n") for (i in 101..499) {

   d.clear()
   var j = i
   while (j > 0) {
      d.add(j % 10)
      j = (j/10).floor
   }
   if (primes.contains(d[0] + d[1]) && primes.contains(d[1] + d[2])) {
       System.write("%(i) ")
       count = count + 1
       if (count % 10 == 0) System.print()
   }

} if (count % 10 != 0) System.print() System.print("\n%(count) strange plus numbers in all.")</lang>

Output:
Strange plus numbers in the open interval (100, 500) are:

111 112 114 116 120 121 123 125 129 141 
143 147 149 161 165 167 202 203 205 207 
211 212 214 216 230 232 234 238 250 252 
256 258 292 294 298 302 303 305 307 320 
321 323 325 329 341 343 347 349 383 385 
389 411 412 414 416 430 432 434 438 470 
474 476 492 494 498 

65 strange plus numbers in all.

x86 Assembly

A 16-bit solution for NASM under DOS. Assemble with nasm -fbin strange.asm -o strange.com. The prime sieve up to 18 is hard-coded.

<lang> org 100h

       xor     cx, cx
       mov     si, 101

L1 mov di, si

       xor     bh, bh

L2 mov ax, di

       div     byte [i100]
       
       mov     al, ah
       xor     ah, ah
       div     byte [i10]
       
       mov     bl, al
       add     bl, ah
       cmp     byte [bx+p], 0
       je      L6
       
       mov     ax, di
       div     byte [i10]
       xor     ah, ah
       mov     di, ax
       cmp     al, 10
       jae     L2
       mov     ax, si
       mov     di, dig

L3 div byte [i10]

       add     ah, 48
       mov     [di], ah
       xor     ah, ah
       inc     di
       test    ax, ax
       jnz     L3

L4 mov ah, 2

       mov     dl, [di-1]
       int     21h
       dec     di
       cmp     di, dig
       jne     L4
       
       mov     ah, 2
       mov     dl, 32
       inc     cx
       cmp     cl, 10
       jne     L5
       xor     cl, cl
       mov     dl, 10

L5 int 21h

L6 inc si

       cmp     si, 500
       jb      L1
       int     20h

i10 db 10 i100 db 100 p db 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0 dig:</lang>

Output:
111 112 114 116 120 121 123 125 129 141
143 147 149 161 165 167 202 203 205 207
211 212 214 216 230 232 234 238 250 252
256 258 292 294 298 302 303 305 307 320
321 323 325 329 341 343 347 349 383 385
389 411 412 414 416 430 432 434 438 470
474 476 492 494 498