Rare numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Go}}: Added a second version based on Nigel Galloway;s approach.)
(→‎Version 2: Removed a redundant declaration.)
Line 365: Line 365:
}
}


const maxDigits = 15
var (
maxDigits = 15
maxSquares = int64(math.Ceil(math.Sqrt(2 * math.Pow10(maxDigits))))
)


func toInt64(digits []int8, reverse bool) int64 {
func toInt64(digits []int8, reverse bool) int64 {

Revision as of 23:55, 24 September 2019

Rare 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.
Definitions and restrictions

Rare   numbers are positive integers   n   where:

  •   n   is expressed in base ten
  •   r   is the reverse of   n     (decimal digits)
  •   n   must be non-palindromic   (nr)
  •   (n+r)   is the   sum
  •   (n-r)   is the   difference   and must be positive
  •   the   sum   and the   difference   must be perfect squares


Task
  •   find and show the first   5   rare   numbers
  •   find and show the first   8   rare   numbers       (optional)
  •   find and show more   rare   numbers                (stretch goal)


Show all output here, on this page.


References



F#

The Function

This solution demonstrates the concept described in Talk:Rare_numbers#30_mins_not_30_years. It uses Cartesian_product_of_two_or_more_lists#Extra_Credit <lang fsharp> // Find all Rare numbers with a digits. Nigel Galloway: September 18th., 2019. let rN a=let izPS=let n=int64(ceil(sqrt(float(2L*(pown 10L a))))) in let rec fN n g=if n*n>g then fN ((n+(g/n))/2L) g else n

                 (fun g->let n=fN n g in n*n=g)
        let n=cP [yield [0L..9L]; for n in [a-3..(-2)..1] do yield [-9L..9L]]
        let i=[yield (pown 10L (a-1))-1L; for n in [a-2..(-1)..a/2] do yield ((pown 10L n)-(pown 10L (a-n-1)))] //[99L; 0L]
        let g=Seq.mapi(fun i n->[for g in max 0L (0L-n)..min 9L (9L-n) do yield (g*(pown 10L (a-i-1))+(n+g)*(pown 10L i),(n+g)*(pown 10L (a-i-1))+g*(pown 10L i))])
        let e n=if a%2=0 then g n else Seq.append (g n) [[for n in [0L..9L] do yield (n*(pown 10L (a/2)),n*(pown 10L (a/2)))]]
        let l=n|>Seq.filter(fun n->let g=Seq.map2(*)n i|>Seq.sum in g>0L && izPS(g))|>Seq.map(e>>cP)|>Seq.concat
        l|>Seq.map(fun n->Seq.fold(fun(n,g) (n',g')->(n+n',g+g'))(0L,0L) n)|>Seq.filter(fun(n,g)->g>(pown 10L (a-1)) && izPS(n+g))

</lang>

The Task

<lang fsharp> [2..12]|>Seq.collect rN |> Seq.iter(printfn "%A") </lang>

Output:
(56L, 65L)
(77126L, 621770L)
(280980182L, 281089082L)
(2022562202L, 2022652202L)
(2002382402L, 2042832002L)
(871479645278L, 872546974178L)
(871457865278L, 872568754178L)
(757480195868L, 868591084757L)
Real: 00:00:58.835, CPU: 00:01:00.421, GC gen0: 3220, gen1: 441, gen2: 16

Stretch Goal

<lang fsharp> let t = System.Diagnostics.Stopwatch.StartNew() rN 13 |> Seq.iter (printfn "%A") t.Stop() printfn "Elapsed Time: %A" t.ElapsedMilliseconds </lang>

Output:

fsi --exec rc.fsx produces:

(5881592039796L, 6979302951885L)
Elapsed Time: 32233L

Go

Version 1

This takes into account all the hints within Shyam Sunder Gupta's webpage. It also makes use of his observation that no rare number below 10^20 ends in 3 and uses a bit arithmetic trick to further filter out numbers that cannot be perfect squares and thereby avoid the expensive math.Sqrt operation.

Despite all this, it's still quite slow, polishing off the first five rare numbers in about 0.75 seconds but taking more than 12.5 minutes to find the next three. However, memory usage is minimal.

Timings are for an Intel Core i7-8565U machine. <lang go>package main

import (

   "fmt"
   "math"
   "time"

)

const (

   maxCount  = 8
   maxDigits = 12
   qi        = maxDigits - 1 // index of last digit

)

func toUint64(digits []int, ai int, reverse bool) uint64 {

   sum := uint64(0)
   if !reverse {
       for i := ai; i < maxDigits; i++ {
           sum = sum*10 + uint64(digits[i])
       }
   } else {
       for i := qi; i >= ai; i-- {
           sum = sum*10 + uint64(digits[i])
       }
   }
   return sum

}

func sumDigits(n uint64) uint64 {

   var sum uint64
   for n > 0 {
       d := n % 10
       sum += d
       n /= 10
   }
   return sum

}

func sumDigitSlice(digits []int, ai int) uint64 {

   sum := 0
   for i := ai; i < maxDigits; i++ {
       sum += digits[i]
   }
   return uint64(sum)

}

func digRoot(n uint64) int {

   for n > 9 {
       n = sumDigits(n)
   }
   return int(n)

}

// 'inc' assumed to be <= 10 func add(digits []int, ai, inc int) int {

   for i := qi; i >= ai-1; i-- {
       q := digits[i]
       q += inc
       if q < 10 {
           digits[i] = q
           if i < ai {
               return i
           } else {
               return ai
           }
       } else {
           digits[i] = q - 10
           inc = 1
       }
   }
   return ai

}

func possibleSquare(n uint64) bool {

   if 0x202021202030213&(1<<(n&63)) != 0 {
       return true
   }
   return false

}

func commatize(n uint64) string {

   s := fmt.Sprintf("%d", n)
   le := len(s)
   for i := le - 3; i >= 1; i -= 3 {
       s = s[0:i] + "," + s[i:]
   }
   return s

}

func main() {

   start := time.Now()
   digits := make([]int, maxDigits)
   ai := maxDigits - 2 // index of first non-zero digit in slice
   a := 2              // first non-zero digit
   digits[ai] = 2      // start from 20 say
   count := 0
   fmt.Printf("The first %d rare numbers are:\n", maxCount)

outer:

   for {
       switch a {
       case 2, 4:
           ai = add(digits, ai, 10)
       case 6:
           ai = add(digits, ai, 5)
       case 8:
           switch digits[qi] {
           case 2:
               ai = add(digits, ai, 5)
           case 7:
               ai = add(digits, ai, 1)
           case 8:
               ai = add(digits, ai, 4)
           }
       }
       a = digits[ai]
       if a%2 == 1 {
           for i := qi - 1; i > ai; i-- {
               digits[i] = 0
           }
           switch a {
           case 3:
               digits[ai], digits[qi] = 4, 0
           case 5:
               digits[ai], digits[qi] = 6, 0
           case 7:
               digits[ai], digits[qi] = 8, 2
           case 9:
               digits[ai], digits[qi] = 0, 2
               ai--
               digits[ai] = 2
           }
           a = digits[ai]
       }
       if qi-ai > 2 {
           b, p := digits[ai+1], digits[qi-1]
           switch a {
           case 2:
               if b < p {
                   continue
               } else if b > p {
                   digits[qi-1] = b
               }
           case 4:
               if (b-p)%2 != 0 {
                   if p < 9 {
                       digits[qi-1]++
                   } else {
                       continue
                   }
               }
           case 6:
               if (b-p)%2 == 0 {
                   if p < 9 {
                       digits[qi-1]++
                   } else {
                       continue
                   }
               }
           case 8:
               switch digits[qi] {
               case 2:
                   if b+p != 9 {
                       if p < 9-b {
                           digits[qi-1] = 9 - b
                       } else {
                           continue
                       }
                   }
               case 7:
                   if b > 1 && (b+p) != 11 {
                       if p < 11-b {
                           digits[qi-1] = 11 - b
                       } else {
                           continue
                       }
                   } else if b < 1 && (b+p) != 1 {
                       if p == 0 {
                           digits[qi-1] = 1
                       } else {
                           continue
                       }
                   }
               case 8:
                   if b < p {
                       continue
                   } else if b > p {
                       if (b-p)%2 == 0 {
                           digits[qi-1] = b
                       } else {
                           continue
                       }
                   }
               }
           }
       }
       s := sumDigitSlice(digits, ai)
       dr := digRoot(s)
       if dr != 2 && dr != 5 && dr != 8 && dr != 9 {
           continue
       }
       n := toUint64(digits, ai, false)
       r := toUint64(digits, ai, true)
       if n <= r || !possibleSquare(n+r) || !possibleSquare(n-r) {
           continue
       }
       for _, x := range [2]uint64{n + r, n - r} {
           z := x % 10
           if z == 2 || z == 3 || z == 7 || z == 8 {
               continue outer
           }
           y := (x / 10) % 10
           switch z {
           case 0:
               if y != 0 {
                   continue outer
               }
           case 5:
               if y != 2 {
                   continue outer
               }
           case 6:
               if y%2 == 0 {
                   continue outer
               }
           case 1, 4, 9:
               if y%2 == 1 {
                   continue outer
               }
           }
           dr = digRoot(x)
           if dr != 1 && dr != 4 && dr != 7 && dr != 9 {
               continue outer
           }
       }
       fn, fr := float64(n), float64(r)
       sr := uint64(math.Sqrt(fn + fr))
       if sr*sr != n+r {
           continue
       }
       sr = uint64(math.Sqrt(fn - fr))
       if sr*sr != n-r {
           continue
       }
       count++
       fmt.Printf("  %d:  %15s\n", count, commatize(n))
       if count == maxCount {
           break
       }
   }
   fmt.Printf("\nTook %s\n", time.Since(start))

}</lang>

Output:
The first 8 rare numbers are:
  1:               65
  2:          621,770
  3:      281,089,082
  4:    2,022,652,202
  5:    2,042,832,002
  6:  868,591,084,757
  7:  872,546,974,178
  8:  872,568,754,178

Took 12m43.807949011s

Version 2

This is based on Nigel Galloway's approach (see Talk page) of working from (n-r) and deducing the Rare numbers with various numbers of digits from there.

It is more than 500 times faster than Version 1, taking 1.3, 2.3, 28.5 and 42.1 seconds to process all 12, 13, 14 and 15 digit numbers respectively. However, it uses a lot of memory for the Cartesian products. <lang go>package main

import (

   "fmt"
   "math"
   "sort"
   "time"

)

type term struct {

   coeff    int64
   ix1, ix2 int8

}

const maxDigits = 15

func toInt64(digits []int8, reverse bool) int64 {

   sum := int64(0)
   if !reverse {
       for i := 0; i < len(digits); i++ {
           sum = sum*10 + int64(digits[i])
       }
   } else {
       for i := len(digits) - 1; i >= 0; i-- {
           sum = sum*10 + int64(digits[i])
       }
   }
   return sum

}

func isSquare(n int64) bool {

   root := int64(math.Sqrt(float64(n)))
   return root*root == n

}

// From the Cartesian product of two or more lists task - Extra credit 1. func cp(a ...[]int8) [][]int8 {

   c := 1
   for _, a := range a {
       c *= len(a)
   }
   if c == 0 {
       return nil
   }
   p := make([][]int8, c)
   b := make([]int8, c*len(a))
   n := make([]int8, len(a))
   s := 0
   for i := range p {
       e := s + len(a)
       pi := b[s:e]
       p[i] = pi
       s = e
       for j, n := range n {
           pi[j] = a[j][n]
       }
       for j := len(n) - 1; j >= 0; j-- {
           n[j]++
           if n[j] < int8(len(a[j])) {
               break
           }
           n[j] = 0
       }
   }
   return p

}

