Juggler sequence: Difference between revisions

From Rosetta Code
Content added Content deleted
(julia example)
m (30917 -> 30817)
Line 247: Line 247:
foreach(k -> juggler(k, false), 20:39)
foreach(k -> juggler(k, false), 20:39)
foreach(juggler,
foreach(juggler,
[113, 173, 193, 2183, 11229, 15065, 15845, 30917, 48443, 275485, 1267909,
[113, 173, 193, 2183, 11229, 15065, 15845, 30817, 48443, 275485, 1267909,
2264915, 5812827])
2264915, 5812827])
@time juggler(7110201)
@time juggler(7110201)
Line 281: Line 281:
15065 66 25 11,723 digits
15065 66 25 11,723 digits
15845 139 43 23,889 digits
15845 139 43 23,889 digits
30917 33 12 22 digits
30817 93 39 45,391 digits
48443 157 60 972,463 digits
48443 157 60 972,463 digits
275485 225 148 1,909,410 digits
275485 225 148 1,909,410 digits

Revision as of 05:45, 19 August 2021

Juggler sequence 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.
Description

A juggler sequence is an integer sequence that starts with a positive integer a[0], with each subsequent term in the sequence being defined by the recurrence relation:

a[k + 1] = floor(a[k] ^ 0.5) if k is even or a[k + 1] = floor(a[k] ^ 1.5) if k is odd.

If a juggler sequence reaches 1, then all subsequent terms are equal to 1. This is known to be the case for initial terms up to 1,000,000 but it is not known whether all juggler sequences after that will eventually reach 1.

Task

Compute and show here the following statistics for juggler sequences with an initial term of a[n] where n is between 20 and 39 inclusive:

  • l[n] - the number of terms needed to reach 1.
  • h[n] - the maximum value reached in that sequence.
  • i[n] - the index of the term (starting from 0) at which the maximum is (first) reached.


If your language supports big integers with an integer square root function, also compute and show here the same statistics for as many as you reasonably can of the following values for n:

113, 173, 193, 2183, 11229, 15065, 15845, 30817, 48443, 275485, 1267909, 2264915, 5812827

Those with fast languages and fast machines may also like to try their luck at n = 7110201.

However, as h[n] for most of these numbers is thousands or millions of digits long, show instead of h[n]:

  • d[n] - the number of digits in h[n]


The results can be (partially) verified against the table here.

Related task


See also
  • oeis:A007320 Number of steps needed for Juggler sequence started at n to reach 1
  • oeis:A094716 Largest value in the Juggler sequence started at n



Factor

Works with: Factor version 0.99 2021-06-02

<lang factor>USING: combinators formatting generalizations io kernel math math.extras math.functions.integer-logs math.order math.ranges sequences strings tools.memory.private ;

next ( m -- n )
   dup odd? [ dup dup * * ] when integer-sqrt ;
new-max ( l i h a -- l i h a )
   [ drop dup ] 2dip nip dup ;
(step) ( l i h a -- l i h a )
   [ 1 + ] 3dip 2dup < [ new-max ] when next ;
step ( l i h a -- l i h a )
   dup 1 = [ (step) ] unless ;
juggler ( n quot: ( h -- obj ) -- l i h )
   [ 0 0 ] [ dup [ step ] to-fixed-point drop ] [ call ] tri*
   [ 1 [-] ] dip ; inline

CONSTANT: fmt "%-8s %-8s %-8s %s\n"

row. ( n quot -- )
   dupd juggler [ commas ] 4 napply fmt printf ; inline
dashes. ( n -- )
   CHAR: - <string> print ;
header. ( str -- )
   [ "n" "l[n]" "i[n]" ] dip fmt printf 45 dashes. ;
juggler. ( seq quot str -- )
   header. [ row. ] curry each ; inline

20 39 [a,b] [ ] "h[n]" juggler. nl

{ 113 173 193 2183 11229 15065 15845 30817 } [ integer-log10 1 + ] "d[n]" juggler.</lang>

