Illegal division by zero - perl

#xyVal = (4,4,6,6,10,12,18,22,24,28,30);
#yVal = (176,178,180,184,192,202,210,218,224,232,238);
#xxVal = (9,9,9,9,9 ,11,13,15,17,19,19);
#xVal = (168,166,164,162,158,150,142,134,122,116,110);
for ($i = 0; $i < scalar(#xVal); $i++){
for ($i = 0; #xyVal[$i] < #xxVal[$i]; $i++){
#yNewVal = #yVal[$i-1] + (#yVal[$i] - #yVal[$i-1])*(#xxVal[$i] - #xyVal[$i-1])/(#xyVal[$i] - #xyVal[$i-1]);
}
}
print #yNewVal;
I understand why its giving me the error Illegal division by zero about line 9 (the #yNewVal = ...)
I want the array to have 0 in it if there is a division between zeros. What am I doing wrong? So, how can I avoid that my application crashes when there is a division by zero?

Your divisor on that line is #xyVal[$i] - #xyVal[$i-1], so any case where you have two identical adjacent values in #xyVAl (e.g. 4,4) will result in a 0, and thus a divide-by-zero error.

You could say:
#yNewVal = ($_ = #xyVal[$i] - #xyVal[$i-1]) == 0 ? 0 : #yVal[$i-1] + (#yVal[$i] - #yVal[$i-1])*(#xxVal[$i] - #xyVal[$i-1])/$_;

well if i understand you correctly:
if (#xyVal[$i] == #xyVal[$i-1])
#yNewVal = 0;
else
#yNewVal = #yVal[$i-1] + (#yVal[$i] - #yVal[$i-1])*(#xxVal[$i] - #xyVal[$i-1])/(#xyVal[$i] - #xyVal[$i-1]);

You can perform a try/catch using eval and conditional operators.
eval {
#yNewVal = #yVal[$i-1] + (#yVal[$i] - #yVal[$i-1])*(#xxVal[$i] - #xyVal[$i-1])/(#xyVal[$i] - #xyVal[$i-1]);
1;
} or do {
#yNewVal = (0);
};
print #yNewVal;
Though, your phrase is returning a scalar value and putting it into an array variable. So you may want to re-factor that.

Related

error: expected '} before else

I am using eclipse and I will ask a stupid question: why the error? code should be ok. I guess I'm just getting old. I just don't see the error. all the {} match. What the code does it sets the hemisphere for geolocation in a flight simulator, as the math should not have negative numbers.
so here goes:
O_lat is tested for zero or a positive number
if positive don't mess with it. and make quadrant = 1
else its negative so we make it positive and make the quadrant = 0
that's it.
int vns1, vew1, vns2, vew2;
if( O_lat >= 0 ){
{ vns1 = 1; }
else {
vns1 = 0;
O_lat = O_lat * -1; }}
All the braces match, but the else is not where it should be for the if.
Remove one of the superfluous braces:
int vns1, vew1, vns2, vew2;
if( O_lat >= 0 ){
vns1 = 1;
}
else {
vns1 = 0;
O_lat = O_lat * -1;
}
Just re-arrange the code a bit:
int vns1, vew1, vns2, vew2;
if( O_lat >= 0 )
{
{ //this is unnecessary
vns1 = 1;
}
else
{
vns1 = 0;
O_lat = O_lat * -1;
}
}//this is unnecessary too

Basic round robin in Perl difference between (++ / +1)

Recently I was trying to make a simple round robin with Perl , and I found a behaviour that I don't understand clearly.
Here the behaviour:
my $a = {index => 0};
for (0 .. 10) {
$a->{index} = ($a->{index}++) % 2;
warn $a->{index};
}
The output of this code will be:
0,0,0,..,0
But if I do the "same" code replacing $a->{index}++ by $a->{index}+1 , the round robin will be fine, example
my $a = {index => 0};
for (0 .. 10) {
$a->{index} = ($a->{index}+1) % 2;
warn $a->{index};
}
The output will be:
1,0,1,0,1,0,1,0...
Someone can explain me the difference between ++ / +1 in this case? I find this really "ugly", because if I don't assign the result to any variable in the case "++" the code will work as expected unless I put the sum inside ().
This code will do a round robin correctly:
my $a = {index => 0};
for (0 .. 10) {
warn $a->{index}++ % 2;
}
With () in the sum, the code will output: 1,2,3,4,5,6,7,8,9
my $a = {index => 0};
for (0 .. 10) {
warn ($a->{index}++) % 2;
}
$a->{index}+1 returns $a->{index}+1, while
$a->{index}++ returns $a->{index} before it was changed.
++$a->{index} returns $a->{index}+1, but it makes no sense to use it in that expression since it needlessly changes $a->{index}.
$a->{index} = ($a->{index}+1) % 2;
Say $a->{index} is initially 0.
$a->{index}+1 returns 1.
Then you assign 1 % 2, which is 1 to $a->{index}.
$a->{index} = $a->{index}++ % 2;
Say $a->{index} is initially 0.
$a->{index}++ sets $a->{index} to 1 and returns 0 (the old value).
Then you assign 0 % 2, which is 0 to $a->{index}.
Options:
$a->{index} = ( $a->{index} + 1 ) % 2;
if ($a->{index}) {
...
}
or
$a->{index} = $a->{index} ? 0 : 1;
if ($a->{index}) {
...
}
or
$a->{index} = !$a->{index};
if ($a->{index}) {
...
}
or
if (++$a->{index} % 2) {
...
}
or
if ($a->{index}++ % 2) {
...
}
Note that the last two options leaves an ever-increasing value in $a->{index} rather than 0 or 1.
Note that the last two options differ in whether the condition will be true or false on the first pass.

perl - algorithm to replace multiple if statements using mod

I have a perl script that parses a large files. It works but it is slow and I see a pattern that i'd like to take advantage of, but i don't know how to write it.
there is a section where i count a number of objectIds, and have to return a value Spaces. The mininum number of *objectIds is 3 and increases in odd increments, my output starts at 3 and increases in multiples of three.
So i have a chain of 30 statements like this
if($objectIds == 3)
{
$spaces = 3;
}
if($objectIds == 5)
{
$spaces = 6;
}
if($objectIds == 7)
{
$spaces = 9;
}
I see that the difference is incrementing by a modulo of 1, i.e. (3 % 3 = 0), (6 % 5 = 1), (9 % 7 = 2), but i can't for the life of me figure out how to optimize this.
This formula should calculate and replace your ifs,
# $spaces = $objectIds + ($objectIds-3)/2;
# $spaces = (2*$objectIds + $objectIds-3)/2;
# $spaces = 3*($objectIds -1)/2;
$spaces = ($objectIds -1) * 3/2;
The first optimisation I see is to use elsif :
if($objectIds == 3)
{
$spaces = 3;
}
elsif($objectIds == 5)
{
$spaces = 6;
}
elsif($objectIds == 7)
{
$spaces = 9;
}

Perl sorting a 3d array

I wand to sort a 3-dimension array in Perl. The elements of the array are in the form:
$arr_3d[indA][indB][indC] , and each element for indC=1 is a number
What I need is, for a given value of indA, sort all the sub-arrays indexed/defined by indB, with the decreasing order of the value of $arr_3d[indA][indB][indC=1],.
e.g. for an 1x2x2 array if:
$arr_3d[1][1][1] = 1
$arr_3d[1][1][2] = 4
$arr_3d[1][2][1] = 2
$arr_3d[1][2][2] = 3
Then after sorting :
$arr_3d[1][1][1] = 2
$arr_3d[1][1][2] = 3
$arr_3d[1][2][1] = 1
$arr_3d[1][2][2] = 4
So after sorting the sub-arrays $arr_3d[1][1] and $arr_3d[1][2] are swapped.
Sorry for the messed up description.. Any ideas?
Regards,
Giorgos
This is related to the " Schwartzian transform in Perl? " . You are really just sorting a single array (#{ $arr_3d[$indA] }).
I test this and it works. You are probably using Fortran index notation (starting at 1), so I changed it to C indexing (starting at 0).
use Data::Dumper;
my #arr_3d ;
$arr_3d[0][0][0] = 1;
$arr_3d[0][1][0] = 2;
$arr_3d[0][0][1] = 4;
$arr_3d[0][1][1] = 3;
my $indA = 0;
my $indC = 0;
my #temp = #{ $arr_3d[$indA] };
#{ $arr_3d[$indA] } = sort { $b->[$indC] <=> $a->[$indC] } #temp;
print Dumper(\#arr_3d);

Consistent random colour highlights

In a table I have columns with to and from dates, I highlight overlaps between rows taking into account the periods, this is done exhaustively in nested loops. This is not the issue.
I need the same colour for the rows that overlap.
sub highlight_overlaps {
my $date_from1;
my $date_to1;
my $date_from2;
my $date_to2;
my $i = 0;
my $j = 0;
for ($i; $i < $#DATE_HOLDER; $i++) {
$date_from1 = $DATE_HOLDER[$i][0];
$date_to1 = $DATE_HOLDER[$i][1];
my $red = int(rand(65)) + 190;
my $green = int(rand(290)) - 55;
my $blue = int(rand(290)) - 55;
for ($j=$i+1; $j<=$#DATE_HOLDER; $j++) {
$date_from2 = $DATE_HOLDER[$j][0];
$date_to2 = $DATE_HOLDER[$j][1];
if (($date_from1 le $date_to2 && $date_to1 ge $date_to2) ||
($date_from1 le $date_from2 && $date_to1 le $date_to2) ||
($date_from1 gt $date_from2 && $date_from1 lt $date_to2)) {
$tb->setCellStyle($i+2, 6, "background-color:rgb($red,$green,$blue);font-size:9pt");
$tb->setCellStyle($i+2, 7, "background-color:rgb($red,$green,$blue);font-size:9pt");
$tb->setCellStyle($j+2, 6, "background-color:rgb($red,$green,$blue);font-size:9pt");
$tb->setCellStyle($j+2, 7, "background-color:rgb($red,$green,$blue);font-size:9pt");
}
}
}
}
This works fine if it's just a pair of dates; say:
1) 25-06-2012 27-06-2012
2) 18-06-2012 29-06-2012
Will get the same colour
If though I have
0) 26-06-2012 28-06-2012
1) 25-06-2012 27-06-2012
2) 18-06-2012 29-06-2012
0 will get a different colour while 1 & 2 are paired as intended.
When and how to pick colours so that different colours are only applied to different overlaps?
Following up on the first answer; how may I represent overlaps in order to store them in a data structure, so that I can colour them after their detection?
You'll have to compare each interval against each other interval, and put them in 'buckets' when they are equal. Now when you compare an interval to a third interval, you put the third in the same bucket as the interval.
Then you print the buckets.
Perl's hash would make for fine buckets.
About your overlap detection
There is no overlap if
date1_to < date2_from OR
date2_to < date1_from
Or, in Perl:
if ($date_to1 lt $date_from2 || $date_to2 lt $date_from1) {
#overlap
}
Invert that either using Perl's unless, or using de Morgan:
if ($date_to1 ge $date_from2 && $date_to2 ge $date_from1) {
#overlap
}