Undulating numbers

From Rosetta Code
Revision as of 08:28, 3 June 2023 by Tigerofdarkness (talk | contribs) (Added Algol 68)
Undulating 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.

An Undulating number in some base is a number which has the digit form ABABAB... where A and B are digits in that base.

For the purposes of this task, we shall only consider a number to be undulating if it has at least 3 digits in a given base and A != B.

Examples

The numbers: 101 and 9898 are undulating numbers in base 10.

The numbers: 50 and 2350 are undulating numbers in base 7 because their base 7 representations are: 101 and 6565 respectively.

Task

For base 10, find and show on this page:

1. All three digit undulating numbers.

2. All four digit undulating numbers.

3. All three digit undulating numbers which are primes.

4. The 600th undulating number.

5. How many undulating numbers are less than 2^53 and the largest such number.

Bonus

Do the same for base 7 expressing the results in base 10 apart from 4. and 5. which should be expressed in base 7 also.

Note that undulating numbers with a given number of digits in base 7 may, of course, have less digits when expressed in base 10 and are unlikely to be still undulating. However, 121 (or 232 in base 7) is an exception to this.

References


ALGOL 68

As undulating numbers are relatively sparse, this counts the numbers by enumerating them as in the Wren and other samples.

BEGIN # show some Undulating numbers - numbers whose digits form the pattern #
      #                                ABAB...                               #

    # returns TRUE if n is prime, FALSE otherwise - uses trial division      #
    PROC is prime = ( LONG INT n )BOOL:
         IF   n < 3       THEN n = 2
         ELIF n MOD 3 = 0 THEN n = 3
         ELIF NOT ODD n   THEN FALSE
         ELSE
             BOOL is a prime := TRUE;
             INT  f          := 5;
             INT  f2         := 25;
             INT  to next    := 24;
             WHILE f2 <= n AND is a prime DO
                 is a prime := n MOD f /= 0;
                 f         +:= 2;
                 f2        +:= to next;
                 to next   +:= 8
             OD;
             is a prime
         FI # is prime # ;
    # returns s with comma separators                                        #
    PROC commatise = ( STRING s )STRING:
         BEGIN
            STRING result := "";
            INT r pos     := -1;
            FOR s pos FROM UPB s BY -1 TO LWB s DO
                IF ( r pos +:= 1 ) = 3 THEN
                    r pos := 0;
                    "," +=: result
                FI;
                s[ s pos ] +=: result
            OD;
            result
         END # commatise # ;
    # returns the undulating number in base b with first digit f and second  #
    #         digit s with d digits in total                                 #
    PROC undulating number = ( INT d, f, s, b )LONG INT:
         BEGIN
            LONG INT un := 0;
            FOR digit TO d DO
                un *:= b +:= IF ODD digit THEN f ELSE s FI
            OD;
            un
         END # undulating number # ;
    # returns a string representation of the undulating number in base b     #
    #         with first digit f and second digit s with d digits in total   #
    PROC undulating string = ( INT d, f, s, b )STRING:
         commatise( whole( undulating number( d, f, s, b ), 0 ) );
    # prints the undulating numbers with d digits in base b                  #
    #        if primes only is TRUE, only prime undulating numbers are shown #
    PROC print undulating numbers = ( INT d, b, BOOL primes only )VOID:
         BEGIN
            INT zero      = ABS "0";
            INT max digit = b - 1;
            IF primes only THEN print( ( "Prime " ) ) FI;
            print( ( whole( d, 0 ), " digit Undulating Numbers in base ", whole( b, 0 ) ) );
            IF b /= 10 THEN print( ( " (shown in base 10)" ) ) FI;
            print( ( ":", newline ) );
            INT p count := 0;
            FOR first digit TO max digit DO
                FOR second digit FROM 0 TO max digit DO
                    IF first digit /= second digit THEN
                        LONG INT un = undulating number( d, first digit, second digit, b );
                        IF IF NOT primes only THEN TRUE ELSE is prime( un ) FI THEN
                            print( ( " ", whole( un, -d ) ) );
                            IF ( p count +:= 1 ) MOD max digit = 0 THEN print( ( newline ) ) FI
                        FI
                    FI
                OD
            OD;
            IF p count MOD max digit /= 0 THEN print( ( newline ) ) FI;
            print( ( newline ) )
         END # print undulating numbers # ;
    # prints the count of undulating numbers up to max number in base b      #
    #        the final one and show number are also shown                    #
    PROC print and count undulating numbers
         = ( INT show number, LONG INT max number, STRING max name, INT b )VOID:
         BEGIN
            LONG INT un       := 0;
            LONG INT last un  := 0;
            INT      un count := 0;
            INT      last f   := 0, last s := 0, last d := 0;
            FOR digits FROM 3 WHILE un < max number DO
                FOR f TO b - 1 WHILE un < max number DO
                    FOR s FROM 0 TO b - 1 WHILE un < max number DO
                        IF f /= s THEN
                            IF ( un := undulating number( digits, f, s, b ) ) < max number THEN
                                last un := un;
                                last d  := digits;
                                last f  := f;
                                last s  := s;
                                IF ( un count +:= 1 ) = show number THEN
                                   print( ( "Undulating number ", whole( show number, 0 ) ) );
                                   print( ( " in base ", whole( b, 0 ), ": " ) );
                                   print( ( undulating string( last d, last f, last s, b ) ) );
                                   IF b /= 10 THEN
                                       print( ( newline, "        which is: " ) );
                                       print( ( commatise( whole( un, 0 ) ) ) );
                                       print( ( " in base 10", newline ) )
                                   FI;
                                   print( ( newline ) )
                                FI
                            FI
                        FI
                    OD
                OD
            OD;
            print( ( "There are ", whole( un count, 0 ) ) );
            print( ( " Undulating nnumbers in base ", whole( b, 0 ), " before ", max name, newline ) );
            print( ( "The last is: ", undulating string( last d, last f, last s, b ), newline ) );
            IF b /= 10 THEN
                print( ( "   which is: ", commatise( whole( last un, 0 ) ), " in base 10", newline ) )
            FI
         END # print and count undulating numbers # ;

    # shows various Undulating numbers in base b                             #
    PROC print undulating info = ( INT b )VOID:
         BEGIN
            print undulating numbers( 3, b, FALSE );
            print undulating numbers( 4, b, FALSE );
            print undulating numbers( 3, b, TRUE  );
            print and count undulating numbers( 600, LONG 2 ^ 53, "2^53", b )
         END # print undulating info # ;

    print undulating info( 10 ); # base 10 undulating numbers                #
    print( ( newline ) );
    print undulating info(  7 )  # base  7 undulating numbers                #