Output:
n        l[n]     i[n]     h[n]
---------------------------------------------
20       3        0        20
21       9        4        140
22       3        0        22
23       9        1        110
24       3        0        24
25       11       3        52,214
26       6        3        36
27       6        1        140
28       6        3        36
29       9        1        156
30       6        3        36
31       6        1        172
32       6        3        36
33       8        2        2,598
34       6        3        36
35       8        2        2,978
36       3        0        36
37       17       8        24,906,114,455,136
38       3        0        38
39       14       3        233,046

n        l[n]     i[n]     d[n]
---------------------------------------------
113      16       9        27
173      32       17       82
193      73       47       271
2,183    72       32       5,929
11,229   101      54       8,201
15,065   66       25       11,723
15,845   139      43       23,889
30,817   93       39       45,391

Go

Translation of: Wren
Library: Go-rcu

This originally took about 13.5 minutes to reach n = 5,812,827 on my machine (Intel core i7-8565U) using Go's native 'math/big' package.

However, when I exchanged that for Go's GMP wrapper there was a massive speed-up (now only 6.4 seconds to reach n = 5,812,827) and even 7,110,201 became viable with an overall time of 1 minute 40 seconds. <lang go>package main

import (

   "fmt"
   "log"
   // "math/big"
   big "github.com/ncw/gmp"
   "rcu"

)

var zero = new(big.Int) var one = big.NewInt(1) var two = big.NewInt(2)

func juggler(n int64) (int, int, *big.Int, int) {

   if n < 1 {
       log.Fatal("Starting value must be a positive integer.")
   }
   count := 0
   maxCount := 0
   a := big.NewInt(n)
   max := big.NewInt(n)
   tmp := new(big.Int)
   for a.Cmp(one) != 0 {
       if tmp.Rem(a, two).Cmp(zero) == 0 {
           a.Sqrt(a)
       } else {
           tmp.Mul(a, a)
           tmp.Mul(tmp, a)
           a.Sqrt(tmp)
       }
       count++
       if a.Cmp(max) > 0 {
           max.Set(a)
           maxCount = count
       }
   }
   return count, maxCount, max, len(max.String())

}

func main() {

   fmt.Println("n    l[n]  i[n]  h[n]")
   fmt.Println("-----------------------------------")
   for n := int64(20); n < 40; n++ {
       count, maxCount, max, _ := juggler(n)
       cmax := rcu.Commatize(int(max.Int64()))
       fmt.Printf("%2d    %2d   %2d    %s\n", n, count, maxCount, cmax)
   }
   fmt.Println()
   nums := []int64{
       113, 173, 193, 2183, 11229, 15065, 15845, 30817,
       48443, 275485, 1267909, 2264915, 5812827, 7110201
   }
   fmt.Println("     n      l[n]   i[n]   d[n]")
   fmt.Println("-----------------------------------")
   for _, n := range nums {
       count, maxCount, _, digits := juggler(n)
       cn := rcu.Commatize(int(n))
       fmt.Printf("%9s   %3d    %3d    %s\n", cn, count, maxCount, rcu.Commatize(digits))
   }

}</lang>

Output:
n    l[n]  i[n]  h[n]
-----------------------------------
20     3    0    20
21     9    4    140
22     3    0    22
23     9    1    110
24     3    0    24
25    11    3    52,214
26     6    3    36
27     6    1    140
28     6    3    36
29     9    1    156
30     6    3    36
31     6    1    172
32     6    3    36
33     8    2    2,598
34     6    3    36
35     8    2    2,978
36     3    0    36
37    17    8    24,906,114,455,136
38     3    0    38
39    14    3    233,046

     n      l[n]   i[n]   d[n]
-----------------------------------
      113    16      9    27
      173    32     17    82
      193    73     47    271
    2,183    72     32    5,929
   11,229   101     54    8,201
   15,065    66     25    11,723
   15,845   139     43    23,889
   30,817    93     39    45,391
   48,443   157     60    972,463
  275,485   225    148    1,909,410
