Cleggy has asked for the wisdom of the Perl Monks concerning the following question:

So, I wanted to understand the printf command and how to manipulate the formatting of a number (yes I am that new to this), namely how to insert a variable into %.f it would seem %.{$var}f does the trick.

And In this small script I thought I had it worked out

If I enter 1.111111111111111111111111111111 (1 with 30 1s after the decimal point) as an experimental value, when asked 'How many digits would you like after the decimal point ? ' if I answer 2 I get 1.11 as expected.

If I answer 10 I get 1.1111111111 as I would expect.

However if I answer 20 I get 1.11111111111111116045 (?)

And if I answer 30 I get 1.111111111111111160454356650007 (?)

Can someone tell me why please.

#! /usr/bin/perl -w # experiment with printf use strict; my $num = 0; my $dig = 0; print 'Input a number :'; chomp( $num = <STDIN> ); print 'How many digits would you like after the decimal point ? '; chomp( $dig = <STDIN> ); print "\n"; print 'Original number was '; print "$num \n"; printf("And to $dig, points is "); printf( "%.${dig}f", $num ); print "\n\n";

Replies are listed 'Best First'.
Re: Why do I get random numbers?
by choroba (Cardinal) on Jun 14, 2018 at 22:18 UTC
Re: Why do I get random numbers?
by AnomalousMonk (Archbishop) on Jun 14, 2018 at 22:36 UTC
    ... manipulate the formatting of a number ... %.{$var}f does the trick.

    Another way is the printf  * format specifier:

    c:\@Work\Perl\monks>perl -wMstrict -le "my $p = 30; my $n = 1.111111111111111111111111111111; ;; printf '%0.*f', $p, $n; " 1.111111111111111200000000000000
    See sprintf for a discussion of all format specifiers.

    Update: Actually,  %.{$var}f doesn't do any trick except to produce an "Invalid conversion in printf..." warning. But the syntax is correct in the OPed example code:
        printf( "%.${dig}f", $num );


    Give a man a fish:  <%-{-{-{-<

      RE :Update: Actually, %.{$var}f doesn't do any trick except to produce an "Invalid conversion in printf..." warning. But the syntax is correct in the OPed example code: printf( "%.${dig}f", $num );

      works for me in :

      perl 5, version 20, subversion 2 (v5.20.2) built for x86_64-linux-gnu-thread-multi (with 101 registered patches)

      Doesn't throw any warnings.

      And sorry for the obviously FAQ however I was surprised that the data changed as I had not done any mathematical calculation on it just stored it and asked for some of it back. However I have obviously specified it is a numerical value by using printf.

      Oh and I have now read " What Every Programmer Should Know About Floating-Point Arithmetic."

      Consider me (somewhat) enlightened (on this topic).

      and when I get a minute I will look at Math::BigFloat:

      Many thanks

      Cleggy

        ... %.{$var}f doesn't do any trick except to produce [a] ... warning.
        works for me in ... perl 5, version 20 ... Doesn't throw any warnings.

        I'm surprised to read that it works in 5.20. I don't see any mention of a new format specifier in the latest sprintf docs. The best I can test in ATM is 5.14:

        c:\@Work\Perl\monks>perl -wMstrict -le "print 'perl version: ', $]; ;; my $p = 30; my $n = 1.111111111111111111111111111111; ;; printf qq{%0.{$p}f}, $n; " perl version: 5.014004 Invalid conversion in printf: "%0.{" at -e line 1. %0.{30}f

        ... I was surprised that the data changed ...

        As to this, I'm sure that, having now read the docs, you realize that IEEE-754 floating point representation (or any other finite representation) is only an approximation that may sometimes happen to be exact, and that it handles base-2 relative-prime fractions no better than base-10 handles 1/3.


        Give a man a fish:  <%-{-{-{-<

Re: Why do I get random numbers?
by syphilis (Archbishop) on Jun 15, 2018 at 00:51 UTC
    1 with 30 1s after the decimal point

    Note that, owing to the limited precision of the double, the last 13 1s have no effect on the value assigned to $num. Those 13 1s might just as well be 9s or 0s:
    C:\>perl -le "printf '%.20e', 1.11111111111111119999999999999;" 1.11111111111111116045e+000
    Cheers,
    Rob
Re: Why do I get random numbers?
by hippo (Archbishop) on Jun 14, 2018 at 23:06 UTC
    Can someone tell me why please.

    It's an FAQ!

Re: Why do I get random numbers?
by Anonymous Monk on Jun 15, 2018 at 13:08 UTC
    To summarize what Choroba linked-to, a floating-point number is (of course) in base-two, and the value 1/10 cannot be precisely represented in base-two just as the value 1/3 cannot be precisely represented in base-ten. (0.33333...) The printf function is performing conversions to represent the value in printable base-ten digits, and beyond a certain number of digits you are seeing those calculations break down as garbage takes over. Plus there is always the issue – true in any sort of floating-point calculation even on a pocket calculator – of the number of "significant digits."