END
Output:
3 digit Undulating Numbers in base 10:
 101 121 131 141 151 161 171 181 191
 202 212 232 242 252 262 272 282 292
 303 313 323 343 353 363 373 383 393
 404 414 424 434 454 464 474 484 494
 505 515 525 535 545 565 575 585 595
 606 616 626 636 646 656 676 686 696
 707 717 727 737 747 757 767 787 797
 808 818 828 838 848 858 868 878 898
 909 919 929 939 949 959 969 979 989

4 digit Undulating Numbers in base 10:
 1010 1212 1313 1414 1515 1616 1717 1818 1919
 2020 2121 2323 2424 2525 2626 2727 2828 2929
 3030 3131 3232 3434 3535 3636 3737 3838 3939
 4040 4141 4242 4343 4545 4646 4747 4848 4949
 5050 5151 5252 5353 5454 5656 5757 5858 5959
 6060 6161 6262 6363 6464 6565 6767 6868 6969
 7070 7171 7272 7373 7474 7575 7676 7878 7979
 8080 8181 8282 8383 8484 8585 8686 8787 8989
 9090 9191 9292 9393 9494 9595 9696 9797 9898

Prime 3 digit Undulating Numbers in base 10:
 101 131 151 181 191 313 353 373 383
 727 757 787 797 919 929

Undulating number 600 in base 10: 4,646,464,646
There are 1125 Undulating nnumbers in base 10 before 2^53
The last is: 8,989,898,989,898,989

3 digit Undulating Numbers in base 7 (shown in base 10):
  50  64  71  78  85  92
 100 107 121 128 135 142
 150 157 164 178 185 192
 200 207 214 221 235 242
 250 257 264 271 278 292
 300 307 314 321 328 335

