Matching FP Numbers and Using Sprintf

M

Mike Flannigan

Maybe it's just me, but I don't find the documentation on
sprintf to be very enlightening. I've read it many times
and still can't figure it out, despite being a math kinda
guy.

I don't expect anybody here to explain it to me. It
would take way too much typing. I have the Camel
book and I'll figure it out today or tomorrow.

But one thing you could help me with is how best to
match a simple number with a decimal point (fp number?).

I want to match the 21.33 and 8.75 on the first line below.
I am using this right now:
/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+\.\d+)\'[WE](\d+).(\d+\.\d+)\'/i;

Does (\d+\.\d+) seem like a good way to you'all? Surely
there is a simpler way. I don't want a string, I want the
number (21.33).

Then I thought to do come calculations and make the
result a number like 99.1458330000 (10 digits after
the decimal point) I could use:

$l = $4+($5/60);
$m = sprintf %.10f, $l;

The error I get is
"Number found where operator expected at . . . line 28,
near "%.p" . . . "

I've tried a bunch of things, but can't fix the problem.


Mike


__DATA__
10 N29° 21.33'W99° 8.75' 2.32 mi
11 N29° 20.16'W99° 10.63'23.55 mi
12 N29° 18.75'W99° 34.02' 8.94 mi
13 N29° 16.76'W99° 42.63' 7.64 mi
 
T

Tad McClellan

Mike Flannigan said:
Subject: Matching FP Numbers and Using Sprintf


Please make two posts with one subject rather than one post
with two subjects.

Maybe it's just me, but I don't find the documentation on
sprintf to be very enlightening. I've read it many times
and still can't figure it out, despite being a math kinda ^^
guy.


What "it"?

If the "it" is a syntax error, like below, then oh well, perl
has to understand your instructions before it will get to
carrying them out.

If the "it" was a semantic error, such as "how do I get only
two digits after the decimal?", then tell us your "it", and
we'll tell you how to sprintf() it.

$m = sprintf %.10f, $l;

The error I get is
"Number found where operator expected at . . . line 28,
near "%.p" . . . "
^^^

Why doesn't that say "%.10"?

Is this your real code? Did you copy/paste it or did you retype it?

I've tried a bunch of things, but can't fix the problem.


Put quotes around strings:

$m = sprintf '%.10f', $l;
 
T

Tad McClellan

Mike Flannigan said:
how best to
match a simple number with a decimal point (fp number?).


You are expected to check the Perl FAQ _before_ posting to
the Perl newsgroup.

perldoc -q number

How do I determine whether a scalar is a number/whole/integer/float?

Which gives regexes for several different interpretations of "number".

I want to match the 21.33 and 8.75 on the first line below.


Then why are you writing a pattern that matches a whole bunch
more that the 21.33 and 8.75 on the first line below?

my( $lat_minutes, $long_minutes ) = /(\d+\.\d+)'/g;

(or, if you want to match more than just those 2 fields, then
you should not say that you want to match just those 2 fields :)
)

I am using this right now:
/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+\.\d+)\'[WE](\d+).(\d+\.\d+)\'/i;
^^^ ^^
^^^ ^^

This does not match the 21.33 and 8.75 on the first line below, so
is that the problem you are asking about?

If so, then that is because you don't allow \s+ before the
longitute, but you do before the latitude.

If not, then is this your real code? Did you copy/paste it or
did you retype it?

/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+\.\d+)\'[WE](\d+).(\d+\.\d+)\'/i;
^^
^^
Single quotes are not special in a regex, so you don't need to escape them.


Does (\d+\.\d+) seem like a good way to you'all?


That depends on what data it must match against.

Looks fine to me for the data you show below.


But if your real data might have:

10 N29° 21.33'W99° .75' 2.32 mi

rather than:

10 N29° 21.33'W99° 0.75' 2.32 mi

then it won't look so fine...

Surely
there is a simpler way.


See above (or the FAQ).

I don't want a string, I want the
number (21.33).


Why do you think that it makes a difference?