1,267,909   151     99    1,952,329
2,264,915   149     89    2,855,584
5,812,827   135     67    7,996,276
7,110,201   205    119    89,981,517

Julia

<lang julia>using Formatting

function juggler(k, countdig=true, maxiters=20000)

   series, m, maxj, maxjpos = [BigInt(k)], BigInt(k), BigInt(k), BigInt(0)
   for i in 1:maxiters
       m = iseven(m) ? isqrt(m) : isqrt(m*m*m)
       if m >= maxj
           maxj, maxjpos  = m, i
       end
       if m == 1
           println(lpad(k, 9), lpad(i, 6), lpad(maxjpos, 6), lpad(format(countdig ?
               ndigits(maxj) : Int(maxj), commas=true), 20), countdig ? " digits" : "")
           return i
       end
   end
   error("Juggler series starting with $k did not converge in $maxiters iterations")

end

println(" n l(n) i(n) h(n) or d(n)\n------------------------------------------") foreach(k -> juggler(k, false), 20:39) foreach(juggler,

   [113, 173, 193, 2183, 11229, 15065, 15845, 30817, 48443, 275485, 1267909,
    2264915, 5812827])

@time juggler(7110201)

</lang>

Output:
       n    l(n)  i(n)       h(n) or d(n) 
------------------------------------------
       20     3     0                  20
       21     9     4                 140
       22     3     0                  22
       23     9     1                 110
       24     3     0                  24
       25    11     3              52,214
       26     6     3                  36
       27     6     1                 140
       28     6     3                  36
       29     9     1                 156
       30     6     3                  36
       31     6     1                 172
       32     6     3                  36
       33     8     2               2,598
       34     6     3                  36
       35     8     2               2,978
       36     3     0                  36
       37    17     8  24,906,114,455,136
       38     3     0                  38
       39    14     3             233,046
      113    16     9                  27 digits
      173    32    17                  82 digits
      193    73    47                 271 digits
     2183    72    32               5,929 digits
    11229   101    54               8,201 digits
    15065    66    25              11,723 digits
    15845   139    43              23,889 digits
    30817    93    39              45,391 digits
    48443   157    60             972,463 digits
   275485   225   148           1,909,410 digits
  1267909   151    99           1,952,329 digits
  2264915   149    89           2,855,584 digits
  5812827   135    67           7,996,276 digits
  7110201   205   119          89,981,517 digits
 89.493898 seconds (1.11 M allocations: 27.713 GiB, 1.19% gc time)

Nim

Using only standard library, so limited to values of n less than 40. <lang Nim>import math, strformat

func juggler(n: Positive): tuple[count: int; max: uint64; maxIdx: int] =

 var a = n.uint64
 result = (0, a, 0)
 while a != 1:
   let f = float(a)
   a = if (a and 1) == 0: sqrt(f).uint64
       else: uint64(f * sqrt(f))
   inc result.count
   if a > result.max:
     result.max = a
     result.maxIdx = result.count

echo "n l[n] h[n] i[n]" echo "——————————————————————————————" for n in 20..39:

 let (l, h, i) = juggler(n)
 echo &"{n}   {l:2}  {h:14}     {i}"</lang>
Output:
n   l[n]            h[n]  i[n]
——————————————————————————————
20    3              20     0
21    9             140     4
22    3              22     0
23    9             110     1
24    3              24     0
25   11           52214     3
26    6              36     3
27    6             140     1
28    6              36     3
29    9             156     1
30    6              36     3
31    6             172     1
32    6              36     3
33    8            2598     2
34    6              36     3
35    8            2978     2
36    3              36     0
37   17  24906114455136     8
38    3              38     0
39   14          233046     3

Perl

<lang perl>#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Juggler_sequence use warnings; use Math::BigInt lib => 'GMP';