func seq(from, to int8) []int8 {

   var res []int8
   for i := from; i <= to; i++ {
       res = append(res, i)
   }
   return res

}

func commatize(n int64) string {

   s := fmt.Sprintf("%d", n)
   le := len(s)
   for i := le - 3; i >= 1; i -= 3 {
       s = s[0:i] + "," + s[i:]
   }
   return s

}

func main() {

   start := time.Now()
   pow := int64(1)
   // terms of (n-r) expression for number of digits from 2 to maxDigits
   allTerms := make([][]term, maxDigits-1)
   for r := 2; r <= maxDigits; r++ {
       var terms []term
       pow *= 10
       pow1, pow2 := pow, int64(1)
       for i1, i2 := int8(0), int8(r-1); i1 < i2; i1, i2 = i1+1, i2-1 {
           terms = append(terms, term{pow1 - pow2, i1, i2})
           pow1 /= 10
           pow2 *= 10
       }
       allTerms[r-2] = terms
   }
   //  map of first minus last digits for 'n' to pairs giving this value
   fml := map[int8][][]int8{
       0: {{2, 2}, {8, 8}},
       1: {{6, 5}, {8, 7}},
       4: Template:4, 0,
       5: Template:8, 3,
       6: {{6, 0}, {8, 2}},
   }
   // map of other digit differences for 'n' to pairs giving this value
   dmd := make(map[int8][][]int8)
   for i := int8(0); i < 100; i++ {
       a := []int8{i / 10, i % 10}
       d := a[0] - a[1]
       dmd[d] = append(dmd[d], a)
   }
   fl := []int8{0, 1, 4, 5, 6}
   dl := seq(-9, 9)
   il := seq(0, 9)
   var rares []int64
   lists := [][]int8{fl}
   fmt.Printf("The rare numbers with up to %d digits are:\n", maxDigits)
   for nd := 2; nd <= maxDigits; nd++ {
       digits := make([]int8, nd)
       if len(allTerms[nd-2]) > len(lists) {
           lists = append(lists, dl)
       }
       var indices [][2]int8
       for _, t := range allTerms[nd-2] {
           indices = append(indices, [2]int8{t.ix1, t.ix2})
       }
       cands := cp(lists...)
       for _, cand := range cands {
           nmr := int64(0)
           for i, t := range allTerms[nd-2] {
               nmr += t.coeff * int64(cand[i])
           }
           if nmr <= 0 || !isSquare(nmr) {
               continue
           }
           var dis [][]int8
           dis = append(dis, seq(0, int8(len(fml[cand[0]]))-1))
           for i := 1; i < len(cand); i++ {
               dis = append(dis, seq(0, int8(len(dmd[cand[i]]))-1))
           }
           if nd%2 == 1 {
               dis = append(dis, il)
           }
           dis = cp(dis...)
           for _, di := range dis {
               digits[indices[0][0]] = fml[cand[0]][di[0]][0]
               digits[indices[0][1]] = fml[cand[0]][di[0]][1]
               le := len(di)
               if nd%2 == 1 {
                   le--
                   digits[nd/2] = di[le]
               }
               for i, d := range di[1:le] {
                   digits[indices[i+1][0]] = dmd[cand[i+1]][d][0]
                   digits[indices[i+1][1]] = dmd[cand[i+1]][d][1]
               }
               r := toInt64(digits, true)
               npr := nmr + 2*r
               if !isSquare(npr) {
                   continue
               }
               rares = append(rares, toInt64(digits, false))
           }
       }
   }
   sort.Slice(rares, func(i, j int) bool { return rares[i] < rares[j] })
   for i, rare := range rares {
       fmt.Printf("  %2d:  %19s\n", i+1, commatize(rare))
   }
   fmt.Printf("\nUp to %d digits processed in %s\n", maxDigits, time.Since(start))

}</lang>

