Why is incorrect value of pi output? - perl

I'm trying to calculate pi using following code that uses Chudnovsky algorithm. When $n is increased, then number of digits after the decimal point. However when $n is small, it can calculate correct value of pi (3.141592...) is output, but when $n is increased, it calculate incorrect value of pi. Why?
#!/usr/bin/perl
use strict;
use warnings;
use GMP qw(:all);
use GMP::Mpf qw(:all);
use GMP::Mpz qw(:all);
use GMP::Mpq qw(:all);
my $n = shift; $n = $n<7?7:$n;
$n *= 8;
my $l = int($n/7) + 1;
my $fmt = '%.' . $n . 'f';
my ($p0, $q0, $t0) = (1, 1, 0);
$p0 = mpz($p0);
$q0 = mpz($q0);
$t0 = mpz($t0);
my ($p, $q, $t, $a) = (0, 0, 0, 0);
$p = mpz($p);
$q = mpz($q);
$t = mpz($t);
$t = mpz($a);
for my $loop (1 .. $l){
$p = (2*$loop -1)*(6*$loop -1)*(6*$loop -5);
$q = ($loop**3)*(640320**3)/24;
$a = (-1)**$loop + (13591409 + 545140134*$loop);
$p *= $p0;
$q *= $q0;
$t = $t0*$p + $a*$p;
$p0 = $p;
$q0 = $q;
$t0 = $t;
}
my $x = sr(640320,$n);
$q = mpf($q,$n);
$t = mpf($t,$n);
my $pi = mpf(640320,$n)*sr(mpf(640320,$n),$n)*$q;
$pi /= mpf(12,$n)*($t + mpf(13591409,$n)*$q);
print $pi . "\n";
sub sr{
my ($x,$i) = #_;
my $s = mpf(0.0,$i);
my $s0 = mpf($x,$i);
for (1 .. $n){
$s = 1/$s0;
$s *= $x;
$s0 = ($s + $s0)/mpf(2.0,$i);
}
return $s;
}

Related

Unable to modify array parameter

This is supposed to put the contents of nums into decreasing order, however sort does not change the contents of nums. Many sites I read have said to pass by reference, but I don't think I'm dereferencing the argument correctly. Bear with me, this is my first Perl program :)
#! /usr/bin/env perl
sub sort {
my #arr = #_;
my $len = scalar #arr;
for (my $i = 1; $i < $len-1; $i = $i + 1) {
my $max = $i;
for (my $j = $i + 1; $j < $len; $j = $j + 1) {
if ($arr[$j] > $arr[$max]) {
$max = $j
}
}
$temp = $arr[$max];
$arr[$max] = $arr[$i];
$arr[$i] = $temp;
}
}
print "Enter 10 numbers: ";
my $numbers = <STDIN>;
my #nums = split ' ', $numbers;
print "Unsorted: #nums\n";
sort \#nums;
print "Sorted: #nums\n";
#Matt Jacob helped me out with this one. This is what I was looking for.
#! /usr/bin/env perl
sub selection_sort {
my $arr = shift;
my $len = scalar #$arr;
for (my $i = 0; $i < $len-1; $i++) {
my $max = $i;
for (my $j = $i + 1; $j < $len; $j++) {
if (#$arr[$j] > #$arr[$max]) {
$max = $j
}
}
my $temp = #$arr[$max];
#$arr[$max] = #$arr[$i];
#$arr[$i] = $temp;
}
}
print "Enter 10 numbers: ";
my $input = <STDIN>;
my #integers = split ' ', $input;
print "Unsorted: #integers\n";
selection_sort \#integers;
print "Sorted: #integers\n";

how to output into a tree like structure via Tree::DAG_Node?

