in reply to sprintf not acting like I expect

First, show a small sample of the output you don't like, and a sample of how you want it to look like.

Next, trim down the code to a minimum that still shows the problem. In this case, it would probably be a short array of primes, and a loop doing sprintf from that array.

Now, my question would be why do you think the number of iterations would be directly proportional to the printed length of the prime numbers?

I'd expect the value of the largest prime to be proportional to the number of iterations. And the printed length of that to be log base 10 of that.

PS: surely there aren't *that* many prime numbers you're collecting. Why not save them all to an array, then check the actual length of the last one and use that to decide how much space you need?

Replies are listed 'Best First'.
Re^2: sprintf not acting like I expect
by NateTut (Deacon) on Dec 03, 2014 at 19:32 UTC
    Ok, consider me properly chastised. I don't post too often and I thought it was clear that the numbers were not lining up. Anyway here's the current output:

    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 +, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, + 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, + 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, + 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, + 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, + 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, + 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,

    I would like all the columns to be lined up. Here's some pared down example code:

    use strict; use warnings; use Data::Dumper::Simple; sub PrintPrimes { my($Primes, $WrapAt, $Iterations) = @_; my $PrimeString = ''; my $PrimeStrings; my $ItLength = length($Iterations); foreach my $Prime (@$Primes) { my $PreviousPrimeString = $PrimeString . "\n"; $PrimeString .= sprintf("%*.0d", $ItLength, $Prime) . ', '; if(length($PrimeString) > $WrapAt) { push(@$PrimeStrings, $PreviousPrimeString); $PrimeString = $Prime . ', '; } } chop($PrimeString); $PrimeString .= "\n\n"; push(@$PrimeStrings, $PrimeString); $PrimeString = ''; foreach my $String (@$PrimeStrings) { $PrimeString .= $String; } return($PrimeString); } my $Primes; @$Primes = ( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 +, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, + 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, ); print(PrintPrimes($Primes, 80, 1000));

      From that, I can see that you have 5 characters (incl. space) between each number. The problem is only that you're not putting the proper amount of space before the first number of each row.

      The chop and push and loop is odd. I suspect you're doing a lot of string analysis in the middle, instead of pre-calculating the important values. I'd suggest a simple:

      my $itemLength = length($iterations); #account for comma and 1 space extra, but at least 1 number per row! my $NumPerRow = int(80/($itemLength+2)) || 1; my $format = "%0${itemLength}d, "; while (@primeNumbers) { printf($format, shift @primeNumbers) for (1..$NumPerRow); print "\n"; }

      There is no need to build up a big string of all the results. IO is buffered by default so many separate prints will be efficient.

        Glad I waited until you posted first! But here is my contribution, non-destructive of the array. Replace the while{} with the following:

        OUTER: for (my $r = 0; $r < @primeNumbers; $r += $NumPerRow) { for (my $c = r; $c - $r < $NumPerRow; $c++) { printf $format, $primeNumbers[$c]; last OUTER if ($c == $#primeNumbers); } print "\n"; }
        1 Peter 4:10