Perl Weekly Challenge 173: Esthetic Number and Sylvester's Sequence

These are some answers to the Week 173 of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few of days from now (on July 17, 2022 at 23:59). This blog post offers some solutions to this challenge, please don’t read on if you intend to complete the challenge on your own.

Task 1: Esthetic Number

You are given a positive integer, $n.

Write a script to find out if the given number is Esthetic Number.

An esthetic number is a positive integer where every adjacent digit differs from its neighbour by 1.

For example,

5456 is an esthetic number as |5 - 4| = |4 - 5| = |5 - 6| = 1
120 is not an esthetic numner as |1 - 2| != |2 - 0| != 1

Esthetic Number in Raku

We write an is-esthetic subroutine which splits the input number into an array of digits and checks, for each digit, whether the absolute value of its difference with the previous one is equal to 1. The subroutine returns False is this value is not 1. If it loops through the end, it returns True.

sub is-esthetic ($n) {
    my @d = $n.comb;     # get an array of digits
    return False if abs(@d[$_] - @d[$_-1]) != 1 for 1..@d.end;
    return True;
}
for <5456 120 121 23456 2346 7654567 765467> -> $test {
    say $test.fmt("%-9d"), is-esthetic($test) ?? "is esthetic" !! "is not esthetic";
}

This program displays the following output:

$ raku ./esthetic_nums.raku
5456     is esthetic
120      is not esthetic
121      is esthetic
23456    is esthetic
2346     is not esthetic
7654567  is esthetic
765467   is not esthetic

Esthetic Number in Perl

This is a port to Perl of the previous Raku program, with an is_esthetic subroutine returning 0 (false value) if the absolute value of the difference between two adjacent digits is not equal to 1.

use strict;
use warnings;
use feature "say";

sub is_esthetic {
    my @d = split //, shift;     # get an array of digits
    for my $i (1..$#d) {
        return 0 if abs($d[$i] - $d[$i -1 ]) != 1;
    }
    return 1;
}
for my $test (qw<5456 120 121 23456 2346 7654567 765467>) {
    say sprintf("%-9d", $test), is_esthetic($test) ? "is esthetic" : "is not esthetic";
}

This program displays the following output:

$ perl ./esthetic_nums.pl
5456     is esthetic
120      is not esthetic
121      is esthetic
23456    is esthetic
2346     is not esthetic
7654567  is esthetic
765467   is not esthetic

Esthetic Number in Julia

In Julia, you can use subscripts to access individual characters of a string:

julia> print("hello World"[5])    # Scala subscripts start at 1
o

You cannot do that in Perl and in Raku. Well, in Raku, you could implement your own postcircumfix [...] operator like this:

multi sub postcircumfix:<[ ]> (Str $s, Int $n) {
    substr-rw $s, $n, 1;
}

but it doesn’t seem to be worth the trouble for such a simple program.

Anyway since subscript can be used for that purpose in Scala, I decided that my program could easily traverse the string representation of the candidate number, without having to split it into an array of individual digits. All we need to do is to coerce the input number into a string.

function is_esthetic(num)
    n = string(num)
    for i in 2:length(n)
        if abs(n[i] - n[i-1]) != 1
            return false
        end
    end
    return true
end

for test in [5456, 120, 121, 23456, 2346, 7654567, 765467]
    println("$test\t", is_esthetic(test) ? "Esthetic" : "Non esthetic")
end

It may not be obvious, but there is quite a bit of magic going on in this line:

if abs(n[i] - n[i-1]) != 1

n[i] and n[i+1] don’t contain digits, but characters representing digits (ASCII representation). For example, if we are processing a '1' character, we are processing ASCII char 49. So, perhaps, we should convert them to integers:

if abs(Int(n[i]) - Int(n[i-1])) != 1

Well, still not quite good. If the number being tested if 12, the line above would compare integers 49 (char ’1’) and 50 (char ’2’), not numbers 1 and 2. To really compare 1 and 2, we would have to subtract Int['0'] (48) from each term:

if abs((Int(n[i]) - Int('0')) - (Int(n[i-1] - Int('0'))) != 1

Of course, subtracting Int('0') (48) from both terms of a subtraction is useless, as the result will be unchanged. But, more broadly, we don’t need to go through the trouble of casting the chars to ints, because Julia can easily compute the numerical difference between two characters. It even works with non-numerical characters such as letters:

julia> print('e' - 'c')
2

Output:

$ julia ./esthetic_nums.jl
5456    Esthetic
120     Non esthetic
121     Esthetic
23456   Esthetic
2346    Non esthetic
7654567 Esthetic
765467  Non esthetic

Esthetic Number in Python

In Python, you can also use subscripts to access individual characters of a string, so I chose to also traverse the string representation of the input integer. But it turned out to be a bit more complicated than in Julia. In Python, we need to cast the individual characters into integers to make the subtraction possible.

def is_esthetic(m):
  n = str(m)
  for i in range(1, len(n)):
    if abs(int(n[i]) - int(n[i - 1 ])) != 1:
      return False
  return True

for test in [5456, 120, 121, 23456, 2346, 7654567, 765467]:
  if is_esthetic(test):
    print("{:<9d} is esthetic".format(test))
  else:
    print("{:<9d} is not esthetic".format(test))

Output:

$ python3 ./esthetic_nums.py
5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Esthetic Number in Ruby

Like in Python, we need to cast characters to integers to make the subtraction possible in Ruby:

def is_esthetic(m)
    n = m.to_s
    for i in 1..(n.length - 1)
        if (n[i].to_i - n[i-1].to_i).abs != 1
            return false
        end
    end
    return true
end

for test in [ 5456, 120, 121, 23456, 2346, 7654567, 765467]
    printf "%-9d ", test 
    if is_esthetic(test)
        print("is esthetic\n")
    else
        print("is not esthetic\n")
    end
end

Output:

5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Esthetic Number in Ring

Like in Julia, there is no need to cast characters to integers in Ring:

for test in [5456, 120, 121, 23456, 2346, 7654567, 765467]
    see test
    if is_esthetic(test)
        see " is esthetic" + nl
    else
        see " is not esthetic" + nl
    ok
next

func is_esthetic (num)
    n = "" + num
    for i = 2 to len(n)
        if fabs(n[i] - n[i-1]) != 1
            return false
        ok
    next
    return true

Output:

$ ring ./esthetic_nums.ring
5456 is esthetic
120 is not esthetic
121 is esthetic
23456 is esthetic
2346 is not esthetic
7654567 is esthetic
765467 is not esthetic

Esthetic Number in Kotlin

Note that the subtraction n[i] - n[i-1] in the is_esthetic function works fine here because a subtraction on two Char values in Kotlin returns an Int value, so that the comments made on the Julia implementation essentially also apply to Kotlin.

import kotlin.math.abs

fun is_esthetic(num: Int): Boolean {
    val n = num.toString()
    for (i in 1..n.length - 1) {
        if (abs(n[i] - n[i-1]) != 1) {
            return false
        }
    }
    return true
}
fun main() {
    for (test in arrayOf(5456, 120, 121, 23456, 2346, 7654567, 765467)) {
        if (is_esthetic(test)) {
            println("$test is esthetic")
        } else {
            println("$test is not esthetic")
        }
    }
}

Output:

5456 is esthetic
120 is not esthetic
121 is esthetic
23456 is esthetic
2346 is not esthetic
7654567 is esthetic
765467 is not esthetic

Esthetic Number in Go

package main

import (
    "fmt"
    "strconv"
)

func is_esthetic(n int) bool {
    s := strconv.Itoa(n)
    for i := 1; i < len(s); i++ {
        if s[i]-s[i-1] != 1 && s[i-1]-s[i] != 1 {
            return false
        }
    }
    return true
}
func main() {
    tests := []int{5456, 120, 121, 23456, 2346, 7654567, 765467}
    for _, test := range tests {
        if is_esthetic(test) {
            fmt.Printf("%-9d is esthetic\n", test)
        } else {
            fmt.Printf("%-9d is not esthetic\n", test)
        }
    }
}

Output:

5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Esthetic Number in D

import std.stdio;
import std.math;
import std.conv;

bool is_esthetic(int num) {
    auto s = to!string(num, 10);
    foreach (i; 1 .. s.length) {
        if (abs(s[i] - s[i-1]) != 1) return false;
    }
    return true;
}
void main() {
    int[] tests = [ 5456, 120, 121, 23456, 2346, 7654567, 765467 ];
    foreach(test; tests) {
        printf("%-9d ", test);
        if (is_esthetic(test)) {
            writeln("is esthetic");
        } else {
            writeln("is not esthetic");
        }
    }
}

Output:

5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Esthetic Number in Nim

import strutils
import std/strformat

proc is_esthetic(num: int): bool =
  let n = intToStr(num)
  for i in 1..len(n)-1:
    if abs(int(n[i]) - int(n[i-1])) != 1:
      return false
  return true

for test in [5456, 120, 121, 23456, 2346, 7654567, 765467]:
  if is_esthetic(test):
    echo fmt("{test:<9}"), " is esthetic"
  else:
    echo fmt("{test:<9}"), " is not esthetic"

Output:

5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Esthetic Number in Rust

Sometimes, a strict typing system can be a straight jacket. Rust’s typing system seems to be such. I was’t able to find a way to subtract characters and take the absolute value of the result. So I had to use two separate conditions: if n[i] != n[i-1] + 1 && n[i-1] != n[i] + 1 ...

fn is_esthetic(num: i32) -> bool {
    let n = num.to_string();
    for i in 1..n.len() {
        if n.as_bytes()[i] != n.as_bytes()[i-1] + 1 &&
           n.as_bytes()[i-1] != n.as_bytes()[i] + 1 {
            return false
        }
    }
    return true
}

fn main() {
    for test in [5456, 120, 121, 23456, 2346, 7654567, 765467] {
        println!("{} -> {}", test, if is_esthetic (test) { " is esthetic"} else { " is not esthetic"});
    }
}

Output:

5456 ->  is esthetic
120 ->  is not esthetic
121 ->  is esthetic
23456 ->  is esthetic
2346 ->  is not esthetic
7654567 ->  is esthetic
765467 ->  is not esthetic

Esthetic Number in Scala

object esthetic extends App {
  def is_esthetic(num: Int): Boolean = {
    val digits = num.toString.split("")
    for (i <- 1 to (digits.size) - 1) {
      if ((digits(i).toInt - digits(i-1).toInt).abs != 1) {
        return false
      }
    }
    return true
  }
  val tests = List(5456, 120, 121, 23456, 2346, 7654567, 765467)
  for (test <- tests) {
    if (is_esthetic(test)) {
      println(s"$test is esthetic")
    } else {
      println(s"$test is not esthetic")
    }
  }
}

Output:

5456 is esthetic
120 is not esthetic
121 is esthetic
23456 is esthetic
2346 is not esthetic
7654567 is esthetic
765467 is not esthetic

Esthetic Number in Java

I’m not a great fan of Java, because I find it too verbose. But it is good, some times, to take a fresh look at things.

import java.lang.Math;

public class EstheticNumber {
    public static void main(String[] args) {
        Integer[] tests = {5456, 120, 121, 23456, 2346, 7654567, 765467};  
        for (int i = 0; i <= 6; i++) {
            if (is_esthetic(tests[i])) {
                System.out.printf("%-9d is esthetic\n", tests[i]);
            } else {
                System.out.printf("%-9d is not esthetic\n", tests[i]);
            }
        }
    }
    public static boolean is_esthetic(int n) {
        String s = Integer.toString(n);
        for (int i = 1; i < s.length(); i++ ) {
            if (Math.abs((int)(s.charAt(i)) - (int)(s.charAt(i-1))) != 1) {
                return false;
            }
        }
        return true;
    }
}

Output:

5456      is esthetic
120       is not esthetic
121       is esthetic
23456     is esthetic
2346      is not esthetic
7654567   is esthetic
765467    is not esthetic

Task 2: Sylvester’s Sequence

Write a script to generate first 10 members of Sylvester’s sequence. For more informations, please refer to the wikipedia page.

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Each number in the sequence is the product of all previous numbers of the sequence plus 1.

The only potential difficulty with this problem is that we’re dealing with very large integers so that, for some programming languages at least, we may encounter an integer overflow error (or values may be converted to floats, with a resulting loss of precision).

Sylvester’s Sequence in Raku

In Raku, Int objects store integral numbers of arbitrary size. So we don’t have to worry about very large integers.

We start with a direct implementation of the definition. We store the sequence in the @s array. To get a new number, we simply compute the product of all items of the @s array (using the [*] meta-operator) and add it to the array.

my @s = 2;
while @s.elems < 10 {
    push @s, 1 + [*] @s;
}
.say for @s;

This program displays the following output:

$ raku ./sylvester.raku
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

The program runs very fast, but is not as efficient as it could be because we are performing some of the multiplications many times. When computing @s[$n+1], we know that @s[$n] contains the product of all values between @s[0] and @s[$n-1] plus 1. Therefore, the n + 1 item of the sequence can be defined recursively as @s[$n] * (@s[$n] - 1) + 1, so that we can perform only one multiplication each time. This can lead to the following modified implementation:

my @n = 2;
push @n, @n[*-1] * (@n[*-1] - 1) + 1 for 1..^10;
.say for @n;

This program displays the same output as above:

$ raku ./sylvester2.raku
2
3
7
43
1807
(lines omitted for brevity)

Sylvester’s Sequence in Perl

In Perl, scalars cannot contain such large integers. But we can use the use BigInt; pragma to convert all numeric literals to Math::BigInt, which can store arbitrarily large integers.

To port the first raku program above to Perl, we implement a prod subroutine that computes the product of all items of its input.

use strict;
use warnings;
use feature "say";
use bigint;

sub prod {
    my $prod = 1;
    $prod *= $_ for @_;
    return $prod;
}

my @s = (2);
while (@s < 10) {
    push @s, 1 + prod @s;
}
say for @s;

This program displays the following output:

$ perl ./sylvester.pl
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

We can avoid the prod subroutine if we use the method of the second Raku program above:

use strict;
use warnings;
use feature "say";
use bigint;

my @s = (2);
push @s, $s[-1] * ($s[-1] - 1) + 1 for 1..9;
say for @s;

This program displays the same output:

$ perl ./sylvester2.pl
2
3
7
43
1807
(lines omitted for brevity)

Sylvester’s Sequence in bc

The Unix bc utility is an arbitrary precision calculator language, so it is tempting to use it for a problem in which the only potential difficulty is the use of very large integers. However, bc’s arrays lack many of the cool features of more modern languages. We will implement the second method above without using any array (printing the values as we compute them).

n = 2
print n, "\n"
count = 1
while (count < 10) {
    n = (n - 1) * n + 1
    print n, "\n"
    count += 1
}
quit

This script displays the following output:

$ bc ./sylvester.bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
16550664732451996419846819544443918001751315270637749784185138876653\
5868639572406808911988131737645185443

One last little problem here is that bc cannot print numbers larger than 70 digits on the same line, so that the last Sylvester number above is cut over two lines. We can pipe the bc output through a Perl one-line filter (or some other utility) to reformat properly the faulty line:

$ bc sylvester.bc | perl -pe 's/\\\s//'
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Another way is to set the BC_LINE_LENGTH environment variable to 0:

$ BC_LINE_LENGTH=0 bc sylvester.bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in dc

The Unix dc utility is also an arbitrary precision calculator language, so it is tempting to use it for a problem in which the only potential difficulty is the use of very large integers. In fact, bc used to be a standard infix front-end to the dc reverse Polish notation.

This is a dc program to display the first 10 elements of the Sylvester’s sequence:

2snlnp9sc[1-ln*1+psnlnlc1-sc0lc>m]dsmx

You can run it as follows:

$ echo '2snlnp9sc[1-ln*1+psnlnlc1-sc0lc>m]dsmx
       ' |  DC_LINE_LENGTH=0 dc
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

OK, I must admit that I golfed it. I usually try to use concise syntax, but don’t commonly golf my solutions. Here, I think that I probably deserve an award for the shortest and most obfuscated golf piece for that problem.

This is now a much more readable version of the same solution:

2sn     # push 2 on the stack, pop 2 off the top of the stack and store it into register n
lnp     # copy the value back on the stack and print it
9sc     # give counter c an initial value of 9
[       # start of macro
  1-    # subtract 1 from stack (value n-1)
  ln    # load n to stack
  *1+p  # compute product n * n-1, add 1 and print
  sn    # pop new value and store it in register n
  ln    # copy new value in  n to stack
  lc    # copy counter to stack
  1-    # decrement counter (subtract 1 from c)
  sc    # store decremented counter in c
  0 lc  # store 0 and counter on stack
  >m    # compare counter to 0 and, if c > 0, run recursively macro in m
]       # end of macro
d       # duplicate macro
sm      # store macro in register m
x       # execute first iteration of macro

Understanding the solution in details would require a lot more explanations than what I can provide here. You are kindly invited to read this other blog post where I describe in detail how I solved the problem in dc.

Sylvester’s Sequence in Julia

With regular integers, we obtain totally wrong results, including negative integers and so forth. All we need to do to fix that problem is to declare our initial variable as a BigInt:

s = BigInt(2)
println(s)
for i in 1:9
    s = s * (s - 1) + 1
    println(s)
end

Output:

$ julia ./sylvester.jl
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Python

Recent versions of Python automatically switch to big integers when needed:

s = [2];
for i in range(9):
  s.append(s[-1] * (s[-1] - 1) + 1)
for j in s:
  print(j)

Output:

$ python3 sylvester.py
2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Ruby

# Ruby automatically switches to Bignum when needed
s = 2
print("#{s}\n")
for i in 1..9
    s = s * (s - 1) + 1
    print("#{s}\n")
end

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Ring

As far as I can tell, Ring doesn’t have a BigNum package. But Ring gracefully switches to floating point arithmetics and thus produces fairly decent approximations of the expected result.

s = 2;
see s + nl
for i = 1 to 9
    s = s * (s - 1) + 1
    see s + nl
next

Output:

$ ring ./sylvester.ring
2
3
7
43
1807
3263443
10650056950807
113423713055421845118910464.00
12864938683278672079501004830742670366487445279604736.00
1.655066473245199625930595525909356695752320791312711997146979916612453687017861571473280717e+104

The three last Sylvester numbers above are computed with floating point arithmetics. As you can see if you compare with the results obtained with other languages above, only the first 16th to 17th digits are accurate.

Sylvester Sequence in Scala

Like in Julia, we only need to declare our initial variable as a BigInt to get the correct results in Scala:

object sylvester extends App {
  var n = BigInt(2)
  println(n)
  for (i <- 1 to 9) {
    n = n * (n - 1) + 1
    println(n)
  }
}

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Kotlin

In Kotlin, we import the java java.math.BigInteger library. Note that it doesn’t know how to mix BigInteger numbers with standard integers in computations, so we need to create one, a BigInteger for 1.

import java.math.BigInteger

fun main () {
    var n = BigInteger("2")
    val one = BigInteger("1")
    for (i in 1..9) {
        n = n * (n - one) + one
        println(n)
    }
}

Output:

3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in D

import std.stdio;
import std.bigint;

void main() {
    BigInt s = "2";
    writeln(s);
    for (int i = 1; i <= 9; i++) {
        s = s * (s - 1) + 1;
        writeln(s);
    }
}

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Lua

I did not succeed to use the library for large integers. Perhaps my Lua installation is faulty, or I missed something else. I still want to show the result to illustrate how wrong a program can go in the event of an integer overflow not properly managed. We’ve seen before that Ring (for example) automatically switches to floats and provides results accurate to the first 16 decimal places. In Lua, this goes horribly wrong, and displays even negative integers.

-- Does not work properly
s = 2
print(s)
for i = 1, 9 do
    s = s * (s - 1) + 1
    print(s)
end

Output:

2
3
7
43
1807
3263443
10650056950807
-3591524960174918149
-8362769992138052065
4108952388197251491

Sylvester’s Sequence in Go

This works properly, but the method-invocation syntax for using big integers in Go is just plainly horrible and very difficult to use. I expected better from one of the world’s largest and wealthiest corporations and some legendary computer scientists, especially when it is claimed that Go was designed to be simple. OK, I must admit that it is still simpler than dc (see above), but dc was designed and written almost half a century ago.

// Go big int syntax really sucks
package main

import (
    "fmt"
    "math/big"
)

func main() {
    s := big.NewInt(2)
    fmt.Println(0, ": ", s)
    one := big.NewInt(1)
    for i := 1; i <= 9; i++ {
        s.Add(new(big.Int).Mul(s, s), new(big.Int).Sub(one, s))
        fmt.Println(i, ": ", s)
    }
}

Output:

0 :  2
1 :  3
2 :  7
3 :  43
4 :  1807
5 :  3263443
6 :  10650056950807
7 :  113423713055421844361000443
8 :  12864938683278671740537145998360961546653259485195807
9 :  165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Nim

import bigints

var s = 2.initBigInt
echo s
for i in 1..9:
    s = s * (s - 1) + 1
    echo s

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Dart

Like in Kotlin, BigInt objects don’t mix in properly with regular integers in Dart. So we need to declare a one BigInt object for integer 1.

void main() { var s = BigInt.from(2); print(s); var one = BigInt.from(1); for (int i = 1; i <= 9; i++) { s = s * (s - one) + one; print(s); } }

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in JavaScript

Here, again, we need to declare a one BigInt object for integer 1.

let s = BigInt (2)
let one = BigInt (1)
console.log(s + " ");
for (let i = 1; i <= 9; i++) {
    s = s * (s - one) + one
    console.log(s + " ");
}

Output:

2 
3 
7 
43 
1807 
3263443 
10650056950807 
113423713055421844361000443 
12864938683278671740537145998360961546653259485195807 
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in TCL

TCL natively supports arbitrarily large integers.

set s 2
puts $s
for {set i 1} {$i <= 9} {incr i} {
    set s [expr ($s * ($s - 1) + 1)]
    puts $s
}

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Sylvester’s Sequence in Java

I said before that I found Java to be a bit too verbose. If you don’t know what I mean, just compare the Java solution below with the TCL solution above.

import java.math.BigInteger;

public class Sylvester {
    public static void main(String[] args) {
        BigInteger n = BigInteger.valueOf(2);
        System.out.printf("%s\n", n);
        BigInteger one = BigInteger.valueOf(1);
        for (int i = 1; i <= 9; i++) {
            n = (n.multiply(n.subtract(one))).add(one);
            System.out.printf("%s\n", n);
        }
    }
}

Output:

2
3
7
43
1807
3263443
10650056950807
113423713055421844361000443
12864938683278671740537145998360961546653259485195807
165506647324519964198468195444439180017513152706377497841851388766535868639572406808911988131737645185443

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 24, 2022. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.