Use of inintialized value $ in concatenation (.) Perl - perl

use warnings;
$a = 5;
$c = 3;
$i;
$x = time();
$m = 32;
$caracter_aleatorio;
#caracteres = (A..Z);
print "Ingrese la cantidad de letras que desea generar=> ";
$n = <STDIN>;
sub generadorMultiplicativo{
$numAleatorio = ((($a*$x) + $c) % $m);
$x = $numAleatorio;
}
for($i=1;$i<=$n;$i++){
&generadorMultiplicativo();
$caracter_aleatorio = $caracteres[$numAleatorio];
if($numAleatorio == 0){
$numAleatorio++;
}
if($numAleatorio > 26){
$numAleatorio = $numAleatorio - 5;
}
print"Letra #$i = $caracter_aleatorio\n";
}
<>;
I know this warning is when the variable doesn't have a value, but I´ve tried everything but it´s the same, it´s a generator of "random" letters.
Could you help me?

Always use strict when writing new code.
Uninitialized warnings means that your $caracter_aleatorio variable is undefined, so you should set a default. Undefined variables are usually a sign of buggy code.
Declare your variables using my
One-letter variables should be avoided for maintenance / readability reasons.
No-longer need to call functions with &foo() notation, foo() is fine.
Use quotes around A and Z to generate the range.
Here is an updated version of your code:
use strict;
use warnings;
my $a = 5;
my $c = 3;
my $i;
my $x = time();
my $m = 32;
my $caracter_aleatorio;
my $numAleatorio;
my #caracteres = ('A'..'Z');
print "Ingrese la cantidad de letras que desea generar=> ";
my $n = <STDIN>;
sub generadorMultiplicativo{
$numAleatorio = ((($a*$x) + $c) % $m);
$x = $numAleatorio;
}
for( $i=1; $i<=$n; $i++ ) {
generadorMultiplicativo();
$caracter_aleatorio = $caracteres[$numAleatorio] || 'unknown';
if($numAleatorio == 0){
$numAleatorio++;
}
if($numAleatorio > 26){
$numAleatorio = $numAleatorio - 5;
}
print"Letra #$i = $caracter_aleatorio\n";
}
Suggestions to improve further:
Learn how to accept/return parameters from subroutines. perldoc perlsub
Input validation, what if I pass in 'abc' instead of 123, numeric vs string comparison operators ( <= vs lt, == vs eq, >= vs gt, etc. ).
Write comments to show high level intent of your code.
Provide a usage/help message to show a new user how to use your script.
The perl documentation is excellent, have a read through perldoc perlintro

To see the issue, after you call generadorMultiplicativo(); you can do some debug printing of $numAleatorio to see that it sometimes goes higher than you intend. That is, it can be greater than 25.
print "DEBUG: $numAleatorio of $#caracteres\n";
Your method tries to fix these out of bounds values, but you have some issues:
26 as the upper limit instead of 25
You subtract 5 if above upper bound but sometimes you are more than 5 above upper bound.
Your pseudorandom number generator is generating values too high.
Recommended rewrite:
use strict;
use warnings;
my #caracteres = ('A'..'Z');
print "Ingres la cantidad de letras que desea generar=> ";
while(my $n = <STDIN>) {
last unless $n =~ /^[0-9]+$/; # Check upper limit?
for (1.. $n) {
print "Letras #%d = %s\n", $_, $caracteres[int(rand(26))];
}
}
Does almost the same thing except you can keep asking for more random chars. Just enter non-digit to exit.
First post/answer and typed on my phone so please forgive my mistakes!

Related

non-numeric argument from user input

