For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > July 2007 > Convert Scientific Notation to decimal equivalent









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Convert Scientific Notation to decimal equivalent
Joseph L. Casale

2007-07-18, 6:59 pm

How can I detect this, I have been running some code for a few days to develop some files and ran into the situation where I am getting the following data for input:

14.95313 14.45312 0
14.95313 1.570813E-015 0
14.95313 -14.45313 0
-14.95313 -28.90625 0
-14.95313 -14.45313 0
-14.95313 1.570813E-015 0
-14.95313 14.45312 0
14.95313 -28.90625 0
0 -28.90625 0
-14.95313 28.90625 0
0 28.90625 0
14.95313 28.90625 0

And my code is skipping some lines as it checks for any erroneous data:
next if grep (/[^0-9.-]/, @data);
But that thinks the scientific notation is bad. I searched the net and didn't find anything. How can I match this specific pattern and convert it?

Thanks!
jlc



Chas Owens

2007-07-18, 6:59 pm

On 7/18/07, Joseph L. Casale <JCasale@activenetwerx.com> wrote:
> How can I detect this, I have been running some code for a few days to
> develop some files and ran into the situation where I am getting the
> following data for input:
>
> 14.95313 14.45312 0
> 14.95313 1.570813E-015 0
> 14.95313 -14.45313 0
> -14.95313 -28.90625 0
> -14.95313 -14.45313 0
> -14.95313 1.570813E-015 0
> -14.95313 14.45312 0
> 14.95313 -28.90625 0
> 0 -28.90625 0
> -14.95313 28.90625 0
> 0 28.90625 0
> 14.95313 28.90625 0
>
> And my code is skipping some lines as it checks for any erroneous data:
> next if grep (/[^0-9.-]/, @data);
> But that thinks the scientific notation is bad. I searched the net and
> didn't find anything. How can I match this specific pattern and convert it?
>
> Thanks!
> jlc


Don't write the regex yourself, use one of the ones in
Regexp::Common*. $RE{num}{real} is probably what you want.

As for how to make "1e3" into 1000, just add 0:

perl -e 'my $i = "1e3"; print $i, " ", $i+0, "\n"';


* http://search.cpan.org/~abigail/Reg...egexp/Common.pm
John W. Krahn

2007-07-18, 6:59 pm

Joseph L. Casale wrote:
> How can I detect this, I have been running some code for a few days to develop some files and ran into the situation where I am getting the following data for input:
>
> 14.95313 14.45312 0
> 14.95313 1.570813E-015 0
> 14.95313 -14.45313 0
> -14.95313 -28.90625 0
> -14.95313 -14.45313 0
> -14.95313 1.570813E-015 0
> -14.95313 14.45312 0
> 14.95313 -28.90625 0
> 0 -28.90625 0
> -14.95313 28.90625 0
> 0 28.90625 0
> 14.95313 28.90625 0
>
> And my code is skipping some lines as it checks for any erroneous data:
> next if grep (/[^0-9.-]/, @data);
> But that thinks the scientific notation is bad. I searched the net and didn't find anything. How can I match this specific pattern and convert it?


perldoc -q "How do I determine whether a scalar is a number"



John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall
Xavier Noria

2007-07-18, 6:59 pm



El Jul 18, 2007, a las 11:19 PM, Joseph L. Casale escribi=F3:
> How can I detect this, I have been running some code for a few days =20=


> to develop some files and ran into the situation where I am getting =20=


> the following data for input:
>
> 14.95313 14.45312 0
> 14.95313 1.570813E-015 0
> 14.95313 -14.45313 0
> -14.95313 -28.90625 0
> -14.95313 -14.45313 0
> -14.95313 1.570813E-015 0
> -14.95313 14.45312 0
> 14.95313 -28.90625 0
> 0 -28.90625 0
> -14.95313 28.90625 0
> 0 28.90625 0
> 14.95313 28.90625 0
>
> And my code is skipping some lines as it checks for any erroneous =20
> data:
> next if grep (/[^0-9.-]/, @data);
> But that thinks the scientific notation is bad. I searched the net =20
> and didn't find anything. How can I match this specific pattern and =20=


> convert it?


I am not sure I understand the problem to solve.

You need to filter out lines that contain something that's *not* a =20
number? If that's the case, is @data a split on whitespace for each =20
line? If that's the case in turn, have a look at

perldoc -q determine

or delegate the job to Regexp::Common:

$ perl -MRegexp::Common -wle 'print 1 if "1.570813E-015" =3D~ /\A$RE=20=