4 digit Undulating Numbers in base 7 (shown in base 10):
  350  450  500  550  600  650
  700  750  850  900  950 1000
 1050 1100 1150 1250 1300 1350
 1400 1450 1500 1550 1650 1700
 1750 1800 1850 1900 1950 2050
 2100 2150 2200 2250 2300 2350

Prime 3 digit Undulating Numbers in base 7 (shown in base 10):
  71 107 157 257 271 307

Undulating number 600 in base 7: 4,646,464,646,464,646,464
        which is: 8,074,217,422,972,642 in base 10

There are 603 Undulating nnumbers in base 7 before 2^53
The last is: 5,252,525,252,525,252,525
   which is: 8,786,648,372,058,464 in base 10

jq

Adapted from Wren

Works with: jq

Also works with gojq, the Go implementation of jq.

## For the sake of gojq:
def _nwise($n):
  def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
  n;

## Generic functions
def lpad($len): tostring | ($len - length) as $l | (" " * $l) + .;

def tobase($b):
  def digit: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[.:.+1];
  def mod: . % $b;
  def div: ((. - mod) / $b);
  def digits: recurse( select(. > 0) | div) | mod ;
  # For jq it would be wise to protect against `infinite` as input, but using `isinfinite` confuses gojq
  select( (tostring|test("^[0-9]+$")) and 2 <= $b and $b <= 36)
  | if . == 0 then "0"
    else [digits | digit] | reverse[1:] | add
    end;

# tabular print
def tprint(columns; wide):
  reduce _nwise(columns) as $row ("";
     . + ($row|map(lpad(wide)) | join(" ")) + "\n" );

def is_prime:
  . as $n
  | if ($n < 2)         then false
    elif ($n % 2 == 0)  then $n == 2
    elif ($n % 3 == 0)  then $n == 3
    elif ($n % 5 == 0)  then $n == 5
    elif ($n % 7 == 0)  then $n == 7
    elif ($n % 11 == 0) then $n == 11
    elif ($n % 13 == 0) then $n == 13
    elif ($n % 17 == 0) then $n == 17
    elif ($n % 19 == 0) then $n == 19
    else sqrt as $s
    | 23
    | until( . > $s or ($n % . == 0); . + 2)
    | . > $s
    end;

## Undulating numbers
def undulating($base; $n):
  53 as $mpow
  | (pow(2;$mpow) - 1) as $limit
  | ($base * $base) as $bsquare
  | { u3: [], u4: [] }
  | reduce range(1; $base) as $a (.;
       reduce range(0; $base) as $b (.;
            if $b == $a then .
            else ($a * $bsquare + $b * $base + $a) as $u
            | .u3 += [$u]
            | ($a * $base + $b) as $v
            | .u4 += [$v * $bsquare + $v]
            end) )
  | "All 3-digit undulating numbers in base \($base):",
     (.u3 | tprint(9; 4)),
     "All 4-digit undulating numbers in base \($base):",
     (.u4 | tprint(9; 5)),
     "All 3-digit undulating numbers which are primes in base \($base):",
     ( .primes = []
      | reduce .u3[] as $u (.;
          if $u % 2 == 1 and $u % 5 != 0 and ($u | is_prime)
          then .primes += [$u]
          else .
          end)
      | (.primes | tprint(10; 4))),
     ( .un = (.u3 + .u4)
      | (.un|length) as $unc
      | .j = 0
      | .i = 0
      | .done = false
      | until(.done;
          .i = 0
          | until(.i >= $unc;
              (.un[.j * $unc + .i] * $bsquare + (.un[.j * $unc + .i] % $bsquare)) as $u
              | if $u > $limit then .done = true | .i = $unc
                else .un += [$u]
                | .i += 1
		        end )
          | .j += 1 )
       | "\nThe \($n)th undulating number in base \($base) is: \(.un[$n-1])",
         (select($base != 10) | "or expressed in base \($base): \(.un[$n-1] | tobase($base))"),
         "\nTotal number of undulating numbers in base \($base) < 2^\($mpow) = \(.un|length)",
         "of which the largest is: \(.un[-1])",
         (select($base != 10) | "or expressed in base \($base): \(.un[-1]| tobase($base))")
       ) ;

