Perl floating point number usage confusion - perl

While using scalar values in perl, I am not able to accomplish the desired results. Need your help in figuring where I am going wrong..
Say I want to loop 9 times and print 0.1 to 0.9
I declared variable $i and using it in for loop as well as inside the loop.
for($i = 1; $i < 10; $i++)
{
$b = $ie-01; # (This where I go wrong, I am not sure If I am following correct
# syntax here, Because I see -1 getting printed instead of $i value
# which is incremented on each loop)
print "The value now is: $b\n";
}
I do know of different ways to get the desired result but I wanna know how to use exponent to get the desired output. . . . .
Why $i is treated as 0 when used in conjunction with e?

I think you only forgot to include the multiplication operator *:
$i * 1e-01
The string $ie-01 will be interpreted as $ie - 01 which is an unititialized variable (i.e. zero) minus one which will give you -1. (You can use the e-notation only with constant numbers but not with variables.)

Your first mistake was not including:
use strict;
use warnings;
This would have told you about the variable $ie not being declared.
There is no reasonable way to make ${i}e-01 work; you would have to eval it, which is not reasonable. The standard way to write it would be:
$b = $i * 0.1;

Related

perl - short factorial calculator returning long strings of 1's

I'm trying to make a program that calculates the factorial of a number. I'm not very familiar with perl, so I think I'm missing some grammar rule.
When I enter 5 the program should return 120. Instead it returns a few dozen 1's. When I try other numbers I still get 1's, but more or less of them depending on if I enter a higher or lower number.
Here's my code:
print"enter a positive # more than 0: \n";
$num = <STDIN>;
$fact = 1;
while($num>1)
(
$fact = $fact x $num;
$num = $num - 1;
)
print $fact;
system("pause");
This is my first post to stack Overflow, so I hope I obeyed all theposting rules.
The problem is this line:
$fact = $fact x $num;
x is not the multiplication operator in Perl. It is used to repeat things. 1 x 5 will produce "11111".
Instead you want *.
$fact = $fact * $num;
Which can be written using *=.
$fact *= $num;
A few other issues...
Get used to strict and warnings now. By default, Perl will let you use variables without declaring them. They are global, which is bad for reasons you'll learn later. Right now it means if you have a typo in a variable name like $face Perl won't tell you about it.
Looping over a list of numbers is better done with a for loop over a range using ...
# Loop from 1 to $num setting $factor each time.
for my $factor (1..$num) {
$fact *= $factor;
}
Instead of using a system call to pause the program, use sleep.

Do not understand Perl hash construct in a histogram code with respect to an array

