Finding palindromic numbers most efficiently
Here, you first check if $x is palindrome, but then you will only print it if $x &gt; $lm:


if ($x eq reverse $x) {
    print "$x is $a * $b" if ($x &gt; $lm);
    last if ($n &gt; 3); # show them all for small numbers
}



It would be more efficient to do the other way around, checking $x &gt; $lm first:

if ($x &gt; $lm) {
    if ($x eq reverse $x) {
        print "$x is $a * $b";
        last if ($n &gt; 3); # show them all for small numbers
    }
}


With \$n = 3\$, this makes a big difference: it saves reversing $x 23602 times.

I also tried rewriting the reverse operation,
somewhat inspired by the the duck's comment:
instead of comparing an entire string with its reverse,
it should be more efficient to compare its first half with the reverse of its second half:

sub is_palindrome {
    my ($word) = (@_);
    my $l = length($word);
    foreach my $i (0 .. $l / 2) {
        if (substr($word, $i, 1) ne substr($word, $l - $i - 1, 1)) {
            return;
        }
    }
    return 1;
}


Although this function does only half of the comparisons as in $x eq reverse $x,
at least as interpreted code, this cannot compete with the speed of the compiled reverse function. Using this function the script runs much slower, unfortunately.