Multiplication large numbers in perl - perl

i have a problem with a scripts below and How to make multification results equals to 1332521814089765.
#!/usr/bin/perl
my $divide = 1332521814089765/1332521809;
my $results1 = int $divide;
print "After Divide: $results1 \n";
my $multiplication = $results1*1332521809;
my $results2 = $multiplication;
print "After Multiplication: $results2 \n"; #How to make multification results equals to 1332521814089765
after searching and make a test here the results but still not get my expected results
my $divide = 1332521814089765/1332521809;
my $multiplication = $divide*1332521809;
my $results = $multiplication/10;
print "My Results: $results\nExpect Results: 1332521814089765\n";

1000000 * 1332521809 is equal to 1332521809000000. Why would you expect 1332521814089765?
Maybe you are multiplying the wrong numbers, which is to say you meant to use
my $multiplication = $divide*1332521809;
instead of
my $multiplication = $results1*1332521809;
Another possibility is that you are trying to find the inverse function of
$y = int($x/$k)
Unfortunately, there is none because there are multiple values of $x that give the same $y.
int(1332521809000000/1332521809) = 1000000
...
int(1332521814089764/1332521809) = 1000000
int(1332521814089765/1332521809) = 1000000
int(1332521814089766/1332521809) = 1000000
...
int(1332523141521808/1332521809) = 1000000

Related

Perl script to convert a binary number to a decimal number