print " n l(n) i(n) h(n) or d(n)\n"; print " ------- ---- ---- ------------\n"; for my $i ( 20 .. 39,

 113, 173, 193, 2183, 11229, 15065, 15845, 30817,
 48443, 275485, 1267909, 2264915, 5812827,
 7110201  # tried my luck, luck takes about 94 seconds
 )
 {
 my $max = my $n = Math::BigInt->new($i);
 my $at = my $count = 0;
 while( $n > 1 )
   {
   $n = sqrt( $n & 1 ? $n ** 3 : $n );
   $count++;
   $n > $max and ($max, $at) = ($n, $count);
   }
 if( length $max < 27 )
   {
   printf "%8d  %4d  %3d  %d\n", $i, $count, $at, $max;
   }
 else
   {
   printf "%8d  %4d  %3d  d(n) = %d digits\n", $i, $count, $at, length $max;
   }
 }</lang>
Output:
       n  l(n) i(n)  h(n) or d(n)
 -------  ---- ----  ------------
      20     3    0  20
      21     9    4  140
      22     3    0  22
      23     9    1  110
      24     3    0  24
      25    11    3  52214
      26     6    3  36
      27     6    1  140
      28     6    3  36
      29     9    1  156
      30     6    3  36
      31     6    1  172
      32     6    3  36
      33     8    2  2598
      34     6    3  36
      35     8    2  2978
      36     3    0  36
      37    17    8  24906114455136
      38     3    0  38
      39    14    3  233046
     113    16    9  d(n) = 27 digits
     173    32   17  d(n) = 82 digits
     193    73   47  d(n) = 271 digits
    2183    72   32  d(n) = 5929 digits
   11229   101   54  d(n) = 8201 digits
   15065    66   25  d(n) = 11723 digits
   15845   139   43  d(n) = 23889 digits
   30817    93   39  d(n) = 45391 digits
   48443   157   60  d(n) = 972463 digits
  275485   225  148  d(n) = 1909410 digits
 1267909   151   99  d(n) = 1952329 digits
 2264915   149   89  d(n) = 2855584 digits
 5812827   135   67  d(n) = 7996276 digits
 7110201   205  119  d(n) = 89981517 digits

Raku

Reaches 30817 fairly quickly but later values suck up enough memory that it starts thrashing the disk cache and performance drops off a cliff (on my system). Killed it after 10 minutes and capped list at 30817. Could rewrite to not try to hold entire sequence in memory at once, but probably not worth it. If you want sheer numeric calculation performance, Raku is probably not where it's at.

<lang perl6>use Lingua::EN::Numbers; sub juggler (Int $n where * > 0) { $n, { $_ +& 1 ?? .³.&isqrt !! .&isqrt } … 1 }

sub isqrt ( \x ) { my ( $X, $q, $r, $t ) = x, 1, 0 ;

   $q +<= 2 while $q ≤ $X ;
   while $q > 1 {
       $q +>= 2; $t = $X - $r - $q; $r +>= 1;
       if $t ≥ 0 { $X = $t; $r += $q }
   }
   $r

}

say " n l[n] i[n] h[n]"; for 20..39 {

   my @j = .&juggler;
   my $max = @j.max;
   printf "%2s %4d  %4d    %s\n", .&comma, +@j-1, @j.first(* == $max, :k), comma $max;

}

say "\n n l[n] i[n] d[n]"; ( 113, 173, 193, 2183, 11229, 15065, 15845, 30817 ).hyper(:1batch).map: {

   my $start = now;
   my @j = .&juggler;
   my $max = @j.max;
   printf "%10s %4d   %4d %10s   %6.2f seconds\n", .&comma, +@j-1, @j.first(* == $max, :k),
     $max.chars.&comma, (now - $start);

}</lang>

Output:
 n  l[n]  i[n]   h[n]
