Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re^2: A locale independent sprintf?

by swl (Priest)
on Jul 29, 2020 at 03:11 UTC ( #11119932=note: print w/replies, xml ) Need Help??


in reply to Re: A locale independent sprintf?
in thread A locale independent sprintf?

Thanks Rob.

I was using that strategy in my code, but it incurs sub overheads and profiling showed my uses were in a fairly hot path for large data sets. (It could also just another example of me micro-optimising, though).

Replies are listed 'Best First'.
Re^3: A locale independent sprintf?
by kcott (Bishop) on Jul 29, 2020 at 03:37 UTC

    Using y/,/./, instead of s/,/./, should be faster (see "perlperf: Search and replace or tr"). Obviously, I can't say whether it will be noticeably or usefully faster.

    You may want the 'r' modifier. Here's a somewhat fudged example for demonstration purposes:

    $ perl -E 'say sprintf("3,%d", 14)' 3,14 $ perl -E 'say sprintf("3,%d", 14) =~ y/,/./' Can't modify constant item in transliteration (tr///) at -e line 1, at + EOF Execution of -e aborted due to compilation errors. $ perl -E 'say sprintf("3,%d", 14) =~ y/,/./r' 3.14

    If you try this, I'd be interested in what sort of speed improvement you see.

    — Ken

      Good point. I'll see if I can set up some benchmarking and post the results.

      Update:

      Running the code below under ubuntu bash under windows with LC_NUMERIC set to de_DE.iso88591 indicates that s///r is about 20% faster than y//r. Both are in the order of millions per second, though.

      And as yet another update, the order does switch between runs so it's not a consistent outcome.

      Results:

      de_DE.iso88591 3,1 3.1 3.1 Rate y_sprintf s_sprintf sprintf y_sprintf 4646523/s -- -19% -63% s_sprintf 5721423/s 23% -- -54% sprintf 12396265/s 167% 117% --

      Code:

      use Benchmark qw {:all}; use 5.016; local $| = 1; use POSIX qw /locale_h/; use locale; print POSIX::setlocale(LC_NUMERIC) . "\n"; my $x; $x = sprintf "%.2g", 3.14; print "$x\n"; $x = sprintf ("%.2g", 3.14) =~ y/,/./r; print "$x\n"; $x = sprintf ("%.2g", 3.14) =~ s/,/./r; print "$x\n"; cmpthese ( -3, { sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14)', y_sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14) =~ y/,/./r', s_sprintf => 'use strict; use warnings; my $x = sprintf ("%.2g +", 3.14) =~ s/,/./r', } );

      (post was further updated to distinguish results from code)

        Interesting and surprising results. You said "the order does switch between runs" but I don't see that in any of the results you posted; there is quite a substantial fluctuation though (11% to 65%).

        I tried with something closer to the code in perlperf to which I linked earlier. I have Cygwin on Win10. I also have Perlbrew. I originally ran under 5.32.0; then switched to 5.30.0 to match your version — there were no significant differences in results. As my locale uses '.', not ',', I simply swapped the substitution (y/./,/ instead of y/,/./). Here's the code I used:

        #!/usr/bin/env perl use 5.016; use warnings; use Benchmark 'cmpthese'; use POSIX 'locale_h'; say POSIX::setlocale(LC_NUMERIC); say sprintf('%.2g', 3.14); say sprintf('%.2g', 3.14) =~ s/\./,/r; say sprintf('%.2g', 3.14) =~ y/./,/r; cmpthese 0 => { sprintf => sub { my $str = sprintf('%.2g', 3.14); return $str; }, y_sprintf => sub { my $str = sprintf('%.2g', 3.14) =~ y/./,/r; ret +urn $str; }, s_sprintf => sub { my $str = sprintf('%.2g', 3.14) =~ s/\./,/r; re +turn $str; }, };

        Here's a typically result:

        $ ./pm_11119934_bench_locale_s_y.pl en_AU.UTF-8 3.1 3,1 3,1 Rate s_sprintf y_sprintf sprintf s_sprintf 2940825/s -- -46% -85% y_sprintf 5493603/s 87% -- -72% sprintf 19713322/s 570% 259% --

        I ran it 5 times with 5.32.0, then 5 times with 5.30.0. The 87% in the representative run only ranged between 85% and 89% in all runs. So, I'm getting y/// almost twice as fast as s///; compared with your s/// being variably faster than y///.

        I added in the 'use strict; use warnings;' which you had. Now the results varied (85% 88% 21% 71% 75%) but 'y_sprintf' was still always faster. (I suspect the 21% is bogus — perhaps some short-lived background process fired up at that time.)

        I then added the 'use locale;' that you had and this substantially slowed down processing: 'y_sprintf' was still faster than 's_sprintf' but I wouldn't say significantly so (5% 1% 7% 12% 8%).

        I next replaced my subs with your strings (',' and '.' swapped as before). Again, 'y_sprintf' was faster and this time closer to, albeit more spread out than, my original results (75% 89% 87% 92% 90%).

        So, I can't replicate your s/// being faster than y///; all my tests indicated that the opposite was the case. I think the addition of 'use strict; use warnings;' was probably unnecessary for the benchmark; and perhaps a distraction. I don't know enough about locales to confidently comment; however, it would seem that if you can live without 'use locale;' that would be a good thing (its doco, locale, has warnings about its use). Perhaps try with some of my variations to see if you get different results.

        — Ken

        Some extra runs while not interacting with the machine. Perl is 5.30.0 via perlbrew under WSL.

        perl -v | head -2 | tail -1 This is perl 5, version 30, subversion 0 (v5.30.0) built for x86_64-li +nux

        Results:

        de_DE.iso88591 3,1 3.1 3.1 Rate y_sprintf s_sprintf sprintf y_sprintf 4716774/s -- -33% -63% s_sprintf 7052758/s 50% -- -45% sprintf 12712918/s 170% 80% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4816895/s -- -34% -61% s_sprintf 7286043/s 51% -- -41% sprintf 12366711/s 157% 70% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4919055/s -- -32% -70% s_sprintf 7182801/s 46% -- -55% sprintf 16134317/s 228% 125% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4694110/s -- -31% -65% s_sprintf 6766241/s 44% -- -50% sprintf 13495072/s 187% 99% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4661016/s -- -36% -70% s_sprintf 7310428/s 57% -- -53% sprintf 15604067/s 235% 113% -- Rate y_sprintf s_sprintf sprintf y_sprintf 5036750/s -- -10% -62% s_sprintf 5583036/s 11% -- -58% sprintf 13364520/s 165% 139% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4737843/s -- -39% -61% s_sprintf 7805896/s 65% -- -36% sprintf 12216419/s 158% 57% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4921710/s -- -31% -62% s_sprintf 7171893/s 46% -- -45% sprintf 12952997/s 163% 81% -- Rate y_sprintf s_sprintf sprintf y_sprintf 5370220/s -- -26% -62% s_sprintf 7269597/s 35% -- -49% sprintf 14253514/s 165% 96% -- Rate y_sprintf s_sprintf sprintf y_sprintf 4708990/s -- -33% -63% s_sprintf 6986810/s 48% -- -45% sprintf 12723873/s 170% 82% --

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11119932]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2020-10-01 17:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My favourite web site is:












    Results (16 votes). Check out past polls.

    Notices?