For Programmers: Free Programming Magazines  


Home > Archive > PERL Beginners > October 2006 > sprintf question









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 sprintf question
mstep@podiuminternational.org

2006-10-30, 7:03 pm



Hello all!


I am not sure, whether I found the right solution to format numbers
like follows:

round numbers to one after the dot AND zero pad the next. I see my
English is not sufficient to explain it properly; so an example

4,567 -> 4.60
2,634 -> 2.60

etc

I found this : sprintf ("%.1f0",$1)

is this like that, it is supposed to work?

here my sprintf exercise:


#!/usr/bin/perl

use strict;
use warnings;

my @numbers;

while (<DATA> )
{
next if /^$/;
tr/,/./;
if (/([\d.]+)/)
{
push @numbers, (sprintf ("%.1f0",$1));
}
}

print "\n";
print join ("\t",@numbers) ;
print "\n\n";

__DATA__
1.20004
5.678923
71.22
35.78889
65,7777
text comes here
4,33333
6,0002
7,44445
7,55556
7,555554

usenet@DavidFilmer.com

2006-10-30, 7:03 pm

mstep@podiuminternational.org wrote:
> I found this : sprintf ("%.1f0",$1)
> is this like that, it is supposed to work?


$1 is a special variable which contains stuff that was matched in a
previous regular expression (see perldoc perlre). That's not what you
want. You want $_, which is the default variable (which is set each
time you loop over <DATA> ). If you make that change, your code will
work.

However, this:
> tr/,/./;


is not really what you want. You want to substitute (not translate),
ie:

> s/,/./g;


Others would probably write it differently, though. For example:

my @numbers = grep( /^[\d.,]+$/, <DATA> );
print join ("\t", map ({s/,/./g; sprintf "%.2f", $_} @numbers)), "\n";


--
The best way to get a good answer is to ask a good question.
David Filmer (http://DavidFilmer.com)

Paul Lalli

2006-10-30, 7:03 pm

use...@DavidFilmer.com wrote:
> mstep@podiuminternational.org wrote:
>
> $1 is a special variable which contains stuff that was matched in a
> previous regular expression (see perldoc perlre). That's not what you
> want. You want $_, which is the default variable (which is set each
> time you loop over <DATA> ). If you make that change, your code will
> work.


Uh, David, did you try running it? The code *does* work, just fine.
The OP *is* using a pattern match with capturing parentheses, and so $1
is exactly what it's supposed to be.

> However, this:
>
> is not really what you want.


I think it is, actually.

> You want to substitute (not translate),
> ie:
>

Except for the fact that the OPs code does the same thing while being
more efficient. Why do you recommend this method instead?
[color=darkred]
> Others would probably write it differently, though. For example:
>
> my @numbers = grep( /^[\d.,]+$/, <DATA> );
> print join ("\t", map ({s/,/./g; sprintf "%.2f", $_} @numbers)), "\n";


So you mean others would write it more illegibly, and to not do what
the OP requested in the first place? I'm very .

To the OP: your requirement is a little odd (rounding to the nearest
tenth, but printing to the nearest hundreth), but I can't think of a
better way of doing it than what you already found.

Paul Lalli

mstep@podiuminternational.org

2006-10-30, 7:03 pm


use...@DavidFilmer.com schrieb:


>
> Others would probably write it differently, though. For example:
>
> my @numbers = grep( /^[\d.,]+$/, <DATA> );
> print join ("\t", map ({s/,/./g; sprintf "%.2f", $_} @numbers)), "\n";
>
>


Hello David,

thank you for your reply! This code snippet is really ingenious, only
it is not answering my question. My suggestion is working as intended.
I don't see, why tr/,/./ is wrong and I should replace it with s/,/./g

But I will read perlre :-) But my question was about sprintf: is it
right to write "%.1f0" to get the number rounded to one place after the
dot and zero padded one place more ... the result should be:

1.20 5.70 71.20 35.80 65.80 4.30 6.00 7.40 7.60
etc

Thank you again for your help and patience


marek

mstep@podiuminternational.org

2006-10-30, 7:03 pm


Paul Lalli schrieb:

> To the OP: your requirement is a little odd (rounding to the nearest
> tenth, but printing to the nearest hundreth), but I can't think of a
> better way of doing it than what you already found.
>
> Paul Lalli



thank you Paul tanking my defence :-)