(10, 7) as $base
| undulating($base; 600), ""
Output:

Essentially as for Wren.

Phix

Translation of: Wren
with javascript_semantics
for base in {10,7} do
    integer n = 600, mpow = 53, bsquare = base * base
    atom limit = power(2,53)-1
    sequence u3 = {}, u4 = {}
    for a=1 to base-1 do
        for b=0 to base-1 do
            if b!=a then
                integer u = a * base + b,
                        v = u * base + a,
                        w = v * base + b
                u3 &= v
                u4 &= w
            end if
        end for
    end for
    for d,u in {{u3,"%3d"},{u4,"%4d"}} do
        printf(1,"All %d digit undulating numbers in base %d:\n%s\n",
                  {d+2,base,join_by(u[1],1,9,"  ",fmt:=u[2])})
    end for
    printf(1,"All 3 digit undulating numbers which are primes in base %d:\n%s\n",
             {base,join_by(filter(u3,is_prime),1,10,"  ",fmt:="%3d")})
    sequence un = u3 & u4
    integer start = 1, done = false
    while not done do
        integer finish = length(un)
        for i=start to finish do
            atom u = un[i] * bsquare + remainder(un[i],bsquare)
            if u>limit then done = true; exit end if
            un &= u
        end for
        start = finish+1
    end while
    printf(1,"The %,d%s undulating number in base %d is: %,d\n", {n,ord(n),base,un[n]})
    if base!=10 then printf(1,"or expressed in base %d : %,a\n", {base,{base,un[n]}}) end if
    printf(1,"\nTotal number of undulating numbers in base %d < 2^%d = %,d\n",{base,mpow,length(un)})
    printf(1,"of which the largest is: %,d\n", un[$])
    if base!=10 then printf(1,"or expressed in base %d : %,a\n", {base,{base,un[$]}}) end if
    printf(1,"\n")
end for

Output same as Wren, except for "⁵³"->"^53". Note that comma-fill on %a under p2js needs a trivial fix ("df".indexOf->"aAdf".indexOf)/1.0.3 or later.

Raku

Translation of: Wren
# 20230602 Raku programming solution

sub undulating ($base, \n) {
   my \limit = 2**(my \mpow = 53) - 1;
   my (\bsquare,@u3,@u4) = $base*$base; 
   for 1..^$base X 0..^$base -> (\a,\b) {
      next if b == a;
      @u3.push(a * bsquare + b * $base + a);
      @u4.push((my \v = a * $base + b) * bsquare + v)
   }
   say "\nAll 3 digit undulating numbers in base $base:";
   .fmt('%3d').say for @u3.rotor: 9;
   say "\nAll 4 digit undulating numbers in base $base:";
   .fmt('%4d').say for @u4.rotor: 9; 
   say "\nAll 3 digit undulating numbers which are primes in base $base:";
   my @primes = @u3.grep: *.is-prime; 
    .fmt('%3d').say for @primes.rotor: 10, :partial;
   my \unc = (my @un = @u3.append: @u4).elems;
   my ($j, $done) = 0, False;
   loop {
      for 0..^unc {
         my  \u = @un[$j * unc + $_] * bsquare + @un[$j * unc + $_] % bsquare;
	 u > limit ?? ( $done = True and last ) !! ( @un.push: u );
      }
      $done ?? ( last ) !! $j++ 
   }
   say "\nThe {n} undulating number in $base $base is: @un[n-1]";
   say "or expressed in base $base : {@un[n-1].base($base)}" unless $base == 10;
   say "\nTotal number of undulating numbers in base $base < 2**{mpow} = {+@un}";
   say "of which the largest is: ", @un[*-1];
   say "or expressed in base $base : {@un[*-1].base($base)}" unless $base == 10;
}

undulating $_, 600 for 10, 7;

You may Try it online!

Wren

Library: Wren-fmt
Library: Wren-math
import "./fmt" for Fmt, Conv
import "./math" for Int