In this code the user is asked to input a number from the keyboard. The variable is then used again at a later point in division.
When the code is run it receives a
360/(whatever number was typed) isn't numeric in addition.
Is Perl interpreting the user input as a string instead of a numeric value?
use strict;
use warnings;
use Language::Logo;
print "Enter a number: ";
chomp(my $number = <STDIN>);
my $lo = new Logo(title => "Logo Demonstration");
$lo->command("update 2; color random; pendown; hideturtle");
for ( my $i = 1; $i < 999; $i++ ) {
my $distance = $i / 4;
$lo->command("forward $distance; right 360/$number");
}
$lo->disconnect("Press ctrl+c to exit");
What if you try:
$lo->command("forward $distance; right " . (360/$number));
If that doesn't work, try to force Perl to "see" $number as a number by adding 0 to it:
$rotation = 360 / ($number+0);
$command = "forward $distance; right " . $rotation;
$lo->command($command);
And if that doesn't work either, try to manually set $command to something that DOES work, and report back.

Scoping in Perl

As a biology student, I'm trying to extend my programming knowledge and I ran into a problem with Perl.
I'm trying to create a program that generates random DNA strings and performs analysis work on the generated data.
In the first part of the program, I am able to print out the strings stored in the array, but the second part I cannot retrieve all but one of the elements of the array.
Could this be part of the scoping rules of Perl?
#!usr/bin/perl
# generate a random DNA strings and print it to file specified by the user.
$largearray[0] = 0;
print "How many nucleotides for the string?\n";
$n = <>;
$mylong = $n;
print "how many strings?\n";
$numstrings = <>;
# #largearray =();
$j = 0;
while ( $j < $numstrings ) {
$numstring = ''; # start with the empty string;
$dnastring = '';
$i = 0;
while ( $i < $n ) {
$numstring = int( rand( 4 ) ) . $numstring; # generate a new random integer
# between 0 and 3, and concatenate
# it with the existing $numstring,
# assigning the result to $numstring.
$i++; # increase the value of $i by one.
}
$dnastring = $numstring;
$dnastring =~ tr/0123/actg/; # translate the numbers to DNA characters.
#print $dnastring;
#print "\n";
$largearray[j] = $dnastring; #append generated string to end of array
#print $largearray[j];
#print $j;
#IN HERE THERE ARE GOOD ARRAY VALUES
#print "\n";
$j++;
}
# ii will be used to continuously take the next couple of strings from largearray
# for LCS matching.
$mytotal = 0;
$ii = 0;
while ( $ii < $numstrings ) {
$line = $largearray[ii];
print $largearray[ii]; #CANNOT RETRIEVE ARRAY VALUES
print "\n";
$ii++;
#string1 = split( //, $line );
$line = $largearray[ii];
#print $largearray[ii];
#print "\n";
$ii++;
chomp $line;
#string2 = split( //, $line );
$n = #string1; #assigning a list to a scalar just assigns the
#number of elements in the list to the scalar.
$m = #string2;
$v = 1;
$Cm = 0;
$Im = 0;
$V[0][0] = 0; # Assign the 0,0 entry of the V matrix
for ( $i = 1; $i <= $n; $i++ ) { # Assign the column 0 values and print
# String 1 See section 5.2 of Johnson
# for loops
$V[$i][0] = -$Im * $i;
}
for ( $j = 1; $j <= $m; $j++ ) { # Assign the row 0 values and print String 2
$V[0][$j] = -$Im * $j;
}
for ( $i = 1; $i <= $n; $i++ ) { # follow the recurrences to fill in the V matrix.
for ( $j = 1; $j <= $m; $j++ ) {
# print OUT "$string1[$i-1], $string2[$j-1]\n"; # This is here for debugging purposes.
if ( $string1[ $i - 1 ] eq $string2[ $j - 1 ] ) {
$t = 1 * $v;
}
else {
$t = -1 * $Cm;
}
$max = $V[ $i - 1 ][ $j - 1 ] + $t;
# print OUT "For $i, $j, t is $t \n"; # Another debugging line.
if ( $max < $V[$i][ $j - 1 ] - 1 * $Im ) {
$max = $V[$i][ $j - 1 ] - 1 * $Im;
}
if ( $V[ $i - 1 ][$j] - 1 * $Im > $max ) {
$max = $V[ $i - 1 ][$j] - 1 * $Im;
}
$V[$i][$j] = $max;
}
} #outer for loop
print $V[$n][$m];
$mytotal += $V[$n][$m]; # append current result to the grand total
print "\n";
} # end while loop
print "the average LCS value for length ", $mylong, " strings is: ";
print $mytotal/ $numstrings;
This isn't a scoping issue. You have declared none of your variables, which has the effect of implicitly making them all global and accessible everywhere in your code
I reformatted your Perl program so that I could read it, and then added this to the top of your program
use strict;
use warnings 'all';
which are essential in every Perl program you write
Then I added
no strict 'vars';
which is a very bad idea, and lets you get away without declaring any variables
The result is this
Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 60.
Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 61.
Argument "ii" isn't numeric in array element at E:\Perl\source\dna.pl line 67.
Argument "j" isn't numeric in array element at E:\Perl\source\dna.pl line 42.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 60.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 61.
Bareword "ii" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 67.
Bareword "j" not allowed while "strict subs" in use at E:\Perl\source\dna.pl line 42.
Execution of E:\Perl\source\dna.pl aborted due to compilation errors.
Line 42 (of my reformatted version) is
$largearray[j] = $dnastring
and lines 60, 61 and 67 are
$line = $largearray[ii];
print $largearray[ii]; #CANNOT RETRIEVE ARRAY VALUES
and
$line = $largearray[ii];
You are using j and ii as array indexes. Those are Perl subroutine calls, not variables. Adding use strict would have stopped this from compiling unless you had also declared sub ii and sub j
You might get away with it if you just change j and ii to $j and $ii, but you are certain to get into further problems
Please make the same changes to your own code, and declare every variable that you need using my as close as possible to the first place they are used
You should also improve your variable naming. Things like #largearray are pointless: the # says that it's an array, and whether it's large or not is relative, and of little use in understanding your code. If you have no better description of its purpose then #table or #data are probably a little better
Likewise, please avoid capital letters and most single-letter names. #V, $Cm and $Im are meaningless, and you would need fewer comments if those names were better
You certainly wouldn't need comments like # end while loop and # outer for loop if you had indented your blocks properly and kept them short enough so that both the beginning and the end can be seen on the screen at the same time, and the fewer comments you can get away with the better, because they badly clutter the code structure
Finally, it's worth noting that the C-style for loop is rarely the best choice in Perl. Your
for ( $i = 1; $i <= $n; $i++ ) { ... }
is much clearer as
for my $i ( 1 .. $n ) { ... }
and declaring the control variable at that point makes it unnecessary to invent new names like $ii for each new loop
I think you have a typo in your code:
ii => must be $ii
don't forget to put this at the beginning of your code:
use strict;
use warnings;
in order to avoid this (and others) kind of errors

