Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Scientific Notation Throws Off Results.

by Elijah (Hermit)
on Jan 13, 2004 at 23:29 UTC ( #321139=perlquestion: print w/ replies, xml ) Need Help??
Elijah has asked for the wisdom of the Perl Monks concerning the following question:

I have a program that converts ATM cells per second to IP bandwidth but when the peak cell rate reaches a point where the answer starts to be displayed in scientific notation the formatting I have gets thrown off.

sub convert { my ($len1, $type); if ($choice eq "Cells to Bits") { if ($pcr && $cell_size) { $answer = $pcr * $cell_size * 8; $len1 = length($answer); print $len1,"\n"; print $answer,"\n"; if (($len1 < 4) || ($len1 > 15)) { $type = "b/s"; }elsif (($len1 >= 4) && ($len1 <= 6)) { $type = "Kb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 4; $answer = substr($answer, 0, 2)." ".$type if $len1 == 5; $answer = substr($answer, 0, 3)." ".$type if $len1 == 6; }elsif (($len1 >= 7) && ($len1 <= 9)) { $type = "Mb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 7; $answer = substr($answer, 0, 2)." ".$type if $len1 == 8; $answer = substr($answer, 0, 3)." ".$type if $len1 == 9; }else{ $type = "Gb/s"; my $count = 1; while ($count < 10) { chop($answer); $count++; } $answer .= " ".$type; } $status = "Conversion Successfull!"; }else{ $status = "Error: required field missing!"; } }elsif ($choice eq "Bits to Cells") { if ($bps && $cell_size2) { $answer = $bps / 8 / $cell_size2; $answer = sprintf("%.0f", $answer) . " cps"; $status = "Conversion Successfull!"; }else{ $status = "Error: required field missing!"; } }else{ $status = "Error: required field missing!"; } }

As you can see I use length to check for number of digits and format accordingly. Well once the length of the answer gets too long perl automatically shortens it by using Scientific notation. My question is is there any way to disable perl from returning calculated results in scientific notation or any other way to stop this from happening?

Comment on Scientific Notation Throws Off Results.
Download Code
Re: Scientific Notation Throws Off Results.
by Zaxo (Archbishop) on Jan 13, 2004 at 23:40 UTC

    You're pushing the limit of perl integers. Either build perl for 64-bit integers or else use Math::BigInt;
    If speed is a problem, use Math::BigInt lib => GMP;

    After Compline,
    Zaxo

Re: Scientific Notation Throws Off Results.
by Abigail-II (Bishop) on Jan 13, 2004 at 23:43 UTC
    Well, I can see where you are using length, but your code fragment offers no indication at all which value Perl is shortening to scientific notation. Are we talking floats here? Integers? Which value are you printing, what are you getting, and what do you want to get?

    Abigail

      Sorry, here is the full code so you might have a better idea of what goes where. It is a gui app written in Tk.

      #!/usr/local/bin/perl -w #perl2exe_include Tk; #perl2exe_include Tk::Photo; #perl2exe_include strict; use Tk; use Tk::Photo; use strict; ########################################### ########################################### ## ## ## This script is a graphical interface ## ## that allows a user to easily convert ## ## IP bandwidth into ATM PCR. ## ## PCR = (Peak Cell rate) ## ## ## ########################################### ########################################### our($choice, $cb, $pcr, $bps, $status, $answer, $cell_size, $cell_size +2); my $window = MainWindow->new; $window->title("ip2atm"); my $frame_space = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame_space2 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame2 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame_space3 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame3 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame4 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame_space5 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame5 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame6 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame_space7 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame7 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame_space8 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame8 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame9 = $window->Frame->pack(-side=>'top', -fill=>'x'); my $frame10 = $window->Frame->pack(-side=>'top', -fill=>'x'); $frame_space->Label()->pack(-fill=>'x'); $frame->Label(-text=>"Choose Conversion Type")->pack(-side=>'top', -an +chor=>'n'); $frame->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame->Button(-text=>"Cells to Bits", -command=>\&cb)-> pack(-side=>'left', -anchor=>'w', -fill=>'none'); $frame->Label(-text=>" ")->pack(-side=>'right', -anchor=>'e'); $frame->Button(-text=>"Bits to Cells", -command=>\&bc)-> pack(-side=>'right', -anchor=>'e', -fill=>'none'); $frame_space2->Label()->pack(-fill=>'x'); $frame2->Label(-text=>"Conversion Type Being Used")->pack(-side=>'top' +, -anchor=>'n'); $frame2->Entry(-textvariable=>\$choice)-> pack(-side=>'bottom', -anchor=>'n', -fill=>'none'); $frame_space3->Label()->pack(-fill=>'x'); $frame3->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame3->Label(-text=>"Enter Peak Cell Rate")->pack(-side=>'left', -an +chor=>'w'); $frame3->Label(-text=>" ")->pack(-side=>'right', -anchor=>'e'); $frame3->Label(-text=>"Enter Bits Per Second")->pack(-side=>'right', - +anchor=>'e'); $frame4->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame4->Entry(-textvariable=>\$pcr)-> pack(-side=>'left', -anchor=>'w', -fill=>'none'); $frame4->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame4->Label(-text=>" ")->pack(-side=>'right', -anchor=>'e'); $frame4->Entry(-textvariable=>\$bps)-> pack(-side=>'right', -anchor=>'e', -fill=>'none'); $frame_space5->Label()->pack(-fill=>'x'); $frame5->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame5->Label(-text=>"Enter Cell Size")->pack(-side=>'left', -anchor= +>'w'); $frame5->Label(-text=>" ")->pack(-side=>'right', -anchor=>'e'); $frame5->Label(-text=>"Enter Cell Size")->pack(-side=>'right', -anchor +=>'e'); $frame6->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame6->Entry(-textvariable=>\$cell_size)-> pack(-side=>'left', -anchor=>'w', -fill=>'none'); $frame6->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame6->Label(-text=>" ")->pack(-side=>'right', -anchor=>'e'); $frame6->Entry(-textvariable=>\$cell_size2)-> pack(-side=>'right', -anchor=>'e', -fill=>'none'); $frame_space7->Label()->pack(-fill=>'x'); $frame7->Button(-text=>" Convert ", -command=>\&convert)-> pack(-side=>'top', -anchor=>'n'); $frame_space8->Label()->pack(-fill=>'x'); $frame8->Label(-text=>" Answer ")->pack(-side=>'top', -anchor=>'n'); $frame9->Label(-text=>" ")->pack(-side=>'left', -anchor=>'w'); $frame9->Entry(-textvariable=>\$answer)-> pack(-side=>'top', -anchor=>'n', -fill=>'none'); $frame10->Button(-text=>" Exit ", -command=>sub{exit;})-> pack(-side=>'bottom', -anchor=>'e'); $window->Label(-textvariable=>\$status, -relief=>'ridge')-> pack(-side=>'bottom', -fill=>'x'); if (-e "converter.gif") { $window->Photo('image', -file=>"converter.gif"); $window->Label(-image=>'image')->pack(-side=>'bottom'); } $status = "Written by: Me"; MainLoop; sub cb { $choice = "Cells to Bits"; $bps = "N/A"; $cell_size2 = "N/A"; $pcr = ""; $cell_size = ""; $answer = ""; } sub bc { $choice = "Bits to Cells"; $pcr = "N/A"; $cell_size = "N/A"; $bps = ""; $cell_size2 = ""; $answer = ""; } sub convert { my ($len1, $type); if ($choice eq "Cells to Bits") { if ($pcr && $cell_size) { $answer = $pcr * $cell_size * 8; $len1 = length($answer); print $len1,"\n"; print $answer,"\n"; if (($len1 < 4) || ($len1 > 15)) { $type = "b/s"; }elsif (($len1 >= 4) && ($len1 <= 6)) { $type = "Kb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 4; $answer = substr($answer, 0, 2)." ".$type if $len1 == 5; $answer = substr($answer, 0, 3)." ".$type if $len1 == 6; }elsif (($len1 >= 7) && ($len1 <= 9)) { $type = "Mb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 7; $answer = substr($answer, 0, 2)." ".$type if $len1 == 8; $answer = substr($answer, 0, 3)." ".$type if $len1 == 9; }else{ $type = "Gb/s"; foreach (my $count=1; $count<10; $count++) { chop($answer); } $answer .= " ".$type; } $status = "Conversion Successfull!"; }else{ $status = "Error: required field missing!"; } }elsif ($choice eq "Bits to Cells") { if ($bps && $cell_size2) { $answer = $bps / 8 / $cell_size2; $answer = sprintf("%.0f", $answer) . " cps"; $status = "Conversion Successfull!"; }else{ $status = "Error: required field missing!"; } }else{ $status = "Error: required field missing!"; } }
      I know that after 15 digits (yes integers) that the format changes to scientific notation therefore I have coded that into my script but after I think

      Here is a debugger output I have going to the command prompt to check the value of the 2 variables ($len1 and $answer) and you cans ee where the length jumps back down and screws me.

      5 41976 6 423576 7 4239576 8 42399576 9 423999576 10 4239999576 11 42399999576 12 423999999576 13 4239999999576 14 42399999999576 15 423999999999576 21 4.23999999999958e+015 21 4.23999999999996e+016 9 4.24e+017

      The first number (as you can see by the code) is the value of the length in digits of the answer and the second (longer number) is the actual answer.

        No doubt very interesting, but I'm not going to try to grok a program several pages long.

        Try posting a short program that exhibits the unwanted behaviour.

        Abigail

Re: Scientific Notation Throws Off Results.
by ysth (Canon) on Jan 14, 2004 at 00:12 UTC
    I assume what's giving you trouble is the:
    $answer = $pcr * $cell_size * 8; $len1 = length($answer);
    part (which computes a number and then calculates the length of its stringified form). Perl by default uses something like $str = sprintf("%.15g",$num) to stringify floating point numbers (where the %g format chooses whether to look like %e or %f). You can do it manually instead, never using the scientfic notation, with:
    $answer = sprintf "%.0f", $answer; $len1 = length($answer);
    You might be better off checking for numberic ranges; for instance (untested):
    if ($answer >= 1000 && $answer < 1000000) { $answer = int($answer/1000) . " Kb/s"; } else ...
    or a version that incorporates rounding instead of truncation:
    if ($answer >= 999.5 && $answer < 999500) { $answer = int($answer/1000 + .5) . " Kb/s"; } else ...
Re: Scientific Notation Throws Off Results.
by bl0rf (Pilgrim) on Jan 14, 2004 at 00:22 UTC
    Get rid of $len and use the numbers themselves:
    if (($answer < 1000) || ($len1 > 1e14)) { $type = "b/s"; }elsif (($answer >= 1000) && ($answer <= 1e6)) { $type = "Kb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 4; $answer = substr($answer, 0, 2)." ".$type if $len1 == 5; $answer = substr($answer, 0, 3)." ".$type if $len1 == 6; }elsif (($len1 > 1e6) && ($len1 <= 1e9)) { $type = "Mb/s"; $answer = substr($answer, 0, 1)." ".$type if $len1 == 7; $answer = substr($answer, 0, 2)." ".$type if $len1 == 8; $answer = substr($answer, 0, 3)." ".$type if $len1 == 9; }else{
    Just do a numeric check on $answer instead of tinkering with $length. By the way, 1e6 means: one multiplied by ten to the six( ten with six zeros).

Re: Scientific Notation Throws Off Results.
by NetWallah (Abbot) on Jan 14, 2004 at 01:53 UTC
    Here is some code I use to display Kilo, Meg, Gig etc .. You could probably use this directly ..
    sub format_kilo # Kilo, mega and gig { my $number = shift; my $fixwidth = shift; my $suffix = " "; if ($number > 0x40000000) { $number /= 0x40000000; $suffix = 'G'; } elsif ($number > 0x100000) { $number /= 0x100000; $suffix = 'M'; } elsif ($number > 0x400) { $number /= 0x400; $suffix = 'K'; } # Split integer and decimal parts of the number and add commas my $integer = int($number); # Add Leading spaces if fixed width $fixwidth and $integer = ' ' x ($fixwidth - length($integer) - le +ngth($suffix)) . $integer; # Combine it all back together and return it. return $integer.$suffix; } ##### Calling sequence ### my ($filename, $filebytes); $filename = "Your file name here...."; $filebytes = -s $filename; print "Opening File=$filename; (". format_kilo($filebytes) . " [=$filebytes] bytes)\n";

    "When you are faced with a dilemma, might as well make dilemmanade. "
Re: Scientific Notation Throws Off Results.
by fruiture (Curate) on Jan 14, 2004 at 15:53 UTC

    bl0rf said it: don't stringify things that you don't actually need as strings. The "number of digits" needs no stringification, it's a logarithm:

    sub number_of_digits { my $number = shift; my $base = shift || 10; 1 + int( log($number) / log($base) ) }
    --
    http://fruiture.de

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://321139]
Approved by dorko
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2014-09-22 10:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (189 votes), past polls