"odd"?
imagine your numbers are multiplicated with complicate rand numbers for
example:

$rand_nr = sprintf("%.2f",0.9 - rand(0.4));
$number *= $rand_nr;

but finally this has to be rounded to %.1f and later for the
LaTeX-Table it is needed to be zero padded one more place. And I could
not find any example in the manual of % perl -f sprintf how to achieve
this. But probably I found the right way anyway:

$number = sprintf ("%.1f0",$number);

sorry for my English


marek

usenet@DavidFilmer.com

2006-10-30, 7:03 pm

mstep@podiuminternational.org wrote:
> I don't see, why tr/,/./ is wrong and I should replace it with s/,/./g


'tr' is used to translate a group of characters to a corresponding
group of another characters (think of a simple substitution cypher).
Paul Lalli, however, claims that it is also more efficient for a simple
one-character substitution. I have never heard that, but Paul knows
more about these things than I do, so I am happy to take his word for
it.

I missed your paren's when I mentally parsed your original code (but
Paul did not), so ignore my remarks about $1. Sorry!

--
The best way to get a good answer is to ask a good question.
David Filmer (http://DavidFilmer.com)

Paul Lalli

2006-10-30, 7:03 pm

m...@podiuminternational.org wrote:
> Paul Lalli schrieb:
>
[color=darkred]
> thank you Paul tanking my defence :-)
>
> "odd"?


Yes. About 95% of the cases I've ever seen, if you want to round your
value to a certain position past the decimal, that's also the position
past the decimal that you want to print. You, however, want to round
your value to 1 position past the decimal, but want to print 2 places
past the decimal.

> imagine your numbers are multiplicated with complicate rand numbers for
> example:


You implied English isn't your native language, so please take this as
friendly assistance, not criticism. The above should read:
"Imagine your numbers are multiplied with complicated random numbers"

> $rand_nr = sprintf("%.2f",0.9 - rand(0.4));
> $number *= $rand_nr;
>
> but finally this has to be rounded to %.1f and later for the
> LaTeX-Table it is needed to be zero padded one more place. And I could
> not find any example in the manual of % perl -f sprintf how to achieve
> this. But probably I found the right way anyway:
>
> $number = sprintf ("%.1f0",$number);


Yes, as I said, it's an unusual requirement, which is why you didn't
find any examples in the docs. If you have that requirement, that's
fine, I believe you. And I agree you've found what is likely to be the
best way to do it.

Paul Lalli

Paul Lalli

2006-10-30, 7:03 pm

use...@DavidFilmer.com wrote:
> mstep@podiuminternational.org wrote:
>
> 'tr' is used to translate a group of characters to a corresponding
> group of another characters (think of a simple substitution cypher).
> Paul Lalli, however, claims that it is also more efficient for a simple
> one-character substitution. I have never heard that, but Paul knows
> more about these things than I do, so I am happy to take his word for
> it.
>


I can't find the reference in the docs that I'm 90% sure I've seen
before, but a simple Benchmark confirms:

#!/usr/bin/perl
use strict;
use warnings;

use Benchmark qw/cmpthese/;

cmpthese(-10, {
'translate' => sub {
my $string = "foo,bar,baz,bam";
$string =~ tr/,/./;
},
'search' => sub {
my $string = "foo,bar,baz,bam";
$string =~ s/,/./g;
},
}
);
__END__

Rate search translate
search 228939/s -- -72%
translate 804994/s 252% --


Paul Lalli

DJ Stunks

2006-10-30, 7:03 pm

Paul Lalli wrote:
> use...@DavidFilmer.com wrote:
>
> I can't find the reference in the docs that I'm 90% sure I've seen
> before, but a simple Benchmark confirms:


I don't know if this is just stating the obvious, but the performance
difference is because tr/// doesn't have the overhead of s///'s big
regular expression engine. The drawback is, of course, that you can't
use metacharacters like \d in the transliteration (as the docs
indicate), however for a simple character replacement like the OPs,
it's clearly the tool of choice.

-jp

mstep@podiuminternational.org

2006-10-30, 7:03 pm


thank you all for your replies! I am learning a lot in this group :-)

One day when I am a little bit more advanced in Perl and style I have
to look to the Benchmark module Paul was mentioning. Really
interesting!

Happy Perling to all :-)


marek

Sponsored Links







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

Copyright 2009 codecomments.com