20    3     0    20
21    9     4    140
22    3     0    22
23    9     1    110
24    3     0    24
25   11     3    52,214
26    6     3    36
27    6     1    140
28    6     3    36
29    9     1    156
30    6     3    36
31    6     1    172
32    6     3    36
33    8     2    2,598
34    6     3    36
35    8     2    2,978
36    3     0    36
37   17     8    24,906,114,455,136
38    3     0    38
39   14     3    233,046

      n     l[n]   i[n]    d[n]
       113   16      9         27     0.01 seconds
       173   32     17         82     0.01 seconds
       193   73     47        271     0.09 seconds
     2,183   72     32      5,929     1.05 seconds
    11,229  101     54      8,201     1.98 seconds
    15,065   66     25     11,723     2.05 seconds
    15,845  139     43     23,889    10.75 seconds
    30,817   93     39     45,391    19.60 seconds

REXX

REXX doesn't have a native integer sqrt function, so one was utilized that was previously written.

Also, one optimization was to examine the last decimal digit for   oddness   (instead of getting the remainder when
dividing by two).

Another optimization was to reduce the number of digits after the   sqrt   was calculated. <lang rexx>/*REXX program calculates and displays the juggler sequence for any positive integer*/ numeric digits 20 /*define the number of decimal digits. */ parse arg LO HI list /*obtain optional arguments from the CL*/ if LO= | LO="," then do; LO= 20; HI= 39; end /*Not specified? Then use the default.*/ if HI= | HI="," then HI= LO /* " " " " " " */ w= length( commas(HI) ) /*find the max width of any number N. */ d= digits(); dd= d + d%3 + 1 /*get # numeric digits; another version*/ if LO>0 then say c('n',w) c("steps",7) c('maxIndex',8) c("biggest term" ,dd) if LO>0 then say c( ,w,.) c("" ,7,.) c( ,8,.) c("" ,dd,.)

   do n=LO  to HI while n>0; steps= juggler(n)  /*invoke JUGGLER: find the juggler num.*/
   nc= commas(n)                                /*maybe add commas to  N.              */
   say right(nc, w)      c(steps, 8)     c(imx, 8)      right( commas(mx), dd-1)
   end   /*n*/
                                                /*biggest term isn't shown for list #s.*/

xtra= words(list) /*determine how many numbers in list. */ if xtra==0 then exit 0 /*no special ginormous juggler numbers?*/ w= max(9, length( commas( word(list, xtra) ) ) ) /*find the max width of any list number*/ say; say; say say c('n',w) c("steps",7) c('maxIndex',8) c("max number of digits",dd) say c( ,w,.) c("" ,7,.) c( ,8,.) c("" ,dd,.)

        do p=1  for xtra;     n= word(list, p)  /*process each of the numbers in list. */
        steps= juggler(n);    nc= commas(n)     /*get a number & pass it on to JUGGLER.*/
        say right(nc, w)   c(steps, 8)   c(imx, 8)      right( commas(length(mx)), dd-1)
        end   /*p*/

exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ c: parse arg c1,c2,c3; if c3== then c3= ' '; else c3= '─'; return center(c1,c2,c3) commas: parse arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ? /*──────────────────────────────────────────────────────────────────────────────────────*/ Isqrt: procedure; parse arg x; q= 1; r= 0 /*obtain X; R will be the Isqrt(X). */

          do until q>x;  q= q * 4               /*multiply   Q   by four until > X.    */
          end   /*until*/
              do while q>1;  q= q % 4           /*processing while Q>1;  quarter Q.    */
              t= x - r - q;  r= r % 2           /*set T ──► X-R-Q;       halve R.      */
              if t>=0  then do; x= t; r= r + q  /*T≥0?  Then set X ──► T;  add Q ──► R.*/
                            end
              end   /*while*/;    return r      /*return the integer square root of  X.*/