Output:
The rare numbers with up to 15 digits are:
   1:                   65
   2:              621,770
   3:          281,089,082
   4:        2,022,652,202
   5:        2,042,832,002
   6:      868,591,084,757
   7:      872,546,974,178
   8:      872,568,754,178
   9:    6,979,302,951,885
  10:   20,313,693,904,202
  11:   20,313,839,704,202
  12:   20,331,657,922,202
  13:   20,331,875,722,202
  14:   20,333,875,702,202
  15:   40,313,893,704,200
  16:   40,351,893,720,200
  17:  200,142,385,731,002
  18:  204,238,494,066,002
  19:  221,462,345,754,122
  20:  244,062,891,224,042
  21:  245,518,996,076,442
  22:  248,359,494,187,442
  23:  403,058,392,434,500
  24:  441,054,594,034,340
  25:  816,984,566,129,618

Up to 15 digits processed in 42.075636626s

Julia

Pretty slow to get 8 rare numbers, even if the squares are checked via table. <lang julia>fixeddigits = Dict(2 => [[0, 0, 2], [8, 8, 2]], 4 => 0, 0, 0,

   6 => [[2, 7, 0], [9, 8, 5]], 8 => [[6, 5, 7],[7, 7, 8]])

squares = Dict([i * i => 1 for i in 1:1500000])

