Compare a sequence with the reference frequency of hexamers
I removed your comments and inserted mine.

# Documentation goes to POD.

=item comparer

Compare a sequence with the reference frequency of hexamers.

First argument the file of to analyse, second argument the file of reference

=cut

sub comparer {
    my ($seq, $ref_seq) = @_; # I like arguments being processed as the first step in the sub. No need to shift twice.

    my %score;
    my %freq_ref = hexamer_freq({ read_fasta($$ref_seq) });
    my %seqs = read_fasta($seq);

    while (my ($id,  $sequen) = each %seqs) {
        my @id_seq = split ' ', $id;
        my @id_name = split /\./, $id_seq[0];
        my ($max, $min);
        for my $i (0 .. 2) {  # No need for a C-style for.
            last if length $sequen &lt;= $i;

            my $sequ = substr $sequen, $i;
            next unless defined $sequ;

            my $rev_sequ = reverse $sequ;
            my @seqs = ($sequ, $rev_sequ);

            for my $j (0 .. $#seqs) {  # C-style eliminated again.
                my %freq_seq = hexamer_freq({ $id_name[0] =&gt; $seqs[$j] }); # Anonymous hash.

                if (keys %freq_seq == 0) {
                    print STDERR log_time(), "Unable to calculate the Hexamer score of $id_name[0]\n";
                    next
                }

                my $score = 0;
                my $n_hexamers = keys %freq_seq; # "scalar" not needed in scalar context.
                for my $hex (keys %freq_seq){
                    if (defined $freq_ref{$hex}){
                        $score += log2($freq_seq{$hex} / $freq_ref{$hex});
                    }
                }

                if (! defined $max || $score / $n_hexamers &gt; $max) {
                    $max = $score / $n_hexamers;
                }
                if (!defined $min || $score / $n_hexamers &lt;= $min) {
                    $min = $score / $n_hexamers
                }

                my $key = $id_name[0] . " frame: $i";
                $key .= (' FWD', ' REV')[$j] if $j &lt; 2;  # Poor man's "switch".
                $score{$key} = [$max, $min];
            }
        }
    }
    return %score
}



There's no need to call subroutines with the &amp; prepended.
Semicolons after blocks are not needed.
To avoid guessing the minimum, just use undef and check for that in the condition. You could also try 'INF', but it's not portable.
Why is the subroutine's second parameter a scalar reference? Is it a very long string?