# printf: zero pad after the decimal a given amount

Discussion in 'Perl Misc' started by jidanni@jidanni.org, Mar 30, 2008.

1. ### Guest

Why is there no way to tell printf to zero pad like the right column:
0.1 :0.100
0.05 :0.050
0.03 :0.030
0.025 :0.025
0.02 :0.020
0.015 :0.015
0.0125 :0.0125
0.01 :0.010
0.009 :0.009
0.00625:0.00625
0.005 :0.005
The challenge: Change only the "WHAT?" below to produce the right
column above. Thanks.
use constant S => 100000;
for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500 ) {
printf "%-7g:WHAT?\n", \$_ / S, \$_ / S;
}

, Mar 30, 2008

2. ### John W. KrahnGuest

wrote:
> Why is there no way to tell printf to zero pad like the right column:
> 0.1 :0.100
> 0.05 :0.050
> 0.03 :0.030
> 0.025 :0.025
> 0.02 :0.020
> 0.015 :0.015
> 0.0125 :0.0125
> 0.01 :0.010
> 0.009 :0.009
> 0.00625:0.00625
> 0.005 :0.005
> The challenge: Change only the "WHAT?" below to produce the right
> column above. Thanks.
> use constant S => 100000;
> for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500 ) {
> printf "%-7g:WHAT?\n", \$_ / S, \$_ / S;
> }

\$ perl -le'
use constant S => 100000;
my \$x;
format =
@<<<<<< : @.#####
\$x, \$x
..
for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500 ) {
\$x = \$_ / S;
write;
}
'
0.1 : 0.10000
0.05 : 0.05000
0.03 : 0.03000
0.025 : 0.02500
0.02 : 0.02000
0.015 : 0.01500
0.0125 : 0.01250
0.01 : 0.01000
0.009 : 0.00900
0.00625 : 0.00625
0.005 : 0.00500

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

John W. Krahn, Mar 31, 2008

3. ### szrGuest

wrote:
> Why is there no way to tell printf to zero pad like the right column:
> 0.1 :0.100
> 0.05 :0.050
> 0.03 :0.030
> 0.025 :0.025
> 0.02 :0.020
> 0.015 :0.015
> 0.0125 :0.0125
> 0.01 :0.010
> 0.009 :0.009
> 0.00625:0.00625
> 0.005 :0.005
> The challenge: Change only the "WHAT?" below to produce the right
> column above. Thanks.
> use constant S => 100000;
> for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500
> ) { printf "%-7g:WHAT?\n", \$_ / S, \$_ / S;
> }

use constant S => 100000;
for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500 ) {
printf "%-7g:%01d.%3.3s%s\n", \$_ / S, int \$_ / S,
sprintf("%05d", \$_),
map { \$_ ? \$_ : '' } (\$_ % 100) =~ m!^(\d+?)0*\$!;
}

__OUTPUT__
0.1 :0.100
0.05 :0.050
0.03 :0.030
0.025 :0.025
0.02 :0.020
0.015 :0.015
0.0125 :0.0125
0.01 :0.010
0.009 :0.009
0.00625:0.00625
0.005 :0.005

--
szr

szr, Mar 31, 2008
4. ### Paul LalliGuest

On Mar 30, 4:09 pm, wrote:
> Why is there no way to tell printf to zero pad like the right column:

Why do you assume that because you don't know the way, there is no
way?