i2dig(i) = (d = Int[]; while i > 0 i, r = divrem(i, 10); push!(d, r) end; d) dig2i(d) = (n = 0; for i in d n = 10 * n + i end; n)

function simplegetrare(upto)

   ret = Int[]
   for n in 0:upto
       dig = i2dig(n)
       r = dig2i(dig)
       nrsum, nrdiff = n + r, n - r
       if nrdiff > 0 && haskey(squares, nrsum) && haskey(squares, nrdiff)
           push!(ret, n)
       end
   end
   ret

end

function getrare(N)

   ret = simplegetrare(20000)
   for i in 0:typemax(Int)
       basedigits = i2dig(i)
       for a in [2,4,6,8], (b, p, q) in fixeddigits[a]
           dig = [[q, p]; basedigits; [b, a]]
           r = dig2i(dig)
           n = dig2i(reverse(dig))
           nrsum, nrdiff = n + r, n - r
           if nrdiff > 0 && haskey(squares, nrsum) && haskey(squares, nrdiff)
               push!(ret, n)
               if length(ret) >= N
                   return ret
               end
           end
       end
   end

end

getrare(3) @time println("The first 8 rare numbers are: ", sort(getrare(8)))

</lang>

Output:
The first 8 rare numbers are: [65, 621770, 281089082, 2022652202, 2042832002, 868591084757, 872546974178, 872568754178]
1379.707737 seconds (9.36 G allocations: 545.177 GiB, 2.25% gc time)