It almost never makes a difference, due to perl's DWIMery.

If you think it does make a difference, then you probably
aren't thinking in Perl yet...

Then I thought to do come calculations and make the
result a number like 99.1458330000 (10 digits after
the decimal point) I could use:


When you search the Perl FAQs for "number" you also find this one:

Why am I getting long decimals (eg, 19.9499999999999)
instead of the numbers I should be getting (eg, 19.95)?

I can't really tell if you know about accuracy/precision issues
as they relate to the representations of numbers in a computer.

If you already knew that, then never mind. :)
 
M

Mike Flannigan

Bill said:
OK, but you forgot the whitespace between degrees and minutes of
longitude.

Right you are. Thank you.

Sure, but you would have better error checking with
(/d{1,3}\.\d{1,3}). Note: You should always check for
a successful match before using captured substrings. I accidently left
a blank line at the end of my example. I left it there to show the
value of this test.

I was already doing this - I just didn't post it in my
first message.

The distinction between string and number in Perl can be confusing, but
you can almost always ignore it.

That's what I thought. I just felt like I was doing this
the wrong way.
Your idea is right, but A FORMAT is a string. It requires quotes. This
is documented indirectly by the examples in perl -f sprintf and by the
references to C documentation. There really is no need for formating
here unless you wish to control the format of output.

Thanks alot for all the help. This is what I finally ended up with:


use strict;
use warnings;

my $oldtrfile = 'rt1.txt';
my $newtrfile = 'tr1.txt';

my $lat;
my $long;

#Get all route lat/longs and convert to decimal degrees
open TRIN, $oldtrfile or die "Cannot open $oldtrfile: $!";
open TROUT, ">", $newtrfile or die "Cannot open $newtrfile: $!";
foreach (<TRIN>) {
next unless
(/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+.\d+)\'[WE](\d+).\s(\d+.\d+)\'/i);
$lat = sprintf "%12.9f", $2+($3/60);
$long = sprintf "%13.10f", $4+($5/60);
print TROUT "TP,DMS,$lat,$long,12/31/1989,0:00:00,0\n";
}

close TRIN;
close TROUT;

print "All done.\n";


__END__


Seems to work like a charm for me. I tried to combine the
sprint statements in the print statement, and get rid of
the $lat, $long, but that did not work for me. I suspect
it can be done, but I couldn't get it done.


Thanks again,


Mike
 
M

Mike Flannigan

Tad said:
You are expected to check the Perl FAQ _before_ posting to
the Perl newsgroup.

perldoc -q number

How do I determine whether a scalar is a number/whole/integer/float?

Which gives regexes for several different interpretations of "number".

Believe me, I checked all the faqs pretty good, and the other
documentation before I posted. I'm just not real good at
finding what I need.
Then why are you writing a pattern that matches a whole bunch
more that the 21.33 and 8.75 on the first line below?

my( $lat_minutes, $long_minutes ) = /(\d+\.\d+)'/g;

I want to match more than those 2 numbers, but my question
only had to do with that part I mentioned.

(or, if you want to match more than just those 2 fields, then
you should not say that you want to match just those 2 fields :)
)
I am using this right now:
/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+\.\d+)\'[WE](\d+).(\d+\.\d+)\'/i;
^^^ ^^
^^^ ^^

This does not match the 21.33 and 8.75 on the first line below, so
is that the problem you are asking about?

If so, then that is because you don't allow \s+ before the
longitute, but you do before the latitude.

Yep, that was a problem. Thanks for pointing it out for me.

If not, then is this your real code? Did you copy/paste it or
did you retype it?
/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+\.\d+)\'[WE](\d+).(\d+\.\d+)\'/i;
^^
^^
Single quotes are not special in a regex, so you don't need to escape them.

That's another great point there. Thanks for enlightening me.
They are now gone from my code.

That depends on what data it must match against.

Looks fine to me for the data you show below.

But if your real data might have:

10 N29° 21.33'W99° .75' 2.32 mi

rather than:

