Find palindromic numbers in both binary and ternary bases

From Rosetta Code
Revision as of 21:02, 21 July 2014 by rosettacode>TimToady (→‎{{header|Perl 6}}: make run 4 times faster)
Find palindromic numbers in both binary and ternary bases 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.
The task

Find and show (in decimal) the first six numbers (non-negative integers) that are palindromes in both base 2 and base 3.

Use zero (0) as the first number found, even though some other definitions ignore it.

Optionally, show the decimal number found in its binary and ternary form.

It's permissible to assume the first two numbers and simply list them.

See also
  • Sequence A60792, Numbers that are palindromic in bases 2 and 3 on The On-Line Encyclopedia of Integer Sequences.


C

Per the observations made by the Ruby code (which are correct), the numbers must have odd number of digits in base 3 with a 1 at the middle, and must have odd number of digits in base 2. <lang c>#include <stdio.h> typedef unsigned long long xint;

int is_palin2(xint n) { xint x = 0; if (!(n&1)) return !n; while (x < n) x = x<<1 | (n&1), n >>= 1; return n == x || n == x>>1; }

xint reverse3(xint n) { xint x = 0; while (n) x = x*3 + (n%3), n /= 3; return x; }

void print(xint n, xint base) { putchar(' '); // printing digits backwards, but hey, it's a palindrome do { putchar('0' + (n%base)), n /= base; } while(n); printf("(%lld)", base); }

void show(xint n) { printf("%llu", n); print(n, 2); print(n, 3); putchar('\n'); }

xint min(xint a, xint b) { return a < b ? a : b; } xint max(xint a, xint b) { return a > b ? a : b; }

int main(void) { xint lo, hi, lo2, hi2, lo3, hi3, pow2, pow3, i, n; int cnt;

show(0); cnt = 1;

lo = 0; hi = pow2 = pow3 = 1;

while (1) { for (i = lo; i < hi; i++) { n = (i * 3 + 1) * pow3 + reverse3(i); if (!is_palin2(n)) continue; show(n); if (++cnt >= 7) return 0; }

if (i == pow3) pow3 *= 3; else pow2 *= 4;

while (1) { while (pow2 <= pow3) pow2 *= 4;

lo2 = (pow2 / pow3 - 1) / 3; hi2 = (pow2 * 2 / pow3 - 1) / 3 + 1; lo3 = pow3 / 3; hi3 = pow3;

if (lo2 >= hi3) pow3 *= 3; else if (lo3 >= hi2) pow2 *= 4; else { lo = max(lo2, lo3); hi = min(hi2, hi3); break; } } } return 0; }</lang>

Output:
0 0(2) 0(3)
1 1(2) 1(3)
6643 1100111110011(2) 100010001(3)
1422773 101011011010110110101(2) 2200021200022(3)
5415589 10100101010001010100101(2) 101012010210101(3)
90396755477 1010100001100000100010000011000010101(2) 22122022220102222022122(3)
381920985378904469 10101001100110110110001110011011001110001101101100110010101(2) 2112200222001222121212221002220022112(3)

D

Translation of: C

<lang d>import core.stdc.stdio;

bool isPalindrome2(ulong n) pure nothrow @nogc {

   ulong x = 0;
   if (!(n & 1))
       return !n;
   while (x < n) {
       x = (x << 1) | (n & 1);
       n >>= 1;
   }
   return n == x || n == (x >> 1);

}

ulong reverse3(ulong n) pure nothrow @nogc {

   ulong x = 0;
   while (n) {
       x = x * 3 + (n % 3);
       n /= 3;
   }
   return x;

}

void printReversed(ubyte base)(ulong n) @nogc {

   putchar(' ');
   do {
       putchar('0' + (n % base));
       n /= base;
   } while(n);
   printf("(%d)", base);

}

void main() @nogc {

   ulong i, cnt, top = 1, mul = 1, even = 0;
   uint count = 0;
   for (i = cnt = 0; cnt < 6; i++) {
       if (i == top) {
           if (even ^= 1)
               top *= 3;
           else {
               i = mul;
               mul = top;
           }
       }
       immutable n = i * mul + reverse3(even ? i / 3 : i);
       if (isPalindrome2(n)) {
           printf("%llu", n);
           printReversed!3(n);
           printReversed!2(n);
           putchar('\n');
           if (++count >= 6) // Print first 6.
               break;
       }
   }

}</lang>

Output:
0 0(3) 0(2)
1 1(3) 1(2)
6643 100010001(3) 1100111110011(2)
1422773 2200021200022(3) 101011011010110110101(2)
5415589 101012010210101(3) 10100101010001010100101(2)
90396755477 22122022220102222022122(3) 1010100001100000100010000011000010101(2)

J

Solution: <lang j>isPalin=: -: |. NB. check if palindrome toBase=: #.inv"0 NB. convert to base(s) in left arg filterPalinBase=: ] #~ isPalin@toBase/ NB. palindromes for base(s) find23Palindromes=: 3 filterPalinBase 2 filterPalinBase ] NB. palindromes in both base 2 and base 3

showBases=: [: ;:inv@|: <@({&'0123456789ABCDEFGH')@toBase/ NB. display bases for numbers

NB.*getfirst a Adverb to get first y items returned by verb u getfirst=: adverb define

 1e5 u getfirst y
 res=. 0$0
 start=. 0
 blk=. i.x
 whilst. y > #res do.
   tmp=. u start + blk
   start=. start + x
   res=. res, tmp
 end.
 res

)</lang> Usage: <lang j> find23Palindromes i. 2e6 NB. binary & ternary palindromes less than 2,000,000 0 1 6643 1422773

  10 2 3 showBases find23Palindromes getfirst 6  NB. first 6 binary & ternary palindomes

0 0 0 1 1 1 6643 1100111110011 100010001 1422773 101011011010110110101 2200021200022 5415589 10100101010001010100101 101012010210101 90396755477 1010100001100000100010000011000010101 22122022220102222022122 </lang>

Java

This takes a while to get to the 6th one (I didn't time it precisely, but it was less than 2 hours on an i7) <lang java>public class Pali23 { public static boolean isPali(String x){ return x.equals(new StringBuilder(x).reverse().toString()); }

public static void main(String[] args){

for(long i = 0, count = 0; count < 6;i++){ if((i & 1) == 0 && (i != 0)) continue; //skip non-zero evens, nothing that ends in 0 in binary can be in this sequence //maybe speed things up through short-circuit evaluation by putting toString in the if //testing up to 10M, base 2 has slightly fewer palindromes so do that one first if(isPali(Long.toBinaryString(i)) && isPali(Long.toString(i, 3))){ System.out.println(i + ", " + Long.toBinaryString(i) + ", " + Long.toString(i, 3)); count++; } } } }</lang>

Output:
0, 0, 0
1, 1, 1
6643, 1100111110011, 100010001
1422773, 101011011010110110101, 2200021200022
5415589, 10100101010001010100101, 101012010210101
90396755477, 1010100001100000100010000011000010101, 22122022220102222022122

PARI/GP

<lang parigp>check(n)={ \\ Check for 2n+1-digit palindromes in base 3

 my(N=3^n);
 forstep(i=N+1,2*N,[1,2],
   my(base2,base3=digits(i,3),k);
   base3=concat(Vecrev(base3[2..n+1]), base3);
   k=subst(Pol(base3),'x,3);
   base2=binary(k);
   if(base2==Vecrev(base2), print1(", "k))
 )

}; print1("0, 1"); for(i=1,11,check(i))</lang>

Output:
0, 1, 6643, 1422773, 5415589, 90396755477

Perl 6

Instead of searching for numbers that are palindromes in one base then checking the other, generate palindromic trinary numbers directly, then check to see if they are also binary palindromes (with additional simplifying constraints as noted in other entries). Outputs the list in decimal, binary and trinary.

<lang perl6>constant palindromes = 0, 1, gather for 1 .. * -> $n {

    my $p = $n.base(3);
    for $p ~ '1' ~ $p.flip -> $r {
       my $s = :3($r);
       next if $s %% 2 or $s.msb % 2;
       my $s2 = $s.base(2);
       next unless $s2 eq $s2.flip;
       take $s;
    }

}

printf "%d, %s, %s\n", $_, .base(2), .base(3) for palindromes[^6];</lang>

Output:
0, 0, 0
1, 1, 1
6643, 1100111110011, 100010001
1422773, 101011011010110110101, 2200021200022
5415589, 10100101010001010100101, 101012010210101
90396755477, 1010100001100000100010000011000010101, 22122022220102222022122

Python

<lang python>from itertools import islice

digits = "0123456789abcdefghijklmnopqrstuvwxyz"

def baseN(num,b):

 if num == 0: return "0"
 result = ""
 while num != 0:
   num, d = divmod(num, b)
   result += digits[d]
 return result[::-1] # reverse

def pal2(num):

   if num == 0 or num == 1: return True
   based = bin(num)[2:]
   return based == based[::-1]

def pal_23():

   yield 0
   yield 1
   n = 1
   while True:
       n += 1
       b = baseN(n, 3)
       revb = b[::-1]
       #if len(b) > 12: break
       for trial in ('{0}{1}'.format(b, revb), '{0}0{1}'.format(b, revb),
                     '{0}1{1}'.format(b, revb), '{0}2{1}'.format(b, revb)):
           t = int(trial, 3)
           if pal2(t):
               yield t

for pal23 in islice(pal_23(), 6):

   print(pal23, baseN(pal23, 3), baseN(pal23, 2))</lang>
Output:
0 0 0
1 1 1
6643 100010001 1100111110011
1422773 2200021200022 101011011010110110101
5415589 101012010210101 10100101010001010100101
90396755477 22122022220102222022122 1010100001100000100010000011000010101

REXX

Programming note:   This version is quite a bit faster than the previous REXX program entered.

For this REXX program, a few deterministic assumptions were made:

  • for the requirement of binary palindromes, the number of binary digits have to be odd.
  • for the requirement of ternary palindromes, the numbers can't end in zero (in base 3).


The method used is to (not find, but) construct a binary palindrome by:

  • using the binary version of a number (abcdef), which may end in binary zeroes,
  • flipping the binary digits (fedcba)     [note that   a   is always   1   (one)],
  • constructing two binary palindromes:
  • abcdef || 0 || fedcba       and
  • abcdef || 1 || fedcba
  • (the above two concatenation steps ensures an odd number of binary digits),
  • ensure the decimal versions are not divisible by 3,
  • convert the decimal numbers to base 3,
  • ensure that the numbers in base 3 are palindromic.

<lang rexx>/*REXX pgm finds decimal #s that are palindromic in binary and ternary.*/ digs=50; numeric digits digs /*biggest known B2B3 pal: 44 dig.*/ parse arg maxHits .; if maxHits== then maxHits=6 /*use 6 as a limit*/ hits=0 /*number of hits (palindromes). */ call show 0,0,0; call show 1,1,1 /*show the first two palindromes.*/ !.= /* [↓] build list of powers of 3*/

    do i=1  until  !.i>10**digs;   !.i=3**i;    end  /*i*/

p=1 /* [↓] primary search: bin pals.*/

 do #=1                               /*use all #s, however, DEC is odd*/
 binH=strip(x2b(d2x(#)),'L',0)        /*convert the number to binary.  */
 binL=reverse(binH)                   /*reverse the binary digits.     */
 dec=x2d(b2x(binH'0'binL));   if dec//3\==0  then call radix3
 dec=x2d(b2x(binH'1'binL));   if dec//3\==0  then call radix3
 end     /*#*/                        /* [↑]   crunch 'til found 'nuff.*/

/*──────────────────────────────────RADIX3 subroutine───────────────────*/ radix3: x=dec /*convert constructed # to base 3*/

     do j=p; if !.j>x then leave; end /*find upper limit of power of 3.*/

q= /*set base 3 result holder to nul*/ p=j-1 /*use this pow of 3 for next time*/

     do k=p  to 1  by -1;  _=!.k;  d=x%_;  q=q || d;  x=x//_;  end  /*k*/

t=q || x /*handle the conversion residual.*/ if t\==reverse(t) then return /*is ternary # not palindromic? */ call show dec,t,strip(x2b(d2x(dec)),,0) /*go and display # in 3 bases.*/ return /* [↑] this process is sluggish.*/ /*──────────────────────────────────SHOW subroutine─────────────────────*/ show: hits=hits+1 /*bump the number of palindromes.*/ say say right('['hits"]",5) right(arg(1),digs) '(decimal), ternary=' arg(2) say right(,5+1+digs) ' binary=' arg(3) if hits<maxHits then return exit /*stick a fork in it, we're done.*/</lang> output when using the input of:   7

  [1]                                                  0 (decimal),    ternary= 0
                                                                        binary= 0

  [2]                                                  1 (decimal),    ternary= 1
                                                                        binary= 1

  [3]                                               6643 (decimal),    ternary= 100010001
                                                                        binary= 1100111110011

  [4]                                            1422773 (decimal),    ternary= 2200021200022
                                                                        binary= 101011011010110110101

  [5]                                            5415589 (decimal),    ternary= 101012010210101
                                                                        binary= 10100101010001010100101

  [6]                                        90396755477 (decimal),    ternary= 22122022220102222022122
                                                                        binary= 1010100001100000100010000011000010101 
 
  [7]                                 381920985378904469 (decimal),    ternary= 2112200222001222121212221002220022112
                                                                        binary= 10101001100110110110001110011011001110001101101100110010101

[Output note:   the first   6th   numbers (above) took about ten seconds to compute.]

Ruby

This program is based on the fact that the double palindromic numbers in base 3 all have a "1" right in the middle. Also, both base 2 and base 3 representations have an odd number of digits.

  1. 1 digit under the number of the palindromic doesn't become zero.
  2. As for the N numbering-system, at the time of the multiple of N, 1 digit below becomes zero.
  3. Palindromic by the even-number digit binary system is 3 multiples.
  4. Palindromic by the even-number digit ternary-system is 4 multiples.
  5. In palindromic by the ternary-system of the odd digit, the value of the center position is an even number in case of "0" or "2".

This program constructs base 3 palindromes using the above "rules" and checks if they happen to be binary palindromes.

<lang ruby>pal23 = Enumerator.new do |y|

 y << 0
 y << 1
 for i in 1 .. 1.0/0.0                 # 1.step do |i|  (Ruby 2.1+)
   n3 = i.to_s(3)
   n = (n3 + "1" + n3.reverse).to_i(3)
   n2 = n.to_s(2)
   y << n  if n2.size.odd? and n2 == n2.reverse
 end

end

puts " decimal ternary binary" 6.times do |i|

 n = pal23.next
 puts "%2d: %12d %s %s" % [i, n, n.to_s(3).center(25), n.to_s(2).center(39)]

end</lang>

Output:
         decimal          ternary                          binary
 0:            0             0                                0                   
 1:            1             1                                1                   
 2:         6643         100010001                      1100111110011             
 3:      1422773       2200021200022                101011011010110110101         
 4:      5415589      101012010210101              10100101010001010100101        
 5:  90396755477  22122022220102222022122   1010100001100000100010000011000010101 

zkl

Brute force, hits the wall hard after a(5) <lang zkl>fcn twoThreeP(n){

  n2s:=n.toString(2); n3s:=n.toString(3); 
  (n2s==n2s.reverse() and n3s==n3s.reverse())

} [0..].filter(5,twoThreeP) .apply2(fcn(n){println(n,"==",n.toString(3),"==",n.toString(2))}) </lang>

Output:
0==0==0
1==1==1
6643==100010001==1100111110011
1422773==2200021200022==101011011010110110101
5415589==101012010210101==10100101010001010100101