Using big numbers in Perl

I have a scenario where I take 2 very big binary strings (having 100 characters) and I need to add them.
The issue is that I am getting the answer in the form 2.000xxxxxxxxxxe+2, whereas I need the precise answer, as another 100 character long string.
chomp($str1=<STDIN>);
chomp($str2=<STDIN>);
print "Str 1 is $str1\n";
print "Str 2 is $str2\n";
$t = $str1 + $str2;
print "Sum is $t\n";
Sample Input
1001101111101011011100101100100110111011111011000100111100111110111101011011011100111001100011111010
1001101111101011011100101100100110111011111011000100111100111110111101011011011100111001100011111010
Sample Output
Str1 is
1001101111101011011100101100100110111011111011000100111100111110111101011011011100111001100011111010
Str2 is
1001101111101011011100101100100110111011111011000100111100111110111101011011011100111001100011111010
Sum is
2.0022022220202e+099
As already suggested, you can use Math::BigInt core module,
use Math::BigInt;
# chomp($str1=<STDIN>);
# chomp($str2=<STDIN>);
# print "Str 1 is $str1\n";
# print "Str 2 is $str2\n";
my $t = Math::BigInt->new("0b$str1") + Math::BigInt->new("0b$str2");
print $t->as_bin;
In order to perform arithmetic on your strings, Perl converts them to floating-point numbers, which are inherently imprecise. If you want to avoid that, use Math::BigInt as already suggested ... or roll your own.
######## WARNING/GUARANTEE: This is practically certain to be
# slower, buggier, less portable, and less secure than Math::BigInt.
# In fact, I planted a security hole just to prove a point. Enjoy.
use strict;
use warnings;
sub addition {
my ($int1, $int2) = #_;
my #int1 = reverse split //, $int1;
my #int2 = reverse split //, $int2;
my $len = scalar(#int1>#int2 ? #int1 : #int2);
my #result;
my $carry = 0;
for (my $i=0; $i < $len; ++$i)
{
$int1[$i] |= 0;
$int2[$i] |= 0;
my $sum = $carry + $int1[$i] + $int2[$i];
if ($sum >= 10)
{
$carry = int($sum / 10);
$sum %= 10;
}
push #result, $sum;
}
push #result, $carry if $carry;
return join ('', reverse #result);
}

Perl: subroutine throwing error with $i

Good morning,
I'm having trouble using a subroutine - if I put certain code into the subroutine, it throws an error of "use of uninitialised value $i in array element".
I have a very long script, so I will only post the bit I believe is relevant.
The subroutine I am calling is commented out underneath &exon_positive_strand (saves you scrolling down). When I remove the subroutine and uncomment the code, I get no errors. I can only imagine it is something to do with $i but I don't know what...
Any advice would be greatly appreciated.
Many thanks,
Ellie
my ($value, $col, $col2, $l_o_b, $left, $matchedID, $diff_three_prime, $diff_five_prime, $sequence, #three_prime_ss, #five_prime_ss, #reverse_five, #reverse_three);
my $i = 0;
open (EXONS_five, '>fasta_exons_five_non');
open (EXONS_three, '>fasta_exons_three_non');
foreach my $match(#exonic_matches) { ## works out exon from boundary relative to correct strand direction ##
if ($exon_ID[$i] !~ m/unknown/ && $dupmatches[$i] == 0)
{
$sequence = '';
$value = $exon_ID[$i];
$col = $exon_left{$value};
$col2 = $exon_right{$value};
#three_prime_ss = split(",", $col); ##splits left column into subcolumns
#five_prime_ss = split(",", $col2); ## splits right columnn into subcolumns
#reverse_three = reverse(#three_prime_ss);
#reverse_five = reverse(#five_prime_ss);
shift(#reverse_five);
if ($strands{$value} =~ m/\+/) {
&exon_positive_strand;
# $diff_three_prime = $LBP[$i] - $three_prime_ss[$exons2{$value} - 1]; ## minus numbers denote a difference to the left (i.e. upsteam)
# $diff_five_prime = $LBP[$i] - $five_prime_ss[$exons2{$value} - 1]; ## minus numbers denote a difference to the left (i.e. upsteam)
# $matchedID = $ID{$LBP[$i]};
# if ($diff_three_prime !~ m/\-/ && $diff_three_prime <= 3) {
# $BP{$LBP[$i]} =~ s/\[[ACTG]\]/$ref[$i]/i; ## putting variant into 50BP seq
# $l_o_b = 20;
# ##$right_of_boundary = 3;
# $l_o_b = $l_o_b + $diff_three_prime;
# $left = 51 - $l_o_b;
# $sequence = substr($BP{$LBP[$i]}, $left, 23);
# }
# elsif ($diff_five_prime =~ m/\-/ && $diff_five_prime >= -3) {
# $BP{$LBP[$i]} =~ s/\[[ACTG]\]/$ref[$i]/i; ## putting variant into 50BP seq
# $l_o_b = 3;
# ##$right_of_boundary = 6;
# $l_o_b = $l_o_b + $diff_five_prime;
# $left = 51 - $l_o_b;
# $sequence = substr( $BP{$LBP[$i]}, $left, 9);
}
}
my $seq_length = length($sequence);
if ($seq_length == 9) {
print EXONS_five (">" . "$match_exon{$col_exon_no[$i]}" . "\n", lc($sequence),"\n");
}
elsif ($seq_length == 23) {
print EXONS_three (">" . "$match_exon{$col_exon_no[$i]}" . "\n", lc($sequence),"\n");
}
$i++;
}
close (EXONS_five);
close (EXONS_three);
"Use of uninitialized value in array element" is not an error, it's a warning. Diagnostics can tell you what it means:
(W uninitialized) An undefined value was used as if it were already
defined. It was interpreted as a "" or a 0, but maybe it was a mistake.
To suppress this warning assign a defined value to your variables.
To help you figure out what was undefined, perl will try to tell you the
name of the variable (if any) that was undefined. In some cases it cannot
do this, so it also tells you what operation you used the undefined value
in. Note, however, that perl optimizes your program and the operation
displayed in the warning may not necessarily appear literally in your
program. For example, "that $foo" is usually optimized into "that "
. $foo, and the warning will refer to the concatenation (.) operator,
even though there is no . in your program.
You need to pass the $i variable to the subroutine:
exon_positive_strand($i);
and
sub exon_positive_strand {
my $i = shift;
...

Perl Recursion and Functions

Having heard about Perl for year I decided to give it a few hours of my time to see how much I could pick up. I got through the basics fine and then got to loops. As a test I wanted to see if I could build a script to recurse through all alphanumerical values of up to 4 characters. I had written a PHP code that did the same thing some time ago so I took the same concept and used it. However when I run the script it puts "a" as the first 3 values and then only loops through the last digit. Anyone see what I am doing wrong?
#!/usr/local/bin/perl
$chars = "abcdefghijklmnopqrstuvwxyz";
$chars .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$chars .= "0123456789";
#charset = split(//, $chars);
$charset_length = scalar(#charset);
sub recurse
{
($width, $position, $base_string) = #_;
for ($i = 0; $i < $charset_length; ++$i) {
$base = $base_string . $charset[$i];
if ($position < $width - 1) {
$pos = $position + 1;
recurse($width, $pos, $base);
}
print $base;
print "\n";
}
}
recurse(4, 0, '');
This is what I get when I run it:
aaaa
aaab
aaac
aaad
aaae
aaaf
aaag
aaah
aaai
aaaj
aaak
aaal
aaam
aaan
aaao
aaap
aaaq
aaar
aaas
aaat
aaau
aaav
aaaw
aaax
aaay
aaaz
aaaA
aaaB
aaaC
aaaD
aaaE
aaaF
aaaG
aaaH
aaaI
aaaJ
aaaK
aaaL
aaaM
aaaN
aaaO
aaaP
aaaQ
aaaR
aaaS
aaaT
aaaU
aaaV
aaaW
aaaX
aaaY
aaaZ
aaa0
aaa1
aaa2
aaa3
aaa4
aaa5
aaa6
aaa7
aaa8
aaa9
aaa9
aaa9
aaa9
You've been bitten by non strict scoping, this code does what it should (note the use strict at the top and the subsequent use of my to guarantee variable scoping).
#!/usr/bin/env perl
use strict;
use warnings;
my $chars = "abcdefghijklmnopqrstuvwxyz";
$chars .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$chars .= "0123456789";
my #charset = split(//, $chars);
my $charset_length = scalar(#charset);
sub recurse {
my ($width, $position, $base_string) = #_;
for (my $i = 0; $i < $charset_length; ++$i) {
my $base = $base_string . $charset[$i];
if ($position < $width - 1) {
my $pos = $position + 1;
recurse($width, $pos, $base);
}
print $base;
print "\n";
}
}
recurse(4, 0, '');
Already well answered, but a more idiomatic approach would be:
use strict;
use warnings;
sub recurse {
my ($width, $base_string, $charset) = #_;
if (length $base_string) {
print "$base_string\n";
}
if (length($base_string) < $width) {
$recurser->($base_string . $_) for #$charset;
}
}
my #charset = ('a'..'z', 'A'..'Z', '0'..'9');
recurse(4, '', \#charset);
There's no need to pass position; it's implicit in the width of the base string passed in. The charset, on the other hand, should be passed in rather than having the subroutine use an external variable.
Alternatively, since the width and character set stay constant, generate a closure that references them:
use strict;
use warnings;
sub make_recurser {
my ($width, $charset) = #_;
my $recurser;
$recurser = sub {
my ($base_string) = #_;
if (length $base_string) {
print "$base_string\n";
}
if (length($base_string) < $width) {
$recurser->($base_string . $_) for #$charset;
}
}
}
my #charset = ('a'..'z', 'A'..'Z', '0'..'9');
my $recurser = make_recurser(4, \#charset);
$recurser->('');
Alternatively, just:
print "$_\n" for glob(('{' . join(',', 'a'..'z', 'A'..'Z', '0'..'9') . '}') x 4);
It has to do with the scope of the variables, you're still changing the same vars when you're calling the recursion. The keyword 'my' declares the variables local to the subroutine.
(http://perl.plover.com/FAQs/Namespaces.html)
I always use perl with 'use strict;' declared, forcing me to decide on the scope of the variables.
sub recurse {
my ($width, $position, $base_string) = #_;
for (my $i = 0; $i < $charset_length; ++$i) {
my $base = $base_string . $charset[$i];
if ($position < $width - 1) {
my $pos = $position + 1;
recurse($width, $pos, $base);
}
print $base;
print " ";
}
}
You seem to be running into some scoping issues. Perl is very flexible, so it is taking a guess at what you want because you haven't told it what you want. One of the first things you'll learn is to add use strict; as for your first statement after the shebang. It will point out the variables that are not being explicitly defined, as well as any variables that are accessed before being created (helps with misspelled variables, etc).
If you make your code look like this, you'll see why you are getting your errors:
sub recurse {
($width, $position, $base_string) = #_;
for ($i = 0; $i < $charset_length; ++$i) {
$base = $base_string . $charset[$i];
if ($position < $width - 1) {
$pos = $position + 1;
recurse($width, $pos, $base);
}
# print "$base\n";
}
print "$position\n";
}
This should output:
3
3
3
3
Because you are not scoping $position correctly with my, you aren't getting a new variable each recurse, you are re-using the same one. Toss a use strict; in there, and fix the errors you get, and the code should be good.
I realize that you're just tinkering with recursion. But as long as you're having fun comparing implementations between two languages you may as well also see how the CPAN can extend your tool set.
If you don't care about the order, you can generate all 13,388,280 permutations of ( 'a'..'z', 'A..'Z', '0'..'9' ) taken four at a time with the CPAN module, Algorithm::Permute
Here is an example of how that code may look.
use strict;
use warnings;
use Algorithm::Permute;
my $p = Algorithm::Permute->new(
[ 'a' .. 'z', 'A' .. 'Z', '0' .. '9' ], # Set of...
4 # <---- at a time.
);
while ( my #res = $p->next ) {
print #res, "\n";
}
The new() method accepts an array ref that enumerates the character set or list of what to permute. Its second argument is how many at a time to include in the permutation. So you're essentially taking 62 items 4 at a time. Then use the next() method to iterate through the permutations. The rest is just window dressing.
The same thing could be reduced to the following Perl one-liner:
perl -MAlgorithm::Permute -e '$p=Algorithm::Permute->new(["a".."z","A".."Z",0..9],4);print #r, "\n" while #r=$p->next;'
There is also a section on permutation, along with additional examples in perlfaq4. It includes several examples and lists some additional modules that handle the details for you. One of Perl's strengths is the size and completeness of the Comprehensive Perl Archive Network (the CPAN).