10 N29° 21.33'W99° 0.75' 2.32 mi

then it won't look so fine...


See above (or the FAQ).


Why do you think that it makes a difference?

I thought it might matter to the "better way" that apparently
is only a figment of my imagination. Apparently there is
no "better" way.

It almost never makes a difference, due to perl's DWIMery.

If you think it does make a difference, then you probably
aren't thinking in Perl yet...


When you search the Perl FAQs for "number" you also find this one:

Why am I getting long decimals (eg, 19.9499999999999)
instead of the numbers I should be getting (eg, 19.95)?

I can't really tell if you know about accuracy/precision issues
as they relate to the representations of numbers in a computer.

If you already knew that, then never mind. :)

Here is my entire code - revised again.
All works great now, thanks.

use strict;
use warnings;

my $oldtrfile = 'rt1.txt';
my $newtrfile = 'tr1.txt';

my $lat;
my $long;

#Get all route lat/longs and convert to decimal degrees
open TRIN, $oldtrfile or die "Cannot open $oldtrfile: $!";
open TROUT, ">", $newtrfile or die "Cannot open $newtrfile: $!";
foreach (<TRIN>) {
next unless
(/^\s{9}(\d{1,3})\s*[NS](\d+).\s+(\d+.\d+)'[WE](\d+).\s(\d+.\d+)'/i);
$lat = sprintf '%.9f', $2+($3/60);
$long = sprintf '%.10f', $4+($5/60);
print TROUT "TP,DMS,$lat,$long,12/31/1989,0:00:00,0\n";
}

close TRIN;
close TROUT;

print "All done.\n";


__END__
 
M

Mike Flannigan

Tad said:
Please make two posts with one subject rather than one post
with two subjects.


What "it"?

As you have probably already figured out, "it" was the
format syntax. To be honest, I still have not figured it
out yet, but I'm still working on it.

For instance, I'm surprised to find that "%12.9f" seems
to give the same output at "%.9f".

I would expect that "%12.9f" would only give 8 numbers
after the decimal for a number over 100
(i.e. W101° 8.75' 2.32 mi), which converts to 101.145830000
but it gives 9 as I want. I just need to hit the book :)


Mike
 
T

Tad McClellan

Mike Flannigan said:
As you have probably already figured out, "it" was the
format syntax.


The only thing wrong with the _syntax_ was the missing quotes.

For instance, I'm surprised to find that "%12.9f" seems
to give the same output at "%.9f".


That is a *different* "it", the second one I described.

You seem to have confused "syntax" with "semantics".

"syntax" has to do with whether it is formed correctly or not.

"semantics" has to do with what it _means_.

I would expect that "%12.9f" would only give 8 numbers
after the decimal for a number over 100


That is a problem with the semantics of (s)printf, not with its syntax.


The first number is the "minimum width", if it is less that 12
chars (counting the decimal point) then it will be padded to 12
chars. If it is more that 12 chars then it will be formatted as
more than 12 chars.

The second number is the number of places after the decimal point,
if there are less than that many, that will be padded out too.

So, %12.9 is normally:

2 chars whole number part
1 decimal point char
9 chars after the decimal point

With the whole number part padded with spaces on the left, and the
decimal part padded with zeros on the right, if required.

Unless the number is >= 100, in which case there will be more than
2 chars in the whole number part, and the entire thing will be
more than the 12 char minimum.
 
J

Jürgen Exner

Anno said:
Have you read Tad's enlightening remarks about "syntax" and
"semantics" in this thread? Take them to heart. You might realize
that syntax isn't something that returns results.

Trivial test: Copy and paste those regexes into a file and run a "perl -c"
on that file:
C:\tmp>perl -c t.pl
t.pl syntax OK

I guess that answers this question.

jue
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Linux: using "clone3" and "waitid" 0
regular expressions and matching delimeters 17
sprintf 15
Problem with sprintf 1
Rounding numbers with sprintf 3
URGENT 1
Regex: deleting non-matching words 3
sprintf problems 6

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top