I'm trying to write a program that can read from a file then put into a heap sort then output in a tree along with the sorted list. But I got stuck, instead of having the put be the numbers used in the heap sort, it just post 1-10 on one line then 1-9 on the next line. I'm really confused and I barely understand this language as it is. I put a example of the out below alone with the output I am hoping to have it draw.
#!/usr/bin/perl
use 5.006;
use strict;
use warnings;
use Tree::DAG_Node;
process_data(read_file('testing.txt'));
process_data((3,1,4,1,5,9,2,6,5,3,6));
sub read_file{
my($filename)=#_;
my #data=();
my #words;
open(my $fh, "<", $filename)
or die "Could not open file: $!\n";
while(<$fh>){
chomp;
#words = split(' ');
foreach my $word(#words){
push #data, $word;
}
}
close $fh;
return #data;
}
sub heap_sort {
my ($a) = #_;
my $n = #$a;
for (my $i = ($n - 2) / 2; $i >= 0; $i--) {
down_heap($a, $n, $i);
}
for (my $i = 0; $i < $n; $i++) {
my $t = $a->[$n - $i - 1];
$a->[$n - $i - 1] = $a->[0];
$a->[0] = $t;
down_heap($a, $n - $i - 1, 0);
}
}
sub down_heap {
my ($a, $n, $i) = #_;
while (1) {
my $j = max($a, $n, $i, 2 * $i + 1, 2 * $i + 2);
last if $j == $i;
my $t = $a->[$i];
$a->[$i] = $a->[$j];
$a->[$j] = $t;
$i = $j;
}
sub max {
my ($a, $n, $i, $j, $k) = #_;
my $m = $i;
$m = $j if $j < $n && $a->[$j] > $a->[$m];
$m = $k if $k < $n && $a->[$k] > $a->[$m];
return $m;
}
}
sub draw_tree{
my(#data)=#_;
my $root = Tree::DAG_Node->new;
$root->name($_[0]);
$root->new_daughter->name($_) for (1..10);
my #names = #data;
my $count = 50;
for my $n ($root->daughters) {
for (split //, $names[$count++]) {
$n->new_daughter->name($_)
}
}
print map "$_\n", #{$root->draw_ascii_tree};
}
sub process_data{
my(#data)=#_;
my #a = #data;
print "#a\n";
print "\n";
heap_sort(\#a);
draw_tree(#a);
print "\n";
print "#a\n";
print "\n";
}
here is the output I get
CMD output of my code
Output I am expecting:
(using example data)
1 1 9 4 5
1
|
1 ----- 9
|
/\
4 5
1 1 4 5 9

Perl : First number to the base of 2nd number(Base : 2 to 9)

I am trying this code, but it is giving some answer in the form of Nan.
The $decimal = ($decimal / $val2); is incorrect I suppose, not able to figure out what fault is there in this code.
Is there any other way to calculate this?
Here is my code:
#!/usr/bin/perl
use strict;
use warnings;
sub Base {
my $val1;
my $val2;
$val1=$_[0];
$val2=$_[1];
my $ans;my $i;
my $decimal;
my $remainder;
$decimal=$val1;
$ans=0;
$i=1;
while($decimal > 0)
{
$remainder = $decimal % $val2;
$ans = $ans + ($remainder * $i);
$i = $i * 10;
$decimal = ($decimal / $val2);
}
print $ans;
}
# Function call
print "enter 1st no.\n ";
my $n1 = <STDIN>;
print "enter 2nd no.\n ";
my $n2 = <STDIN>;
Base($n1,$n2);
$decimal = $decimal / $val2;
should be
$decimal = int( $decimal / $val2 );
or
$decimal = ( $decimal - $remainder ) / $val2;

How to use variables in a equation using Perl

I'm trying to use possible variables in a equation with Perl.
For example:
#!/usr/bin/perl -w
$a = "yellow";
$b = "orange";
$c = "col1fl0ur";
$c = $a + $b;
print "$a + $b = $c \n";
I want to be able to state the value for each variable $a, $b, $c, then be able to say that
$a + $b = "col1fl0ur"
You may ask; whats the point? just print out col1fl0ur, butI want to be able to use many more variables as well, such as in this case:
#!/usr/bin/perl -w
###values###
$a = "yellow";
$b = "orange";
$c = "col1fl0ur";
$d = "derp";
$e = "oplo";
$f = "qwerty";
###defining the equation###
$c = $a + $b;
$d = $a + $c;
$f = $d + $c;
###Printing###
print "$a + $b = $c \n";
print "$a + $c = $d \n";
print "$d + $c = $f \n";
It would help a lot if you explained your real problem, but something like this may help.
Note that you should never use $a and $b in live code as they are reserved variable names.
use strict;
use warnings;
my ($a, $b, $c, $d, $e, $f) = qw( yellow orange col1fl0ur derp oplo qwerty );
### defining the equation ###
my %sum;
$sum{$a}{$b} = $c;
$sum{$a}{$c} = $d;
$sum{$d}{$c} = $f;
### Printing ###
for my $pair ([$a, $b], [$a, $c], [$d, $c]) {
my ($p1, $p2) = #$pair;
printf "%s + %s = %s\n", $p1, $p2, $sum{$p1}{$p2};
}
output
yellow + orange = col1fl0ur
yellow + col1fl0ur = derp
derp + col1fl0ur = qwerty
If you want $b + $a to be the same as $a + $b then you will have to say so explicitly. For example,
$sum{$a}{$b} = $c;
$sum{$b}{$a} = $c;
you may use Overload pragma..
You can create a new package as follows:
package Tst;
use overload "+" => \&myadd;
sub new {
my $class = shift;
my $value = shift;
return bless \$value => $class;
}
sub myadd {
my ($x, $y) = #_;
$x = ref($x) ? $$x : $x;
$y = ref($y) ? $$y : $y;
my $value = '';
if ($x eq 'yellow' and $y eq 'orange'){
$value = 'col1fl0ur';
}
return $value;
}
1
Then in your Main program, you can do the things you like:
use Tst;
my $a = Tst->new('yellow');
my $b = Tst->new('orange');
my $c = $a + $b;
say $c;
This prints out col1fl0ur.
Rather than assigning values to Perl variables ($a, $b, $c, etc.) you might consider creating a data structure that will suit your purposes (whatever they may be!?!). Borodin's answer takes a partial step in that direction.
This example takes that idea a bit farther: the terms in your "mathematical" system would not be linked to individual Perl variables; instead they would be components of a larger data structure.
use strict;
use warnings;
my %xs = (
a => 'yellow',
b => 'orange',
c => 'col1fl0ur',
d => 'foo',
e => 'bar',
f => 'fubb',
g => 'blub',
);
$xs{'a + b'} = $xs{c};
$xs{'a * c'} = $xs{d};
$xs{'d / c'} = $xs{f};
$xs{'a + b - d + f'} = $xs{g};
printf("%15s = %s\n", $_, $xs{$_}) for sort keys %xs;
Output:
a = yellow
a * c = foo
a + b = col1fl0ur
a + b - d + f = blub
b = orange
c = col1fl0ur
d = foo
d / c = fubb
e = bar
f = fubb
g = blub

calculating molecular weight in perl

I have a perl script but it calculate molecular weight only when sequence is given. However I want to calculate molecular weight of protein sequences which is in fasta file.
print "Enter the amino acid sequence:\n";
$a = < STDIN > ;
chomp($a);
my #a = ();
my $a = '';
$x = length($a);
print "Length of sequence is : $x";
#a = split('', $a);
$b = 0;
my %data = (
A=>71.09, R=>16.19, D=>114.11, N=>115.09,
C=>103.15, E=>129.12, Q=>128.14, G=>57.05,
H=>137.14, I=>113.16, L=>113.16, K=>128.17,
M=>131.19, F=>147.18, P=>97.12, S=>87.08,
T=>101.11, W=>186.12, Y=>163.18, V=>99.14
);
foreach $i(#a) {
$b += $data{$i};
}
$c = $b - (18 * ($x - 1));
print "\nThe molecular weight of the sequence is $c";
first of all u must tell us what format has .fasta files. As i know they looks like
>seq_ID_1 descriptions etc
ASDGDSAHSAHASDFRHGSDHSDGEWTSHSDHDSHFSDGSGASGADGHHAH
ASDSADGDASHDASHSAREWAWGDASHASGASGASGSDGASDGDSAHSHAS
SFASGDASGDSSDFDSFSDFSD
>seq_ID_2 descriptions etc
ASDGDSAHSAHASDFRHGSDHSDGEWTSHSDHDSHFSDGSGASGADGHHAH
ASDSADGDASHDASHSAREWAWGDASHASGASGASG
if we will make suggestion that your code works fine, and counts molecular weight all we need is to read fasta files, parse them and count weight by yours code. It's more easy that sounds like.
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
for my $file (#ARGV) {
open my $fh, '<:encoding(UTF-8)', $file;
my $input = join q{}, <$fh>;
close $fh;
while ( $input =~ /^(>.*?)$([^>]*)/smxg ) {
my $name = $1;
my $seq = $2;
$seq =~ s/\n//smxg;
my $mass = calc_mass($seq);
print "$name has mass $mass\n";
}
}
sub calc_mass {
my $a = shift;
my #a = ();
my $x = length $a;
#a = split q{}, $a;
my $b = 0;
my %data = (
A=>71.09, R=>16.19, D=>114.11, N=>115.09,
C=>103.15, E=>129.12, Q=>128.14, G=>57.05,
H=>137.14, I=>113.16, L=>113.16, K=>128.17,
M=>131.19, F=>147.18, P=>97.12, S=>87.08,
T=>101.11, W=>186.12, Y=>163.18, V=>99.14
);
for my $i( #a ) {
$b += $data{$i};
}
my $c = $b - (18 * ($x - 1));
return $c;
}