I was looking at this histogram perl code: http://snippets.aktagon.com/snippets/62-how-to-generate-a-histogram-with-perl and I do not understand what line#3 is dong:
# This calculates the frequencies for all available bins in the data set
my %histogram;
$histogram{ceil(($_ + 1) / $bin_width) -1}++ for #list;
Questions I have are:
What is $_ here? I tried to print it but it turns empty.
I do understand the math but what does the ++ hash and for #list mean? I have not seen this construct before.
$_ is the current element of #list
The code can be rewritten as follows:
# Enumerate all values in the input list
foreach my $value (#list) {
# Compute histogram bin into which to place the current value
my $bin_index = ceil(($value + 1) / $bin_width) - 1;
# Increment the number of values in the bin
$histogram{$bin_index}++;
}
It is a postfix for loop.
Your attempt to print $_ is probably failing because you are putting it outside the loop (but you didn't share your code for that attempt).
It could be rewritten as:
my %histogram;
for my $value (#list) {
$histogram{ceil(($value + 1) / $bin_width) -1}++
}
$_ here is used as implicit foreach variable; same thing could be explicitly written as
my %histogram;
for my $n (#list) {
my $key = ceil(($n + 1) / $bin_width) -1;
$histogram{$key} += 1;
}
$_ is the current context value. In this case, the current iteration element of your for #list loop.
The hash contains the number of occurrences for each "bin".
The bin is calculated using the ceil function and a $bin_width, and it serves as the key for the hash (the value is the occurrence counter that gets accumulated into).
The ++ increments the current count for this bin in every iteration. On the first time this happens, Perl automatically assumes 0 for the missing element and the ++ will set it to 1.

Perl script for creating two arrays

Input: A list of numbers on command line
Output: Two lists of numbers ,one with input numbers that are greater than zero and one with those that are less than zero (Ignoring zero valued numbers)
here is my code
#!/usr/bin/perl
$i++ = 0;
$j++ = 0;
while ($number = <>)
{
if($number<0)
$first[$i++]=$number;
else
$second[$j++]=$number;
}
print "The numbers with value less than zero are\n";
foreach $number (#first)
print $number;
print "The numbers with value greater than zero are\n"
foreach $number(#second)
print $number;
I am getting the following silly errors which i am not able to rectify.The errors are
divide.pl: 2: ++: not found
divide.pl: 3: ++: not found
divide.pl: 5: Syntax error: ")" unexpected
Can anybody help me out with rectifying these errors please? I am new to perl script
Curly braces on compound statements are not optional in Perl.
Your statements:
$i++=0;
$j++=0;
don't make sense; you probably just want to delete the "++".
You're missing a semicolon on one of your print statements.
Once you've got those problems fixed, you should add
use strict;
use warnings;
after the #! line. This will introduce more error messages; you'll need to fix those as well. For example, you'll need to declare your variables using my().
The code you present will hardly compile. Loops should have {} around the main block, arrays are better created with push (or unshift), you should use strict and warnings, and you can't do increments at the same time as assignments (e.g. $i++ = 0).
use v5.10;
use strict;
use warnings;
my (#first, #second);
while (<STDIN>) { # <STDIN> clearer than <> in this case
chomp;
if ($_ < 0) {
push #first, $_;
} elsif ($_ > 0) {
push #second, $_;
}
}
say "Numbers less than zero:";
say "#first";
say "Numbers greater than zero:";
say "#second";
I don't know what $i++ = 0 is supposed to mean, but change that to $i = 0 to initialize the variables.
Also, the first thing yuu should do in the while loop is call chomp($number) to remove spurious newlines - 5\n is not a number and treating it as one will confuse perl.
Once you've fixed that, post any new errors that show up - I don't see any other problems though.
How are you executing this perl script? Beyond the errors mentioned about the code itself. It looks like you are attempting to evaluate the code using dash instead of perl.
The errors you should be seeing if you were executing it with Perl would be like:
Can't modify postincrement (++) in scalar assignment at /tmp/foo.pl
line 2, near "0;"
But instead, your errors are more in line with what dash outputs:
$ dash /tmp/foo.pl
/tmp/foo.pl: 2: ++: not found
/tmp/foo.pl: 3: ++: not found
Once you've verified that you are running your perl script properly you can start working through the other problems people have mentioned your code. The easiest way to do this is to run it via perl divide.pl instead of whatever you are doing.

perl exponentiation results in "nan"

i have the following problem:
I have a number of values x and I need to compute x^e (e being euler's number).
I do this:
$x = $x ** exp(1);
This results in "nan" for all of my test cases.
However if I print the values of $x before I do this and then take one and change above line to this:
$x = -12.4061063212051 ** exp(1);
it results in perfectly fine numbers.
Can anyone point out what I am doing wrong here?
Thanks
PS: Maybe the error hides somewhere else, so here is how i compute $x:
$y = #some float value taken from the output string of another program
$x = ($y/(303 * 0.0019872041));
print $x; #prints number
$x = $x ** exp(1);
print $x; #prints "nan"
It's all about operator precedence:
$x = -12.4061063212051 ** exp(1);
is really
$x = - (12.4061063212051 ** exp(1));
as seen using
$ perl -MO=Deparse,-p -e'$x = -12.4061063212051 ** $e'
($x = (-(12.4061063212051 ** $e)));
-e syntax OK
Which is fine.
If you try the following it will also fail just as your program:
$x = (- 12.4061063212051) ** exp(1);
And it should, there is no real number that meets this criteria.
Let's make things a bit easier for the moment, and suppose that we were taking $x**2.5. Well, since 2.5==5.0/2.0, we have $x**2.5==$x**(5.0/2.0)==($x**0.5)**5.0. Or, in other words, $x**2.5 is the same thing as the fifth power of sqrt($x).
Since computers tend to only deal with real numbers by default, what do you think would happen if, say $x==-1?
Yeah....now, what if $x<0$ and we wanted to take $x**exp(1) (the decimal approximation that Perl uses for exp(1) is 2.71828182845905)?

Mysterious "uninitialized value in an array" in algorithm for Perl challenge

Currently learning Perl, and trying to solve a little challenge to find the sum of even terms from the first 4,000,000 Fibonacci terms. I have created a Fibonacci array that seems to work, and then tried different methods to throw out the odd-valued terms, and continually run into an error when trying to sum my resulting array, getting reports of:
Use of uninitialized value in addition (+) at prob2_3.plx line 23
Here is what I have:
#!/usr/bin/perl -w
# prob2_2.plx
use warnings;
use strict;
my #fib; my $i; my $t; my $n;
#fib = (1, 2);
for ($i=2; $i<4000000; $i++) {
my $new= ( $fib[$i-1] + $fib[$i-2] );
push #fib, $new;}
for ($t=3; $t<4000000; $t++) {
if (($fib[$t] % 2) != 0 ) {
delete $fib[$t]; } }
my $total = 0;
for ($n=1; $n<$#fib; $n++) {
$total += $fib[($n+1)];}
print $total;
The warning means you are adding undef to something. delete $fib[$t]; is a bad way of doing $fib[$t] = undef;, which you later add to $total.
You have at least one other error:
The first two Fibonacci numbers are 0 and 1, not 1 and 2.
You have a major problem:
The 4,000,000th Fib number is going to be extremely large, much too large to fit in a double.
For reference purposes,
10,000th has 2090 digits: 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626
20,000th has 4180 digits: 1564344347109763849734765364072743458162050946855915883181245417404580803852433819127477934504143316103671237797087184052487157589846395314335101792632666883301188491698850377253383735812017943059782268835280360618754466932406192674904182868594738499500415166599602737300793712012046275485369495600019495004126039595217556097603510836899682827827626851274417838565958464881549888154511565687715162081527027421167926710592169405764372872023265791851279526521097739802047796738013885512616267273220024096214780132567479711643567372517808245262560562426651659391013837988476506124649092538307827326285964637268328029765707984607120961599796336714632362497169952413163370558311283612961033588836334352432860332222878648950508154331165678617373097939647648015552782638392654938551724289386017566932982065441392025369213734676739845068956966278536757235977421127565055467060906533383001625925978595472181091151062798507286798754728450358266089744616465914255799764431508559485853637841082521780322710748029546001980460990695999087046617731317608498316428164179967150350939374702201821818895349621858954893061034598954341939850973673870946183079728029105624782161827626661367017673681922257604178810154438462080217794489109678386881153826838075832058191153133704042628156419344516917867369755345135618986917642004521509538436204298618130363401395547933177643760161135638357088649014469358006518300404036431113143777969391584246934245800739809135619744598808977628245309941537928439431608665523308894967310600529498446943933665468406306292762942409786097847875240014036353917928156220446650579514092031254308059314931618726692376640987446459276331196950780063664171751110087644649773058213117640640085100552927878404516279461437503857017398937097042607258059612257878307007002086913210922626760728342901272768408974906007921227446242552261362505471751722906558235533709070548109789519920405521647836164156675304784097782435865165640401897107828859121831521126567446611716077075769257072773697947064329836969249852382976202348037425889031090020976240691949742160088733357875561841760194799534815496104106903184713919847662253483806138312440578732122855388348848736018217032877013531004653902335692761900988709302797685265501972628217528866551995479526195626503247164073793787381643388365618488630255600890924552511767690989186316859159306438477097458585889829326938198129884953178437411315486719927412151054551726325421747462698125767761987300812744880048122138953746796038485281452086680809803469350470844184375258620810652745992631459076192613797545486775651410699327289089628593588395142531659083933746399666161863597357735290387376161440280731398703030590410957840047591721635117677190494658658256770952605314604687704388833897300447300322491720569722311756874534871145435101596346787454258165870310592717473670917638475152605474446188958081898150393481484970581519902582271877141251593259282483539345792009117894084860435326938689664322383123823631494470354941767039585133484331342468806167901166928052638999423311570618981137348891538818027216596300491989181231598151123614651043205656474490923109982595235880446420678700336717534914381729578113169753046083981752465156933790288020841880688083888166659362896648911608716373579944854235997384986302902608821566689026676371268703303207406827737925274781301986480762462594420398637607893961010824979395439225300832931626540179218558345947558472159906873998923767432504278838419479068093778976997276416592421223235719653905071392295735398272851826350645605643470417155719500185143594804374322010189545136205568856276559806316789533450612097900180399440915139647060459321993254566103255011590902408116018722996267956826555434955409390951728022815209412027248353062982911544674007147249326697275010788100666958314965810320432736615962898175585320993128871046552842068867557341007383399180807449030159797672605530835244157256109268527578172314358255179589605335375414082046575557122636364391407861922824529441261003866098066404526541912783214030236752423547997110159548536582622929575859635210831021463323632502412193578592457118234067116894159316798758933206918936334540039454055299101076302263831614132510576874528929742319396129011617501
Even the 10,000th is too large for a double, and the 20,000th is double the size of the 10,000th, so imagine how large the 4,000,000th will be!
Stylistic issues:
my $i; for ($i=2; $i<4000000; $i++)
is much harder to read than
for my $i (2..$N-1)
with the following at the top to avoid having to repeat the number everywhere:
my $N = 4_000_000;
As if the fact that the 4 millionth Fibonacci number is more than 10^835950 isn't a big enough problem, this is not very good:
for ($t=3; $t<4000000; $t++) {
if (($fib[$t] % 2) != 0 ) {
delete $fib[$t]; } }
my $total = 0;
for ($n=1; $n<$#fib; $n++) {
$total += $fib[($n+1)];}
Why are you walking through the list twice here? Much better would be to combine the two loops into one. You want the sum of the odd terms, so sum the odd terms. Don't delete the odd terms (stylistically very bad) and then walk over the list again, relying on the fact that undef has a numerical value of 0 (but only with a warning).
And mn, the formatting of that code is very, very ugly. Eventually you will write code that someone else needs to read or maintain. My motto: Imagine that the person who will maintain your code is a psychopath who knows where you live.
As ikegami points out, your uninitialized problem is assuming delete removes elements from an array, when in fact it just sets them to undef (unless they are at the end of the array).
Given the storage requirements of the larger Fibonacci numbers, you don't want them in an array at all; fortunately, there's no need to keep them around for this problem.
I would do it like this (takes many minutes to run):
use strict;
use warnings;
use Math::BigInt 'lib' => 'GMP';
my $fib_A = Math::BigInt->new(0);
my $fib_B = Math::BigInt->new(1);
my $sum = Math::BigInt->new(0);
# get the next 3999998
for (1..(4000000-2)) {
my $next = $fib_A + $fib_B;
$sum += $next if $next % 2 == 0;
($fib_A, $fib_B) = ($fib_B, $next);
}
print "The sum is $sum\n";