> 0.1    :0.100
> 0.05   :0.050
> 0.03   :0.030
> 0.025  :0.025
> 0.02   :0.020
> 0.015  :0.015
> 0.0125 :0.0125
> 0.01   :0.010
> 0.009  :0.009
> 0.00625:0.00625
> 0.005  :0.005
> The challenge: Change only the "WHAT?" below to produce the right
> column above. Thanks.
> use constant S => 100000;
> for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500 ) {
>     printf "%-7g:WHAT?\n", \$_ / S, \$_ / S;
>

%.03f

\$ perl -e'printf("%.03f\n", .1)'
0.100

Paul Lalli

Paul Lalli, Mar 31, 2008
5. ### szrGuest

Paul Lalli wrote:
> On Mar 30, 4:09 pm, wrote:
>> Why is there no way to tell printf to zero pad like the right column:

>
> Why do you assume that because you don't know the way, there is no
> way?
>
>> 0.1 :0.100
>> 0.05 :0.050
>> 0.03 :0.030
>> 0.025 :0.025
>> 0.02 :0.020
>> 0.015 :0.015
>> 0.0125 :0.0125
>> 0.01 :0.010
>> 0.009 :0.009
>> 0.00625:0.00625
>> 0.005 :0.005
>> The challenge: Change only the "WHAT?" below to produce the right
>> column above. Thanks.
>> use constant S => 100000;
>> for ( 10000, 5000, 3000, 2500, 2000, 1500, 1250, 1000, 900, 625, 500
>> ) { printf "%-7g:WHAT?\n", \$_ / S, \$_ / S;
>>

>
> %.03f
>
> \$ perl -e'printf("%.03f\n", .1)'
> 0.100
>
> Paul Lalli

Actually that truncates to 3 decimal places, which isn't what the op
required:

\$ perl -e'printf("%.03f\n", .00625)'
0.006

See my other post for a working solution.

--
szr

szr, Mar 31, 2008
6. ### Dr.RuudGuest

schreef:
> Why is there no way to tell printf to zero pad like the right column:
> 0.1 :0.100
> 0.05 :0.050
> 0.03 :0.030
> 0.025 :0.025
> 0.02 :0.020
> 0.015 :0.015
> 0.0125 :0.0125
> 0.01 :0.010
> 0.009 :0.009
> 0.00625:0.00625
> 0.005 :0.005

\$ perl -wle'
print "".reverse sprintf "%05.1f", "".reverse sprintf "%f", \$_
for qw/.1 .05 .03 .025 .02 .015 .0125 .01 .009 .00625 .005
1.987654321E1/
'
0.100
0.050
0.030
0.025
0.020
0.015
0.0125
0.010
0.009
0.00625
0.005
9.876543

--
Affijn, Ruud

"Gewoon is een tijger."

Dr.Ruud, Mar 31, 2008
7. ### Guest

wrote:
> Why is there no way to tell printf to zero pad like the right column:

One reason is that what you want is ill-defined. If we are going to tweak
sprintf to make it suit our personal preferences, I'd rather see a
conversion character that behaved just like %f if given a good number, but
returned the empty string if given either an empty string or undef (rather
than converting it to zero and then applying %f to the zero.)

> 0.1 :0.100
> 0.05 :0.050
> 0.03 :0.030
> 0.025 :0.025
> 0.02 :0.020
> 0.015 :0.015

Apparently you want to preserve non-zero digits even if that means going
beyond 3 digits right of the decimal. But why did you stop at 4?

0.014999999999999999444888

> 0.0125 :0.0125

0.0125000000000000006938893

How many consecutive zeros or nines are needed before you decide there are
enough to ignore what is the right of them?

Xho

--
The costs of publication of this article were defrayed in part by the
this fact.

, Mar 31, 2008
8. ### Ben MorrowGuest

Quoth :
> wrote:
> > Why is there no way to tell printf to zero pad like the right column:

>
> One reason is that what you want is ill-defined. If we are going to tweak
> sprintf to make it suit our personal preferences, I'd rather see a
> conversion character that behaved just like %f if given a good number, but
> returned the empty string if given either an empty string or undef (rather
> than converting it to zero and then applying %f to the zero.)
>
> > 0.1 :0.100
> > 0.05 :0.050
> > 0.03 :0.030
> > 0.025 :0.025
> > 0.02 :0.020
> > 0.015 :0.015

>
> Apparently you want to preserve non-zero digits even if that means going
> beyond 3 digits right of the decimal. But why did you stop at 4?
>
> 0.014999999999999999444888
>
> > 0.0125 :0.0125

>
>
> 0.0125000000000000006938893
>
> How many consecutive zeros or nines are needed before you decide there are
> enough to ignore what is the right of them?

It appears to me the OP wants either 3 s.f. after the point or 3 places,
whichever comes out shorter. Something like

sub fmt {
return
map /(\d*\.\d{3}\d*?)0*\$/,
map /(\d*\.0*[1-9]\d\d)/,
map { sprintf "%.308f", \$_ }
@_;
}

appears to work, but it's hardly pretty . The 308 is the number of
places required to represent DBL_MIN with 53-bit doubles; if your perl
is using 64-bit long doubles you will need 4932 instead.

Ben

Ben Morrow, Mar 31, 2008
9. ### Ted ZlatanovGuest

On Mon, 31 Mar 2008 21:55:16 +0100 Ben Morrow <> wrote:

BM> It appears to me the OP wants either 3 s.f. after the point or 3 places,
BM> whichever comes out shorter. Something like

BM> sub fmt {
BM> return
BM> map /(\d*\.\d{3}\d*?)0*\$/,
BM> map /(\d*\.0*[1-9]\d\d)/,
BM> map { sprintf "%.308f", \$_ }
BM> @_;
BM> }

BM> appears to work, but it's hardly pretty . The 308 is the number of
BM> places required to represent DBL_MIN with 53-bit doubles; if your perl
BM> is using 64-bit long doubles you will need 4932 instead.

Is there any harm in always using 4932? I would guess not, except maybe
for wasted CPU cycles.

Ted

Ted Zlatanov, Apr 1, 2008
10. ### Dr.RuudGuest

Frank Seitz schreef:
> Dr.Ruud:

>> \$ perl -wle'
>> print "".reverse sprintf "%05.1f", "".reverse sprintf "%f", \$_
>> for qw/.1 .05 .03 .025 .02 .015 .0125 .01 .009 .00625 .005
>> 1.987654321E1/
>> '
>> 0.100
>> [...]
>> 9.876543
>>
>>

>
> And how do you deal with negative numbers and numbers >= 10?

Hey! There were only numbers in [0..1>, so I already extended it to
[0..10>.

Oh well,

perl -wle'
\$n=length(int abs),
print+(\$_<0?"-":"").reverse sprintf"%0*.*f",\$n+4,\$n,
"".reverse sprintf"%f",abs
for qw/0 .1 .05 .03 .025 .02 .015 .0125 .01 .009 .00625 .005
1234567.89 -9876543.21/
'
0.000
0.100
0.050
0.030
0.025
0.020
0.015
0.0125
0.010
0.009
0.00625
0.005
1234567.890
-9876543.210

--
Affijn, Ruud

"Gewoon is een tijger."

Dr.Ruud, Apr 2, 2008