var undulating = Fn.new { |base, n|
    var mpow = 53
    var limit = 2.pow(mpow) - 1
    var u3 = []
    var u4 = []
    var bsquare = base * base
    for (a in 1...base) {
        for (b in 0...base) {
            if (b == a) continue
            var u = a * bsquare + b * base + a
            u3.add(u)
            var v = a * base + b
            u4.add(v * bsquare + v)
        }
    }
    System.print("All 3 digit undulating numbers in base %(base):")
    Fmt.tprint("$3d ", u3, 9)
    System.print("\nAll 4 digit undulating numbers in base %(base):")
    Fmt.tprint("$4d ", u4, 9)
    System.print("\nAll 3 digit undulating numbers which are primes in base %(base):")
    var primes = []
    for (u in u3) {
        if (u % 2 == 1 && u % 5 != 0 && Int.isPrime(u)) primes.add(u)
    }
    Fmt.tprint("$3d ", primes, 10)
    var un = u3 + u4
    var unc = un.count
    var j = 0
    var done = false
    while (true) {
       for (i in 0...unc) {
           var u = un[j * unc + i] * bsquare + un[j * unc + i] % bsquare
           if (u > limit) {
                done = true
                break
           }
           un.add(u)
       }
       if (done) break
       j = j + 1
    }
    Fmt.print("\nThe $,r undulating number in base $d is: $,d", n, base, un[n-1])
    if (base != 10) Fmt.print("or expressed in base $d : $,s", base, Conv.itoa(un[n-1], base))
    Fmt.print("\nTotal number of undulating numbers in base $d < 2$S = $,d", base, mpow, un.count)
    Fmt.print("of which the largest is: $,d", un[-1])
    if (base != 10) Fmt.print("or expressed in base $d : $,s", base, Conv.itoa(un[-1], base))
    System.print()
}

for (base in [10, 7]) undulating.call(base, 600)
Output:
All 3 digit undulating numbers in base 10:
101  121  131  141  151  161  171  181  191 
202  212  232  242  252  262  272  282  292 
303  313  323  343  353  363  373  383  393 
404  414  424  434  454  464  474  484  494 
505  515  525  535  545  565  575  585  595 
606  616  626  636  646  656  676  686  696 
707  717  727  737  747  757  767  787  797 
808  818  828  838  848  858  868  878  898 
909  919  929  939  949  959  969  979  989 

All 4 digit undulating numbers in base 10:
1010  1212  1313  1414  1515  1616  1717  1818  1919 
2020  2121  2323  2424  2525  2626  2727  2828  2929 
3030  3131  3232  3434  3535  3636  3737  3838  3939 
4040  4141  4242  4343  4545  4646  4747  4848  4949 
5050  5151  5252  5353  5454  5656  5757  5858  5959 
6060  6161  6262  6363  6464  6565  6767  6868  6969 
7070  7171  7272  7373  7474  7575  7676  7878  7979 
8080  8181  8282  8383  8484  8585  8686  8787  8989 
9090  9191  9292  9393  9494  9595  9696  9797  9898 

All 3 digit undulating numbers which are primes in base 10:
101  131  151  181  191  313  353  373  383  727 
757  787  797  919  929 

The 600th undulating number in base 10 is: 4,646,464,646

Total number of undulating numbers in base 10 < 2⁵³ = 1,125
of which the largest is: 8,989,898,989,898,989

All 3 digit undulating numbers in base 7:
 50   64   71   78   85   92  100  107  121 
128  135  142  150  157  164  178  185  192 
200  207  214  221  235  242  250  257  264 
271  278  292  300  307  314  321  328  335 

All 4 digit undulating numbers in base 7:
 350   450   500   550   600   650   700   750   850 
 900   950  1000  1050  1100  1150  1250  1300  1350 
1400  1450  1500  1550  1650  1700  1750  1800  1850 
1900  1950  2050  2100  2150  2200  2250  2300  2350 

All 3 digit undulating numbers which are primes in base 7:
 71  107  157  257  271  307 

The 600th undulating number in base 7 is: 8,074,217,422,972,642
or expressed in base 7 : 4,646,464,646,464,646,464

Total number of undulating numbers in base 7 < 2⁵³ = 603
of which the largest is: 8,786,648,372,058,464
or expressed in base 7 : 5,252,525,252,525,252,525