I have to write a Perl script that converts a binary number, specified as an
argument, to a decimal number. In the question there's a hint to use the reverse function.
We have to assume that the binary number is in this format
EDIT: This is what I've progressed to (note this is code from my textbook that I've messed with):
#!/usr/bin/perl
# dec2.pl: Converts decimal number to binary
#
die("No arguments\n") if ( $#ARGV == -1 ) ;
foreach $number (#ARGV) {
$original_number = $number ;
until ($number == 0 ) {
$bit = $number % 2 ;
unshift (#bit_arr, $bit) ;
$number = int($number / 2 );
}
$binary_number = join ("", #bit_arr) ;
print reverse ("The decimal number of $binary_number is $original_number\n");
$#bit_arr = -1;
}
When executed:
>./binary.pl 8
The decimal number of 1000 is 8
I don't know how to word it to make the program know to add up all of the 1's in the number that is inputted.
You could just use sprintf to do the converting for you...
sprintf("%d", 0b010101); # Binary string 010101 -> Decimal 21
sprintf("%b", 21) # Decimal 21 -> Binary 010101 string
Of course, you can also just eval a binary string with 0b in front to indicate binary:
my $binary_string = '010101';
my $decimal = eval("0b$binary"); # 21
You don't have to use reverse, but it makes it easy to think about the problem with respect to exponents and array indices.
use strict;
use warnings;
my $str = '111110100';
my #bits = reverse(split(//, $str));
my $sum = 0;
for my $i (0 .. $#bits) {
next unless $bits[$i];
$sum += 2 ** $i;
}
First of all, you are suppose to convert from a binary to decimal, not the other way around, which you means you take an input like $binary = '1011001';.
The first thing you need to do is obtain the individual bits (a0, a1, etc) from that. We're talking about splitting the string into its individual digits.
for my $bit (split(//, $binary)) {
...
}
That should be a great starting point. With that, you have all that you need to apply the following refactoring of the formula you posted:
n = ( ( ( ... )*2 + a2 )*2 + a1 )*2 + a0
[I have no idea why reverse would be recommended. It's possible to use it, but it's suboptimal.]

Simple Perl For-Loop

I have a for loop and I want to increment the variable by 0.1 each time, however the value changes differently from the increment and I am unsure as to why.
I've simplified the for loop and it still gives a strange output:
for (my $t = 1000; $t < 1500 ;$t+=0.1) {
print "$t\n";
}
It prints:
1034.9
1035
1035.1
1035.2
1035.3
1035.4
1035.49999999999
1035.59999999999
1035.69999999999
1035.79999999999
1035.89999999999
1035.99999999999
1036.09999999999
1036.19999999999
1036.29999999999
[it then goes on like this to 1500]
I do not know where the decimal places are coming from. Is this a problem with my understanding of Perl?
Thanks in advance.
1/10 is a periodic number in binary like 1/3 is in decimal. It cannot be represented exactly as a floating point number.
$ perl -e'printf "%.20g\n", 0.1'
0.10000000000000001
Never compare a floating pointer number to another without involving a tolerance, and be wary of accumulation of error.
The simple solution here to to do the arithmetic using integers, and generate the floating point numbers when needed
for (my $tx10 = 10000; $tx10 < 15000; ++$tx10) {
my $t = $tx10/10;
print "$t\n";
}
which simplifies to
for my $tx10 (10000..14999) {
my $t = $tx10/10;
print "$t\n";
}
____ ____ ____
0.1 = 0.00011 0.4 = 0.0110 0.7 = 0.10110
____ ____
0.2 = 0.0011 0.5 = 0.1 0.8 = 0.11001
____ ____ ____
0.3 = 0.01001 0.6 = 0.1001 0.9 = 0.11100
for (my $t = 1000; $t < 1500 ;$t+=.1) {
printf("%.1f\n", $t);
}
Alternative:
for (10000..14999) {
my $t = $_/10;
print "$t\n";
}
Since 0.1 cannot be exactly specified in binary, rounding errors will accumulate in your code. In this answer, the amount always stays close enough to exact so that perl's internal number to string rounding will display the correct number. Lesson: use integers whenever possible.
To test for the condition
perl -le 'for (my $t = 1000.0; $t < 1500.0 ;$t+=0.1) { print $t}'| perl -n -e '($a)=/(\d$)/; print "fail $a $b $_" if ($a eq $b); $b=$a'
yet another way to fix it
perl -le 'for (my $t = 1000.0; $t < 1500.0 ;$t+=0.1) { $t=sprintf("%.1f", $t); print $t}'| perl -n -e '($a)=/(\d$)/; print "fail $a $b $_" if ($a eq $b); $b=$a'

pass 3 value to sub : Too many arguments for

I have an input like this:
100 200 A_30:120,A_140:180,B_180:220
100 300 A_70:220,B_130:300,A_190:200,A_60:300
I want to count number of A or B in each line and also compare range of A or B in each line with the range in two first column and return the length of intersection. e.g. output for first line: A:2 A_length:40 B:1 B_length:20
while(<>){
chomp($_);
my #line = split("\t| ", $_);
my $col1 = $line[0];
my $col2 = $line[1];
my #col3 = split(",",$line[2]);
my $A=0;
my $B=0;
my $A_length=0;
my $B_length=0;
for my $i (0 .. #col3-1){
my $col3 = $col3[$i];
if ($col3 =~ /A/){
my $length=0;
$length = range ($col3,$col1,$col2);
$A_length = $A_length+$length;
$A++;
}
if ($col3 =~ /B/){
my $length=0;
$length = range ($col3,$col1,$col2);
$B_length = $B_length+$length;
$B++;
}
$i++;
}
print("#A: ",$A,"\t","length_A: ",$A_length,"\t","#B: ",$B,"\t","length_B: ",$B_length,"\n");}
sub range {
my ($col3, $col1, $col2) = ($_[0],$_[1],$_[2]);
my #sub = split(":|_", $col3);
my $sub_strt = $sub[1];
my $sub_end = $sub[2];
my $sub_length;
if (($col1 >= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($sub_end) - ($col1);}
if (($col1 >= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($col2) - ($col1);}
if(($col1 <= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($sub_end) - ($sub_strt);}
if(($col1 <= $sub_strt) && ($col2 <= $sub_end)){
$sub_length = ($col2) - ($sub_strt);}
return $sub_length;
}
I FIXED IT :)
Perl already has a builtin length function, which only takes one argument. As perl is compiling your script and gets to your length function call, it doesn't know about the sub length { ... } that you have defined later in the script, so it complains that you are using the builtin length function incorrectly.
How to fix this? This is Perl, so there are many ways
name your function something else. Making a function with the same name as a Perl builtin function is usually a bad idea
Call your function with the & sigil: my $length = &length($col3,$col1,$col2); That will be enough of a hint to the compiler that your function call does not refer to the builtin function.
Qualify your function call with a package name, in this case main::length($col3,$col1,$col2) or just ::length($col3,$col1,$col2).
Note that even if Perl did know about the length function you defined (you could get Perl to know by moving the sub length { ... } definition to the top of the script, for example), the function call would still be ambiguous to the compiler, the compiler would emit a warning like
Ambiguous call resolved as CORE::length(), qualify as such or use & at ...
and your script would still fail to compile. Here CORE::length would mean that Perl is resolving the ambiguity in favor of the builtin function.

Using perl's reduce to compute dot-product

Suppose I have the following two equal-sized arrays in my perl program:
my #arr1 = 1..5;
my #arr2 = 6..10;
I'm trying to get their dot-product using the reduce function defined in the List::Util core module but the following is not working for me:
my $dot_prod = reduce { $arr1[$a] * $arr2[$a] + $arr1[$b] * $arr2[$b] }0..$#arr1;
I get 50 as my output instead of the expected 130.
The documentation describes the behavior of reduce as follows:
The first call will be with $a and $b set to the first two elements of
the list, subsequent calls will be done by setting $a to the result of
the previous call and $b to the next element in the list.
Thus, in this case, on the first iteration reduce will set $a = 0 and $b = 1, and hence, execute
$arr1[0] * $arr2[0] + $arr1[1] * $arr2[1]
This temporary result happens to be 20.
Now, for the second iteration, $a is set to the result of the previous iteratrion and so $a = 20 and $b = 2. Thus, the following will be executed
$arr1[20] * $arr2[20] + $arr1[2] * $arr2[2]
which is not what we want.
A possible workaround:
prepend an initial 0 to the list provided as input to reduce as follows:
my $dot_prod = reduce { $a + $arr1[$b] * $arr2[$b] } 0, 0..$#arr1;
This gives us the desired result since on the first iteration $a = $b = 0 and we'll compute
0 + $arr[0] * $arr[0]
whose result will be 6.
Then in the second iteration, we'll have $a = 6 $b = 1 and so we'll compute
6 + $arr1[1] * $arr2[1]
etc.
Honestly,
my $dot_prod = reduce { $a + $arr1[$b] * $arr2[$b] } 0, 0..$#arr1;
isn't the most readable. There is this:
my $dot_prod = sum map { $arr1[$_]*$arr2[$_] } 0..$#arr1;
But that doesn't use reduce. Well, we could simply implement sum in terms of reduce instead of using List::Util's, and perhaps even inline it:
my $dot_prod = reduce { $a+$b } map { $arr1[$_]*$arr2[$_] } 0..$#arr1;
Here are the previously posted solutions in a runnable program:
my #arr1 = 1..3;
my #arr2 = 6..8;
use List::Util qw(reduce sum) ;
my $dot_prod0 = reduce { $a + $arr1[$b] * $arr2[$b] } 0,0..$#arr1; #reduce
print "Dot product0 = ".$dot_prod0."\n";
my $dot_prod1 = sum map { $arr1[$_]*$arr2[$_] } 0..$#arr1; #sum map
print "Dot product1 = ".$dot_prod1."\n";
my $dot_prod2 = reduce { $a+$b } map { $arr1[$_]*$arr2[$_] } 0..$#arr1; #reduce map
print "Dot product2 = ".$dot_prod2."\n";

Perl - Returning the maximum value in a data set

I have never delved into the world of Perl before and I find it pretty confusing and could use some help. In the code below the calc() section returns a running average of an'input' over 'count' samples. I would like to modify that so the calc() returns the maximum value within the sample set. Thanks in advance for the help!
sub calc
{
my ($this, $dim, $input, $count) = #_;
if ($count < 1)
{
warn "count=$count is less than 1.";
return undef;
}
my $inputsum_in = $this->{inputsum};
my ($inputcumsum, $inputsum_out) = PDL::CumulativeSumOver2($input, $inputsum_in);
my $inputdelay = $this->delay('inputhistory', $input);
my $inputdelaysum_in = $this->{inputdelaysum};
my ($inputdelaycumsum, $inputdelaysum_out) = PDL::CumulativeSumOver2($inputdelay, $inputdelaysum_in);
$this->{inputsum} = $inputsum_out;
$this->{inputdelaysum} = $inputdelaysum_out;
my $sampleno = $this->{sampleno};
my $divider = $count;
if($sampleno < $count)
{
my $last = $dim - 1;
$divider = sequence($dim) + ($sampleno + 1);
my $start = $count - $sampleno;
$divider->slice("$start:$last") .= $count if $start <= $last;
$this->{sampleno} = $sampleno + $dim;
}
return ($inputcumsum - $inputdelaycumsum) / $divider;
}
How about
$max = max($input);
PDL Primitives
If you want to find the maximum of a certain list of values, you do not need to write your own subroutine. There is already a function that comes shipped with perl v5.7.3 or higher:
use List::Util qw(max); # core module since v5.7.3
use strict;
use warnings;
print max(1 .. 10); # prints 10
EDIT: Here is the loop I take it you need.
Read input data from sensor
append new data to stored data
Throw away excess data
Evaluate
Here's how I'd do it.
my $storedData = pdl;
# $storedData is now a vector containing one element, 0
while (! stopCondition()) {
my $input = readSensorData(); # step 1
$storedData = $storedData->append($input); # step 2
if ($storedData->nelem > $count) { # step 3
$storedData = $storedData->slice("-$count:-1");
# note that -1 points to the last element in a piddle and -X refers to
# the element X-1 away from the end (true for piddles and native arrays)
}
my ($max, $min) = evaluate($storedData); # step 4
}
I'm not sure if this answers your question, but your comment below seems pretty different from the question you have above. Consider editing the above to better reflect what you're having trouble with or asking a new question.
An easy way to get a running average is with a finite impulse response filter, aka convolution. Convolve any signal with a (normalized) rectangular impulse and you get running average.
my $filter = ones($count) / $count;
my $runningAve = convolveND($input, $filter);
my $max = $runningAve->max`;
Or in one line
my $max = convolveND($input, ones($count) / $count)->max;
convolveND is documented here.
There is one thing to be careful of with this method, which is that the values at the beginning and end of the $runningAve piddle aren't really running averages. To ensure that the output is the same size as the input convolveND (by default) effectively concatenates zeroes to the beginning and end of the input, the result being that the first and last few elements of $runningAve are lower than actual running averages. (Note that a running average should have N - (window - 1) elements in principle, N being the size of $input.) Since these "bad" values will necessarily be lower than the actual running average values, they won't disturb the maximum that you want. (Re "by default": convolveND has other ways of handling edges, as you will see in the documentation linked to above.)
(NB: I am not a PDL expert. There may be a cheaper way to get the running average that's cheaper than convolveND, something like $ra = $input->range(...)->sumover(0) / $count, but I don't know what you'd put in the ... and the above is readable. See also http://search.cpan.org/~jlapeyre/PDL-DSP-Iir-0.002/README.pod#moving_average)