/*──────────────────────────────────────────────────────────────────────────────────────*/ juggler: parse arg #; imx= 0; mx= # /*get N; set index of MX and MX ──► 0.*/

        @.=0; @.1=1; @.3=1; @.5=1; @.7=1; @.9=1 /*set semaphores (≡1) for odd dec. digs*/
          do j=1  until z==1                    /*here is where we begin to juggle.    */
          parse var  #    -1  _               /*obtain the last decimal digit of  #. */
          if @._  then do;       cube= #*#*#    /*Odd? Then compute integer sqrt(#**3).*/
                       if pos(., cube)>0  then do    /*need to increase decimal digits.*/
                                               parse var  cube    with    'E'  x
                                               if x>=digits()  then numeric digits x+2
                                               end
                       z= Isqrt(#*#*#)          /*compute the integer sqrt(#**3)       */
                       end
                  else z= Isqrt(#)              /*Even? Then compute integer sqrt(#).  */
          L= length(z)
          if L>=d  then numeric digits L+1      /*reduce the number of numeric digits. */
          if z>mx  then do;  mx= z; imx= j; end /*found a new max;  set MX;  set IMX.  */
          #= z
          end   /*j*/;                 return j</lang>
output   when using the inputs:     ,   ,   113   173   193   2183   11229   15065   30817   48443
n   steps  maxIndex        biggest term
── ─────── ──────── ───────────────────────────
20    3        0                             20
21    9        4                            140
22    3        0                             22
23    9        1                            110
24    3        0                             24
25    11       3                         52,214
26    6        3                             36
27    6        1                            140
28    6        3                             36
29    9        1                            156
30    6        3                             36
31    6        1                            172
32    6        3                             36
33    8        2                          2,598
34    6        3                             36
35    8        2                          2,978
36    3        0                             36
37    17       8             24,906,114,455,136
38    3        0                             38
39    14       3                        233,046


    n      steps  maxIndex    max number of digits
───────── ─────── ──────── ───────────────────────────
      113    16       9                             27
      173    32       17                            82
      193    73       47                           271
    2,183    72       32                         5,929
   11,229   101       54                         8,201
   15,065    66       25                        11,723
   15,845   139       43                        23,889
   30,817    93       39                        45,391
   48,443   157       60                       972,463

Wren

Library: Wren-fmt
Library: Wren-big

This took about 14.5 minutes to reach n = 15,845 on my machine and I gave up after that. <lang ecmascript>import "/fmt" for Fmt import "/big" for BigInt

var zero = BigInt.zero var one = BigInt.one var two = BigInt.two

var juggler = Fn.new { |n|

   if (n < 1) Fiber.abort("Starting value must be a positive integer.")
   var a = BigInt.new(n)
   var count = 0
   var maxCount = 0
   var max = a.copy()
   while (a != one) {
       if (a.isEven) {
           a = a.isqrt
       } else {
           a = (a.square * a).isqrt
       }
       count = count + 1
       if (a > max) {
           max = a
           maxCount = count
       }
   }
   return [count, maxCount, max, max.toString.count]

}

System.print("n l[n] i[n] h[n]") System.print("-----------------------------------") for (n in 20..39) {

   var res = juggler.call(n)
   Fmt.print("$2d    $2d   $2d    $,i", n, res[0], res[1], res[2])

} System.print() var nums = [113, 173, 193, 2183, 11229, 15065, 15845] System.print(" n l[n] i[n] d[n]") System.print("----------------------------") for (n in nums) {

   var res = juggler.call(n)
   Fmt.print("$,6d   $3d    $3d   $,6i", n, res[0], res[1], res[3])

}</lang>

Output:
n    l[n]  i[n]  h[n]
-----------------------------------
20     3    0    20
21     9    4    140
22     3    0    22
23     9    1    110
24     3    0    24
25    11    3    52,214
26     6    3    36
27     6    1    140
28     6    3    36
29     9    1    156
30     6    3    36
31     6    1    172
32     6    3    36
33     8    2    2,598
34     6    3    36
35     8    2    2,978
36     3    0    36
37    17    8    24,906,114,455,136
38     3    0    38
39    14    3    233,046

n        l[n]   i[n]   d[n]
----------------------------
   113    16      9       27
   173    32     17       82
   193    73     47      271
 2,183    72     32    5,929
11,229   101     54    8,201
15,065    66     25   11,723
15,845   139     43   23,889