{num}{real}\z/'
1

-- fxn

Chas Owens

2007-07-18, 6:59 pm

On 7/18/07, Chas Owens <chas.owens@gmail.com> wrote:
> On 7/18/07, Joseph L. Casale <JCasale@activenetwerx.com> wrote:
>
> Don't write the regex yourself, use one of the ones in
> Regexp::Common*. $RE{num}{real} is probably what you want.
>
> As for how to make "1e3" into 1000, just add 0:
>
> perl -e 'my $i = "1e3"; print $i, " ", $i+0, "\n"';
>
>
> * http://search.cpan.org/~abigail/Reg...egexp/Common.pm
>


It is important to note that the print function* will use scientific
notation on numbers that are very large or very small. For instance
0.000000000000001570813 will be printed as "1.570813e-15". If you
absolutely must have 0.000000000000001570813 then you will need to use
printf or sprintf:

#!/usr/bin/perl

use strict;
use warnings;

my @n = (
0.000000000000001570813,
10000000000000000000000,
"1e4",
"1e-4"
);

for my $n (@n) {
my $s = expand($n);
print "$n is $s\n";
}

sub expand {
my $n = shift;
return $n unless $n =~ /^(.*)e([-+]?)(.*)$/;
my ($num, $sign, $exp) = ($1, $2, $3);
my $sig = $sign eq '-' ? "." . ($exp - 1 + length $num) : '';
return sprintf "%${sig}f", $n;
}


* actually any conversion of a number to string for very large or
small numbers, that is why the unless in expand works.
Chas Owens

2007-07-18, 6:59 pm

On 7/18/07, Joseph L. Casale <JCasale@activenetwerx.com> wrote:
> Interesting,
> I see from your regexp you use a \A and \z, from Perldoc this means:
> \A Match only at beginning of string
> \z Match only at end of string


Is "foo10bar" valid? /^$RE{num}{real}$/ says no, but /$RE{num}{real}/
says yes. \A and \z are similar to ^ and $, but are not effected by
the m and s flags (which is not an issue in your case since you are
splitting on whitespace).

>
> I am not sure I understand this requirement?
>
> In my case, I am checking an array of 3 scalars. Does this make sense:
> next unless @data =~ /$RE {num}{real}/;
> Does the regexp know to evaluate each element in the array implicitly?
> Or do I need to tell it this?


Not in Perl 5 (Perl 6 will have the smart match operator ~~). If you
want to bail if any of the values in @data are not numbers then you
should say

next if grep { not /^$RE{num}{real}$/ } @data;

Or if you want to reduce @data to just the numbers

next unless my @num = grep { /^$RE{num}{real}$/ } @data;
Chas Owens

2007-07-18, 9:59 pm

On 7/18/07, Joseph L. Casale <JCasale@activenetwerx.com> wrote:
> Chas,
> Sorry but I am not clear on what you mean by reduce? Do you mean
> remove all non numbers from the array?

snip

Sort of, the code doesn't modify the original array, it creates a new
array with only the values that are numbers.
Xavier Noria

2007-07-19, 7:59 am

El Jul 19, 2007, a las 12:19 AM, Joseph L. Casale escribi=F3:

> Interesting,
> I see from your regexp you use a \A and \z, from Perldoc this means:
> \A Match only at beginning of string
> \z Match only at end of string
>
> I am not sure I understand this requirement?


^ and $ depend on flags, and $ allows an optional trailing newline. =20
When I want to match a complete string exactly, I tend to use \A and =20
\z because they convey that intention clearly.

If your code processes line by line and splits on whitespace, \A ... =20
\z is equivalent to ^ ... $.

> In my case, I am checking an array of 3 scalars. Does this make sense:
> next unless @data =3D~ /$RE {num}{real}/;
> Does the regexp know to evaluate each element in the array =20
> implicitly? Or do I need to tell it this?


Detecting whether something holds in an array is the job of grep:

my $numbers =3D grep /\A$RE{num}{real}\z/, @data;
next unless $numbers =3D=3D @data;

-- fxn

Dr.Ruud

2007-07-21, 3:59 am

Xavier Noria schreef:

> Detecting whether something holds in an array is the job of grep:
>
> my $numbers = grep /\A$RE{num}{real}\z/, @data;
> next unless $numbers == @data;



Alternative:

die if grep !/\A$RE{num}{real}\z/, @data;
my $numbers = scalar @data;

--
Affijn, Ruud

"Gewoon is een tijger."
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com