Palindromic Set
with Raku and Perl

by Arne Sommer

Palindromic Set with Raku and Perl

[130] Published 29. May 2021.

This is my response to the Perl Weekly Challenge #114.

Challenge #114.1: Next Palindrome Number

You are given a positive integer $N.

Write a script to find out the next Palindrome Number higher than the given integer $N.

Example:
Input: $N = 1234
Output: 1331

Input: $N = 999
Output: 1001

We have handled palindromic numbers before in the weekly challenges. See Palindromic Stack with Raku and Perl (Challenge 095.1: Palindrome Number) for the last one.

File: next-palindrome-number
#! /usr/bin/env raku

unit sub MAIN (Int $N where $N > 0, :v($verbose));  # [1]

for $N + 1 .. Inf -> $candidate                     # [2]
{
  say ": Candidate $candidate" if $verbose;

  if $candidate eq $candidate.flip                  # [3]
  {
    say $candidate;                                 # [4]
    exit;                                           # [4a]
  }
}

[1] Ensure a positive integer.

[2] Start with the very next number ($N + 1), and go on indefinitely.

[3] TIs the number palindromic?. We use flip to reverse a string. (Note that reverse will reverse the order of items in an array, list etc.) Note the use of string comparison eq to ensure that leading zeroes (after the flip) are retained. Also note that this does not really matter here, as stripping them away will give a shorter string - which cannot be palindromic.

[4] print the number, and exit [4a].

See docs.raku.org/routine/flip for more information about flip.

See docs.raku.org/routine/reverse for more information about reverse.

Running it:

$ ./next-palindrome-number 1234
1331

$ ./next-palindrome-number 999
1001

With verbose mode:

$ ./next-palindrome-number -v 1234
: Candidate 1235
: Candidate 1236
…
: Candidate 1330
: Candidate 1331
1331

$ ./next-palindrome-number -v 999
: Candidate 1000
: Candidate 1001
1001

A Perl Version

This is a straight forward translation of the Raku version.

File: next-palindrome-number-perl
#! /usr/bin/env perl

use strict;
use warnings;
use feature 'say';
use Getopt::Long;

my $verbose = 0;

GetOptions("verbose"  => \$verbose);

my $N = $ARGV[0] // die "Specify a positive integer";

die "Not a positive integer" unless $N =~ /^[1-9]\d*$/;

while ($N++)                   # [1]
{
  say ": Candidate $N" if $verbose;

  if ($N eq reverse($N))       # [2]
  {
    say $N;
    exit;
  }
}

[1] Perl does not have an infinity value, but we can count up like this.

[2] Note that reverse works on strings as well as lists (as opposed to in Raku).

Running it gives the same result as the Raku version:

$ ./next-palindrome-number-perl 1234
1331

$ ./next-palindrome-number-perl 999
1001

$ ./next-palindrome-number-perl -v 999
: Candidate 1000
: Candidate 1001
1001

Challenge #114.2: Higher Integer Set Bits

You are given a positive integer $N.

Write a script to find the next higher integer having the same number of 1 bits in binary representation as $N.

Example:
Input: $N = 3
Output: 5

Binary representation of $N is 011. There are two 1 bits. So the next
higher integer is 5 having the same the number of 1 bits i.e. 101.

Input: $N = 12
Output: 17

Binary representation of $N is 1100. There are two 1 bits. So the next
higher integer is 17 having the same number of 1 bits i.e. 10001.

We have handled binary numbers before as well. See Counting Water with Raku and Perl (Challenge 079.1: Count Bit Set) for the last one.

File: higher-integer-set-bits
#! /usr/bin/env raku

unit sub MAIN (Int $N where $N > 0, :v($verbose));        # [1]

my $ones = $N.fmt('%b').comb.sum;                         # [2]

if $verbose
{
  say ": Initial value: $N (binary: { $N.fmt('%b') })";
  say ": - Number of one bits: $ones";
}

for $N + 1 .. Inf -> $candidate                           # [3]
{
  say ": Candidate $candidate (binary: { $candidate.fmt('%b') })" if $verbose;

  if $candidate.fmt('%b').comb.sum == $ones               # [4]
  {
    say $candidate;                                       # [4a]
    exit;                                                 # [4b]
  }
}

[1] Ensure a positive integer (again).

[2] Convert the (decimal) number to binary (fmt('%b')), split it into indididual digits (comb) and count the number of ones (with sum - as zeroes does not add up to anything).

[3] Start with the very next number, and go on to infinity.

[4] Does the current candidate have the same number of ones? If so print it [4a] and exit [4b].

See docs.raku.org/routine/fmt more information about fmt.

Running it:

$ ./higher-integer-set-bits 3
5

$ ./higher-integer-set-bits 12
17

With verbose mode:

$ ./higher-integer-set-bits -v 3
: Initial value: 3 (binary: 11)
: - Number of one bits: 2
: Candidate 4 (binary: 100)
: Candidate 5 (binary: 101)
5

$ ./higher-integer-set-bits -v 12
: Initial value: 12 (binary: 1100)
: - Number of one bits: 2
: Candidate 13 (binary: 1101)
: Candidate 14 (binary: 1110)
: Candidate 15 (binary: 1111)
: Candidate 16 (binary: 10000)
: Candidate 17 (binary: 10001)
17

Looking good.

Perl

This is a straight forward translation of the Raku version.

File: higher-integer-set-bits-perl
#! /usr/bin/env perl

use strict;
use warnings;
use feature 'say';
use List::Util qw/sum/;
use Getopt::Long;

my $verbose = 0;

GetOptions("verbose"  => \$verbose);

my $N = $ARGV[0] // die "Specify a positive integer";

die "Not a positive integer" unless $N =~ /^[1-9]\d*$/;

my $ones = sum(split(//, sprintf('%b', $N)));

if ($verbose)
{
  say ": Initial value: $N (binary: ", sprintf('%b', $N) , ")";
  say ": - Number of one bits: $ones";
}

while ($N += 1)
{
  say ": Candidate $N (binary: ", sprintf('%b', $N), ")" if $verbose;

  if (sum(split(//, sprintf('%b', $N))) == $ones)
  {
    say $N;
    exit;
  }
}

Running it gives the same result as the Raku version:

$ ./higher-integer-set-bits-perl 3
5

$ ./higher-integer-set-bits-perl 12
17

$ ./higher-integer-set-bits-perl -v 3
: Initial value: 3 (binary: 11)
: - Number of one bits: 2
: Candidate 4 (binary: 100)
: Candidate 5 (binary: 101)
5

$ ./higher-integer-set-bits-perl -v 12
: Initial value: 12 (binary: 1100)
: - Number of one bits: 2
: Candidate 13 (binary: 1101)
: Candidate 14 (binary: 1110)
: Candidate 15 (binary: 1111)
: Candidate 16 (binary: 10000)
: Candidate 17 (binary: 10001)
17

And that's it.