REXX

(See the discussion page for a simplistic 1st version that computes   rare   numbers only using the task's basic rules).

Most of the hints (properties of rare numbers) within Shyam Sunder Gupta's   webpage   have been incorporated in this
REXX program and the logic is now expressed within the list of   AB...PQ   (abutted numbers within the   @g   list).

These improvements made this REXX version around   25%   faster than the previous version   (see the discussion page). <lang rexx>/*REXX program calculates and displays a specified amount of rare numbers. */ numeric digits 20; w= digits() + digits() % 3 /*use enough dec. digs for calculations*/ parse arg many . /*obtain optional argument from the CL.*/ if many== | many=="," then many= 5 /*Not specified? Then use the default.*/ @g= 2002 2112 2222 2332 2442 2552 2662 2772 2882 2992 4000 4010 4030 4050 4070 4090 4100 ,

   4110 4120 4140 4160 4180 4210 4230 4250 4270 4290 4300 4320 4340 4360 4380 4410 4430 ,
   4440 4450 4470 4490 4500 4520 4540 4560 4580 4610 4630 4650 4670 4690 4700 4720 4740 ,
   4760 4780 4810 4830 4850 4870 4890 4900 4920 4940 4960 4980 4990 6010 6015 6030 6035 ,
   6050 6055 6070 6075 6090 6095 6100 6105 6120 6125 6140 6145 6160 6165 6180 6185 6210 ,
   6215 6230 6235 6250 6255 6270 6275 6290 6295 6300 6305 6320 6325 6340 6345 6360 6365 ,
   6380 6385 6410 6415 6430 6435 6450 6455 6470 6475 6490 6495 6500 6505 6520 6525 6540 ,
   6545 6560 6565 6580 6585 6610 6615 6630 6635 6650 6655 6670 6675 6690 6695 6700 6705 ,
   6720 6725 6740 6745 6760 6765 6780 6785 6810 6815 6830 6835 6850 6855 6870 6875 6890 ,
   6895 6900 6905 6920 6925 6940 6945 6960 6965 6980 6985 8007 8008 8017 8027 8037 8047 ,
   8057 8067 8077 8087 8092 8097 8107 8117 8118 8127 8137 8147 8157 8167 8177 8182 8187 ,
   8197 8228 8272 8297 8338 8362 8387 8448 8452 8477 8542 8558 8567 8632 8657 8668 8722 ,
   8747 8778 8812 8837 8888 8902 8927 8998      /*4 digit abutted numbers for AB and PQ*/

@g#= words(@g)

        /* [↓]─────────────────boolean arrays are used for checking for digit presence.*/

@dr.=0; @dr.2= 1; @dr.5=1 ; @dr.8= 1; @dr.9= 1 /*rare # must have these digital roots.*/ @ps.=0; @ps.2= 1; @ps.3= 1; @ps.7= 1; @ps.8= 1 /*perfect squares must end in these.*/ @149.=0; @149.1=1; @149.4=1; @149.9=1 /*values for Z that need an even Y. */ @odd.=0; do i=-9 by 2 to 9; @odd.i=1 /* " " N " " " " A. */

         end   /*i*/

@gen.=0; do i=1 for words(@g); parse value word(@g,i) with a 2 b 3 p 4 q; @gen.a.b.p.q=1

              /*# AB···PQ  could be a good rare value*/
         end   /*i*/

div9= 9 /*dif must be ÷ 9 when N has even #digs*/ evenN= \ (10 // 2) /*initial value for evenness of N. */

  1. = 0 /*the number of rare numbers (so far)*/
   do n=10                                      /*Why 10?  All 1 dig #s are palindromic*/
   parse var   n   a  2  b  3    -2  p  +1  q /*get 1st\2nd\penultimate\last digits. */
   if @odd.a  then do;  n=n+10**(length(n)-1)-1 /*bump N so next N starts with even dig*/
                        evenN=\(length(n+1)//2) /*flag when N has an even # of digits. */
                        if evenN  then div9=  9 /*when dif isn't divisible by   9  ... */
                                  else div9= 99 /*  "   "    "        "     "  99   "  */
                        iterate                 /*let REXX do its thing with  DO  loop.*/
                   end                          /* {it's allowed to modify a DO index} */
   if \@gen.a.b.p.q  then iterate               /*can  N  not be a rare AB···PQ number?*/
   r= reverse(n)                                /*obtain the reverse of the number  N. */
   if r>n   then iterate                        /*Difference will be negative?  Skip it*/
   if n==r  then iterate                        /*Palindromic?   Then it can't be rare.*/
   dif= n-r;   parse var  dif    -2  y  +1  z /*obtain the last 2 digs of difference.*/
   if @ps.z  then iterate                       /*Not 0, 1, 4, 5, 6, 9? Not perfect sq.*/
      select
      when z==0   then if y\==0    then iterate /*Does Z = 0?   Then  Y  must be zero. */
      when z==5   then if y\==2    then iterate /*Does Z = 5?   Then  Y  must be two.  */
      when z==6   then if y//2==0  then iterate /*Does Z = 6?   Then  Y  must be odd.  */
      otherwise        if @149.z   then if y//2  then iterate /*Z=1,4,9? Y must be even*/
      end   /*select*/                          /* [↑]  the OTHERWISE handles Z=8 case.*/
   if dif//div9\==0  then iterate               /*Difference isn't ÷ by div9? Then skip*/
   sum= n+r;   parse var  sum    -2  y  +1  z /*obtain the last two digits of the sum*/
   if @ps.z  then iterate                       /*Not 0, 2, 5, 8, or 9? Not perfect sq.*/
      select
      when z==0   then if y\==0    then iterate /*Does Z = 0?   Then  Y  must be zero. */
      when z==5   then if y\==2    then iterate /*Does Z = 5?   Then  Y  must be two.  */
      when z==6   then if y//2==0  then iterate /*Does Z = 6?   Then  Y  must be odd.  */
      otherwise        if @149.z   then if y//2  then iterate /*Z=1,4,9? Y must be even*/
      end   /*select*/                          /* [↑]  the OTHERWISE handles Z=8 case.*/
   if evenN  then if sum//11 \==0  then iterate /*N has even #digs? Sum must be ÷ by 11*/
   $= a + b                                     /*a head start on figuring digital root*/
                      do k=3  for length(n) - 2 /*now, process the rest of the digits. */
                      $= $ + substr(n, k, 1)    /*add the remainder of the digits in N.*/
                      end   /*k*/
      do while $>9                              /* [◄]  Algorithm is good for 111 digs.*/
      if $>9  then $= left($,1) + substr($,2,1) + substr($,3,1,0)     /*>9?  Reduce it.*/
      end   /*while*/
   if \@dr.$                 then iterate       /*Doesn't have good digital root?  Skip*/
   if iSqrt(sum)**2 \== sum  then iterate       /*Not a perfect square?  Then skip it. */
   if iSqrt(dif)**2 \== dif  then iterate       /* "  "    "       "       "    "   "  */
   #= # + 1;                 call tell          /*bump rare number counter;  display #.*/
   if #>=many  then leave                       /* [↑]  W:  the width of # with commas.*/
   end   /*n*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: parse arg _; do jc=length(_)-3 to 1 by -3; _=insert(',', _, jc); end; return _ tell: say right(th(#),length(#)+9) ' rare number is:' right(commas(n),w); return th: parse arg th;return th||word('th st nd rd',1+(th//10)*(th//100%10\==1)*(th//10<4)) /*──────────────────────────────────────────────────────────────────────────────────────*/ iSqrt: parse arg x; $= 0; q= 1; do while q<=x; q=q*4; end

         do while q>1; q=q%4; _= x-$-q;  $= $%2;  if _>=0  then do;      x=_;  $=$+q; end
         end   /*while q>1*/;                     return $</lang>
output   when using the input of:     8
       1st  rare number is:                           65
       2nd  rare number is:                      621,770
       3rd  rare number is:                  281,089,082
       4th  rare number is:                2,022,652,202
       5th  rare number is:                2,042,832,002
       6th  rare number is:              868,591,084,757
       7th  rare number is:              872,546,974,178
       8th  rare number is:              872,568,754,178